Skip to content

Commit

Permalink
vsock: connect: generate helper script
Browse files Browse the repository at this point in the history
Directly connecting to the remote shell using socat launching 'bash'
remotely doesn't give a nice user experience: env vars like $HOME are
not propagated, the terminal size is set to 80x24, the command that is
typed is not visible, the directory is not the one picked with --cwd,
etc.

To give a better user experience, the '--vsock-connect' option is now
creating a script that is setting up the missing pieces. This script is
executed when the VM is launched with '--vsock' without any arguments.

Note that it is required to pass info from the host, when launching
'--vsock-connect', to the VM, e.g. for the terminal size. This is done
via the script that is executed once connected to the vsock inside the
VM. The VM needs access to this script, and the host needs to be able to
modify it. Such script is then created in /tmp/virtme-vsock/<CID>.sh on
both the host and the VM. If the whole filesystem is mounted (default),
this file will be accessible from the VM. If not, a mount point will be
added to access the parent directory from the VM.

Signed-off-by: Matthieu Baerts (NGI0) <[email protected]>
  • Loading branch information
matttbe committed Dec 2, 2024
1 parent 180654c commit 5fbbc15
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 26 deletions.
18 changes: 0 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,24 +354,6 @@ Examples
$ vng --vsock-connect
```

- Connect to a remote shell with proper dimensions, env vars, and using 'Fish':
```
# Start the vng instance with vsock support:
$ vng --vsock "${PWD}/console.sh"
# In a separate terminal run the following commands:
$ read -r rows columns <<< "$(stty size)"
$ cat <<-EOF > console.sh
#! /bin/bash
stty rows ${rows} columns ${columns}
cd "\${virtme_chdir}"
HOME=${HOME}
fish # use use zsh, tmux, byobu, screen, etc.
EOF
$ chmod +x console.sh
$ vng --vsock-connect
```

- Run virtme-ng inside a docker container:
```
$ docker run -it --privileged ubuntu:23.10 /bin/bash
Expand Down
59 changes: 54 additions & 5 deletions virtme/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,16 @@ def make_parser() -> argparse.ArgumentParser:
g.add_argument(
"--vsock",
action="store",
default=None,
help="Enable a VSock to communicate from the host to the device and "
+ "execute the specified command.",
nargs="?",
metavar="COMMAND",
const="",
help="Enable a VSock to communicate from the host to the device. "
+ "An argument can be optionally specified to start a different command.",
)
g.add_argument(
"--vsock-cid",
action="store",
metavar="CID",
type=int,
default=3,
help="CID for the VSock.",
Expand Down Expand Up @@ -866,7 +869,27 @@ def is_subpath(path, potential_parent):
def do_it() -> int:
args = _ARGPARSER.parse_args()

vsock_script_path = os.path.join(tempfile.gettempdir(), "virtme-vsock",
f"{args.vsock_cid}.sh")

if args.vsock_connect:
# Note: we could accept arguments passed to --vsock-connect to run a
# specific command, and return, without requiring an interactive tty.
try:
(cols, rows) = os.get_terminal_size()
except OSError:
cols, rows = (80, 24)

with open(vsock_script_path, 'w', encoding="utf-8") as file:
print((
'#! /bin/bash\n'
f'stty rows {rows} cols {cols} iutf8 echo\n'
'HOME=$(getent passwd ${virtme_user:-root} | cut -d: -f6)\n'
'cd ${virtme_chdir:+"${virtme_chdir}"}\n'
'exec su ${virtme_user:-root}'
), file=file)
os.chmod(vsock_script_path, 0o755)

tty = os.ttyname(sys.stdin.fileno())
command = ['socat', f'file:{tty},raw,echo=0',
f'VSOCK-CONNECT:{args.vsock_cid}:1024']
Expand Down Expand Up @@ -1409,8 +1432,34 @@ def get_net_mac(index):
]
)

if args.vsock:
kernelargs.extend([f"virtme.vsockexec=`{args.vsock}`"])
def cleanup_vsock_script():
os.unlink(vsock_script_path)

if args.vsock is not None:
if os.path.exists(vsock_script_path):
arg_fail("vsock: '%s' file exists: " % vsock_script_path
+ "another VM is running with the same --vsock-cid? "
+ "If not, remove this file.")

# create an empty file that can be populated later on
vsock_script_dir = os.path.dirname(vsock_script_path)
os.makedirs(vsock_script_dir, exist_ok=True)
open(vsock_script_path, 'w', encoding="utf-8").close()
atexit.register(cleanup_vsock_script)

if args.vsock:
vsock_exec = args.vsock
else:
vsock_exec = vsock_script_path
if args.root != "/":
virtfs_config = VirtFSConfig(
path=vsock_script_dir,
mount_tag="virtme.vsockmount",
)
export_virtfs(qemu, arch, qemuargs, virtfs_config)
kernelargs.append("virtme_vsockmount=%s" % vsock_script_dir)

kernelargs.extend([f"virtme.vsockexec=`{vsock_exec}`"])
qemuargs.extend(["-device", "vhost-vsock-pci,guest-cid=%d" % args.vsock_cid])

if args.pwd:
Expand Down
4 changes: 4 additions & 0 deletions virtme/guest/virtme-init
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ fi

vsock_exec=$(sed -ne "s/.*virtme.vsockexec=\`\(.*\)\`.*/\1/p" /proc/cmdline)
if [[ -n "${vsock_exec}" ]]; then
if [[ -n "${virtme_vsockmount}" ]]; then
mkdir -p "${virtme_vsockmount}"
mount -t 9p -o version=9p2000.L,trans=virtio,access=any "virtme.vsockmount" "${virtme_vsockmount}"
fi
socat "VSOCK-LISTEN:1024,reuseaddr,fork" \
"EXEC:\"${vsock_exec}\",pty,stderr,setsid,sigint,sane,echo=0" &
fi
Expand Down
6 changes: 4 additions & 2 deletions virtme_ng/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,15 +362,17 @@ def make_parser():
parser.add_argument(
"--vsock",
action="store",
const="bash -i",
nargs="?",
metavar="COMMAND",
const="",
help="Enable a VSock to communicate from the host to the device. "
+ "An argument can be optionally specified to start a different shell.",
+ "An argument can be optionally specified to start a different command.",
)

parser.add_argument(
"--vsock-cid",
action="store",
metavar="CID",
type=int,
help="CID for the VSock.",
)
Expand Down
2 changes: 1 addition & 1 deletion virtme_ng_init
Submodule virtme_ng_init updated 1 files
+13 −0 src/main.rs

0 comments on commit 5fbbc15

Please sign in to comment.