From 8a6d558402bddfc9ab62812b3116e8f467467e09 Mon Sep 17 00:00:00 2001 From: mirsal Date: Wed, 4 Aug 2021 11:32:32 +0000 Subject: [PATCH 1/3] Retrieve IPv6 addresses from VMs This commit allows the model to fetch IPv6 addresses from running VMs and populate VirtualMachine objects with the value if it was retrieved successfully --- capsulflask/shell_scripts/get.sh | 5 +++-- capsulflask/spoke_model.py | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/capsulflask/shell_scripts/get.sh b/capsulflask/shell_scripts/get.sh index 6d57a35..ee579ef 100755 --- a/capsulflask/shell_scripts/get.sh +++ b/capsulflask/shell_scripts/get.sh @@ -29,7 +29,8 @@ if virsh domuuid "$vmname" | grep -vqE '^[\t\s\n]*$'; then esac fi -# this gets the ipv4 +# this gets the vm ip addresses ipv4="$(virsh domifaddr "$vmname" | awk '/ipv4/ {print $4}' | cut -d'/' -f1)" +ipv6="$(virsh domifaddr "$vmname" | awk '/ipv6/ {print $4}' | cut -d'/' -f1)" -echo "$exists $state $ipv4" \ No newline at end of file +echo "$exists $state $ipv4 $ipv6" diff --git a/capsulflask/spoke_model.py b/capsulflask/spoke_model.py index 9ab0d3a..25107b0 100644 --- a/capsulflask/spoke_model.py +++ b/capsulflask/spoke_model.py @@ -114,24 +114,30 @@ class ShellScriptSpoke(VirtualizationInterface): if len(fields) < 3: return VirtualMachine(id, current_app.config["SPOKE_HOST_ID"], state=state) - ipaddr = fields[2] + ip4addr = fields[2] - if not re.match(r"^([0-9]{1,3}\.){3}[0-9]{1,3}$", ipaddr): + if not re.match(r"^([0-9]{1,3}\.){3}[0-9]{1,3}$", ip4addr): return VirtualMachine(id, current_app.config["SPOKE_HOST_ID"], state=state) if get_ssh_host_keys: try: - completedProcess2 = run([join(current_app.root_path, 'shell_scripts/ssh-keyscan.sh'), ipaddr], capture_output=True) + completedProcess2 = run([join(current_app.root_path, 'shell_scripts/ssh-keyscan.sh'), ip4addr], capture_output=True) self.validate_completed_process(completedProcess2) ssh_host_keys = json.loads(completedProcess2.stdout.decode("utf-8")) - return VirtualMachine(id, current_app.config["SPOKE_HOST_ID"], state=state, ipv4=ipaddr, ssh_host_keys=ssh_host_keys) + return VirtualMachine(id, current_app.config["SPOKE_HOST_ID"], state=state, ipv4=ip4addr, ssh_host_keys=ssh_host_keys) except: current_app.logger.warning(f""" - failed to ssh-keyscan {id} at {ipaddr}: + failed to ssh-keyscan {id} at {ip4addr}: {my_exec_info_message(sys.exc_info())}""" ) - return VirtualMachine(id, current_app.config["SPOKE_HOST_ID"], state=state, ipv4=ipaddr) + if len(fields) < 4: + return VirtualMachine(id, current_app.config["SPOKE_HOST_ID"], state=state, ipv4=ip4addr) + + ip6addr = fields[3] + + return VirtualMachine(id, current_app.config["SPOKE_HOST_ID"], state=state, ipv4=ip4addr, ipv6=ip6addr) + def list_ids(self) -> list: completedProcess = run([join(current_app.root_path, 'shell_scripts/list-ids.sh')], capture_output=True) From 17c915c1bf680382b6f84039abe38cdc357836e9 Mon Sep 17 00:00:00 2001 From: mirsal Date: Wed, 4 Aug 2021 14:55:29 +0000 Subject: [PATCH 2/3] Support dualstack ipv6 in the console controller This commit updates the console controller logic and a few bits in the model in order to support multiple address families (ipv4 and ipv6) --- capsulflask/console.py | 48 ++++++++++++++++++++++------------------- capsulflask/db_model.py | 6 +++++- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/capsulflask/console.py b/capsulflask/console.py index d4cdbe8..2b3ae0c 100644 --- a/capsulflask/console.py +++ b/capsulflask/console.py @@ -29,12 +29,14 @@ def make_capsul_id(): letters_n_nummers = generate(alphabet="1234567890qwertyuiopasdfghjklzxcvbnm", size=10) return f"capsul-{letters_n_nummers}" -def double_check_capsul_address(id, ipv4, get_ssh_host_keys): +def double_check_capsul_address(id, ipv4, ipv6, get_ssh_host_keys): try: result = current_app.config["HUB_MODEL"].get(id, get_ssh_host_keys) if result != None and result.ipv4 != None and result.ipv4 != ipv4: - ipv4 = result.ipv4 - get_model().update_vm_ip(email=session["account"], id=id, ipv4=result.ipv4) + get_model().update_vm_ipv4(email=session["account"], id=id, ipv4=result.ipv4) + + if result != None and result.ipv6 != None and result.ipv6 != ipv6: + get_model().update_vm_ipv6(email=session["account"], id=id, ipv6=result.ipv6) if result != None and result.ssh_host_keys != None and get_ssh_host_keys: get_model().update_vm_ssh_host_keys(email=session["account"], id=id, ssh_host_keys=result.ssh_host_keys) @@ -61,37 +63,38 @@ def index(): # for now we are going to check the IP according to the virt model # on every request. this could be done by a background job and cached later on... for vm in vms: - result = double_check_capsul_address(vm["id"], vm["ipv4"], False) + result = double_check_capsul_address(vm["id"], vm["ipv4"], vm["ipv6"], False) if result is not None: vm["ipv4"] = result.ipv4 + vm["ipv6"] = result.ipv6 vm["state"] = result.state else: vm["state"] = "unknown" - mappedVms = [] for vm in vms: - ip_display = vm['ipv4'] - if not ip_display: - if vm["state"] == "running": - ip_display = "..booting.." - else: - ip_display = "unknown" - - ip_display_class = "ok" - if not vm['ipv4']: - if vm["state"] == "running": - ip_display_class = "waiting-pulse" - else: - ip_display_class = "yellow" + ip_display = {} + ip_display_class = {} + for af in ['ipv4', 'ipv6']: + ip_display[af] = vm[af] + ip_display_class[af] = "ok" + if not ip_display[af]: + if vm["state"] == "running": + ip_display[af] = "..booting.." + ip_display_class[af] = "waiting-pulse" + else: + ip_display[af] = "unknown" + ip_display_class[af] = "yellow" mappedVms.append(dict( id=vm['id'], size=vm['size'], state=vm['state'], - ipv4=ip_display, - ipv4_status=ip_display_class, - os=vm['os'], + ipv4=ip_display['ipv4'], + ipv4_status=ip_display_class['ipv4'], + ipv6=ip_display['ipv6'], + ipv6_status=ip_display_class['ipv6'], + os=vm['os'], created=vm['created'].strftime("%b %d %Y") )) @@ -168,10 +171,11 @@ def detail(id): else: needs_ssh_host_keys = "ssh_host_keys" not in vm or len(vm["ssh_host_keys"]) == 0 - vm_from_virt_model = double_check_capsul_address(vm["id"], vm["ipv4"], needs_ssh_host_keys) + vm_from_virt_model = double_check_capsul_address(vm["id"], vm["ipv4"], vm['ipv6'], needs_ssh_host_keys) if vm_from_virt_model is not None: vm["ipv4"] = vm_from_virt_model.ipv4 + vm["ipv6"] = vm_from_virt_model.ipv6 vm["state"] = vm_from_virt_model.state if needs_ssh_host_keys: vm["ssh_host_keys"] = vm_from_virt_model.ssh_host_keys diff --git a/capsulflask/db_model.py b/capsulflask/db_model.py index ff53381..ce65091 100644 --- a/capsulflask/db_model.py +++ b/capsulflask/db_model.py @@ -179,10 +179,14 @@ class DBModel: self.cursor.fetchall() )) - def update_vm_ip(self, email, id, ipv4): + def update_vm_ipv4(self, email, id, ipv4): self.cursor.execute("UPDATE vms SET public_ipv4 = %s WHERE email = %s AND id = %s", (ipv4, email, id)) self.connection.commit() + def update_vm_ipv6(self, email, id, ipv6): + self.cursor.execute("UPDATE vms SET public_ipv6 = %s WHERE email = %s AND id = %s", (ipv6, email, id)) + self.connection.commit() + def update_vm_ssh_host_keys(self, email, id, ssh_host_keys): for key in ssh_host_keys: self.cursor.execute(""" From d238bc9551d4ce14f83020fe932845ef6f602718 Mon Sep 17 00:00:00 2001 From: mirsal Date: Wed, 4 Aug 2021 14:59:30 +0000 Subject: [PATCH 3/3] cosmetics: Remove trailing whitespace --- capsulflask/console.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/capsulflask/console.py b/capsulflask/console.py index 2b3ae0c..3dabb11 100644 --- a/capsulflask/console.py +++ b/capsulflask/console.py @@ -87,8 +87,8 @@ def index(): ip_display_class[af] = "yellow" mappedVms.append(dict( - id=vm['id'], - size=vm['size'], + id=vm['id'], + size=vm['size'], state=vm['state'], ipv4=ip_display['ipv4'], ipv4_status=ip_display_class['ipv4'],