1
0
Fork 0
arangodb/js/server/modules/org/arangodb/cluster/kickstarter.js

304 lines
9.5 KiB
JavaScript

/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, stupid: true */
/*global module, require, exports, ArangoAgency, SYS_TEST_PORT */
////////////////////////////////////////////////////////////////////////////////
/// @brief Cluster kickstarting functionality using dispatchers
///
/// @file js/server/modules/org/arangodb/cluster/kickstarter.js
///
/// DISCLAIMER
///
/// Copyright 2014 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Kickstarter functionality
// -----------------------------------------------------------------------------
var download = require("internal").download;
var executeExternal = require("internal").executeExternal;
var fs = require("fs");
var wait = require("internal").wait;
var exchangePort = require("org/arangodb/cluster/planner").exchangePort;
var print = require("internal").print;
var actions = {};
function getAddrPort (endpoint) {
var pos = endpoint.indexOf("://");
if (pos !== -1) {
return endpoint.substr(pos+3);
}
return endpoint;
}
function getAddr (endpoint) {
var addrPort = getAddrPort(endpoint);
var pos = addrPort.indexOf(":");
if (pos !== -1) {
return addrPort.substr(0,pos);
}
return addrPort;
}
function getPort (endpoint) {
var pos = endpoint.lastIndexOf(":");
if (pos !== -1) {
return parseInt(endpoint.substr(pos+1),10);
}
return 8529;
}
actions.startAgent = function (dispatchers, cmd) {
var agentDataDir = fs.join(cmd.dataPath,
"agent"+cmd.agencyPrefix+cmd.extPort);
if (fs.exists(agentDataDir)) {
fs.removeDirectoryRecursive(agentDataDir,true);
}
var args = ["-data-dir", agentDataDir,
"-name", "agent"+cmd.agencyPrefix+cmd.extPort,
"-bind-addr", (cmd.onlyLocalhost ? "127.0.0.1:"
: "0.0.0.0:")+cmd.extPort,
"-addr", getAddrPort(
exchangePort(dispatchers[cmd.dispatcher].endpoint,
cmd.extPort)),
"-peer-bind-addr", (cmd.onlyLocalhost ? "127.0.0.1:"
: "0.0.0.0:")+cmd.intPort,
"-peer-addr", getAddrPort(
exchangePort(dispatchers[cmd.dispatcher].endpoint,
cmd.intPort)) ];
var i;
if (cmd.peers.length > 0) {
args.push("-peers");
var st = getAddrPort(cmd.peers[0]);
for (i = 1; i < cmd.peers.length; i++) {
st = st + "," + getAddrPort(cmd.peers[i]);
}
args.push(getAddrPort(cmd.peers[0]));
}
var pid = executeExternal(cmd.agentPath, args);
var res;
while (true) {
wait(0.5); // Wait a bit to give it time to startup
res = download("http://localhost:"+cmd.extPort+"/v2/keys/");
if (res.code === 200) {
return {"error":false, "isAgent": true, "pid": pid};
}
}
};
function encode (st) {
var st2 = "";
var i;
for (i = 0; i < st.length; i++) {
if (st[i] === "_") {
st2 += "@U";
}
else if (st[i] === "@") {
st2 += "@@";
}
else {
st2 += st[i];
}
}
return encodeURIComponent(st2);
}
function sendToAgency (agencyURL, path, obj) {
var res;
var body;
print("Sending ",path," to agency...");
if (typeof obj === "string") {
var count = 0;
while (count++ <= 2) {
body = "value="+encodeURIComponent(obj);
//print("sending:",agencyURL+path,"\nwith body",body);
res = download(agencyURL+path,body,
{"method":"PUT", "followRedirects": true,
"headers": { "Content-Type": "application/x-www-form-urlencoded"}});
//print("Code ", res.code);
if (res.code === 201) {
return true;
}
}
return res;
}
if (typeof obj !== "object") {
return "Strange object found: not a string or object";
}
var keys = Object.keys(obj);
var i;
if (keys.length !== 0) {
for (i = 0; i < keys.length; i++) {
res = sendToAgency (agencyURL, path+"/"+encode(keys[i]), obj[keys[i]]);
if (res !== true) {
return res;
}
}
return true;
}
// Create a directory
var count2 = 0;
while (count2++ <= 2) {
body = "dir=true";
res = download(agencyURL+path,body,
{"method": "PUT", "followRedirects": true,
"headers": { "Content-Type": "application/x-www-form-urlencoded"}});
if (res.code === 201) {
return true;
}
}
return res;
}
actions.sendConfiguration = function (dispatchers, cmd) {
var url = "http://"+getAddrPort(cmd.agency.endpoints[0])+"/v2/keys";
var res = sendToAgency(url, "", cmd.data);
if (res === true) {
return {"error":false, "isAgencyConfiguration": true};
}
return {"error":true, "isAgencyConfiguration": true, "suberror": res};
};
actions.startLauncher = function (dispatchers, cmd) {
var url = "http://"+getAddrPort(cmd.agency.endpoints[0])+"/v2/keys/"+
cmd.agency.agencyPrefix+"/";
print("Downloading ",url+"Launchers/"+cmd.name);
var res = download(url+"Launchers/"+cmd.name,"",{method:"GET",
followRedirects:true});
if (res.code !== 200) {
return {"error": true, "isStartLauncher": true, "suberror": res};
}
var body = JSON.parse( res.body );
var info = JSON.parse(body.node.value);
var id,ep,args,pids,port;
print("Starting servers...");
var i;
print(info);
var servers = info.DBservers.concat(info.Coordinators);
pids = [];
for (i = 0; i < servers.length; i++) {
id = servers[i];
print("Downloading ",url+"Target/MapIDToEndpoint/"+id);
res = download(url+"Target/MapIDToEndpoint/"+id);
if (res.code !== 200) {
return {"error": true, "pids": pids,
"isStartLauncher": true, "suberror": res};
}
print("Starting server ",id);
body = JSON.parse(res.body);
ep = JSON.parse(body.node.value);
port = getPort(ep);
args = ["--cluster.my-id", id,
"--cluster.agency-prefix", cmd.agency.agencyPrefix,
"--cluster.agency-endpoint", cmd.agency.endpoints[0],
"--server.endpoint"];
if (cmd.onlyLocalhost) {
args.push("tcp://127.0.0.1:"+port);
}
else {
args.push("tcp://0.0.0.0:"+port);
}
args.push("--log.file");
var logfile = fs.join(cmd.dataPath,"log-"+cmd.agency.agencyPrefix+"-"+id);
if (fs.exists(logfile)) {
fs.remove(logfile);
}
args.push(logfile);
var datadir = fs.join(cmd.dataPath,"data-"+cmd.agency.agencyPrefix+"-"+id);
if (fs.exists(datadir)) {
fs.removeDirectoryRecursive(datadir,true);
}
fs.makeDirectory(datadir);
args.push(datadir);
pids.push(executeExternal(cmd.arangodPath, args));
}
return {"error": false, "pids": pids};
};
function Kickstarter (startupPlan) {
this.startupPlan = startupPlan;
if (!startupPlan.hasOwnProperty("myname")) {
startupPlan.myname = "me";
}
}
Kickstarter.prototype.launch = function () {
var startupPlan = this.startupPlan;
var myname = startupPlan.myname;
var dispatchers = startupPlan.dispatchers;
var cmds = startupPlan.commands;
var results = [];
var cmd;
var error = false;
var i;
for (i = 0; i < cmds.length; i++) {
cmd = cmds[i];
if (cmd.dispatcher === undefined || cmd.dispatcher === myname) {
var res = actions[cmd.action](dispatchers, cmd);
results.push(res);
if (res.error === true) {
error = true;
break;
}
}
else {
var ep = dispatchers[cmd.dispatcher].endpoint;
var body = JSON.stringify({ "dispatchers": dispatchers,
"commands": [cmd],
"myname": cmd.dispatcher });
var url = "http" + ep.substr(3) + "/_admin/dispatch";
var response = download(url, body, {"method": "post"});
try {
if (response.code !== 200) {
error = true;
}
results.push(JSON.parse(response.body));
}
catch (err) {
results.push({"error":true, "errorMessage": "exception in JSON.parse"});
error = true;
break;
}
}
}
if (error) {
return {"error": true, "errorMessage": "some error during launch",
"results": results};
}
return {"error": false, "errorMessage": "none",
"results": results};
};
exports.Kickstarter = Kickstarter;
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
/// Local Variables:
/// mode: outline-minor
/// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
/// End: