Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | 2x 2x 2x 2x 2x 2x 2x 2x 3x 21x 18x 8x 7x 7x 7x 4x 4x 4x 4x 3x 3x 3x 3x 3x 13x 11x 11x 3x 3x 3x 3x 8x 8x 8x 8x 8x 8x 8x 8x 7x 2x 2x 1x 2x | "use strict";
/**
* @typedef Order
* @type {object}
* @property {string} provider - cloud provider
* @property {number} numNodes - number of nodes
* @property {string} os - operating system
* @property {number} rootVolume - root storage volume in GB
* @property {boolean} shareStorage - if true, head node's storage is shared via NFSv4
* @property {object} headOnlyParam - additional parameters only for head node
* @property {string} publicKey - public key which will be stored in head node
* @property {string} id - id for cloud provider (e.g. access key for AWS)
* @property {string} pw - pw for cloud provider (e.g. secret access key for AWS)
* @property {string } batch - batch system's name
* @property {boolean} runJobOnBatchServer - run jobs on batch server(head node) or not (default true)
* @property {string[]} batchSetupScript - array of commands to be issued after batch server setup
* @property {string[]} packages - array of package names to be installed
* @property {string} mpi - MPI library
* @property {string} compiler - compiler
* @property {string} playbook - playbook which will be run after cluster is up
* @property {function} debug - debug output function
* @property {function} info - info output function
*/
/**
* @typedef Host
* @type {object}
* @property {string} publicNetwork.hostname - hostname in public network
* @property {string} publicNetwork.IP - IP address in public network
* @property {string} privateNetwork.hostname - hostname in private network
* @property {string} privateNetwork.IP - IP address in private network
*/
/**
* @typedef Cluster
* @type {object}
* @property {string} user - username at head node
* @property {string} clusterID - unique string for cluster
* @property {string} privateKey - private key to login to head node. if publicKey is specified in order object, this property is undefined.
* @property {Host[]} headNodes - ip, hostname of head node in public and private network.
* @property {Host[]} childNodes - ip, hostname of child nodes in private network.
* @property {string} id - specified value in order
* @property {string} pw - specified value in order
*/
const Ajv = require("ajv");
const ajv = new Ajv({ useDefaults: true, $data: true });
require("ajv-keywords")(ajv);
const debugLib = require("debug");
const debug = debugLib("abc4:interface");
const info = debugLib("abc4:info");
const { getMethod } = require("./providers/index");
const { idSchema, orderSchema } = require("./validation/index");
/**
* Parse id string and return provider.
* @param {string } id - Id string to be parsed.
* @returns {string } - Provider name.
*/
function getProviderFromID(id) {
return /abc4_([a-z]*)_/.exec(id)[1];
}
function setLogger(opt) {
//set logger function of "debug"
Iif (typeof opt.debug === "function") {
if (!debug.enabled) {
const namespace = debugLib.disable();
debugLib.enable(`abc4:*,${namespace}`);
}
debug.log = opt.debug;
}
//set logger function of "info"
Iif (typeof opt.info === "function") {
if (!info.enabled) {
const namespace = debugLib.disable();
debugLib.enable(`abc4:info,${namespace}`);
}
info.log = opt.info || opt.debug;
}
}
/**
* Perform minimum argument validation and delegate to actual method.
* @param {string} method - Name of method.
* @param {Object} opt - Option object.
* @param {string} opt.clusterID - Id string for cluster which is included in Cluster object.
* @param {string} opt.id - Same as order.id.
* @param {string} opt.pw - Same as order.pw.
* @param {number} opt.n - Num nodes to be increased or decreased (if method is not increase or decrease, this property is ignored).
* @param {Function} opt.debug - Same as order.debug.
* @param {Function} opt.info - Same as order.info.
* @returns {Promise} - Just fullfilled with undefined when method is done.
*/
async function templateCmd(method, opt = {}) {
setLogger(opt);
const clusterID = opt.clusterID;
info(`${method}: ${clusterID}`);
if (!ajv.validate(idSchema, clusterID)) {
const err = new Error("Invalid ID specified");
err.clusterID = clusterID;
debug("invalid id", clusterID);
throw err;
}
const provider = getProviderFromID(clusterID);
const cmd = getMethod(provider, method);
const rt = await cmd(clusterID, opt);
info(`${method} done`);
return rt;
}
/**
* Create HPC cluster on cloud.
* @param {Order} order - Order object for the cluster to build.
* @returns {Cluster} - Cluster object which is just created.
*/
async function create(order) {
setLogger(order);
info(`create ${order.numNodes} node cluster`);
//validate order
if (!ajv.validate(orderSchema, order)) {
const err = new Error("order parse failed");
err.ajv_errors = ajv.errors;
info("invalid order", ajv.errors);
throw err;
}
const provider = order.provider.toLowerCase();
const createCluster = getMethod(provider, "create");
let cluster;
try {
cluster = await createCluster(order);
} catch (e) {
//clean up process must be perfoemed in each createCluster()
//so, just log and re-throw Error here
info("cluster creation failed", e);
throw e;
}
info(`cluster creation done on ${provider}: ${cluster.clusterID}`);
info("but cloud-init process may be still running");
info("you can check it with 'cloud-init status'");
return cluster;
}
/**
* Destroy cluster which was created by create().
* @param {Object} opt
* @returns {boolean} True if all instance is successfully destried.
*/
async function destroy(opt) {
await templateCmd.bind(null, "destroy", opt)();
info("destroy cluster done");
return true;
}
/**
* Destroy cluster which was created by create().
* @param {Object} opt
* @returns {Object} List of instances created by abc4.
*/
async function list(opt) {
return templateCmd.bind(null, "list", opt)();
}
/**
* Increase child node in the cluster.
* @param {Object} opt
* @returns {boolean} True if child node is successfully increased.
*/
async function increase(opt) {
return templateCmd.bind(null, "increase", opt)();
}
/**
* Decrease child node in the cluster.
* @param {Object} opt
* @returns {boolean} True if child node is successfully decreased.
*/
async function decrease(opt) {
return templateCmd.bind(null, "decrease", opt)();
}
/**
* Suspend all nodes in the cluster.
* @param {Object} opt
* @returns {boolean} True if all instance is successfully suspended.
*/
async function suspend(opt) {
return templateCmd.bind(null, "suspend", opt)();
}
/**
* Resume all nodes in the cluster.
* @param {Object} opt
* @returns {boolean} True if all instance is successfully resumed.
*/
async function resume(opt) {
return templateCmd.bind(null, "resume", opt)();
}
module.exports = {
create,
destroy,
list,
increase,
decrease,
suspend,
resume
};
|