Skip to content

Commit

Permalink
Add "enable console" option to VirtualBox VMs (True by default).
Browse files Browse the repository at this point in the history
Add "start at" option to VirtualBox VMs (adapter start index, 0 by default).
  • Loading branch information
grossmj committed Aug 26, 2014
1 parent 934404c commit 80ab811
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 31 deletions.
5 changes: 4 additions & 1 deletion gns3server/modules/virtualbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,10 @@ def vbox_start(self, request):
try:
vbox_instance.start()
except VirtualBoxError as e:
self.send_custom_error(str(e))
if self._vboxwrapper:
self.send_custom_error("{}: {}".format(e, self._vboxwrapper.read_stderr()))
else:
self.send_custom_error(str(e))
return
self.send_response(True)

Expand Down
12 changes: 11 additions & 1 deletion gns3server/modules/virtualbox/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,15 @@
"adapters": {
"description": "number of adapters",
"type": "integer",
"minimum": 0,
"minimum": 1,
"maximum": 36, # maximum given by the ICH9 chipset in VirtualBox
},
"adapter_start_index": {
"description": "adapter index from which to start using adapters",
"type": "integer",
"minimum": 0,
"maximum": 35, # maximum given by the ICH9 chipset in VirtualBox
},
"adapter_type": {
"description": "VirtualBox adapter type",
"type": "string",
Expand All @@ -96,6 +102,10 @@
"maximum": 65535,
"type": "integer"
},
"enable_console": {
"description": "enable the console",
"type": "boolean"
},
"headless": {
"description": "headless mode",
"type": "boolean"
Expand Down
78 changes: 53 additions & 25 deletions gns3server/modules/virtualbox/virtualbox_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __init__(self, vmname, vboxmanager, host):
self._console = 0
self._adapters = []
self._headless = False
self._enable_console = True
self._adapter_type = "Automatic"

try:
Expand Down Expand Up @@ -101,6 +102,16 @@ def headless(self, headless):

self._headless = headless

@property
def enable_console(self):

return self._enable_console

@enable_console.setter
def enable_console(self, enable_console):

self._enable_console = enable_console

@property
def adapters(self):

Expand All @@ -123,13 +134,17 @@ def adapter_type(self, adapter_type):

def start(self):

if len(self._adapters) > self._maximum_adapters:
raise VirtualBoxError("Number of adapters above the maximum supported of {}".format(self._maximum_adapters))

if self._machine.state == self._vboxmanager.constants.MachineState_Paused:
self.resume()
return

self._get_session()
self._set_network_options()
self._set_console_options()
if self._enable_console:
self._set_console_options()

progress = self._launch_vm_process()
log.info("VM is starting with {}% completed".format(progress.percent))
Expand All @@ -145,25 +160,26 @@ def start(self):
except Exception:
pass

# starts the Telnet to pipe thread
pipe_name = self._get_pipe_name()
if sys.platform.startswith('win'):
try:
self._serial_pipe = open(pipe_name, "a+b")
except OSError as e:
raise VirtualBoxError("Could not open the pipe {}: {}".format(pipe_name, e))
self._serial_pipe_thread = PipeProxy(self._vmname, msvcrt.get_osfhandle(self._serial_pipe.fileno()), self._host, self._console)
#self._serial_pipe_thread.setDaemon(True)
self._serial_pipe_thread.start()
else:
try:
self._serial_pipe = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self._serial_pipe.connect(pipe_name)
except OSError as e:
raise VirtualBoxError("Could not connect to the pipe {}: {}".format(pipe_name, e))
self._serial_pipe_thread = PipeProxy(self._vmname, self._serial_pipe, self._host, self._console)
#self._serial_pipe_thread.setDaemon(True)
self._serial_pipe_thread.start()
if self._enable_console:
# starts the Telnet to pipe thread
pipe_name = self._get_pipe_name()
if sys.platform.startswith('win'):
try:
self._serial_pipe = open(pipe_name, "a+b")
except OSError as e:
raise VirtualBoxError("Could not open the pipe {}: {}".format(pipe_name, e))
self._serial_pipe_thread = PipeProxy(self._vmname, msvcrt.get_osfhandle(self._serial_pipe.fileno()), self._host, self._console)
#self._serial_pipe_thread.setDaemon(True)
self._serial_pipe_thread.start()
else:
try:
self._serial_pipe = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self._serial_pipe.connect(pipe_name)
except OSError as e:
raise VirtualBoxError("Could not connect to the pipe {}: {}".format(pipe_name, e))
self._serial_pipe_thread = PipeProxy(self._vmname, self._serial_pipe, self._host, self._console)
#self._serial_pipe_thread.setDaemon(True)
self._serial_pipe_thread.start()

def stop(self):

Expand Down Expand Up @@ -196,8 +212,14 @@ def stop(self):
log.info("VM is stopping with {}% completed".format(self.vmname, progress.percent))

self._lock_machine()

for adapter_id in range(0, len(self._adapters)):
if self._adapters[adapter_id] is None:
continue
self._disable_adapter(adapter_id, disable=True)
if self._enable_console:
serial_port = self._session.machine.getSerialPort(0)
serial_port.enabled = False
self._session.machine.saveSettings()
self._unlock_machine()
except Exception as e:
Expand Down Expand Up @@ -252,11 +274,17 @@ def _set_network_options(self):
#raise VirtualBoxError("VirtualBox error: {}".format(e))

for adapter_id in range(0, len(self._adapters)):

try:
# VirtualBox starts counting from 0
adapter = self._session.machine.getNetworkAdapter(adapter_id)
vbox_adapter_type = adapter.adapterType
if self._adapters[adapter_id] is None:
# force enable to avoid any discrepancy in the interface numbering inside the VM
# e.g. Ethernet2 in GNS3 becoming eth0 inside the VM when using a start index of 2.
adapter.enabled = True
continue

vbox_adapter_type = adapter.adapterType
if self._adapter_type == "PCnet-PCI II (Am79C970A)":
vbox_adapter_type = self._vboxmanager.constants.NetworkAdapterType_Am79C970A
if self._adapter_type == "PCNet-FAST III (Am79C973)":
Expand Down Expand Up @@ -310,9 +338,9 @@ def _set_network_options(self):
except Exception as e:
raise VirtualBoxError("VirtualBox error: {}".format(e))

#for adapter_id in range(len(self._ethernet_adapters), self._maximum_adapters):
# log.debug("disabling remaining adapter {}".format(adapter_id))
# self._disable_adapter(adapter_id)
for adapter_id in range(len(self._adapters), self._maximum_adapters):
log.debug("disabling remaining adapter {}".format(adapter_id))
self._disable_adapter(adapter_id)

try:
self._session.machine.saveSettings()
Expand Down Expand Up @@ -526,4 +554,4 @@ def _unlock_machine(self):
log.warn("cannot unlock the machine for {}, retrying {}: {}".format(self._vmname, retry + 1, e))
time.sleep(1)
last_exception = e
continue
continue
74 changes: 70 additions & 4 deletions gns3server/modules/virtualbox/virtualbox_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ def __init__(self,
self._console = console
self._ethernet_adapters = []
self._headless = False
self._enable_console = True
self._vmname = vmname
self._adapter_start_index = 0
self._adapter_type = "Automatic"

working_dir_path = os.path.join(working_dir, "vbox", "vm-{}".format(self._id))
Expand Down Expand Up @@ -137,9 +139,11 @@ def defaults(self):

vbox_defaults = {"name": self._name,
"vmname": self._vmname,
"adapters": len(self._ethernet_adapters),
"adapters": self.adapters,
"adapter_start_index": self._adapter_start_index,
"adapter_type": "Automatic",
"console": self._console,
"enable_console": self._enable_console,
"headless": self._headless}

return vbox_defaults
Expand Down Expand Up @@ -329,6 +333,38 @@ def headless(self, headless):
log.info("VirtualBox VM {name} [id={id}] has disabled the headless mode".format(name=self._name, id=self._id))
self._headless = headless

@property
def enable_console(self):
"""
Returns either the console is enabled or not
:returns: boolean
"""

return self._enable_console

@enable_console.setter
def enable_console(self, enable_console):
"""
Sets either the console is enabled or not
:param enable_console: boolean
"""

if enable_console:
if self._vboxwrapper:
self._vboxwrapper.send('vbox setattr "{}" enable_console True'.format(self._name))
else:
self._vboxcontroller.enable_console = True
log.info("VirtualBox VM {name} [id={id}] has enabled the console".format(name=self._name, id=self._id))
else:
if self._vboxwrapper:
self._vboxwrapper.send('vbox setattr "{}" enable_console False'.format(self._name))
else:
self._vboxcontroller.enable_console = False
log.info("VirtualBox VM {name} [id={id}] has disabled the console".format(name=self._name, id=self._id))
self._enable_console = enable_console

@property
def vmname(self):
"""
Expand Down Expand Up @@ -374,17 +410,47 @@ def adapters(self, adapters):
"""

self._ethernet_adapters.clear()
for _ in range(0, adapters):
for adapter_id in range(0, self._adapter_start_index + adapters):
if adapter_id < self._adapter_start_index:
self._ethernet_adapters.append(None)
continue
self._ethernet_adapters.append(EthernetAdapter())

if self._vboxwrapper:
self._vboxwrapper.send('vbox setattr "{}" nics {}'.format(self._name, len(self._ethernet_adapters)))
self._vboxwrapper.send('vbox setattr "{}" nics {}'.format(self._name, adapters))
else:
self._vboxcontroller.adapters = self._ethernet_adapters

log.info("VirtualBox VM {name} [id={id}]: number of Ethernet adapters changed to {adapters}".format(name=self._name,
id=self._id,
adapters=len(self._ethernet_adapters)))
adapters=adapters))

@property
def adapter_start_index(self):
"""
Returns the adapter start index for this VirtualBox VM instance.
:returns: index
"""

return self._adapter_start_index

@adapter_start_index.setter
def adapter_start_index(self, adapter_start_index):
"""
Sets the adapter start index for this VirtualBox VM instance.
:param adapter_start_index: index
"""

if self._vboxwrapper:
self._vboxwrapper.send('vbox setattr "{}" nic_start_index {}'.format(self._name, adapter_start_index))

self._adapter_start_index = adapter_start_index
self.adapters = self.adapters # this forces to recreate the adapter list with the correct index
log.info("VirtualBox VM {name} [id={id}]: adapter start index changed to {index}".format(name=self._name,
id=self._id,
index=adapter_start_index))

@property
def adapter_type(self):
Expand Down

0 comments on commit 80ab811

Please sign in to comment.