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:
Chris Burroughs 2016-12-21 14:24:24 -05:00
parent 2453bc12e8
commit 3a369e4bb8
7 changed files with 108 additions and 47 deletions

View File

@ -7,6 +7,9 @@ Known issues:
## 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#153] Bump restify-clients dep. Thanks, github.com/tomgco.

View File

@ -46,20 +46,66 @@ Have the URL handy as you'll need it in the next step.
### Installation
1. Install [node.js](http://nodejs.org/).
2. `npm install -g triton`
Install [node.js](http://nodejs.org/), then:
npm install -g triton
Verify that it is installed and on your PATH:
$ 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,
for example:
To use `triton`, you'll need to configure it to talk to a Triton DataCenter
API endpoint (called CloudAPI). Commonly that is done using a Triton profile:
SDC_URL=https://us-east-3b.api.joyent.com
SDC_ACCOUNT=dave.eddy@joyent.com
SDC_KEY_ID=04:0c:22:25:c9:85:d8:e4:fa:27:0d:67:94:68:9e:e9
$ triton profile create
A profile name. A short string to identify a CloudAPI endpoint to the
`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

View File

@ -25,6 +25,7 @@ var path = require('path');
var vasync = require('vasync');
var common = require('./common');
var constants = require('./constants');
var mod_config = require('./config');
var errors = require('./errors');
var lib_tritonapi = require('./tritonapi');
@ -35,21 +36,6 @@ var lib_tritonapi = require('./tritonapi');
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 = [
{
@ -262,7 +248,8 @@ CLI.prototype.init = function (opts, args, callback) {
}
if (opts.version) {
console.log(this.name, packageJson.version);
console.log('Triton CLI', packageJson.version);
console.log(packageJson.homepage);
callback(false);
return;
}
@ -274,7 +261,7 @@ CLI.prototype.init = function (opts, args, callback) {
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() {
if (self._config === undefined) {
@ -292,26 +279,48 @@ CLI.prototype.init = function (opts, args, callback) {
this.__defineGetter__('profile', function getProfile() {
if (self._profile === undefined) {
try {
self._profile = mod_config.loadProfile({
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.log.trace({profile: self._profile}, 'loaded profile');
}
return self._profile;
});
try {
self.tritonapi = lib_tritonapi.createClient({
this.__defineGetter__('tritonapi', function getTritonapi() {
if (self._tritonapi === undefined) {
self._tritonapi = lib_tritonapi.createClient({
log: self.log,
profile: self.profile,
config: self.config
});
} catch (createErr) {
callback(createErr);
return;
self.log.trace('created tritonapi');
}
return self._tritonapi;
});
if (process.env.TRITON_COMPLETE) {
/*
@ -338,9 +347,9 @@ CLI.prototype.init = function (opts, args, callback) {
CLI.prototype.fini = function fini(subcmd, err, cb) {
this.log.trace({err: err, subcmd: subcmd}, 'cli fini');
if (this.tritonapi) {
this.tritonapi.close();
delete this.tritonapi;
if (this._tritonapi) {
this._tritonapi.close();
delete this._tritonapi;
}
cb();
};
@ -732,7 +741,6 @@ function main(argv) {
//---- exports
module.exports = {
CONFIG_DIR: CONFIG_DIR,
CLI: CLI,
main: main
};

View File

@ -314,7 +314,7 @@ function _createProfile(opts, cb) {
next(err);
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);
next();
});

View File

@ -80,7 +80,9 @@ function _listProfiles(cli, opts, args, cb) {
if (!haveCurr) {
if (profiles.length === 0) {
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 {
process.stderr.write('\nWarning: There is no current profile. '
+ 'Use "triton profile set-current ..."\n'

View File

@ -166,7 +166,8 @@ function profileDockerSetup(opts, cb) {
'Docker client.'));
common.promptYesNo({msg: 'Continue? [y/n] '}, function (answer) {
if (answer !== 'y') {
console.error('Aborting');
console.error('Skipping Docker setup (you can run '
+ '"triton profile docker-setup" later).');
next(true);
} else {
next();

View File

@ -3,6 +3,7 @@
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
"version": "4.15.0",
"author": "Joyent (joyent.com)",
"homepage": "https://github.com/joyent/node-triton",
"dependencies": {
"assert-plus": "0.2.0",
"backoff": "2.4.1",
@ -24,7 +25,7 @@
"sshpk": "1.10.1",
"sshpk-agent": "1.4.2",
"strsplit": "1.0.0",
"tabula": "1.7.0",
"tabula": "1.9.0",
"vasync": "1.6.3",
"verror": "1.6.0",
"which": "1.2.4",