412 lines
22 KiB
HTML
412 lines
22 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
|
<!--
|
|
Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
-->
|
|
<html dir="ltr" lang="en">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
|
|
<title>MySQL Cluster</title>
|
|
<link rel="icon" type="image/x-icon" href="/img/favicon.ico"/>
|
|
<link rel="stylesheet" type="text/css"
|
|
href="dojo/dijit/themes/claro/claro.css"/>
|
|
<link rel="stylesheet" type="text/css" href="css/welcome.css"/>
|
|
<style type="text/css">
|
|
@import "dojo/dojox/form/resources/CheckedMultiSelect.css";
|
|
</style>
|
|
<script type="text/javascript" src="dojo/dojo/dojo.js" djConfig="parseOnLoad: true, locale: 'en'"></script>
|
|
<script type="text/javascript">
|
|
// Path to top level mcc module
|
|
dojo.registerModulePath("mcc", "../../js/mcc");
|
|
dojo.require("dijit.form.Button");
|
|
dojo.require("dojo.dom");
|
|
dojo.require("dojo.dom-construct");
|
|
dojo.require("dojo.domReady!");
|
|
dojo.require("dojox.widget.Standby");
|
|
|
|
// MCC modules immediately required
|
|
if (!!window.MSInputMethodContext && !!document.documentMode) {
|
|
dojo.require("mcc.userconfigIE");
|
|
} else {
|
|
dojo.require("mcc.userconfig");
|
|
}
|
|
function parseURLParams(url) {
|
|
var queryStart = url.indexOf("?") + 1,
|
|
queryEnd = url.indexOf("#") + 1 || url.length + 1,
|
|
query = url.slice(queryStart, queryEnd - 1),
|
|
pairs = query.replace(/\+/g, " ").split("&"),
|
|
parms = {}, i, n, v, nv;
|
|
|
|
if (query === url || query === "") return;
|
|
//Actually there are no K/V pairs in this concrete example.
|
|
//The output is in form of [config1.mcc, config2.mcc,...].
|
|
return pairs;
|
|
}
|
|
var url = window.location.href;
|
|
var cfgList = parseURLParams(url);
|
|
console.debug('[DBG]cfgList: ' + cfgList);
|
|
let picked = 'New configuration';
|
|
var standby = new dojox.widget.Standby({target: "configure-box"});
|
|
|
|
|
|
function doStuff() {
|
|
standby.show();
|
|
|
|
function do_post(msg) {
|
|
// Convert to json string
|
|
var jsonMsg = JSON.stringify(msg); //dojo.toJson(msg);
|
|
//var dbgMsg = JSON.stringify(msg); //dojo.toJson(msg);
|
|
// Return deferred from xhrPost
|
|
return dojo.xhrPost({
|
|
url: "/cmd",
|
|
headers: { "Content-Type": "application/json" },
|
|
postData: jsonMsg,
|
|
handleAs: "json"
|
|
});
|
|
}
|
|
// Generic error handler closure
|
|
function errorHandler(req, onError) {
|
|
if (onError) {
|
|
return onError;
|
|
} else {
|
|
return function (error) {
|
|
console.error("An error occurred while executing '" + req.cmd +
|
|
" (" + req.seq + ")': " + error);
|
|
};
|
|
}
|
|
}
|
|
|
|
// Generic reply handler closure
|
|
function replyHandler(onReply, onError) {
|
|
return function (reply) {
|
|
if (reply && reply.stat && reply.stat.errMsg != "OK") {
|
|
if (onError) {
|
|
onError(reply.stat.errMsg, reply);
|
|
} else {
|
|
alert(reply.stat.errMsg);
|
|
}
|
|
} else {
|
|
try{
|
|
onReply(reply);
|
|
} catch (E) {
|
|
alert("Error in formatting reply.");
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
function cffileExistsReq(mesg, onReply, onError) {
|
|
console.debug("[DBG]Composing cffileExistsReq message for host localhost.");
|
|
var ms = mesg;
|
|
// Call do_post, provide callbacks
|
|
do_post(ms).then(replyHandler(onReply, onError),
|
|
errorHandler(ms.head, onError));
|
|
}
|
|
function createCfgFileReq(mesg, onReply, onError) {
|
|
console.debug("[DBG]Composing createCfgFileReq message for host localhost.");
|
|
var ms = mesg;
|
|
// Call do_post, provide callbacks
|
|
do_post(ms).then(replyHandler(onReply, onError),
|
|
errorHandler(ms.head, onError));
|
|
}
|
|
function readCfgFileReq(mesg, onReply, onError) {
|
|
console.debug("[DBG]Composing readCfgFileReq message for host localhost.");
|
|
var ms = mesg;
|
|
// Call do_post, provide callbacks
|
|
do_post(ms).then(replyHandler(onReply, onError),
|
|
errorHandler(ms.head, onError));
|
|
}
|
|
|
|
var cf = picked;
|
|
if (cf) {
|
|
if (cf == 'New configuration') {
|
|
cf = "NewConfig";
|
|
cf = prompt("Please provide the name for new configuration file: ");
|
|
if (cf == null || cf == "") {
|
|
//Cancelled or empty.
|
|
console.warn("window.location.reload() - CF name NULL or EMPTY");
|
|
standby.hide();
|
|
window.location.reload();
|
|
return;
|
|
}
|
|
}
|
|
// We are no longer sending cfgname.MCC from back end!
|
|
if ( /\.(mcc)$/i.test(cf) === false ) {
|
|
cf += '.mcc';
|
|
}
|
|
mcc.userconfig.setConfigFile(cf);
|
|
|
|
var defCfg = mcc.userconfig.getDefaultCfg();
|
|
var fileExists = false;
|
|
var res = new dojo.Deferred();
|
|
var msg = {
|
|
head: {cmd: "cffileExistsReq", seq: 0},
|
|
body: {
|
|
ssh: {keyBased: false, user: "", pwd: ""},
|
|
hostName: 'localhost',
|
|
path: "~",
|
|
fname: cf
|
|
}
|
|
};
|
|
cffileExistsReq(
|
|
msg,
|
|
function (reply) {
|
|
//File with that name already exists. Will load that later on.
|
|
console.debug("[DBG]reply.body.hostRes.exists is: " + reply.body.hostRes.exists);
|
|
fileExists = reply.body.hostRes.exists == 1;
|
|
res.resolve(true);
|
|
return res;
|
|
},
|
|
function (errMsg, reply) {
|
|
console.error("Error happened while checking for existence of " + cf + ' file!'+
|
|
"Error message is: " + errMsg);
|
|
alert("Error happened while checking for existence of " + cf + ' file!'+
|
|
"Error message is: " + errMsg);
|
|
res.resolve(false);
|
|
return res;
|
|
}
|
|
);
|
|
res.then(function(success){
|
|
console.debug("[DBG]cffileExistsReq success: ", success);
|
|
return true;
|
|
}, function(error){
|
|
console.error("cffileExistsReq error: ", error);
|
|
return false;
|
|
}).then(function(info){
|
|
console.debug("[DBG]cffileExistsReq has finished with success status: " + info);
|
|
if (info) {
|
|
//var cfNoExt = cf.substr(0, cf.lastIndexOf('.')) || cf;
|
|
console.debug("[DBG]FileExists is NOT " + (!fileExists));
|
|
if (!fileExists) {
|
|
var res2 = new dojo.Deferred();
|
|
console.debug("[DBG]Config doesn't exit. Creating file, writing defaults.");
|
|
//Fill new config with predefined defaults:
|
|
msg = {
|
|
head: {cmd: "createCfgFileReq", seq: 1},
|
|
body: {
|
|
ssh: {keyBased: false, user: "", pwd: ""},
|
|
hostName: 'localhost',
|
|
path: "~",
|
|
fname: cf,
|
|
contentString: defCfg,
|
|
phr: ""
|
|
}
|
|
};
|
|
createCfgFileReq(
|
|
msg,
|
|
function (resFNC) {
|
|
console.debug("[DBG]Configuration didn't exits. Created.");
|
|
res2.resolve(true);
|
|
return res2;
|
|
},
|
|
function (errMsgFNC) {
|
|
console.error("Unable to create config file " + cf+ " in HOME directory: " + errMsgFNC);
|
|
//This is bad, bail out and just work from tree.
|
|
cf = "";
|
|
res2.resolve(false);
|
|
return res2;
|
|
}
|
|
);
|
|
res2.then(function(success1){
|
|
console.debug("[DBG]createCfgFileReq success: ", success1);
|
|
return true;
|
|
}, function(error1){
|
|
console.error("createCfgFileReq error: ", error1);
|
|
return false;
|
|
}).then(function(info1){
|
|
console.debug("[DBG]createCfgFileReq has finished with success status: ", info1);
|
|
if (info1) {
|
|
console.debug("[DBG]Setting global conf file.");
|
|
mcc.userconfig.setConfigFile(cf);
|
|
mcc.userconfig.setConfigFileContents(defCfg);
|
|
window.name = JSON.stringify({
|
|
"CFC": mcc.userconfig.getConfigFileContents(),
|
|
"CF": cf,
|
|
"CFPP": ""});
|
|
standby.hide();
|
|
window.open('content.html', '_self');
|
|
}
|
|
});
|
|
} else {
|
|
console.debug("[DBG]Reading from existing config file.");
|
|
console.debug("[DBG]Setting global conf file.");
|
|
mcc.userconfig.setConfigFile(cf);
|
|
msg = {
|
|
head: {cmd: "readCfgFileReq", seq: 1},
|
|
body: {
|
|
ssh: {keyBased: false, user: "", pwd: ""},
|
|
hostName: 'localhost',
|
|
path: "~",
|
|
fname: cf,
|
|
phr: ""
|
|
}
|
|
};
|
|
readCfgFileReq(
|
|
msg,
|
|
function (reply) {
|
|
console.debug("[DBG]readCfgFileReq has finished with success.");
|
|
// Just in case someone thinks it's funny to create empty mcc file...
|
|
if (reply.body.hostRes.contentString.length > 10) {
|
|
// "Someone" thought _on_ would be nice value for Boolean.
|
|
// Now have to convert to _true_.
|
|
mcc.userconfig.setConfigFileContents(
|
|
reply.body.hostRes.contentString.replace(/"on"/g, 'true'));
|
|
} else {
|
|
mcc.userconfig.setConfigFileContents(defCfg);
|
|
}
|
|
window.name = JSON.stringify({
|
|
"CFC": mcc.userconfig.getConfigFileContents(),
|
|
"CF": cf,
|
|
"CFPP": ""});
|
|
standby.hide();
|
|
window.open('content.html', '_self');
|
|
},
|
|
function (errMsgFNC) {
|
|
console.error("window.location.reload() - errMsgFNC");
|
|
standby.hide();
|
|
alert("Unable to read config file " + cf +
|
|
" in HOME directory: " + errMsgFNC);
|
|
//This is bad, bail out and just work from tree.
|
|
cf = "";
|
|
window.location.reload();
|
|
return;
|
|
}
|
|
);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
console.debug("[DBG]window.location.reload() - LAST");
|
|
standby.hide();
|
|
window.location.reload();
|
|
return;
|
|
}
|
|
} //doStuff()
|
|
|
|
dojo.ready(function() {
|
|
// Check browser type
|
|
var supportedUa = navigator.userAgent.match(/firefox|safari|chrome|msie/gi);
|
|
|
|
console.debug("[DBG]Browser application name is " + navigator.appName);
|
|
console.debug("[DBG]Browser application version is " + navigator.appVersion);
|
|
console.debug("[DBG]User agent string is: " + navigator.userAgent);
|
|
console.debug("[DBG]User agent " + supportedUa + " is supported");
|
|
|
|
if (!supportedUa) {
|
|
alert("You seem to be using a " + navigator.appName +
|
|
" browser, which is currently not supported by the " +
|
|
"MySQL Cluster configuration tool. You may choose to " +
|
|
"continue anyway, but beware that the tool may not " +
|
|
"work as intended.");
|
|
}
|
|
|
|
document.body.appendChild(standby.domNode);
|
|
standby.startup();
|
|
|
|
// No need to send path along as it is always HOME.
|
|
function populateMultiSelect(optionData){
|
|
require([
|
|
"dojox/form/CheckedMultiSelect",
|
|
"dojo/dom", "dojo/_base/window", "dojo/domReady!"
|
|
], function(CheckedMultiSelect, dom, win){
|
|
var sel = dojo.byId('sid1');
|
|
var ss1 = new CheckedMultiSelect({
|
|
name: 'sid1',
|
|
options: optionData,
|
|
onChange: function(val){
|
|
picked = val;
|
|
console.debug("[DBG]PICKED: " + picked);
|
|
},
|
|
multiple: false,
|
|
class: "narrow wrap",
|
|
style: "white-space: normal; height: 85%;"
|
|
}, sel);
|
|
ss1.startup();
|
|
document.getElementById("sid1").focus();
|
|
ss1.on("keydown", function(e) {
|
|
console.debug("[DBG]CMS.keydown");
|
|
switch(e.keyCode) {
|
|
case dojo.keys.ENTER:
|
|
dojo.stopEvent(e);
|
|
console.debug("[DBG]CMS.keydown ENTER");
|
|
break;
|
|
case dojo.keys.TAB:
|
|
dojo.stopEvent(e);
|
|
console.debug("[DBG]CMS.keydown TAB");
|
|
break;
|
|
default:
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
var opts = new Array();
|
|
opts.push(
|
|
{value: "New configuration",
|
|
label: "New configuration",
|
|
selected: true}
|
|
);
|
|
|
|
if (cfgList) {
|
|
console.debug("[DBG]Found " + cfgList.length + " configurations.");
|
|
console.info('List of configurations found: %s', cfgList);
|
|
for (var i = 0; i < cfgList.length; i++) {
|
|
opts.push({value:cfgList[i], label:cfgList[i]});
|
|
}
|
|
} else {
|
|
console.warn("No existing configurations found.");
|
|
}
|
|
populateMultiSelect(opts);
|
|
});
|
|
</script>
|
|
</head>
|
|
<body class="claro">
|
|
<!-- Welcome title image -->
|
|
<div id="title"><img alt="Oracle logo" src="img/welcome-title.png"></div>
|
|
<!-- Big MySQL Logo image in the background -->
|
|
<div id="mysql-logo"><img alt="MySQL logo" src="img/welcome-mysql-logo.png"></div>
|
|
<!-- Configuration box: Start from scratch or continue -->
|
|
<div id="configure-box-wrapper" style="display: flex; flex-wrap: nowrap;top: 300px">
|
|
<div id="intro-box" style="width: -webkit-fill-available; display: flow-root; margin-right: 2%; height: 400px; font-size: large;color: wheat;">
|
|
<h2> MCC quick reference:</h2>
|
|
<p> ➤ Create <b>New configuration</b> or resume work on existing one by picking it from the list.</p>
|
|
<p> ➤ RUN configuration will load it from disk to MCC and allow you to continue working on/with it.</p>
|
|
<p> ➤ SECURITY: The configuration files are located in your HOME/.mcc directory and stored in plain text. Configuration files do not store sensitive information, like passwords, but do store user names and External/Internal IP addresses of hosts.</p>
|
|
<p> ➤ SECURITY: Please use properly signed certificate to encrypt communication between front and back end.</p>
|
|
<p> ➤ Make sure to allow pop-up windows in the browser where MCC runs as we communicate important things using that mechanism.</p>
|
|
</div>
|
|
<div id="configure-box" style="margin: 5px auto; height: 400px; float: right;position: relative">
|
|
<div id = "configListContainer" style="width: 95%; height: 85%;margin: 10 auto;float: left;text-align: left;border: 0;">
|
|
<select id="sid1" class="narrow wrap"></select>
|
|
</div>
|
|
<div id = "configBtnContainer" style="width: 95%; margin: 10 auto; position: absolute; bottom: 0;">
|
|
<button
|
|
type="button"
|
|
id="createNewCluster"
|
|
style="width: 100%;height: 80%;margin: 5 auto;float: left;text-align: center;border: 2px solid;background-color: #011D33;font-size: large;"
|
|
>RUN configuration
|
|
</button>
|
|
<script type="text/javascript">
|
|
function clickRunB() {
|
|
doStuff();
|
|
}
|
|
document.getElementById("createNewCluster").addEventListener("click", clickRunB);
|
|
</script>
|
|
</div>
|
|
</div><!--CONFIGUREBOX-->
|
|
</div> <!--CONFIGUREBOX WRAPPER-->
|
|
</body>
|
|
</html>
|