← Back to team overview

ubuntu-bugcontrol team mailing list archive

[Merge] ~jslarraz/ubuntu-qa-tools:add-vm-name-resolution into ubuntu-qa-tools:master

 

Jorge Sancho Larraz has proposed merging ~jslarraz/ubuntu-qa-tools:add-vm-name-resolution into ubuntu-qa-tools:master.

Commit message:
uvt: add cmd_ssh and perform address resolution using virsh when possible

Requested reviews:
  Ubuntu Bug Control (ubuntu-bugcontrol)

For more details, see:
https://code.launchpad.net/~jslarraz/ubuntu-qa-tools/+git/ubuntu-qa-tools/+merge/460382

When trying to create a snap with uvt I was not able to make address resolution using libnss-libvirt to work. 

This MR modifies uvt to perform the address resolution internally using `virsh domifaddr` instead of relying on the OS. It will fallback to the old behavior if this resolution does not work.

This MR also add a new command called `uvt ssh <vm-name> (pretty much a shortcut for `uvt cmd <vm-name> bash`) that opens an interactive session in the target machine. 

Both changes together may remove the need of network setup (install libnss-libvirt + config /etc/nsswitch.conf) from the setup step on certain configurations. It will additionally enable us to package uvt as a snap 
-- 
Your team Ubuntu Bug Control is requested to review the proposed merge of ~jslarraz/ubuntu-qa-tools:add-vm-name-resolution into ubuntu-qa-tools:master.
diff --git a/vm-tools/uvt b/vm-tools/uvt
index c7b0143..884b5bf 100755
--- a/vm-tools/uvt
+++ b/vm-tools/uvt
@@ -468,6 +468,58 @@ def cmd_cmd():
             print("Error: VM '%s' command failed. Aborting." % machine, file=sys.stderr)
             sys.exit(1)
 
+def cmd_ssh():
+    '''Run a command inside a virtual machine'''
+
+    usage = "usage: %prog ssh [options] <vm>"
+
+    epilog = "\n" + \
+             "Eg:\n" + \
+             "$ uvt ssh sec-jammy-amd64\n\n" + \
+             "This will open an interactive session on the single VM named 'sec-jammy-amd64'\n"
+
+    optparse.OptionParser.format_epilog = lambda self, formatter: self.epilog
+    parser = optparse.OptionParser(usage = usage, epilog = epilog)
+
+    parser.add_option("-s", "--start", dest="start", default=False, action='store_true',
+                      help="Start the VM (and shutdown if it wasn't running")
+
+    parser.add_option("-t", "--timeout", dest="timeout", default=90, metavar="TIMEOUT",
+                      help="wait TIMEOUT seconds for VM to come up if -s is used (default: %default)")
+
+    parser.add_option("-f", "--force-ssh", dest="force_ssh", default=False, action='store_true',
+                      help="force the SSH keys to be taken")
+
+    parser.add_option("-r", "--root", dest="root", default=False, action='store_true',
+                      help="login to the VM as root")
+
+    parser.add_option("-u", "--user", dest="user", default=None, metavar="USER",
+                      help="login to the VM as user")
+
+    parser.add_option("-q", "--quiet", dest="quiet", default=False, action='store_true',
+                      help="only report hostnames and output")
+
+    (opt, args) = parser.parse_args()
+    machine = args[0]
+
+    if opt.user is not None and opt.root:
+        print("Error: may specify only one of --root and --user.\n", file=sys.stderr)
+        sys.exit(1)
+
+    print("----- %s -----" % machine)
+    if check_vm_exists(machine) == False:
+        print("Error: VM '%s' does not exist, skipping." % machine, file=sys.stderr)
+        return
+
+    result = vm_run_command(machine, "bash", root=opt.root, start=opt.start,
+                            start_timeout=opt.timeout, force_keys=opt.force_ssh,
+                            quiet=opt.quiet, output=True, interactive=True,
+                            verbose=False, user=opt.user)
+
+    if result == False:
+        print("Error: VM '%s' command failed. Aborting." % machine, file=sys.stderr)
+        sys.exit(1)
+
 def cmd_repo():
     '''Adds or removes a local repo to a VM'''
 
@@ -1415,8 +1467,8 @@ def vm_run_command(vm_name, command, root=False, start=False,
             print("Could not start VM: %s" % vm_name)
             return False
 
-    dns_name = vm_ping(vm_name)
-    if dns_name == "":
+    vm_addr = vm_ping(vm_name)
+    if vm_addr == "":
         print("Could not ping VM: %s" % vm_name)
         return False
 
@@ -1440,7 +1492,7 @@ def vm_run_command(vm_name, command, root=False, start=False,
         ssh_command += ['-q']
     ssh_command += ['-o', 'BatchMode=yes']
 
-    ssh_command += [dns_name, command]
+    ssh_command += [vm_addr, command]
 
     if interactive:
         rc, out = runcmd(ssh_command, stderr = None, stdout = None, stdin = None)
@@ -1519,9 +1571,9 @@ def vm_stop(vm_name):
     # a shutdown menu.
 
     # If we can connect using ssh, issue a shutdown command
-    dns_host = vm_ping(vm_name)
-    if dns_host != "" and ssh_connect(dns_host):
-        vm_run_command(dns_host, "shutdown -h now", root=True,
+    vm_addr = vm_ping(vm_name)
+    if vm_addr != "" and ssh_connect(vm_addr):
+        vm_run_command(vm_addr, "shutdown -h now", root=True,
                        force_keys=True, output=False, ignore_rc=True)
     else:
         rc, out = runcmd(["virsh", "--connect", uvt_conf["vm_connect"],
@@ -1563,9 +1615,16 @@ def vm_start_wait(vm_name, timeout=1800, quiet=False, clone_name=None):
 
 def vm_ping(vm_name):
     '''Attempts to ping a VM'''
-    rc, out = runcmd(["ping", "-c1", "-w1", vm_name])
-    if rc == 0 and ssh_connect(vm_name) == True:
-        return vm_name
+
+    # Try to resolve address first
+    rc, out = runcmd(["virsh", "--connect", uvt_conf["vm_connect"],
+                      "domifaddr", vm_name])
+    addr_search = re.search("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", out)
+    vm_addr = addr_search.group(0) if ((rc == 0) and (addr_search is not None)) else vm_name
+
+    rc, out = runcmd(["ping", "-c1", "-w1", vm_addr])
+    if rc == 0 and ssh_connect(vm_addr) == True:
+        return vm_addr
     return ""
 
 def ssh_connect(host, resolve=True):
@@ -3608,6 +3667,7 @@ commands = {
     'update'   : cmd_update,
     'clone'    : cmd_clone,
     'cmd'      : cmd_cmd,
+    'ssh'      : cmd_ssh,
     'list'     : cmd_list,
     'config'   : cmd_config,
     'dump'     : cmd_dump,

Follow ups