Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add convenience script for ssh-ing into VM instance #4

Open
wants to merge 6 commits into
base: docs
Choose a base branch
from
Open

Conversation

smklein
Copy link
Contributor

@smklein smklein commented Feb 4, 2021

Usage:

# Use configuration from defaults.sh, login as current user.
$ ./ssh
# Same, but login as root.
$ USER=root ./ssh
# Login to a machine setup with a different configuration (i.e., config/foobar.sh)
$ ./ssh foobar

@smklein smklein requested a review from jclulow February 4, 2021 01:49
@smklein
Copy link
Contributor Author

smklein commented Feb 4, 2021

I'm trying to create a setup where I have "one VM for development", and "one VM under test" - it's kinda a pain to try to remember which IP address is associated with which one, so this is a little shortcut to make my workflow better.

@jclulow
Copy link
Collaborator

jclulow commented Feb 4, 2021

I have a pattern I end up using a bit that might help here. I have a script, _nc_virsh, (in my ~/bin which is in my $PATH):

#!/bin/bash
# vim: set ts=8 sts=8 sw=8 noet:

fatal() {
	local rc=$1
	local msg=$2
	shift 2

	printf "ERROR: $msg\n" "$@" >&2
	exit $rc
}

DOMAIN="$1"
LOOKUPHOST="$2"
LOOKUPPORT="$3"

if [[ -z $DOMAIN || -z $LOOKUPHOST || -z $LOOKUPPORT ]]; then
	fatal 2 'missing arguments'
fi

sans_domain=$(sed "s/\\.${DOMAIN}\$//" <<< "$LOOKUPHOST")

if ! res=$(virsh domifaddr "$sans_domain"); then
	fatal 3 'could not look up libvirt domain "%s"\n' "$sans_domain"
fi

if ! ip=$(awk '$3 == "ipv4" { gsub("/.*", "", $4);
    print($4); exit(0); }' <<< "$res") || [[ -z "$ip" ]]; then
	fatal 4 'could not locate IP address for "%s"\n' "$sans_domain"
fi

printf 'translating "%s" --> %s\n' "$sans_domain" "$ip" >&2

exec nc "$ip" "$LOOKUPPORT"

I then configure an entry in ~/.ssh/config:

Host *.vm
        User jclulow
        ProxyCommand _nc_virsh vm %h %p
        ForwardAgent yes
        ServerAliveInterval 15

When ssh is figuring out how to connect, if it matches the *.vm wildcard then this entry gets used. For example, if I ssh helios.vm, it invokes the script: _nc_virsh vm helios.vm 22. The script then uses virsh (as you've done in your helper) the get the IP address and invokes nc as a ProxyCommand to start the connection:

$ ssh root@helios.vm
translating "helios" --> 192.168.122.15
The illumos Project     master-0-g8af575c0af    December 2020
root@helios:~# logout
Connection to helios.vm closed.

$ ssh helios.vm
translating "helios" --> 192.168.122.15
The illumos Project     master-0-g8af575c0af    December 2020
You have new mail.
jclulow@helios:~$ logout
Connection to helios.vm closed.

It has the advantage that it will work for other tools that leverage ssh like rsync and scp and git:

$ rsync root@helios.vm:./
translating "helios" --> 192.168.122.15
drwx------              6 2020/12/04 02:08:32 .
-rw-------             37 2020/12/04 02:08:32 .bash_history
-rw-r--r--            158 2020/12/02 11:28:33 .bashrc
-rw-r--r--            377 2020/12/02 11:28:33 .profile
drwx------              3 2020/12/04 00:19:35 .ssh

It will correctly fail to connect if the domain you specify is not running or doesn't exist:

 $ ssh tribblix.vm
error: Failed to query for interfaces addresses
error: Requested operation is not valid: domain is not running
ERROR: could not look up libvirt domain "tribblix"

What do you think?

@smklein
Copy link
Contributor Author

smklein commented Feb 4, 2021

I have a pattern I end up using a bit that might help here. I have a script, _nc_virsh, (in my ~/bin which is in my $PATH):

#!/bin/bash
# vim: set ts=8 sts=8 sw=8 noet:

fatal() {
	local rc=$1
	local msg=$2
	shift 2

	printf "ERROR: $msg\n" "$@" >&2
	exit $rc
}

DOMAIN="$1"
LOOKUPHOST="$2"
LOOKUPPORT="$3"

if [[ -z $DOMAIN || -z $LOOKUPHOST || -z $LOOKUPPORT ]]; then
	fatal 2 'missing arguments'
fi

sans_domain=$(sed "s/\\.${DOMAIN}\$//" <<< "$LOOKUPHOST")

if ! res=$(virsh domifaddr "$sans_domain"); then
	fatal 3 'could not look up libvirt domain "%s"\n' "$sans_domain"
fi

if ! ip=$(awk '$3 == "ipv4" { gsub("/.*", "", $4);
    print($4); exit(0); }' <<< "$res") || [[ -z "$ip" ]]; then
	fatal 4 'could not locate IP address for "%s"\n' "$sans_domain"
fi

printf 'translating "%s" --> %s\n' "$sans_domain" "$ip" >&2

exec nc "$ip" "$LOOKUPPORT"

I then configure an entry in ~/.ssh/config:

Host *.vm
        User jclulow
        ProxyCommand _nc_virsh vm %h %p
        ForwardAgent yes
        ServerAliveInterval 15

When ssh is figuring out how to connect, if it matches the *.vm wildcard then this entry gets used. For example, if I ssh helios.vm, it invokes the script: _nc_virsh vm helios.vm 22. The script then uses virsh (as you've done in your helper) the get the IP address and invokes nc as a ProxyCommand to start the connection:

$ ssh root@helios.vm
translating "helios" --> 192.168.122.15
The illumos Project     master-0-g8af575c0af    December 2020
root@helios:~# logout
Connection to helios.vm closed.

$ ssh helios.vm
translating "helios" --> 192.168.122.15
The illumos Project     master-0-g8af575c0af    December 2020
You have new mail.
jclulow@helios:~$ logout
Connection to helios.vm closed.

It has the advantage that it will work for other tools that leverage ssh like rsync and scp and git:

$ rsync root@helios.vm:./
translating "helios" --> 192.168.122.15
drwx------              6 2020/12/04 02:08:32 .
-rw-------             37 2020/12/04 02:08:32 .bash_history
-rw-r--r--            158 2020/12/02 11:28:33 .bashrc
-rw-r--r--            377 2020/12/02 11:28:33 .profile
drwx------              3 2020/12/04 00:19:35 .ssh

It will correctly fail to connect if the domain you specify is not running or doesn't exist:

 $ ssh tribblix.vm
error: Failed to query for interfaces addresses
error: Requested operation is not valid: domain is not running
ERROR: could not look up libvirt domain "tribblix"

What do you think?

So, first impressions: That's extremely rad, and I plan on playing with my ssh config way more now that I know it applies to this suite of commands.

The only thing that bums me out about that current implementation is that it requires some... manual intervention to make things work (custom script, custom path, custom config). I updated this PR to incorporate basically everything you did, but hopefully make it easier for folks checking out this repo for the first time.

TL;DR:

  • ssh_setup.sh adds the ssh config, pointing to the _nc_virsh.sh script within the repo
  • _nc_virsh.sh acts more-or-less exactly like your version, but with minor usability tweaks (listing valid domains if the user misspells something).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants