npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ashnazg/ssh

v1.3.0

Published

a wrapper for scp-like ops so I can write ansible-like scripts

Downloads

7

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