joyent/node-triton#137 triton CLI tool fails in default usecase
Reviewed by: Chris Burroughs <chris.burroughs@joyent.com> Approved by: Chris Burroughs <chris.burroughs@joyent.com>
This commit is contained in:
parent
2453bc12e8
commit
3a369e4bb8
@ -7,6 +7,9 @@ Known issues:
|
|||||||
|
|
||||||
## not yet released
|
## not yet released
|
||||||
|
|
||||||
|
- [joyent/node-triton#137] Improve the handling for the getting started case
|
||||||
|
when a user may not have envvars or a profile setup.
|
||||||
|
|
||||||
- [joyent/node-triton#158] tritonapi image cache never expires
|
- [joyent/node-triton#158] tritonapi image cache never expires
|
||||||
|
|
||||||
- [joyent/node-triton#153] Bump restify-clients dep. Thanks, github.com/tomgco.
|
- [joyent/node-triton#153] Bump restify-clients dep. Thanks, github.com/tomgco.
|
||||||
|
62
README.md
62
README.md
@ -46,20 +46,66 @@ Have the URL handy as you'll need it in the next step.
|
|||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
1. Install [node.js](http://nodejs.org/).
|
Install [node.js](http://nodejs.org/), then:
|
||||||
2. `npm install -g triton`
|
|
||||||
|
npm install -g triton
|
||||||
|
|
||||||
Verify that it is installed and on your PATH:
|
Verify that it is installed and on your PATH:
|
||||||
|
|
||||||
$ triton --version
|
$ triton --version
|
||||||
Triton CLI 1.0.0
|
Triton CLI 4.15.0
|
||||||
|
https://github.com/joyent/node-triton
|
||||||
|
|
||||||
Configure the proper environmental variables that correspond to the API endpoint and account,
|
To use `triton`, you'll need to configure it to talk to a Triton DataCenter
|
||||||
for example:
|
API endpoint (called CloudAPI). Commonly that is done using a Triton profile:
|
||||||
|
|
||||||
SDC_URL=https://us-east-3b.api.joyent.com
|
$ triton profile create
|
||||||
SDC_ACCOUNT=dave.eddy@joyent.com
|
A profile name. A short string to identify a CloudAPI endpoint to the
|
||||||
SDC_KEY_ID=04:0c:22:25:c9:85:d8:e4:fa:27:0d:67:94:68:9e:e9
|
`triton` CLI.
|
||||||
|
name: sw1
|
||||||
|
|
||||||
|
The CloudAPI endpoint URL.
|
||||||
|
url: https://us-sw-1.api.joyent.com
|
||||||
|
|
||||||
|
Your account login name.
|
||||||
|
account: bob
|
||||||
|
|
||||||
|
Available SSH keys:
|
||||||
|
1. 2048-bit RSA key with fingerprint 4e:e7:56:9a:b0:91:31:3e:23:8d:f8:62:12:58:a2:ec
|
||||||
|
* [in homedir] bob-20160704 id_rsa
|
||||||
|
|
||||||
|
The fingerprint of the SSH key you want to use, or its index in the list
|
||||||
|
above. If the key you want to use is not listed, make sure it is either saved
|
||||||
|
in your SSH keys directory or loaded into the SSH agent.
|
||||||
|
keyId: 1
|
||||||
|
|
||||||
|
Saved profile "sw1".
|
||||||
|
|
||||||
|
WARNING: Docker uses TLS-based authentication with a different security model
|
||||||
|
from SSH keys. As a result, the Docker client cannot currently support
|
||||||
|
encrypted (password protected) keys or SSH agents. If you continue, the
|
||||||
|
Triton CLI will attempt to format a copy of your SSH *private* key as an
|
||||||
|
unencrypted TLS cert and place the copy in ~/.triton/docker for use by the
|
||||||
|
Docker client.
|
||||||
|
Continue? [y/n] y
|
||||||
|
Setting up profile "sw1" to use Docker.
|
||||||
|
Setup profile "sw1" to use Docker (v1.12.3). Try this:
|
||||||
|
eval "$(triton env --docker sw1)"
|
||||||
|
docker info
|
||||||
|
|
||||||
|
Set "sw1" as current profile (because it is your only profile).
|
||||||
|
|
||||||
|
Or instead of using profiles, you can set the required environment variables
|
||||||
|
(`triton` defaults to an "env" profile that uses these environment variables if
|
||||||
|
no profile is set). For example:
|
||||||
|
|
||||||
|
TRITON_URL=https://us-sw-1.api.joyent.com
|
||||||
|
TRITON_ACCOUNT=bob
|
||||||
|
TRITON_KEY_ID=SHA256:j2WoSeOWhFy69BQ0uCR3FAySp9qCZTSCEyT2vRKcL+s
|
||||||
|
|
||||||
|
For compatibility with the older [sdc-* tools from
|
||||||
|
node-smartdc](https://github.com/joyent/node-smartdc), `triton` also supports
|
||||||
|
`SDC_URL`, `SDC_ACCOUNT`, etc. environment variables.
|
||||||
|
|
||||||
|
|
||||||
### Bash completion
|
### Bash completion
|
||||||
|
78
lib/cli.js
78
lib/cli.js
@ -25,6 +25,7 @@ var path = require('path');
|
|||||||
var vasync = require('vasync');
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('./common');
|
var common = require('./common');
|
||||||
|
var constants = require('./constants');
|
||||||
var mod_config = require('./config');
|
var mod_config = require('./config');
|
||||||
var errors = require('./errors');
|
var errors = require('./errors');
|
||||||
var lib_tritonapi = require('./tritonapi');
|
var lib_tritonapi = require('./tritonapi');
|
||||||
@ -35,21 +36,6 @@ var lib_tritonapi = require('./tritonapi');
|
|||||||
|
|
||||||
var packageJson = require('../package.json');
|
var packageJson = require('../package.json');
|
||||||
|
|
||||||
var CONFIG_DIR;
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
/*
|
|
||||||
* For better or worse we are using APPDATA (i.e. the *Roaming* AppData
|
|
||||||
* dir) over LOCALAPPDATA (non-roaming). The former is meant for "user"
|
|
||||||
* data, the latter for "machine" data.
|
|
||||||
*
|
|
||||||
* TODO: We should likely separate out the *cache* subdir to
|
|
||||||
* machine-specific data dir.
|
|
||||||
*/
|
|
||||||
CONFIG_DIR = path.resolve(process.env.APPDATA, 'Joyent', 'Triton');
|
|
||||||
} else {
|
|
||||||
CONFIG_DIR = path.resolve(process.env.HOME, '.triton');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var OPTIONS = [
|
var OPTIONS = [
|
||||||
{
|
{
|
||||||
@ -262,7 +248,8 @@ CLI.prototype.init = function (opts, args, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opts.version) {
|
if (opts.version) {
|
||||||
console.log(this.name, packageJson.version);
|
console.log('Triton CLI', packageJson.version);
|
||||||
|
console.log(packageJson.homepage);
|
||||||
callback(false);
|
callback(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -274,7 +261,7 @@ CLI.prototype.init = function (opts, args, callback) {
|
|||||||
opts.url = format('https://%s.api.joyent.com', opts.J);
|
opts.url = format('https://%s.api.joyent.com', opts.J);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.configDir = CONFIG_DIR;
|
this.configDir = constants.CLI_CONFIG_DIR;
|
||||||
|
|
||||||
this.__defineGetter__('config', function getConfig() {
|
this.__defineGetter__('config', function getConfig() {
|
||||||
if (self._config === undefined) {
|
if (self._config === undefined) {
|
||||||
@ -292,26 +279,48 @@ CLI.prototype.init = function (opts, args, callback) {
|
|||||||
|
|
||||||
this.__defineGetter__('profile', function getProfile() {
|
this.__defineGetter__('profile', function getProfile() {
|
||||||
if (self._profile === undefined) {
|
if (self._profile === undefined) {
|
||||||
self._profile = mod_config.loadProfile({
|
try {
|
||||||
configDir: self.configDir,
|
self._profile = mod_config.loadProfile({
|
||||||
name: self.profileName
|
configDir: self.configDir,
|
||||||
});
|
name: self.profileName
|
||||||
|
});
|
||||||
|
} catch (pErr) {
|
||||||
|
/*
|
||||||
|
* Let's be nice for the getting started use case where we
|
||||||
|
* defaulted to 'env' profile (e.g. the user has never created
|
||||||
|
* one) and the minimal envvars aren't set. I.e. The user just
|
||||||
|
* installed and ran `triton ls` or some other command.
|
||||||
|
*/
|
||||||
|
if (pErr.code === 'Config' && self.profileName === 'env' &&
|
||||||
|
!opts.profile && !self.config.profile)
|
||||||
|
{
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
pErr.message += '\n'
|
||||||
|
+ ' No profile information could be loaded.\n'
|
||||||
|
+ ' Use "triton profile create" to create a profile or provide\n'
|
||||||
|
+ ' the required "CloudAPI options" described in "triton --help".\n'
|
||||||
|
+ ' See https://github.com/joyent/node-triton#setup for more help.';
|
||||||
|
/* END JSSTYLED */
|
||||||
|
}
|
||||||
|
throw pErr;
|
||||||
|
}
|
||||||
self._applyProfileOverrides(self._profile);
|
self._applyProfileOverrides(self._profile);
|
||||||
self.log.trace({profile: self._profile}, 'loaded profile');
|
self.log.trace({profile: self._profile}, 'loaded profile');
|
||||||
}
|
}
|
||||||
return self._profile;
|
return self._profile;
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
this.__defineGetter__('tritonapi', function getTritonapi() {
|
||||||
self.tritonapi = lib_tritonapi.createClient({
|
if (self._tritonapi === undefined) {
|
||||||
log: self.log,
|
self._tritonapi = lib_tritonapi.createClient({
|
||||||
profile: self.profile,
|
log: self.log,
|
||||||
config: self.config
|
profile: self.profile,
|
||||||
});
|
config: self.config
|
||||||
} catch (createErr) {
|
});
|
||||||
callback(createErr);
|
self.log.trace('created tritonapi');
|
||||||
return;
|
}
|
||||||
}
|
return self._tritonapi;
|
||||||
|
});
|
||||||
|
|
||||||
if (process.env.TRITON_COMPLETE) {
|
if (process.env.TRITON_COMPLETE) {
|
||||||
/*
|
/*
|
||||||
@ -338,9 +347,9 @@ CLI.prototype.init = function (opts, args, callback) {
|
|||||||
|
|
||||||
CLI.prototype.fini = function fini(subcmd, err, cb) {
|
CLI.prototype.fini = function fini(subcmd, err, cb) {
|
||||||
this.log.trace({err: err, subcmd: subcmd}, 'cli fini');
|
this.log.trace({err: err, subcmd: subcmd}, 'cli fini');
|
||||||
if (this.tritonapi) {
|
if (this._tritonapi) {
|
||||||
this.tritonapi.close();
|
this._tritonapi.close();
|
||||||
delete this.tritonapi;
|
delete this._tritonapi;
|
||||||
}
|
}
|
||||||
cb();
|
cb();
|
||||||
};
|
};
|
||||||
@ -732,7 +741,6 @@ function main(argv) {
|
|||||||
//---- exports
|
//---- exports
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
CONFIG_DIR: CONFIG_DIR,
|
|
||||||
CLI: CLI,
|
CLI: CLI,
|
||||||
main: main
|
main: main
|
||||||
};
|
};
|
||||||
|
@ -314,7 +314,7 @@ function _createProfile(opts, cb) {
|
|||||||
next(err);
|
next(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('Set "%s" as current profile (because it is ' +
|
console.log('\nSet "%s" as current profile (because it is ' +
|
||||||
'your only profile).', data.name);
|
'your only profile).', data.name);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
@ -80,7 +80,9 @@ function _listProfiles(cli, opts, args, cb) {
|
|||||||
if (!haveCurr) {
|
if (!haveCurr) {
|
||||||
if (profiles.length === 0) {
|
if (profiles.length === 0) {
|
||||||
process.stderr.write('\nWarning: There is no current profile. '
|
process.stderr.write('\nWarning: There is no current profile. '
|
||||||
+ 'Use "triton profile create" to create one.\n');
|
+ 'Use "triton profile create" to create one,\n'
|
||||||
|
+ 'or set the required "SDC_*/TRITON_*" environment '
|
||||||
|
+ 'variables: see "triton --help".\n');
|
||||||
} else {
|
} else {
|
||||||
process.stderr.write('\nWarning: There is no current profile. '
|
process.stderr.write('\nWarning: There is no current profile. '
|
||||||
+ 'Use "triton profile set-current ..."\n'
|
+ 'Use "triton profile set-current ..."\n'
|
||||||
|
@ -166,7 +166,8 @@ function profileDockerSetup(opts, cb) {
|
|||||||
'Docker client.'));
|
'Docker client.'));
|
||||||
common.promptYesNo({msg: 'Continue? [y/n] '}, function (answer) {
|
common.promptYesNo({msg: 'Continue? [y/n] '}, function (answer) {
|
||||||
if (answer !== 'y') {
|
if (answer !== 'y') {
|
||||||
console.error('Aborting');
|
console.error('Skipping Docker setup (you can run '
|
||||||
|
+ '"triton profile docker-setup" later).');
|
||||||
next(true);
|
next(true);
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
|
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
|
||||||
"version": "4.15.0",
|
"version": "4.15.0",
|
||||||
"author": "Joyent (joyent.com)",
|
"author": "Joyent (joyent.com)",
|
||||||
|
"homepage": "https://github.com/joyent/node-triton",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"assert-plus": "0.2.0",
|
"assert-plus": "0.2.0",
|
||||||
"backoff": "2.4.1",
|
"backoff": "2.4.1",
|
||||||
@ -24,7 +25,7 @@
|
|||||||
"sshpk": "1.10.1",
|
"sshpk": "1.10.1",
|
||||||
"sshpk-agent": "1.4.2",
|
"sshpk-agent": "1.4.2",
|
||||||
"strsplit": "1.0.0",
|
"strsplit": "1.0.0",
|
||||||
"tabula": "1.7.0",
|
"tabula": "1.9.0",
|
||||||
"vasync": "1.6.3",
|
"vasync": "1.6.3",
|
||||||
"verror": "1.6.0",
|
"verror": "1.6.0",
|
||||||
"which": "1.2.4",
|
"which": "1.2.4",
|
||||||
|
Reference in New Issue
Block a user