UNPKG

mecano

Version:

Common functions for system deployment.

910 lines (886 loc) 30.1 kB
// Generated by CoffeeScript 1.11.1 var Stream, each, exec, file, fs, ini, misc, path, string, tilde, util, slice = [].slice; fs = require('fs'); path = require('path'); each = require('each'); util = require('util'); Stream = require('stream'); exec = require('ssh2-exec'); ini = require('ini'); tilde = require('tilde-expansion'); file = require('./file'); string = require('./string'); misc = module.exports = { array: { flatten: function(arr, ret) { var i, m, ref1; if (ret == null) { ret = []; } for (i = m = 0, ref1 = arr.length; 0 <= ref1 ? m < ref1 : m > ref1; i = 0 <= ref1 ? ++m : --m) { if (Array.isArray(arr[i])) { misc.array.flatten(arr[i], ret); } else { ret.push(arr[i]); } } return ret; }, intersect: function(array) { var argument, i, item, j, len, len1, m, n, result; if (array === null) { return []; } result = []; for (i = m = 0, len = array.length; m < len; i = ++m) { item = array[i]; if (result.indexOf(item) !== -1) { continue; } for (j = n = 0, len1 = arguments.length; n < len1; j = ++n) { argument = arguments[j]; if (argument.indexOf(item) === -1) { break; } } if (j === arguments.length) { result.push(item); } } return result; }, unique: function(array) { var el, len, m, o; o = {}; for (m = 0, len = array.length; m < len; m++) { el = array[m]; o[el] = true; } return Object.keys(o); }, merge: function() { var array, arrays, el, len, len1, m, n, r; arrays = 1 <= arguments.length ? slice.call(arguments, 0) : []; r = []; for (m = 0, len = arrays.length; m < len; m++) { array = arrays[m]; for (n = 0, len1 = array.length; n < len1; n++) { el = array[n]; r.push(el); } } return r; } }, regexp: { escape: function(str) { return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); } }, object: { equals: function(obj1, obj2, keys) { var k, keys1, keys2, len, m; keys1 = Object.keys(obj1); keys2 = Object.keys(obj2); if (keys) { keys1 = keys1.filter(function(k) { return keys.indexOf(k) !== -1; }); keys2 = keys2.filter(function(k) { return keys.indexOf(k) !== -1; }); } else { keys = keys1; } if (keys1.length !== keys2.length) { return false; } for (m = 0, len = keys.length; m < len; m++) { k = keys[m]; if (obj1[k] !== obj2[k]) { return false; } } return true; }, diff: function(obj1, obj2, keys) { var diff, k, keys1, keys2, v; if (!keys) { keys1 = Object.keys(obj1); keys2 = Object.keys(obj2); keys = misc.array.merge(keys1, keys2, misc.array.unique(keys1)); } diff = {}; for (k in obj1) { v = obj1[k]; if (!(keys.indexOf(k) >= 0)) { continue; } if (obj2[k] === v) { continue; } diff[k] = []; diff[k][0] = v; } for (k in obj2) { v = obj2[k]; if (!(keys.indexOf(k) >= 0)) { continue; } if (obj1[k] === v) { continue; } if (diff[k] == null) { diff[k] = []; } diff[k][1] = v; } return diff; }, clone: function(obj) { return misc.merge({}, obj); } }, path: { normalize: function(location, callback) { return tilde(location, function(location) { return callback(path.normalize(location)); }); }, resolve: function() { var callback, locations, m, normalized; locations = 2 <= arguments.length ? slice.call(arguments, 0, m = arguments.length - 1) : (m = 0, []), callback = arguments[m++]; normalized = []; return each(locations).call(function(location, next) { return misc.path.normalize(location, function(location) { normalized.push(location); return next(); }); }).then(function() { return callback(path.resolve.apply(path, normalized)); }); } }, mode: { stringify: function(mode) { if (typeof mode === 'number') { return mode.toString(8); } else { return mode; } }, compare: function() { var i, l, m, mode, modes, ref, ref1; modes = 1 <= arguments.length ? slice.call(arguments, 0) : []; ref = misc.mode.stringify(modes[0]); for (i = m = 1, ref1 = modes.length; 1 <= ref1 ? m < ref1 : m > ref1; i = 1 <= ref1 ? ++m : --m) { mode = misc.mode.stringify(modes[i]); l = Math.min(ref.length, mode.length); if (mode.substr(-l) !== ref.substr(-l)) { return false; } } return true; } }, file: require('./file'), /* `isPortOpen(port, host, callback)`: Check if a port is already open */ isPortOpen: function(port, host, callback) { if (arguments.length === 2) { callback = host; host = '127.0.0.1'; } return exec("nc " + host + " " + port + " < /dev/null", function(err, stdout, stderr) { if (!err) { return callback(null, true); } if (err.code === 1) { return callback(null, false); } return callback(err); }); }, /* `merge([inverse], obj1, obj2, ...]`: Recursively merge objects -------------------------------------------------------------- On matching keys, the last object take precedence over previous ones unless the inverse arguments is provided as true. Only objects are merge, arrays are overwritten. Enrich an existing object with a second one: obj1 = { a_key: 'a value', b_key: 'b value'} obj2 = { b_key: 'new b value'} result = misc.merge obj1, obj2 assert.eql result, obj1 assert.eql obj1.b_key, 'new b value' Create a new object from two objects: obj1 = { a_key: 'a value', b_key: 'b value'} obj2 = { b_key: 'new b value'} result = misc.merge {}, obj1, obj2 assert.eql result.b_key, 'new b value' Using inverse: obj1 = { b_key: 'b value'} obj2 = { a_key: 'a value', b_key: 'new b value'} misc.merge true, obj1, obj2 assert.eql obj1.a_key, 'a value' assert.eql obj1.b_key, 'b value' */ merge: function() { var clone, copy, from, i, inverse, m, name, options, ref1, ref2, src, target, to; target = arguments[0]; from = 1; to = arguments.length; if (typeof target === 'boolean') { inverse = !!target; target = arguments[1]; from = 2; } if (typeof target !== "object" && typeof target !== 'function') { target = {}; } for (i = m = ref1 = from, ref2 = to; ref1 <= ref2 ? m < ref2 : m > ref2; i = ref1 <= ref2 ? ++m : --m) { if ((options = arguments[i]) !== null) { for (name in options) { src = target[name]; copy = options[name]; if (target === copy) { continue; } if ((copy != null) && typeof copy === 'object' && !Array.isArray(copy) && !(copy instanceof RegExp)) { clone = src && (src && typeof src === 'object' ? src : {}); target[name] = misc.merge(false, clone, copy); } else if (copy !== void 0) { if (!(inverse && typeof target[name] !== 'undefined')) { target[name] = copy; } } } } } return target; }, kadmin: function(options, cmd) { var realm; realm = options.realm ? "-r " + options.realm : ''; if (options.kadmin_principal) { return "kadmin " + realm + " -p " + options.kadmin_principal + " -s " + options.kadmin_server + " -w " + options.kadmin_password + " -q '" + cmd + "'"; } else { return "kadmin.local " + realm + " -q '" + cmd + "'"; } }, yaml: { merge: function(original, new_obj, undefinedOnly) { var k, v; for (k in original) { v = original[k]; if (v && typeof v === 'object' && typeof new_obj[k] !== 'undefined') { new_obj[k] = misc.yaml.merge(v, new_obj[k], undefinedOnly); continue; } if (typeof new_obj[k] === 'undefined') { new_obj[k] = v; } } return new_obj; }, clean: function(original, new_obj, undefinedOnly) { var k, v; for (k in original) { v = original[k]; if (v && typeof v === 'object' && new_obj[k]) { original[k] = misc.yaml.clean(v, new_obj[k], undefinedOnly); continue; } if (new_obj[k] === null) { delete original[k]; } } return original; } }, ini: { clean: function(content, undefinedOnly) { var k, v; for (k in content) { v = content[k]; if (v && typeof v === 'object') { content[k] = misc.ini.clean(v, undefinedOnly); continue; } if (typeof v === 'undefined') { delete content[k]; } if (!undefinedOnly && v === null) { delete content[k]; } } return content; }, safe: function(val) { if (typeof val !== "string" || val.match(/[\r\n]/) || val.match(/^\[/) || (val.length > 1 && val.charAt(0) === "\"" && val.slice(-1) === "\"") || val !== val.trim()) { return JSON.stringify(val); } else { return val.replace(/;/g, '\\;'); } }, dotSplit: function (str) { return str.replace(/\1/g, '\2LITERAL\\1LITERAL\2') .replace(/\\\./g, '\1') .split(/\./).map(function (part) { return part.replace(/\1/g, '\\.') .replace(/\2LITERAL\\1LITERAL\2/g, '\1') }) }, parse: function(content, options) { return ini.parse(content); }, /* Each category is surrounded by one or several square brackets. The number of brackets indicates the depth of the category. Options are * `comment` Default to ";" */ parse_multi_brackets: function(str, options) { var comment, current, data, lines, stack; if (options == null) { options = {}; } lines = string.lines(str); current = data = {}; stack = [current]; comment = options.comment || ';'; lines.forEach(function(line, _, __) { var depth, match, parent; if (!line || line.match(/^\s*$/)) { return; } if (match = line.match(/^\s*(\[+)(.+?)(\]+)\s*$/)) { depth = match[1].length; if (depth === stack.length) { parent = stack[depth - 1]; parent[match[2]] = current = {}; stack.push(current); } if (depth > stack.length) { throw new Error("Invalid child " + match[2]); } if (depth < stack.length) { stack.splice(depth, stack.length - depth); parent = stack[depth - 1]; parent[match[2]] = current = {}; return stack.push(current); } } else if (comment && (match = line.match(RegExp("^\\s*(" + comment + ".*)$")))) { return current[match[1]] = null; } else if (match = line.match(/^\s*(.+?)\s*=\s*(.+)\s*$/)) { return current[match[1]] = match[2]; } else if (match = line.match(/^\s*(.+?)\s*$/)) { return current[match[1]] = null; } }); return data; }, /* Same as the parse_multi_brackets instead it takes in count values which are defined on several lines As an example the ambari-agent .ini configuration file * `comment` Default to ";" */ parse_multi_brackets_multi_lines: function(str, options) { var comment, current, data, lines, previous, stack, writing; if (options == null) { options = {}; } lines = string.lines(str); current = data = {}; stack = [current]; comment = options.comment || ';'; writing = false; previous = {}; lines.forEach(function(line, _, __) { var depth, match, parent; if (!line || line.match(/^\s*$/)) { return; } if (match = line.match(/^\s*(\[+)(.+?)(\]+)\s*$/)) { depth = match[1].length; if (depth === stack.length) { parent = stack[depth - 1]; parent[match[2]] = current = {}; stack.push(current); } if (depth > stack.length) { throw new Error("Invalid child " + match[2]); } if (depth < stack.length) { stack.splice(depth, stack.length - depth); parent = stack[depth - 1]; parent[match[2]] = current = {}; return stack.push(current); } } else if (comment && (match = line.match(RegExp("^\\s*(" + comment + ".*)$")))) { writing = false; return current[match[1]] = null; } else if (match = line.match(/^\s*(.+?)\s*=\s*(.+)\s*$/)) { writing = false; current[match[1]] = match[2]; previous = match[1]; return writing = true; } else if (match = line.match(/^\s*(.+?)\s*$/)) { if (writing) { return current[previous] += match[1]; } else { return current[match[1]] = null; } } }); return data; }, stringify: function(obj, section, options) { var children, dotSplit, eol, out, safe; if (options == null) { options = {}; } if (arguments.length === 2) { options = section; section = void 0; } if (options.separator == null) { options.separator = ' = '; } eol = process.platform === "win32" ? "\r\n" : "\n"; safe = misc.ini.safe; dotSplit = misc.ini.dotSplit; children = []; out = ""; Object.keys(obj).forEach(function(k, _, __) { var val; val = obj[k]; if (val && Array.isArray(val)) { return val.forEach(function(item) { return out += safe(k + "[]") + options.separator + safe(item) + "\n"; }); } else if (val && typeof val === "object") { return children.push(k); } else { return out += safe(k) + options.separator + safe(val) + eol; } }); if (section && out.length) { out = "[" + safe(section) + "]" + eol + out; } children.forEach(function(k, _, __) { var child, nk; nk = dotSplit(k).join('\\.'); child = misc.ini.stringify(obj[k], (section ? section + "." : "") + nk, options); if (out.length && child.length) { out += eol; } return out += child; }); return out; }, stringify_single_key: function(obj, section, options) { var children, dotSplit, eol, out, safe; if (options == null) { options = {}; } if (arguments.length === 2) { options = section; section = void 0; } if (options.separator == null) { options.separator = ' = '; } eol = process.platform === "win32" ? "\r\n" : "\n"; safe = misc.ini.safe; dotSplit = misc.ini.dotSplit; children = []; out = ""; Object.keys(obj).forEach(function(k, _, __) { var val; val = obj[k]; if (val && Array.isArray(val)) { return val.forEach(function(item) { return out += val === '' ? ("" + k) + "\n" : safe(k + "[]") + options.separator + safe(item) + "\n"; }); } else if (val && typeof val === "object") { return children.push(k); } else { return out += val === '' ? ("" + k) + eol : safe(k) + options.separator + safe(val) + eol; } }); if (section && out.length) { out = "[" + safe(section) + "]" + eol + out; } children.forEach(function(k, _, __) { var child, nk; nk = dotSplit(k).join('\\.'); child = misc.ini.stringify_single_key(obj[k], (section ? section + "." : "") + nk, options); if (out.length && child.length) { out += eol; } return out += child; }); return out; }, stringify_square_then_curly: function(content, depth, options) { var element, i, indent, isArray, isBoolean, isNull, isObj, k, len, m, n, out, outa, prefix, ref1, v; if (depth == null) { depth = 0; } if (options == null) { options = {}; } if (arguments.length === 2) { options = depth; depth = 0; } if (options.separator == null) { options.separator = ' = '; } out = ''; indent = ' '; prefix = ''; for (i = m = 0, ref1 = depth; 0 <= ref1 ? m < ref1 : m > ref1; i = 0 <= ref1 ? ++m : --m) { prefix += indent; } for (k in content) { v = content[k]; isBoolean = typeof v === 'boolean'; isNull = v === null; isArray = Array.isArray(v); isObj = typeof v === 'object' && !isNull && !isArray; if (isObj) { if (depth === 0) { out += prefix + "[" + k + "]\n"; out += misc.ini.stringify_square_then_curly(v, depth + 1, options); out += "\n"; } else { out += "" + prefix + k + options.separator + "{\n"; out += misc.ini.stringify_square_then_curly(v, depth + 1, options); out += prefix + "}\n"; } } else { if (isArray) { outa = []; for (n = 0, len = v.length; n < len; n++) { element = v[n]; outa.push("" + prefix + k + options.separator + element); } out += outa.join('\n'); } else if (isNull) { out += "" + prefix + k + options.separator + "null"; } else if (isBoolean) { out += "" + prefix + k + options.separator + (v ? 'true' : 'false'); } else { out += "" + prefix + k + options.separator + v; } out += '\n'; } } return out; }, /* Each category is surrounded by one or several square brackets. The number of brackets indicates the depth of the category. Taking now indent option into consideration: some file are indent aware ambari-agent .ini file */ stringify_multi_brackets: function(content, depth, options) { var i, indent, isBoolean, isNull, isObj, k, m, out, prefix, ref1, v; if (depth == null) { depth = 0; } if (options == null) { options = {}; } if (arguments.length === 2) { options = depth; depth = 0; } if (options.separator == null) { options.separator = ' = '; } out = ''; indent = options.indent != null ? options.indent : ' '; prefix = ''; for (i = m = 0, ref1 = depth; 0 <= ref1 ? m < ref1 : m > ref1; i = 0 <= ref1 ? ++m : --m) { prefix += indent; } for (k in content) { v = content[k]; isBoolean = typeof v === 'boolean'; isNull = v === null; isObj = typeof v === 'object' && !isNull; if (isObj) { continue; } if (isNull) { out += "" + prefix + k; } else if (isBoolean) { out += "" + prefix + k + options.separator + (v ? 'true' : 'false'); } else { out += "" + prefix + k + options.separator + v; } out += '\n'; } for (k in content) { v = content[k]; isNull = v === null; isObj = typeof v === 'object' && !isNull; if (!isObj) { continue; } out += "" + prefix + (string.repeat('[', depth + 1)) + k + (string.repeat(']', depth + 1)) + "\n"; out += misc.ini.stringify_multi_brackets(v, depth + 1, options); } return out; } }, cgconfig: { parse: function(str) { var current_controller_name, current_default, current_group, current_group_controller, current_group_name, current_group_perm, current_group_perm_content, current_group_section, current_group_section_perm_name, current_mount, current_mount_section, lines, list_of_group_sections, list_of_mount_sections; lines = string.lines(str); list_of_mount_sections = []; list_of_group_sections = {}; current_mount = false; current_group = false; current_group_name = ''; current_group_controller = false; current_group_perm = false; current_group_perm_content = false; current_default = false; current_mount_section = null; current_group_section = null; current_controller_name = null; current_group_section_perm_name = null; lines.forEach(function(line, _, __) { var base, base1, match, match_admin, name, name1, name2, name3, name4, sep, type, value; if (!line || line.match(/^\s*$/)) { return; } if (!current_mount && !current_group && !current_default) { if (/^mount\s{$/.test(line)) { current_mount = true; current_mount_section = []; } if (/^(group)\s([A-z|0-9|\/]*)\s{$/.test(line)) { current_group = true; match = /^(group)\s([A-z|0-9|\/]*)\s{$/.exec(line); current_group_name = match[2]; current_group_section = {}; if (list_of_group_sections[name1 = "" + current_group_name] == null) { list_of_group_sections[name1] = {}; } } if (/^(default)\s{$/.test(line)) { current_group = true; current_group_name = ''; current_group_section = {}; return list_of_group_sections[name2 = "" + current_group_name] != null ? list_of_group_sections[name2] : list_of_group_sections[name2] = {}; } } else { if (current_mount) { if (/^}$/.test(line)) { list_of_mount_sections.push.apply(list_of_mount_sections, current_mount_section); current_mount = false; current_mount_section = []; } else { line = line.replace(';', ''); sep = '='; if (line.indexOf(':') !== -1) { sep = ':'; } line = line.split(sep); current_mount_section.push({ type: "" + (line[0].trim()), path: "" + (line[1].trim()) }); } } if (current_group) { if (/^(\s*)?}$/.test(line)) { if (current_group) { if (current_group_controller) { return current_group_controller = false; } else if (current_group_perm) { if (current_group_perm_content) { return current_group_perm_content = false; } else { return current_group_perm = false; } } else { current_group = false; return current_group_section = null; } } } else { match = /^\s*(cpuset|cpu|cpuacct|memory|devices|freezer|net_cls|blkio)\s{$/.exec(line); if (!current_group_perm && !current_group_controller) { if (/^\s*perm\s{$/.test(line)) { current_group_perm = true; current_group_section['perm'] = {}; list_of_group_sections["" + current_group_name]['perm'] = {}; } if (match) { current_group_controller = true; current_controller_name = match[1]; current_group_section["" + current_controller_name] = {}; return (base = list_of_group_sections["" + current_group_name])[name3 = "" + current_controller_name] != null ? base[name3] : base[name3] = {}; } } else if (current_group_perm && current_group_perm_content) { line = line.replace(';', ''); line = line.split('='); type = line[0], value = line[1]; current_group_section['perm'][current_group_section_perm_name][type.trim()] = value.trim(); return list_of_group_sections["" + current_group_name]['perm'][current_group_section_perm_name][type.trim()] = value.trim(); } else if (current_group_controller) { line = line.replace(';', ''); sep = '='; if (line.indexOf(':') !== -1) { sep = ':'; } line = line.split(sep); type = line[0], value = line[1]; return (base1 = list_of_group_sections["" + current_group_name]["" + current_controller_name])[name4 = type.trim()] != null ? base1[name4] : base1[name4] = value.trim(); } else { match_admin = /^\s*(admin|task)\s{$/.exec(line); if (match_admin) { _ = match_admin[0], name = match_admin[1]; current_group_perm_content = true; current_group_section_perm_name = name; current_group_section['perm'][name] = {}; return list_of_group_sections["" + current_group_name]['perm'][name] = {}; } } } } } }); return { mounts: list_of_mount_sections, groups: list_of_group_sections }; }, stringify: function(obj, options) { var count, group, group_render, i, indent, k, key, len, m, mount, mount_render, n, name, prop, ref1, ref2, ref3, ref4, ref5, render, sections, val, value; if (options == null) { options = {}; } if (obj.mounts == null) { obj.mounts = []; } if (obj.groups == null) { obj.groups = {}; } render = ""; if (options.indent == null) { options.indent = 2; } indent = ''; for (i = m = 1, ref1 = options.indent; 1 <= ref1 ? m <= ref1 : m >= ref1; i = 1 <= ref1 ? ++m : --m) { indent += ' '; } sections = []; if (obj.mounts.length !== 0) { mount_render = "mount {\n"; ref2 = obj.mounts; for (k = n = 0, len = ref2.length; n < len; k = ++n) { mount = ref2[k]; mount_render += "" + indent + mount.type + " = " + mount.path + ";\n"; } mount_render += '}'; sections.push(mount_render); } count = 0; ref3 = obj.groups; for (name in ref3) { group = ref3[name]; group_render = (name === '') || (name === 'default') ? 'default {\n' : "group " + name + " {\n"; for (key in group) { value = group[key]; if (key === 'perm') { group_render += indent + "perm {\n"; if (value['admin'] != null) { group_render += "" + indent + indent + "admin {\n"; ref4 = value['admin']; for (prop in ref4) { val = ref4[prop]; group_render += "" + indent + indent + indent + prop + " = " + val + ";\n"; } group_render += "" + indent + indent + "}\n"; } if (value['task'] != null) { group_render += "" + indent + indent + "task {\n"; ref5 = value['task']; for (prop in ref5) { val = ref5[prop]; group_render += "" + indent + indent + indent + prop + " = " + val + ";\n"; } group_render += "" + indent + indent + "}\n"; } group_render += indent + "}\n"; } else { group_render += "" + indent + key + " {\n"; for (prop in value) { val = value[prop]; group_render += "" + indent + indent + prop + " = " + val + ";\n"; } group_render += indent + "}\n"; } } group_render += '}'; count++; sections.push(group_render); } return sections.join("\n"); } }, tmpfs: { parse: function(str) { var files, lines; lines = string.lines(str); files = {}; lines.forEach(function(line, _, __) { var age, argu, gid, i, key, mode, mount, obj, ref1, ref2, results, type, uid, values; if (!line || line.match(/^#.*$/)) { return; } values = (ref1 = line.split(/\s+/), type = ref1[0], mount = ref1[1], mode = ref1[2], uid = ref1[3], gid = ref1[4], age = ref1[5], argu = ref1[6], ref1); obj = {}; ref2 = ['type', 'mount', 'perm', 'uid', 'gid', 'age', 'argu']; results = []; for (i in ref2) { key = ref2[i]; obj[key] = values[i] !== void 0 ? values[i] : '-'; if (i === ("" + (values.length - 1))) { if (obj['mount'] != null) { results.push(files[mount] = obj); } else { results.push(void 0); } } else { results.push(void 0); } } return results; }); return files; }, stringify: function(obj) { var i, k, key, lines, ref1, v; lines = []; for (k in obj) { v = obj[k]; ref1 = ['mount', 'perm', 'uid', 'gid', 'age', 'argu']; for (i in ref1) { key = ref1[i]; v[key] = v[key] !== void 0 ? v[key] : '-'; } lines.push(v.type + " " + v.mount + " " + v.perm + " " + v.uid + " " + v.gid + " " + v.age + " " + v.argu); } return lines.join('\n'); } } };