mirror of
https://github.com/GNS3/gns3-server.git
synced 2024-12-22 06:07:51 +00:00
VMware vmnets management almost complete.
This commit is contained in:
parent
0287b4607d
commit
3729a10783
@ -504,7 +504,7 @@ class VirtualBoxVM(BaseVM):
|
|||||||
"""
|
"""
|
||||||
Returns either GNS3 can use any VirtualBox adapter on this instance.
|
Returns either GNS3 can use any VirtualBox adapter on this instance.
|
||||||
|
|
||||||
:returns: index
|
:returns: boolean
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self._use_any_adapter
|
return self._use_any_adapter
|
||||||
@ -520,7 +520,7 @@ class VirtualBoxVM(BaseVM):
|
|||||||
if use_any_adapter:
|
if use_any_adapter:
|
||||||
log.info("VirtualBox VM '{name}' [{id}] is allowed to use any adapter".format(name=self.name, id=self.id))
|
log.info("VirtualBox VM '{name}' [{id}] is allowed to use any adapter".format(name=self.name, id=self.id))
|
||||||
else:
|
else:
|
||||||
log.info("VirtualBox VM '{name}' [{id}] is not allowd to use any adapter".format(name=self.name, id=self.id))
|
log.info("VirtualBox VM '{name}' [{id}] is not allowed to use any adapter".format(name=self.name, id=self.id))
|
||||||
self._use_any_adapter = use_any_adapter
|
self._use_any_adapter = use_any_adapter
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -21,11 +21,14 @@ VMware player/workstation server module.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import asyncio
|
import asyncio
|
||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from gns3server.utils.interfaces import interfaces
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -42,6 +45,12 @@ class VMware(BaseManager):
|
|||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._vmrun_path = None
|
self._vmrun_path = None
|
||||||
|
self._vmnets = []
|
||||||
|
self._vmnet_start_range = 2
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
self._vmnet_end_range = 19
|
||||||
|
else:
|
||||||
|
self._vmnet_end_range = 255
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vmrun_path(self):
|
def vmrun_path(self):
|
||||||
@ -82,6 +91,62 @@ class VMware(BaseManager):
|
|||||||
self._vmrun_path = vmrun_path
|
self._vmrun_path = vmrun_path
|
||||||
return vmrun_path
|
return vmrun_path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_vmnet_interfaces():
|
||||||
|
|
||||||
|
vmnet_interfaces = []
|
||||||
|
for interface in interfaces():
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
if "netcard" in interface:
|
||||||
|
windows_name = interface["netcard"]
|
||||||
|
else:
|
||||||
|
windows_name = interface["name"]
|
||||||
|
match = re.search("(VMnet[0-9]+)", windows_name)
|
||||||
|
if match:
|
||||||
|
vmnet = match.group(1)
|
||||||
|
if vmnet not in ("VMnet1", "VMnet8"):
|
||||||
|
vmnet_interfaces.append(vmnet)
|
||||||
|
elif interface["name"].startswith("vmnet"):
|
||||||
|
vmnet = interface["name"]
|
||||||
|
if vmnet not in ("vmnet1", "vmnet8"):
|
||||||
|
vmnet_interfaces.append(interface["name"])
|
||||||
|
return vmnet_interfaces
|
||||||
|
|
||||||
|
def is_managed_vmnet(self, vmnet):
|
||||||
|
|
||||||
|
self._vmnet_start_range = self.config.get_section_config("VMware").getint("vmnet_start_range", self._vmnet_start_range)
|
||||||
|
self._vmnet_end_range = self.config.get_section_config("VMware").getint("vmnet_end_range", self._vmnet_end_range)
|
||||||
|
match = re.search("vmnet([0-9]+)$", vmnet, re.IGNORECASE)
|
||||||
|
if match:
|
||||||
|
vmnet_number = match.group(1)
|
||||||
|
if self._vmnet_start_range <= int(vmnet_number) <= self._vmnet_end_range:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def allocate_vmnet(self):
|
||||||
|
|
||||||
|
if not self._vmnets:
|
||||||
|
raise VMwareError("No more VMnet interfaces available")
|
||||||
|
return self._vmnets.pop(0)
|
||||||
|
|
||||||
|
def refresh_vmnet_list(self):
|
||||||
|
|
||||||
|
vmnet_interfaces = self.get_vmnet_interfaces()
|
||||||
|
|
||||||
|
# remove vmnets already in use
|
||||||
|
for vm in self._vms.values():
|
||||||
|
for used_vmnet in vm.vmnets:
|
||||||
|
if used_vmnet in vmnet_interfaces:
|
||||||
|
log.debug("{} is already in use".format(used_vmnet))
|
||||||
|
vmnet_interfaces.remove(used_vmnet)
|
||||||
|
|
||||||
|
# remove vmnets that are not managed
|
||||||
|
for vmnet in vmnet_interfaces.copy():
|
||||||
|
if vmnet in vmnet_interfaces and self.is_managed_vmnet(vmnet) is False:
|
||||||
|
vmnet_interfaces.remove(vmnet)
|
||||||
|
|
||||||
|
self._vmnets = vmnet_interfaces
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def host_type(self):
|
def host_type(self):
|
||||||
"""
|
"""
|
||||||
|
@ -30,9 +30,9 @@ import configparser
|
|||||||
import shutil
|
import shutil
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from gns3server.utils.interfaces import interfaces
|
|
||||||
from gns3server.utils.asyncio import wait_for_process_termination
|
from gns3server.utils.asyncio import wait_for_process_termination
|
||||||
from gns3server.utils.asyncio import monitor_process
|
from gns3server.utils.asyncio import monitor_process
|
||||||
|
from collections import OrderedDict
|
||||||
from pkg_resources import parse_version
|
from pkg_resources import parse_version
|
||||||
from .vmware_error import VMwareError
|
from .vmware_error import VMwareError
|
||||||
from ..nios.nio_udp import NIOUDP
|
from ..nios.nio_udp import NIOUDP
|
||||||
@ -56,8 +56,11 @@ class VMwareVM(BaseVM):
|
|||||||
super().__init__(name, vm_id, project, manager, console=console)
|
super().__init__(name, vm_id, project, manager, console=console)
|
||||||
|
|
||||||
self._linked_clone = linked_clone
|
self._linked_clone = linked_clone
|
||||||
|
self._vmx_pairs = OrderedDict()
|
||||||
self._ubridge_process = None
|
self._ubridge_process = None
|
||||||
self._ubridge_stdout_file = ""
|
self._ubridge_stdout_file = ""
|
||||||
|
self._vmnets = []
|
||||||
|
self._maximum_adapters = 10
|
||||||
self._closed = False
|
self._closed = False
|
||||||
|
|
||||||
# VMware VM settings
|
# VMware VM settings
|
||||||
@ -67,6 +70,7 @@ class VMwareVM(BaseVM):
|
|||||||
self._adapters = 0
|
self._adapters = 0
|
||||||
self._ethernet_adapters = {}
|
self._ethernet_adapters = {}
|
||||||
self._adapter_type = "e1000"
|
self._adapter_type = "e1000"
|
||||||
|
self._use_any_adapter = False
|
||||||
|
|
||||||
if not os.path.exists(vmx_path):
|
if not os.path.exists(vmx_path):
|
||||||
raise VMwareError('VMware VM "{name}" [{id}]: could not find VMX file "{}"'.format(name, vmx_path))
|
raise VMwareError('VMware VM "{name}" [{id}]: could not find VMX file "{}"'.format(name, vmx_path))
|
||||||
@ -81,7 +85,13 @@ class VMwareVM(BaseVM):
|
|||||||
"headless": self.headless,
|
"headless": self.headless,
|
||||||
"enable_remote_console": self.enable_remote_console,
|
"enable_remote_console": self.enable_remote_console,
|
||||||
"adapters": self._adapters,
|
"adapters": self._adapters,
|
||||||
"adapter_type": self.adapter_type}
|
"adapter_type": self.adapter_type,
|
||||||
|
"use_any_adapter": self.use_any_adapter}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vmnets(self):
|
||||||
|
|
||||||
|
return self._vmnets
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _control_vm(self, subcommand, *additional_args):
|
def _control_vm(self, subcommand, *additional_args):
|
||||||
@ -92,25 +102,15 @@ class VMwareVM(BaseVM):
|
|||||||
log.debug("Control VM '{}' result: {}".format(subcommand, result))
|
log.debug("Control VM '{}' result: {}".format(subcommand, result))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _get_vmnet_interfaces(self):
|
def _get_vmx_setting(self, name, value=None):
|
||||||
|
|
||||||
vmnet_intefaces = []
|
if name in self._vmx_pairs:
|
||||||
for interface in interfaces():
|
if value is not None:
|
||||||
if sys.platform.startswith("win"):
|
if self._vmx_pairs[name] == value:
|
||||||
if "netcard" in interface:
|
return value
|
||||||
windows_name = interface["netcard"]
|
else:
|
||||||
else:
|
return self._vmx_pairs[name]
|
||||||
windows_name = interface["name"]
|
return None
|
||||||
match = re.search("(VMnet[0-9]+)", windows_name)
|
|
||||||
if match:
|
|
||||||
vmnet = match.group(1)
|
|
||||||
if vmnet not in ("VMnet1", "VMnet8"):
|
|
||||||
vmnet_intefaces.append(vmnet)
|
|
||||||
elif interface["name"].startswith("vmnet"):
|
|
||||||
vmnet = interface["name"]
|
|
||||||
if vmnet not in ("vmnet1", "vmnet8"):
|
|
||||||
vmnet_intefaces.append(interface["name"])
|
|
||||||
return vmnet_intefaces
|
|
||||||
|
|
||||||
def _set_network_options(self):
|
def _set_network_options(self):
|
||||||
|
|
||||||
@ -119,43 +119,70 @@ class VMwareVM(BaseVM):
|
|||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise VMwareError('Could not read VMware VMX file "{}": {}'.format(self._vmx_path, e))
|
raise VMwareError('Could not read VMware VMX file "{}": {}'.format(self._vmx_path, e))
|
||||||
|
|
||||||
vmnet_interfaces = self._get_vmnet_interfaces()
|
# first to some sanity checks
|
||||||
for adapter_number in range(0, self._adapters):
|
for adapter_number in range(0, self._adapters):
|
||||||
nio = self._ethernet_adapters[adapter_number].get_nio(0)
|
connected = "ethernet{}.startConnected".format(adapter_number)
|
||||||
if nio:
|
if self._get_vmx_setting(connected):
|
||||||
if "ethernet{}.present".format(adapter_number) in self._vmx_pairs:
|
del self._vmx_pairs[connected]
|
||||||
|
|
||||||
# check for the connection type
|
# check if any vmnet interface managed by GNS3 is being used on existing VMware adapters
|
||||||
connection_type = "ethernet{}.connectionType".format(adapter_number)
|
if self._get_vmx_setting("ethernet{}.present".format(adapter_number), "TRUE"):
|
||||||
if connection_type in self._vmx_pairs:
|
connection_type = "ethernet{}.connectionType".format(adapter_number)
|
||||||
if self._vmx_pairs[connection_type] not in ("hostonly", "custom"):
|
if self._vmx_pairs[connection_type] in ("hostonly", "custom"):
|
||||||
raise VMwareError("Attachment ({}) already configured on adapter {}. "
|
|
||||||
"Please set it to 'hostonly' or 'custom' to allow GNS3 to use it.".format(self._vmx_pairs[connection_type],
|
|
||||||
adapter_number))
|
|
||||||
# check for the vmnet interface
|
|
||||||
vnet = "ethernet{}.vnet".format(adapter_number)
|
vnet = "ethernet{}.vnet".format(adapter_number)
|
||||||
if vnet in self._vmx_pairs:
|
if vnet in self._vmx_pairs:
|
||||||
vmnet = os.path.basename(self._vmx_pairs[vnet])
|
vmnet = os.path.basename(self._vmx_pairs[vnet])
|
||||||
if vmnet in vmnet_interfaces:
|
if self.manager.is_managed_vmnet(vmnet):
|
||||||
vmnet_interfaces.remove(vmnet)
|
raise VMwareError("Network adapter {} is already associated with VMnet interface {} which is managed by GNS3, please remove".format(adapter_number, vmnet))
|
||||||
else:
|
|
||||||
raise VMwareError("Network adapter {} is not associated with a VMnet interface".format(adapter_number))
|
|
||||||
|
|
||||||
# check for adapter type
|
# check for adapter type
|
||||||
# adapter_type = "ethernet{}.virtualDev".format(adapter_number)
|
if self._adapter_type != "default":
|
||||||
# if adapter_type in self._vmx_pairs and self._vmx_pairs[adapter_type] != self._adapter_type:
|
adapter_type = "ethernet{}.virtualDev".format(adapter_number)
|
||||||
# raise VMwareError("Network adapter {} is not of type {}".format(self._adapter_type))
|
if adapter_type in self._vmx_pairs and self._vmx_pairs[adapter_type] != self._adapter_type:
|
||||||
# else:
|
raise VMwareError("Network adapter {} is not of type {}, please fix or remove it".format(self._adapter_type))
|
||||||
# self._vmx_pairs[adapter_type] = self._adapter_type
|
|
||||||
else:
|
|
||||||
new_ethernet_adapter = {"ethernet{}.present".format(adapter_number): "TRUE",
|
|
||||||
"ethernet{}.connectionType".format(adapter_number): "custom",
|
|
||||||
"ethernet{}.vnet".format(adapter_number): "vmnet1",
|
|
||||||
"ethernet{}.addressType".format(adapter_number): "generated",
|
|
||||||
"ethernet{}.generatedAddressOffset".format(adapter_number): "0"}
|
|
||||||
self._vmx_pairs.update(new_ethernet_adapter)
|
|
||||||
|
|
||||||
#raise VMwareError("Network adapter {} does not exist".format(adapter_number))
|
# check if connected to an adapter configured for nat or bridge
|
||||||
|
if self._ethernet_adapters[adapter_number].get_nio(0) and not self._use_any_adapter:
|
||||||
|
if self._get_vmx_setting("ethernet{}.present".format(adapter_number), "TRUE"):
|
||||||
|
# check for the connection type
|
||||||
|
connection_type = "ethernet{}.connectionType".format(adapter_number)
|
||||||
|
if connection_type in self._vmx_pairs:
|
||||||
|
if self._vmx_pairs[connection_type] in ("nat", "bridged", "hostonly"):
|
||||||
|
raise VMwareError("Attachment ({}) already configured on network adapter {}. "
|
||||||
|
"Please remove it or allow GNS3 to use any adapter.".format(self._vmx_pairs[connection_type],
|
||||||
|
adapter_number))
|
||||||
|
|
||||||
|
# now configure VMware network adapters
|
||||||
|
self.manager.refresh_vmnet_list()
|
||||||
|
for adapter_number in range(0, self._adapters):
|
||||||
|
ethernet_adapter = {"ethernet{}.present".format(adapter_number): "TRUE",
|
||||||
|
"ethernet{}.addressType".format(adapter_number): "generated",
|
||||||
|
"ethernet{}.generatedAddressOffset".format(adapter_number): "0"}
|
||||||
|
self._vmx_pairs.update(ethernet_adapter)
|
||||||
|
if self._adapter_type != "default":
|
||||||
|
self._vmx_pairs["ethernet{}.virtualDev".format(adapter_number)] = self._adapter_type
|
||||||
|
|
||||||
|
connection_type = "ethernet{}.connectionType".format(adapter_number)
|
||||||
|
if not self._use_any_adapter and connection_type in self._vmx_pairs and self._vmx_pairs[connection_type] in ("nat", "bridged", "hostonly"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
vnet = "ethernet{}.vnet".format(adapter_number)
|
||||||
|
if vnet in self._vmx_pairs:
|
||||||
|
vmnet = os.path.basename(self._vmx_pairs[vnet])
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
vmnet = self.manager.allocate_vmnet()
|
||||||
|
finally:
|
||||||
|
self._vmnets.clear()
|
||||||
|
self._vmnets.append(vmnet)
|
||||||
|
self._vmx_pairs["ethernet{}.connectionType".format(adapter_number)] = "custom"
|
||||||
|
self._vmx_pairs["ethernet{}.vnet".format(adapter_number)] = vmnet
|
||||||
|
|
||||||
|
# disable remaining network adapters
|
||||||
|
for adapter_number in range(self._adapters, self._maximum_adapters):
|
||||||
|
if self._get_vmx_setting("ethernet{}.present".format(adapter_number), "TRUE"):
|
||||||
|
log.debug("disabling remaining adapter {}".format(adapter_number))
|
||||||
|
self._vmx_pairs["ethernet{}.startConnected".format(adapter_number)] = "FALSE"
|
||||||
|
|
||||||
self.manager.write_vmx_file(self._vmx_path, self._vmx_pairs)
|
self.manager.write_vmx_file(self._vmx_path, self._vmx_pairs)
|
||||||
self._update_ubridge_config()
|
self._update_ubridge_config()
|
||||||
@ -180,7 +207,7 @@ class VMwareVM(BaseVM):
|
|||||||
if sys.platform.startswith("linux"):
|
if sys.platform.startswith("linux"):
|
||||||
config[bridge_name] = {"source_linux_raw": vmnet_interface}
|
config[bridge_name] = {"source_linux_raw": vmnet_interface}
|
||||||
elif sys.platform.startswith("win"):
|
elif sys.platform.startswith("win"):
|
||||||
windows_interfaces = interfaces()
|
windows_interfaces = self.manager.get_vmnet_interfaces()
|
||||||
npf = None
|
npf = None
|
||||||
for interface in windows_interfaces:
|
for interface in windows_interfaces:
|
||||||
if "netcard" in interface and vmnet_interface in interface["netcard"]:
|
if "netcard" in interface and vmnet_interface in interface["netcard"]:
|
||||||
@ -333,7 +360,39 @@ class VMwareVM(BaseVM):
|
|||||||
self._ubridge_process.kill()
|
self._ubridge_process.kill()
|
||||||
self._ubridge_process = None
|
self._ubridge_process = None
|
||||||
|
|
||||||
yield from self._control_vm("stop")
|
try:
|
||||||
|
yield from self._control_vm("stop")
|
||||||
|
finally:
|
||||||
|
|
||||||
|
self._vmnets.clear()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._vmx_pairs = self.manager.parse_vmware_file(self._vmx_path)
|
||||||
|
except OSError as e:
|
||||||
|
raise VMwareError('Could not read VMware VMX file "{}": {}'.format(self._vmx_path, e))
|
||||||
|
|
||||||
|
# remove the adapters managed by GNS3
|
||||||
|
for adapter_number in range(0, self._adapters):
|
||||||
|
if self._get_vmx_setting("ethernet{}.vnet".format(adapter_number)) or \
|
||||||
|
self._get_vmx_setting("ethernet{}.connectionType".format(adapter_number)) is None:
|
||||||
|
vnet = "ethernet{}.vnet".format(adapter_number)
|
||||||
|
if vnet in self._vmx_pairs:
|
||||||
|
vmnet = os.path.basename(self._vmx_pairs[vnet])
|
||||||
|
if not self.manager.is_managed_vmnet(vmnet):
|
||||||
|
continue
|
||||||
|
log.debug("removing adapter {}".format(adapter_number))
|
||||||
|
for key in self._vmx_pairs.keys():
|
||||||
|
if key.startswith("ethernet{}.".format(adapter_number)):
|
||||||
|
del self._vmx_pairs[key]
|
||||||
|
|
||||||
|
# re-enable any remaining network adapters
|
||||||
|
for adapter_number in range(self._adapters, self._maximum_adapters):
|
||||||
|
if self._get_vmx_setting("ethernet{}.present".format(adapter_number), "TRUE"):
|
||||||
|
log.debug("enabling remaining adapter {}".format(adapter_number))
|
||||||
|
self._vmx_pairs["ethernet{}.startConnected".format(adapter_number)] = "TRUE"
|
||||||
|
|
||||||
|
self.manager.write_vmx_file(self._vmx_path, self._vmx_pairs)
|
||||||
|
|
||||||
log.info("VMware VM '{name}' [{id}] stopped".format(name=self.name, id=self.id))
|
log.info("VMware VM '{name}' [{id}] stopped".format(name=self.name, id=self.id))
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@ -521,6 +580,30 @@ class VMwareVM(BaseVM):
|
|||||||
id=self.id,
|
id=self.id,
|
||||||
adapter_type=adapter_type))
|
adapter_type=adapter_type))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def use_any_adapter(self):
|
||||||
|
"""
|
||||||
|
Returns either GNS3 can use any VMware adapter on this instance.
|
||||||
|
|
||||||
|
:returns: boolean
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self._use_any_adapter
|
||||||
|
|
||||||
|
@use_any_adapter.setter
|
||||||
|
def use_any_adapter(self, use_any_adapter):
|
||||||
|
"""
|
||||||
|
Allows GNS3 to use any VMware adapter on this instance.
|
||||||
|
|
||||||
|
:param use_any_adapter: boolean
|
||||||
|
"""
|
||||||
|
|
||||||
|
if use_any_adapter:
|
||||||
|
log.info("VMware VM '{name}' [{id}] is allowed to use any adapter".format(name=self.name, id=self.id))
|
||||||
|
else:
|
||||||
|
log.info("VMware VM '{name}' [{id}] is not allowed to use any adapter".format(name=self.name, id=self.id))
|
||||||
|
self._use_any_adapter = use_any_adapter
|
||||||
|
|
||||||
def adapter_add_nio_binding(self, adapter_number, nio):
|
def adapter_add_nio_binding(self, adapter_number, nio):
|
||||||
"""
|
"""
|
||||||
Adds an adapter NIO binding.
|
Adds an adapter NIO binding.
|
||||||
|
@ -67,6 +67,10 @@ VMWARE_CREATE_SCHEMA = {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
},
|
},
|
||||||
|
"use_any_adapter": {
|
||||||
|
"description": "allow GNS3 to use any VMware adapter",
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
"required": ["name", "vmx_path", "linked_clone"],
|
"required": ["name", "vmx_path", "linked_clone"],
|
||||||
@ -112,6 +116,10 @@ VMWARE_UPDATE_SCHEMA = {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
},
|
},
|
||||||
|
"use_any_adapter": {
|
||||||
|
"description": "allow GNS3 to use any VMware adapter",
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
}
|
}
|
||||||
@ -164,6 +172,10 @@ VMWARE_OBJECT_SCHEMA = {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
},
|
},
|
||||||
|
"use_any_adapter": {
|
||||||
|
"description": "allow GNS3 to use any VMware adapter",
|
||||||
|
"type": "boolean",
|
||||||
|
},
|
||||||
"console": {
|
"console": {
|
||||||
"description": "console TCP port",
|
"description": "console TCP port",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
|
Loading…
Reference in New Issue
Block a user