@ashnazg/ssh
v1.3.0
Published
a wrapper for scp-like ops so I can write ansible-like scripts
Downloads
5
Readme
title: "@ashnazg/ssh" sidebar_label: SSH
Usage
var ssh = require('@ashnazg/ssh'); // ~/projects/ashnazg-npm/ssh/ssh.js
ssh.verbosity(1); // optional. accepts these tiers:
// 0: quiet
// 1: print action headers
// 2: show rsync progress
// 3: print all close values
var {code, stdout, stderr, duration_ms} = ssh('user@server', 'echo foo');
// 'host' can also be {user:'foo', ip:'ip or dns'}
// options
ssh('host', 'cmd', {
reject: true, // rejects on any exit value other than 0. set this to false on cmds where you WANT to grab all exit codes of your cmd. (ssh fails still throw.)
connect_timeout: 5, // in seconds
batch_mode: true, // die rather than have the ssh-client go into interactive "not in known_hosts" flow
disable_hostkey_check: false, // RISKY see below
inherit: false, // setting this to true will bind the ssh cmd's unix streams to your process's own -- nice for some CLI use cases
stdio: [...], // for finer control than 'inherit', see node spawn stdio docs
// probably just an internally used feature:
onChildCreated(child) {
// this is for manipulating the child process immediately upon creation. This is useful for things like streaming data to stdin.
}
});
stream and execute bash script
You can run a bash script remotely:
ssh.script(host, '~/local/script/path', ['--script','--opts'])
note see ssh.write()'s stdio behavior. (note that I really need to fix that; script()'s caller needs to have the option of capturing stderr/out.)
You can run arbitrary large bash scripts without it being on disk or crammed into the CLI mode:
ssh(host, ['optional array of script args'], {stream: ['lots of bash']});
ssh(host, {stream: ['lines']});
NOTE stream mode takes over stdin (as well as out and err until I implement better stdio configurability)
rsync
note rsync's special behavior about whether the source path has a trailing slash.
If you're calling this from a CLI/terminal, note that verbosity(2) will automatically also set rsync's stdout to be your screen by forcing {inherit: true} to be on. You can disable that bit of behavior by setting {inherit} or {stdio} to anything that's not 'undefined'
ssh.rsync(host, '~/files/', '/remote/path');
write one file and set attributes
- data can be a string, an array of strings, or a JSON-able object.
- if you add an option of {chmod: 0600} it'll chmod the file.
- {chown: 'user'} works in a similar fashion.
ssh.write(host, ['data'], remote_dest, {append: false, sudo: false, chmod: undefined, chown: undefined})
ssh.append(...) is the same but with {append: true} preconfigured
ssh.read(host, 'fn') returns 'raw file contents'
note: the above two do not respect {inherit} or {stdio} options, as they're overwriting those to use the file stream themselves.
test for connectivity
There's only one helper function that treats ssh connectivity problems as a resolve(true) instead of a rejection, and treats any cmd exit code as 'good enough'.
ssh.canSshAs('xander@server'); // like all of these, it also takes {user:'xander', ip:'server'}
To save on trips to the well, it also takes a command, so that if you are connecting, you get your next question answered as well. (I use this to figure out whether apt-get or yum is the package
manager.) Note that canSshAs is similar to ssh.stdout.scalar()
in that your command's stdout is trimmed and returned
ssh.canSshAs('x@s', {command: 'which apt-get yum'});
// result: '/usr/bin/apt-get'
A variation on the above that addes retries: ssh.waitForReadiness(host);
will try 10 times, 5 seconds between timeouts and the next try. If it ever succeeds, the default command will return the path to apt-get or yum.
The optional configs specific to this function are:
ssh.waitForReadiness(host, {
tries: 10,
retry_delay: 5,
initial_delay: 0,
cmd: 'which apt-get yum'
});
If you're waiting for a newly provisioned box, and know it'll be N seconds before it could be responsibe, you can pass N as initial_delay
so you're not waiting attempts too early.
Silly useful shorthand notations
These all have an optional trailing {options} that supports the above fields. Some like getVersion() also support the extra fields mentioned here.
ssh.stdout() returns "stdout" instead of {stdout, ...}
ssh.stdout.lines() returns ['std1', 'out2'] with all EOL delimiters removed
ssh.stdout.scalar() returns 'stdout' but with whitespace trimmed off both ends
ssh.exitCode() returns the integer instead of {code,...}
ssh.truthy() returns true if code=0
ssh.exists(host, filename) returns bool
ssh.install(host, package_name, options) just runs apt-get. (or the host's packager if host is a server record like {user,ip,packager})
ssh.isInPath(host, program_name) returns true if 'which' finds it in PATH
ssh.userExists(host, username) returns bool (it checks /etc/passwd)
ssh.getVersion(host, program_name, {line: 1}) returns a string. returns null if not found.
Release 1.3.0
- meta now supports 'success'
- mkdir now uses -mMODE
- rejections now have at minimum {code,message} to be more error-like
- added more tools, such as createUser, which can install rsa keys and sudoer powers on request.
- ssh.canConnect
- ssh.canSudo
- ssh.waitForReadiness
- ssh.userExists
- ssh.setHostname
- ssh.getVersion
Release 1.2.0
A complete rewrite, breaking every signature in the old version.
Release 0.1.0
Added:
- ssh.canSshAs and waitForReadiness
- ssh.stdout.lines (to the docs at least)
- ssh.stdout.scalar