From 5cf00a3e09630ad4754fad6799f6e056c2f4dbef Mon Sep 17 00:00:00 2001 From: gryf Date: Sat, 5 Jun 2021 19:14:49 +0200 Subject: [PATCH] Rework port for the ssh forwarding. Till now, user has to provide port number (by commandline or through config file), otherwise 2222 will be set. That's unfortunate in case you need to have multiple machines and forgot about setting the correct port. In this patch random port will be used if no port is provided. --- box.py | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/box.py b/box.py index e936bce..420c545 100755 --- a/box.py +++ b/box.py @@ -3,6 +3,7 @@ import argparse import collections.abc import os +import random import shutil import string import subprocess @@ -42,7 +43,6 @@ boxpy_data: disk_size: 10240 key: ~/.ssh/id_rsa memory: 2048 - port: 2222 ''' COMPLETIONS = {'bash': '''\ _boxpy() { @@ -494,7 +494,7 @@ class VBoxManage: '--delete']) != 0: raise BoxVBoxFailure(f'Removing VM {self.name_or_uuid} failed') - def create(self, cpus, memory, port): + def create(self, cpus, memory, port=None): self.uuid = None memory = convert_to_mega(memory) @@ -513,6 +513,9 @@ class VBoxManage: if not self.uuid: raise BoxVBoxFailure(f'Cannot create VM "{self.name_or_uuid}".') + if not port: + port = self._find_unused_port() + if subprocess.call(['vboxmanage', 'modifyvm', self.name_or_uuid, '--memory', str(memory), '--cpus', str(cpus), @@ -575,6 +578,48 @@ class VBoxManage: f'--{nic}', kind]) != 0: raise BoxVBoxFailure(f'Cannot modify VM "{self.name_or_uuid}".') + def _find_unused_port(self): + self.get_vm_info() + try: + out = subprocess.check_output(['vboxmanage', 'list', 'vms'], + encoding=sys.getdefaultencoding(), + stderr=subprocess.DEVNULL) + except subprocess.CalledProcessError: + return 0 + + used_ports = [] + for line in out.split('\n'): + if not line: + continue + vm_uuid = line.split('{')[1][:-1] + if self.vm_info['uuid'] == vm_uuid: + continue + + try: + info = (subprocess + .check_output(['vboxmanage', 'showvminfo', vm_uuid], + encoding=sys.getdefaultencoding(), + stderr=subprocess.DEVNULL)) + except subprocess.CalledProcessError: + continue + + for line in info.split('\n'): + if line.startswith('Config file:'): + config = line.split('Config ' 'file:')[1].strip() + + dom = xml.dom.minidom.parse(config) + gebtn = dom.getElementsByTagName + + if len(gebtn('Forwarding')): + used_ports.append(gebtn('Forwarding')[0] + .getAttribute('hostport')) + + while True: + port = random.randint(2000, 2999) + if port not in used_ports: + self.vm_info['port'] = port + return port + def _get_vm_config(self): if self.vm_info.get('config_file'): return self.vm_info['config_file'] @@ -858,6 +903,9 @@ def vmcreate(args, conf=None): # dettach ISO image _cleanup(vbox, iso, image, path_to_iso) vbox.poweron() + + # reread config to update fields + conf = Config(args, vbox) print('You can access your VM by issuing:') print(f'ssh -p {conf.port} -i {conf.ssh_key_path[:-4]} ' f'{DISTROS[conf.distro]["username"]}@localhost') @@ -937,7 +985,7 @@ def main(): create.add_argument('-n', '--hostname', help="VM hostname. Default same as vm name") create.add_argument('-p', '--port', help="set ssh port for VM, default " - "2222") + "random port from range 2000-2999") create.add_argument('-s', '--disk-size', help="disk size to be expanded " "to. By default to 10GB") create.add_argument('-u', '--cpus', type=int, help="amount of CPUs to be "