mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 14:01:15 +02:00
Make sure used ports in a project are cleaned up when closing it.
This commit is contained in:
1 parent
2d6d153262
commit
153914bf97
17 files changed
+127
-65
No files matched your search
@@ -50,9 +50,9 @@ class BaseVM:
|
||||
self._temporary_directory = None
|
||||
|
||||
if self._console is not None:
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(self._console)
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(self._console, self._project)
|
||||
else:
|
||||
self._console = self._manager.port_manager.get_free_tcp_port()
|
||||
self._console = self._manager.port_manager.get_free_tcp_port(self._project)
|
||||
|
||||
log.debug("{module}: {name} [{id}] initialized. Console port {console}".format(
|
||||
module=self.manager.module_name,
|
||||
@@ -203,8 +203,8 @@ class BaseVM:
|
||||
if console == self._console:
|
||||
return
|
||||
if self._console:
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(console, self._project)
|
||||
log.info("{module}: '{name}' [{id}]: console port set to {port}".format(
|
||||
module=self.manager.module_name,
|
||||
name=self.name,
|
||||
|
||||
@@ -109,7 +109,7 @@ class ATMSwitch(Device):
|
||||
|
||||
for nio in self._nios.values():
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
try:
|
||||
yield from self._hypervisor.send('atmsw delete "{}"'.format(self._name))
|
||||
@@ -162,7 +162,7 @@ class ATMSwitch(Device):
|
||||
|
||||
nio = self._nios[port_number]
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
log.info('ATM switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
|
||||
@@ -76,7 +76,7 @@ class EthernetHub(Bridge):
|
||||
|
||||
for nio in self._nios:
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
try:
|
||||
yield from Bridge.delete(self)
|
||||
@@ -121,7 +121,7 @@ class EthernetHub(Bridge):
|
||||
|
||||
nio = self._mappings[port_number]
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
yield from Bridge.remove_nio(self, nio)
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
|
||||
@@ -117,7 +117,7 @@ class EthernetSwitch(Device):
|
||||
|
||||
for nio in self._nios.values():
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
try:
|
||||
yield from self._hypervisor.send('ethsw delete "{}"'.format(self._name))
|
||||
@@ -164,7 +164,7 @@ class EthernetSwitch(Device):
|
||||
|
||||
nio = self._nios[port_number]
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
yield from self._hypervisor.send('ethsw remove_nio "{name}" {nio}'.format(name=self._name, nio=nio))
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
|
||||
@@ -108,7 +108,7 @@ class FrameRelaySwitch(Device):
|
||||
|
||||
for nio in self._nios.values():
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
try:
|
||||
yield from self._hypervisor.send('frsw delete "{}"'.format(self._name))
|
||||
@@ -163,7 +163,7 @@ class FrameRelaySwitch(Device):
|
||||
|
||||
nio = self._nios[port_number]
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
log.info('Frame Relay switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
|
||||
@@ -109,16 +109,16 @@ class Router(BaseVM):
|
||||
self._dynamips_ids[project.id].append(self._dynamips_id)
|
||||
|
||||
if self._aux is not None:
|
||||
self._aux = self._manager.port_manager.reserve_tcp_port(self._aux)
|
||||
self._aux = self._manager.port_manager.reserve_tcp_port(self._aux, self._project)
|
||||
else:
|
||||
allocate_aux = self.manager.config.get_section_config("Dynamips").getboolean("allocate_aux_console_ports", False)
|
||||
if allocate_aux:
|
||||
self._aux = self._manager.port_manager.get_free_tcp_port()
|
||||
self._aux = self._manager.port_manager.get_free_tcp_port(self._project)
|
||||
else:
|
||||
log.info("Creating a new ghost IOS instance")
|
||||
if self._console:
|
||||
# Ghost VMs do not need a console port.
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = None
|
||||
self._dynamips_id = 0
|
||||
self._name = "Ghost"
|
||||
@@ -326,18 +326,18 @@ class Router(BaseVM):
|
||||
self._dynamips_ids[self._project.id].remove(self._dynamips_id)
|
||||
|
||||
if self._console:
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = None
|
||||
|
||||
if self._aux:
|
||||
self._manager.port_manager.release_tcp_port(self._aux)
|
||||
self._manager.port_manager.release_tcp_port(self._aux, self._project)
|
||||
self._aux = None
|
||||
|
||||
for adapter in self._slots:
|
||||
if adapter is not None:
|
||||
for nio in adapter.ports.values():
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
if self in self._hypervisor.devices:
|
||||
self._hypervisor.devices.remove(self)
|
||||
@@ -876,8 +876,8 @@ class Router(BaseVM):
|
||||
old_console=self._console,
|
||||
new_console=console))
|
||||
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = self._manager.port_manager.reserve_tcp_port(console, self._project)
|
||||
|
||||
@property
|
||||
def aux(self):
|
||||
@@ -904,8 +904,8 @@ class Router(BaseVM):
|
||||
old_aux=self._aux,
|
||||
new_aux=aux))
|
||||
|
||||
self._manager.port_manager.release_tcp_port(self._aux)
|
||||
self._aux = self._manager.port_manager.reserve_tcp_port(aux)
|
||||
self._manager.port_manager.release_tcp_port(self._aux, self._project)
|
||||
self._aux = self._manager.port_manager.reserve_tcp_port(aux, self._project)
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_cpu_usage(self, cpu_id=0):
|
||||
@@ -1228,7 +1228,7 @@ class Router(BaseVM):
|
||||
if nio is None:
|
||||
return
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
adapter.remove_nio(port_number)
|
||||
|
||||
log.info('Router "{name}" [{id}]: NIO {nio_name} removed from port {slot_number}/{port_number}'.format(name=self._name,
|
||||
|
||||
@@ -111,7 +111,7 @@ class IOUVM(BaseVM):
|
||||
log.debug('IOU "{name}" [{id}] is closing'.format(name=self._name, id=self._id))
|
||||
|
||||
if self._console:
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = None
|
||||
|
||||
adapters = self._ethernet_adapters + self._serial_adapters
|
||||
@@ -119,7 +119,7 @@ class IOUVM(BaseVM):
|
||||
if adapter is not None:
|
||||
for nio in adapter.ports.values():
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
yield from self.stop()
|
||||
|
||||
@@ -875,7 +875,7 @@ class IOUVM(BaseVM):
|
||||
|
||||
nio = adapter.get_nio(port_number)
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
adapter.remove_nio(port_number)
|
||||
log.info("IOU {name} [id={id}]: {nio} removed from {adapter_number}/{port_number}".format(name=self._name,
|
||||
id=self._id,
|
||||
|
||||
@@ -173,9 +173,11 @@ class PortManager:
|
||||
host,
|
||||
last_exception))
|
||||
|
||||
def get_free_tcp_port(self):
|
||||
def get_free_tcp_port(self, project):
|
||||
"""
|
||||
Get an available TCP port and reserve it
|
||||
|
||||
:param project: Project instance
|
||||
"""
|
||||
|
||||
port = self.find_unused_port(self._console_port_range[0],
|
||||
@@ -185,36 +187,43 @@ class PortManager:
|
||||
ignore_ports=self._used_tcp_ports)
|
||||
|
||||
self._used_tcp_ports.add(port)
|
||||
project.record_tcp_port(port)
|
||||
log.debug("TCP port {} has been allocated".format(port))
|
||||
return port
|
||||
|
||||
def reserve_tcp_port(self, port):
|
||||
def reserve_tcp_port(self, port, project):
|
||||
"""
|
||||
Reserve a specific TCP port number
|
||||
|
||||
:param port: TCP port number
|
||||
:param project: Project instance
|
||||
"""
|
||||
|
||||
if port in self._used_tcp_ports:
|
||||
raise HTTPConflict(text="TCP port {} already in use on host".format(port, self._console_host))
|
||||
self._used_tcp_ports.add(port)
|
||||
project.record_tcp_port(port)
|
||||
log.debug("TCP port {} has been reserved".format(port))
|
||||
return port
|
||||
|
||||
def release_tcp_port(self, port):
|
||||
def release_tcp_port(self, port, project):
|
||||
"""
|
||||
Release a specific TCP port number
|
||||
|
||||
:param port: TCP port number
|
||||
:param project: Project instance
|
||||
"""
|
||||
|
||||
if port in self._used_tcp_ports:
|
||||
self._used_tcp_ports.remove(port)
|
||||
project.remove_tcp_port(port)
|
||||
log.debug("TCP port {} has been released".format(port))
|
||||
|
||||
def get_free_udp_port(self):
|
||||
def get_free_udp_port(self, project):
|
||||
"""
|
||||
Get an available UDP port and reserve it
|
||||
|
||||
:param project: Project instance
|
||||
"""
|
||||
|
||||
port = self.find_unused_port(self._udp_port_range[0],
|
||||
@@ -224,28 +233,33 @@ class PortManager:
|
||||
ignore_ports=self._used_udp_ports)
|
||||
|
||||
self._used_udp_ports.add(port)
|
||||
project.record_udp_port(port)
|
||||
log.debug("UDP port {} has been allocated".format(port))
|
||||
return port
|
||||
|
||||
def reserve_udp_port(self, port):
|
||||
def reserve_udp_port(self, port, project):
|
||||
"""
|
||||
Reserve a specific UDP port number
|
||||
|
||||
:param port: UDP port number
|
||||
:param project: Project instance
|
||||
"""
|
||||
|
||||
if port in self._used_udp_ports:
|
||||
raise HTTPConflict(text="UDP port {} already in use on host".format(port, self._console_host))
|
||||
self._used_udp_ports.add(port)
|
||||
project.record_udp_port(port)
|
||||
log.debug("UDP port {} has been reserved".format(port))
|
||||
|
||||
def release_udp_port(self, port):
|
||||
def release_udp_port(self, port, project):
|
||||
"""
|
||||
Release a specific UDP port number
|
||||
|
||||
:param port: UDP port number
|
||||
:param project: Project instance
|
||||
"""
|
||||
|
||||
if port in self._used_udp_ports:
|
||||
self._used_udp_ports.remove(port)
|
||||
project.remove_udp_port(port)
|
||||
log.debug("UDP port {} has been released".format(port))
|
||||
@@ -62,6 +62,8 @@ class Project:
|
||||
self._vms = set()
|
||||
self._vms_to_destroy = set()
|
||||
self.temporary = temporary
|
||||
self._used_tcp_ports = set()
|
||||
self._used_udp_ports = set()
|
||||
|
||||
if path is None:
|
||||
path = os.path.join(self._location, self._id)
|
||||
@@ -168,6 +170,46 @@ class Project:
|
||||
self._temporary = temporary
|
||||
self._update_temporary_file()
|
||||
|
||||
def record_tcp_port(self, port):
|
||||
"""
|
||||
Associate a reserved TCP port number with this project.
|
||||
|
||||
:param port: TCP port number
|
||||
"""
|
||||
|
||||
if port not in self._used_tcp_ports:
|
||||
self._used_tcp_ports.add(port)
|
||||
|
||||
def record_udp_port(self, port):
|
||||
"""
|
||||
Associate a reserved UDP port number with this project.
|
||||
|
||||
:param port: UDP port number
|
||||
"""
|
||||
|
||||
if port not in self._used_udp_ports:
|
||||
self._used_udp_ports.add(port)
|
||||
|
||||
def remove_tcp_port(self, port):
|
||||
"""
|
||||
Removes an associated TCP port number from this project.
|
||||
|
||||
:param port: TCP port number
|
||||
"""
|
||||
|
||||
if port in self._used_tcp_ports:
|
||||
self._used_tcp_ports.remove(port)
|
||||
|
||||
def remove_udp_port(self, port):
|
||||
"""
|
||||
Removes an associated UDP port number from this project.
|
||||
|
||||
:param port: UDP port number
|
||||
"""
|
||||
|
||||
if port in self._used_udp_ports:
|
||||
self._used_udp_ports.remove(port)
|
||||
|
||||
def _update_temporary_file(self):
|
||||
"""
|
||||
Update the .gns3_temporary file in order to reflect current
|
||||
@@ -309,12 +351,17 @@ class Project:
|
||||
else:
|
||||
log.info("Project {id} with path '{path}' closed".format(path=self._path, id=self._id))
|
||||
|
||||
port_manager = PortManager.instance()
|
||||
if port_manager.tcp_ports:
|
||||
log.debug("TCP ports still in use: {}".format(port_manager.tcp_ports))
|
||||
if self._used_tcp_ports:
|
||||
log.warning("Project {} has TCP ports still in use: {}".format(self.id, self._used_tcp_ports))
|
||||
if self._used_udp_ports:
|
||||
log.warning("Project {} has UDP ports still in use: {}".format(self.id, self._used_udp_ports))
|
||||
|
||||
if port_manager.udp_ports:
|
||||
log.debug("UDP ports still in use: {}".format(port_manager.udp_ports))
|
||||
# clean the remaining ports that have not been cleaned by their respective VM or device.
|
||||
port_manager = PortManager.instance()
|
||||
for port in self._used_tcp_ports.copy():
|
||||
port_manager.release_tcp_port(port, self)
|
||||
for port in self._used_udp_ports.copy():
|
||||
port_manager.release_udp_port(port, self)
|
||||
|
||||
@asyncio.coroutine
|
||||
def commit(self):
|
||||
|
||||
@@ -93,9 +93,9 @@ class QemuVM(BaseVM):
|
||||
self._process_priority = "low"
|
||||
|
||||
if self._monitor is not None:
|
||||
self._monitor = self._manager.port_manager.reserve_tcp_port(self._monitor)
|
||||
self._monitor = self._manager.port_manager.reserve_tcp_port(self._monitor, self._project)
|
||||
else:
|
||||
self._monitor = self._manager.port_manager.get_free_tcp_port()
|
||||
self._monitor = self._manager.port_manager.get_free_tcp_port(self._project)
|
||||
|
||||
self.adapters = 1 # creates 1 adapter by default
|
||||
log.info("QEMU VM {name} [id={id}] has been created".format(name=self._name,
|
||||
@@ -122,8 +122,8 @@ class QemuVM(BaseVM):
|
||||
if monitor == self._monitor:
|
||||
return
|
||||
if self._monitor:
|
||||
self._manager.port_manager.release_monitor_port(self._monitor)
|
||||
self._monitor = self._manager.port_manager.reserve_monitor_port(monitor)
|
||||
self._manager.port_manager.release_monitor_port(self._monitor, self._project)
|
||||
self._monitor = self._manager.port_manager.reserve_monitor_port(monitor, self._project)
|
||||
log.info("{module}: '{name}' [{id}]: monitor port set to {port}".format(
|
||||
module=self.manager.module_name,
|
||||
name=self.name,
|
||||
@@ -699,10 +699,10 @@ class QemuVM(BaseVM):
|
||||
log.debug('QEMU VM "{name}" [{id}] is closing'.format(name=self._name, id=self._id))
|
||||
yield from self.stop()
|
||||
if self._console:
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = None
|
||||
if self._monitor:
|
||||
self._manager.port_manager.release_tcp_port(self._monitor)
|
||||
self._manager.port_manager.release_tcp_port(self._monitor, self._project)
|
||||
self._monitor = None
|
||||
|
||||
@asyncio.coroutine
|
||||
@@ -825,7 +825,7 @@ class QemuVM(BaseVM):
|
||||
|
||||
nio = adapter.get_nio(0)
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
adapter.remove_nio(0)
|
||||
log.info("QEMU VM {name} [id={id}]: {nio} removed from adapter {adapter_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
|
||||
@@ -305,14 +305,14 @@ class VirtualBoxVM(BaseVM):
|
||||
|
||||
log.debug("VirtualBox VM '{name}' [{id}] is closing".format(name=self.name, id=self.id))
|
||||
if self._console:
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = None
|
||||
|
||||
for adapter in self._ethernet_adapters:
|
||||
if adapter is not None:
|
||||
for nio in adapter.ports.values():
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
yield from self.stop()
|
||||
|
||||
@@ -828,7 +828,7 @@ class VirtualBoxVM(BaseVM):
|
||||
|
||||
nio = adapter.get_nio(0)
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
adapter.remove_nio(0)
|
||||
|
||||
log.info("VirtualBox VM '{name}' [{id}]: {nio} removed from adapter {adapter_number}".format(name=self.name,
|
||||
|
||||
@@ -74,12 +74,12 @@ class VPCSVM(BaseVM):
|
||||
|
||||
log.debug("VPCS {name} [{id}] is closing".format(name=self._name, id=self._id))
|
||||
if self._console:
|
||||
self._manager.port_manager.release_tcp_port(self._console)
|
||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||
self._console = None
|
||||
|
||||
nio = self._ethernet_adapter.get_nio(0)
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
self._terminate_process()
|
||||
|
||||
@@ -334,7 +334,7 @@ class VPCSVM(BaseVM):
|
||||
|
||||
nio = self._ethernet_adapter.get_nio(port_number)
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
self._ethernet_adapter.remove_nio(port_number)
|
||||
|
||||
log.info("VPCS {name} [{id}]: {nio} removed from port {port_number}".format(name=self._name,
|
||||
|
||||
Reference in new issue
Block a user