acs
Version:
Appcelerator Server Side Node
462 lines (414 loc) • 20.5 kB
JavaScript
'use strict';
/**
* nettle - a command line for ACS custom node.js services Appcelerator
* Proprietary - DO NOT REDISTRIBUTE Copyright (c) 2012 by Appcelerator, Inc.
*/
var program = require('commander'),
u = require('./util.js'),
logger = require('./logger'),
ccommander = require('./ccommander'),
nettleLogger = require('./nettlelogger'),
colors = require('colors'),
_ = require('underscore'),
pkginfo = require('pkginfo')(module, 'name', 'version');
program.name = 'ack';
exports.toString = function() {
return program.name;
};
ccommander.customize(program, copyright);
program.version(module.exports.version, '-v, --version')
.description('Deploy multiple containerized apps to AMPLIFY Runtime Services or Kubernetes')
.usage('[COMMAND] [COMMON OPTIONS]')
.option('--host <ars-api-host>', 'Host of ARS API server')
.option('--port <ars-api-port>', 'Port of ARS API server')
.option('-b, --no-colors', 'Turn off colors')
.option('--no-banner', 'Turn off banner')
.option('-l, --loglevel <level>', 'Level for logging: fatal, error, warn, info, debug, trace. default: info')
.option('--dates', 'Turn on dates in logging');
program.removeAllListeners('version');
program.on('version', function() {
var args = _.rest(program.rawArgs, 2);
if (program.rawArgs.length > 5 || _.difference(args, ['-v', '--version', '-nc', '--no-colors', '--no-banner']).length > 0) {
console.log('-v, --version can not be used with options other than \'--no-colors\' and \'--no-banner\'.');
} else {
console.log(program._version);
}
process.exit(0);
});
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ack commands >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
program.command('new <name>')
.description('Create a new helm chart from the built-in template')
.aliases(['create'])
.option('-d, --dir <path>', 'Specify a path where the chart will be created')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.dir = cmd.dir;
});
program.command('list [name]')
.description('List namespaces or check a specific namespace')
.aliases(['ls'])
.option('-o, --org <orgid>', 'Specify the organization for the namespace')
.option('-m, --mine', 'List namespaces created by the current user only')
.option('--start-date <start-date>', 'Specify start date for namespaces')
.option('--end-date <end-date>', 'Specify end date for namespaces')
.option('--per-page <per-page>', 'Specify item number in a single page, defaults to 100')
.option('--more', 'Get next page of namespaces')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.org = cmd.org;
this.mine = cmd.mine;
this.start_date = cmd.startDate;
this.end_date = cmd.endDate;
this.per_page = cmd.perPage;
this.more = cmd.more;
});
var getCmd = program.command('get [type] [name]')
.description('Get details of a release')
.detail('The "type" argument specifies the type of information to check. ' +
'Supported types fall into 2 groups: ' +
'\n Helm release data: status, history, hooks, manifest, notes, values' +
'\n Deployed resources: ingresses(ing), services(svc), pods(po), deployments(deploy), replicasets(rs), statefulsets(sts), jobs, horizontalpodautoscalers(hpa), all')
.option('-n, --namespace <namespace-name>', 'Specify the namespace to check its release')
.option('-o, --output <format>', 'Specify the output format (list|table|json)')
.option('-a, --all', 'Dump all (computed) values (for "get values" only)')
.option('-r, --release <release-name>', 'Specify the release name for checking certificate secret')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.output = cmd.output;
this.all = cmd.all;
this.release = cmd.release;
});
getCmd.command('cert <certname>')
.description('Show the secret holding the specified certificate')
.option('-n, --namespace <namespace-name>', 'The namespace for the certificate')
.action(function(args) {
var cmd = this.getChildCommand('cert');
program.namespace = cmd.namespace;
});
program.command('init <namespace>')
.description('Create a new namespace')
.option('-o, --org <orgid>', 'Specify the organization for the namespace')
.option('-s, --size <serversize>', 'Specify the default server size for the workloads in this namespace. Available options: \'Dev\' \'Small\' \'Medium\' \'Large\' \'XLarge\'.')
.option(' --proxy <proxy enabler>', 'Specify if proxy is required for application deployment. This option leads to access log unavailable. Available options : \'true\' or \'false\'.')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.org = cmd.org;
this.size = cmd.size;
this.proxy = cmd.proxy;
});
var installCmd = program.command('install <release-name>')
.description('Install new release')
.option('-n, --namespace <namespace-name>', 'Specify the namespace to install the chart to')
.option('-f, --file <chart-path>', 'Specify the path to the chart package or directory')
.option(' --values <chart-values-file-path>', 'Specify the path to the chart values file')
.option('--force', 'Proceed with install even when there are existing resources in the namespace')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.chartFilePath = cmd.file;
this.chartValues = cmd.values;
this.force = cmd.force;
});
installCmd.command('cert <certname>')
.description('Add a certificate by installing a helm release holding a secret for it')
.option('-n, --namespace <namespace-name>', 'The namespace for the certificate')
.option('--cert <certfile>', 'The certificate file for creating a TLS secret')
.option('--key <keyfile>', 'The key file for creating a TLS secret')
.option('--file <cert-archive>', 'The certificate archive file (e.g. .p12 or .pfx file) that includes certificate, key, and any intermediate certificates')
.option('-y, --yes', 'Skip asking for confirmation')
.action(function(args) {
// args include arguments after command name 'add'
// If a command does not need any argument args will include the Command object only.
// get current command. 'this' is parent Command object
var cmd = this.getChildCommand('cert');
program.namespace = cmd.namespace;
});
var updateCmd = program.command('update <namespace|release> <name>')
.description('Update a namespace or a release')
.option('-o, --org <orgid>', 'Specify the organization for the namespace to update')
.option('-s, --size <serversize>', 'Specify the default server size for updating namespace. Available options: \'Dev\' \'Small\' \'Medium\' \'Large\' \'XLarge\'.')
.option('-n, --namespace <namespace-name>', 'Specify the namespace for the release to update')
.option('-f, --file <chart-file-path>', 'Specify the path to the chart package or directory')
.option(' --values <chart-values-file-path>', 'Specify the path to the chart values file')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.org = cmd.org;
this.size = cmd.size;
this.namespace = cmd.namespace;
this.chartFilePath = cmd.file;
this.chartValues = cmd.values;
});
updateCmd.command('cert <certname>')
.description('Update a certificate by upgrading the helm release holding it')
.option('-n, --namespace <namespace-name>', 'The namespace for the certificate')
.option('--cert <certfile>', 'The certificate file for updating a TLS secret')
.option('--key <keyfile>', 'The key file for updating a TLS secret')
.option('--file <cert-archive>', 'The certificate archive file (e.g. .p12 or .pfx file) that includes certificate, key, and any intermediate certificates')
.option('-y, --yes', 'Skip asking for confirmation')
.action(function(args) {
var cmd = this.getChildCommand('cert');
program.namespace = cmd.namespace;
});
program.command('rollback <release-name>')
.description('Rollback a release to a specific revision')
.option('-n, --namespace <namespace-name>', 'Specify the namespace for the release.')
.option('-r, --revision <revision>', 'Specify the revision to rollback to')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.revision = cmd.revision;
});
var removeCmd = program.command('remove <namespace|release|hpa> <name>')
.description('Delete a namespace, release, or horizontalpodautoscalers(hpa)')
.aliases(['rm', 'delete'])
.option('-o, --org <orgid>', 'Specify the organization for the namespace')
.option('-n, --namespace <namespace-name>', 'The namespace for the release to delete')
.option('-f, --force', 'Delete releases that may be in inconsistent state')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.org = cmd.org;
this.namespace = cmd.namespace;
this.force = cmd.force;
});
removeCmd.command('cert <certname>')
.description('Delete the helm release holding the specified certificate')
.option('-n, --namespace <namespace-name>', 'The namespace for the certificate')
.option('-y, --yes', 'Skip asking for confirmation')
.action(function(args) {
var cmd = this.getChildCommand('cert');
program.namespace = cmd.namespace;
});
program.command('clean <namespace>')
.description('Delete all resources in a namespace')
.detail('This is meant for cleaning the left (orphan) resources after "ack rm release".')
.option('-o, --org <orgid>', 'Specify the organization for the namespace')
.option('-f, --force', 'Delete resources without asking for confirmation')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.org = cmd.org;
this.force = cmd.force;
});
program.command('config [kubeconfigfile]')
.description('Config the specified or default (~/.acs.kube) kubeconfig file')
.option('-g, --generate', 'Generate a new kubeconfig file')
.option('-n, --namespace <namespace>', 'Set default namespace in the kubeconfig file')
.option('-t, --token', 'Update token in the kubeconfig file')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.generate = cmd.generate;
this.namespace = cmd.namespace;
this.token = cmd.token;
});
program.command('publish <appname>')
.description('Publish a docker image to ARS')
.detail('* A helm chart will be created for deploying the docker image to ARS.\n'
+ ' * The docker image will be retagged as <ARS-registry-domain>/<orgid>/<appname>:<app-version> and pushed to the ARS docker registry.')
.option('-n, --namespace <namespace-name>', 'Specify the namespace to publish to')
.option('--image <name[:tag]>', 'The name of the docker image. Will use \'latest\' if tag is not specified.')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.org = cmd.org;
this.image = cmd.image;
});
program.command('log')
.description('List console logs of pods and their containers')
.option('-n, --namespace <namespace-name>', 'Specify the namespace to get logs')
.option('-d, --controller-name <controller-name>', 'Filter logs by deployment/statefultset/job/cronjob name')
.option('-p, --pod <pod-name>', 'Filter logs by pod name')
.option('-c, --container <container-name>', 'Filter logs by container name')
.option('--show-pod-containers', 'Show pod and container name in logs')
.option('--start-date <start-date>', 'Specify start date for logs')
.option('--end-date <end-date>', 'Specify end date for logs')
.option('--per-page <per-page>', 'Specify item number in a single page, defaults to 100')
.option('--more', 'Get next page of log entries')
.option('--tail', 'Tail the log entries, tailing will ignore --start-date, --end-date, --per-page, and --more options')
.option('--tail-interval <tail-interval>', 'Tail the log entries with the specified interval(in seconds)')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.ars_deployment_name = cmd.controllerName;
this.pod = cmd.pod;
this.container = cmd.container;
this.show_pod_containers = cmd.showPodContainers;
this.start_date = cmd.startDate;
this.end_date = cmd.endDate;
this.per_page = cmd.perPage;
this.more = cmd.more;
this.tail = cmd.tail;
this.tail_interval = cmd.tailInterval;
});
program.command('accesslog')
.description('List access logs of all pods')
.option('-n, --namespace <namespace-name>', 'Specify the namespace to get access logs')
.option('-d, --controller-name <controller-name>', 'Filter access logs by deployment/statefultset name')
.option('--serverid <serverid>', 'Filter access logs by serverid (pod)')
.option('--show-serverid', 'Show serverid (pod) in access logs')
.option('--start-date <start-date>', 'Specify start date for access logs')
.option('--end-date <end-date>', 'Specify end date for access logs')
.option('--per-page <per-page>', 'Specify item number in a single page, defaults to 100')
.option('--more', 'Get next page of log entries')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.serverid = cmd.serverid;
this.ars_deployment_name = cmd.controllerName;
this.show_serverid = cmd.showServerid;
this.start_date = cmd.startDate;
this.end_date = cmd.endDate;
this.per_page = cmd.perPage;
this.more = cmd.more;
});
program.command('usage')
.description('List the resource usage of containers in a helm release')
.option('-n, --namespace <namespace-name>', 'Specify the namespace to get resource usage')
.option('-d, --controller-name <controller-name>', 'Filter resource usage by deployment/statefultset/job/cronjob name')
.option('-c, --container <container-name>', 'Filter resource usage by container name')
.option('--serverid <serverid>', 'Filter resource usage by serverid (pod)')
.option('--show-serverid', 'Show serverid (pod) in resource usage')
.option('--start-date <start-date>', 'Specify start date for filtering resource usage, example: 2020-06-23 18:30')
.option('--end-date <end-date>', 'Specify end date for filtering resource usage, example: 2020-06-23 18:36')
.option('--per-page <per-page>', 'Specify item number in a single page, defaults to 100, maximum is 1000')
.option('--more', 'Get next page of resource usage entries')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.ars_deployment_name = cmd.controllerName;
this.container = cmd.container;
this.serverid = cmd.serverid;
this.show_serverid = cmd.showServerid;
this.start_date = cmd.startDate;
this.end_date = cmd.endDate;
this.per_page = cmd.perPage;
this.more = cmd.more;
});
program.command('autoscale <type> <name>')
.description('Create a autosaler (hpa) for a deployed resource')
.option('-n, --namespace <namespace-name>', 'The namespace of the resource')
.option('--hpa-name <hpa-name>', 'The name for the autoscaler. If not specified, the name of the input resource will be used.')
.option('--min <min-pods>', 'The lower limit for the number of pods. default: 1')
.option('--max <max-pods>', 'The upper limit for the number of pods')
.option('--cpa-percent <cpu-percent>', 'The target average CPU utilization (represented as a percent of requested CPU) over all the pods. default: 80')
.option('--update', 'Update an existing horizontal autoscaler')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.scalerName = cmd.hpaName;
this.min = cmd.min;
this.max = cmd.max;
this.cpuPercent = cmd.cpuPercent
this.update = cmd.update;
});
program.command('restart <resourceType> <resourceName>')
.description('Restart a workload ("deployment" or "statefulset")')
.option('-n, --namespace <namespace-name>', 'The namespace of the resource')
.option('-y, --yes', 'Skip asking for confirmation')
.action(function() {
var cmd = ccommander.restoreParams(this);
this.namespace = cmd.namespace;
this.yes = cmd.yes;
});
program.command('login-registry')
.description('Login to the in-cluster docker registry. This should be run after you have been authenticated with "axway auth login".')
.action(function() {
ccommander.restoreParams(this);
});
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
program.parse(process.argv);
//setup colors
logger.colors(program.colors);
logger.dates(program.dates);
var loglevel = program.loglevel || 'info'
nettleLogger.setLevel(loglevel);
if (!program.colors) {
colors.mode = 'none';
}
process.on('uncaughtException', function(err) {
if (err && err.code === 'EADDRINUSE') {
u.die('Assigned port is already in use. Please see if you have a running instance of this service on this machine.');
}
nettleLogger.error(err.stack? err.stack: err);
});
var killSignals = [ 'SIGINT', 'SIGTERM' ];
for ( var i = 0; i < killSignals.length; i++) {
process.on(killSignals[i], function() {
process.exit();
});
}
function copyright() {
var c = 'ACK CLI'.cyan + ', version ' + module.exports.version + '\n' +
'Copyright (c) 2012-' + new Date().getFullYear() +
', Axway, Inc. All Rights Reserved.\n';
if (!program.colors) {
c = colors.stripColors(c);
}
return c;
}
function help() {
console.log(program.helpInformation());
process.exit(1);
}
function main(args) {
if (args.length === 0) {
help();
}
var cmd = (program.runningSubCommand && program.runningSubCommand.name) || args[0];
// for child commands
var cmdObj = args[args.length-1];
var childCommand = false;
if(typeof cmdObj == 'object') {
cmd = cmdObj.parent.name + "-" + cmdObj.name;
childCommand = true;
}
var validCmdNames = ['install-cert', 'update-cert', 'remove-cert', 'get-cert'];
program.commands.forEach(function(command) {
validCmdNames.push(command.name);
if(command.aliases()) {
validCmdNames.push(...command.aliases());
}
});
if(validCmdNames.includes(cmd)) {
if(program.banner) {
console.log(copyright());
}
u.findAuthToken(program, execCommand);
// u.getAccessToken(program, execCommand);
} else {
console.log();
logger.error('Unknown command: ' + cmd.red);
help();
}
function execCommand() {
var globalConfig = u.getGlobalConfig();
var cmdPath = './command/kube/';
if(!childCommand) {
args = args.splice(1);
}
if ((globalConfig && globalConfig.cookie) || program.accessToken || program.iamUser) {
require(cmdPath + getCmdFile(cmd)).run(args, program);
} else {
// need authentication and no cookie/access token exists
u.requireLogin([], program, function() {
process.stdin.destroy();
// continue previous command after user login successfully
program.isCallback = true;
require(cmdPath + getCmdFile(cmd)).run(args, program);
});
}
}
}
const cmdFileMapping = {
'install-cert': 'crt-add',
'update-cert': 'crt-update',
'remove-cert': 'crt-delete',
'get-cert': 'crt-show'
};
function getCmdFile(cmd) {
let cmdFile = cmdFileMapping[cmd];
if (cmdFile) {
return cmdFile;
}
return cmd;
}
main(program.args);