virsh
itself does not supply ssh
capabilities in managing the VMs*.
If we want to access the machine through ssh
, we may only do that through the ssh
command.
Following are the 2 steps for that.
1. Setting Up the SSH Access
For the first step there are 2 tracks
Pre-Configure the Machine (eg: Cloud-Init)
We could use cloud-init (may be also preseed.cfg/kickstart ... etc.) to install the public key.
# Cloud-init snippet
users:
- name: your_username
ssh-authorized-keys:
- your_public_ssh_key
Manual Configuration
Ensure that ssh daemon is running in the VM, if you have an interactive access, you could run virsh console $vm_name
then set up the ssh daemon.
If there's no interactive access you'll need to use any of the following:
virt-customize
while the machine is shut off virt-customize -d "$vm_name" --run-command "command to install ssh"
or
expect
to send keystrokes to setup the VM, which could be found in the appendix of this answer.
or
- any other tool that sends keystrokes to the VM
Install your public key into the VM:
# virt-copy-in requires the virtual machine to be stopped
# for example this should return `shut off`
virsh dominfo my_vm | grep State | awk -F':' '{print $2}' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
# virt-copy-in takes a file argument and a directory argument
# thus we need to use a correct filename before copying
if [ ! -f ~/.ssh/id_rsa ]; then
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
fi
cp ~/.ssh/id_rsa.pub /tmp/authorized_keys
# Finally, virt-copy-in may require sudo
virt-copy-in -d "$vm_name" /tmp/authorized_keys /home/ubuntu/.ssh/
2. Accessing the VM
- Capture the IP address:
export vm_ip_address=$(virsh domifaddr my_vm | awk '/ipv4/ {print $4}' | awk -F'/' '{print $1}')
- ssh into the machine
export vm_user=ubuntu # set the correct username here
ssh $vm_user@$vm_ip_address
* virsh
could use ssh
to communicate with remote servers, but that has nothing to do with accessing the virtual machines themselves.
Appendix
Following is an expect snippet that could be used to automate setting up the interactive console access in a non-interactive manner.
#!/usr/bin/expect -f
Function to wait for a specific string before sending the command
proc wait_for_prompt { } {
expect "# " ; # Modify the expected prompt if needed
}
Function to send a command and wait for the output
proc send_command { command } {
send "$command\r"
expect "# " ; # Modify the expected prompt if needed
}
Replace 'vm_name' with the actual name of your virtual machine
set vm_name "my_vm"
Replace 'your_command' with the command you want to run inside the VM
set command_to_run1 "sudo apt-get install openssh-server."
set command_to_run2 "sudo systemctl start ssh"
set command_to_run3 "sudo systemctl enable ssh"
#spawn virsh start $vm_name
Spawn the virsh command
spawn virsh
Wait for the virsh prompt
expect "virsh # "
Start the virtual machine
send "start $vm_name\r"
send "console $vm_name\r"
Wait for the console to start
Send double enters
send_command ""
send_command ""
expect -timeout 100 "ubuntu login"
Set password
send_command "ubuntu"
send_command "ubuntu"
we may need to login again if prompted
send_command "ubuntu"
send_command "ubuntu"
run the commands
send_command "$command_to_run1"
send_command "$command_to_run2"
send_command "$command_to_run3"
Wait for the output of the command to appear
expect "your_expected_output" ; # Modify this line to match the expected output
Exit the console
send "\x1d"
expect eof
error: internal error: character device console0 is not using a PTY
– Dave Ankin Jun 20 '22 at 08:12virsh console
I had to provide the password, which I am totally unaware of. – s3cret Aug 09 '23 at 01:52