mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-25 01:38:08 +00:00
Merge branch '1.5' into 2.0
This commit is contained in:
commit
da6cb13338
15
CHANGELOG
15
CHANGELOG
@ -1,5 +1,20 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 1.5.0b1 23/05/2016
|
||||||
|
|
||||||
|
* Allow an IOS router to stop even the Dynamips hypervisor command fail to be sent. Ref #488.
|
||||||
|
* Extract private-config only when necessary (content is different than the default). Fixes #520.
|
||||||
|
* Fixes disabling the VPCS relay feature. Fixes #521.
|
||||||
|
* Fixes wrong exception in Docker VM implementation.
|
||||||
|
* Force Npcap DLL to be used first for Dynamips and uBridge (instead of the one from Winpcap if installed).
|
||||||
|
* Fixed startup-config is lost if you change any IOS router settings. Fixes #1233.
|
||||||
|
* Fixes check for NPF service and add check for NPCAP service on Windows.
|
||||||
|
* Fix ProcessLookupError X11VNC
|
||||||
|
* Force tag latest for docker image if no tag is specified
|
||||||
|
* Cleanup unbreakable space
|
||||||
|
* Do not raise error if vmrun.exe is named vmrun.EXE
|
||||||
|
* Load docker api only for Linux
|
||||||
|
|
||||||
## 1.5.0a2 10/05/2016
|
## 1.5.0a2 10/05/2016
|
||||||
|
|
||||||
* Fix distribution on PyPi
|
* Fix distribution on PyPi
|
||||||
|
@ -34,6 +34,7 @@ from gns3server.utils.get_resource import get_resource
|
|||||||
|
|
||||||
from gns3server.ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError
|
from gns3server.ubridge.ubridge_error import UbridgeError, UbridgeNamespaceError
|
||||||
from ..base_node import BaseNode
|
from ..base_node import BaseNode
|
||||||
|
|
||||||
from ..adapters.ethernet_adapter import EthernetAdapter
|
from ..adapters.ethernet_adapter import EthernetAdapter
|
||||||
from ..nios.nio_udp import NIOUDP
|
from ..nios.nio_udp import NIOUDP
|
||||||
from .docker_error import (
|
from .docker_error import (
|
||||||
|
@ -602,8 +602,8 @@ class Dynamips(BaseManager):
|
|||||||
elif startup_config_content:
|
elif startup_config_content:
|
||||||
startup_config_path = self._create_config(vm, default_startup_config_path, startup_config_content)
|
startup_config_path = self._create_config(vm, default_startup_config_path, startup_config_content)
|
||||||
yield from vm.set_configs(startup_config_path)
|
yield from vm.set_configs(startup_config_path)
|
||||||
# An empty startup config crash dynamips
|
elif os.path.isfile(default_startup_config_path) and os.path.getsize(default_startup_config_path) == 0:
|
||||||
else:
|
# An empty startup-config may crash Dynamips
|
||||||
startup_config_path = self._create_config(vm, default_startup_config_path, "!\n")
|
startup_config_path = self._create_config(vm, default_startup_config_path, "!\n")
|
||||||
yield from vm.set_configs(startup_config_path)
|
yield from vm.set_configs(startup_config_path)
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
Represents a Dynamips hypervisor and starts/stops the associated Dynamips process.
|
Represents a Dynamips hypervisor and starts/stops the associated Dynamips process.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import asyncio
|
import asyncio
|
||||||
@ -117,6 +118,12 @@ class Hypervisor(DynamipsHypervisor):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
self._command = self._build_command()
|
self._command = self._build_command()
|
||||||
|
env = os.environ.copy()
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
# add the Npcap directory to $PATH to force Dynamips to use npcap DLL instead of Winpcap (if installed)
|
||||||
|
system_root = os.path.join(os.path.expandvars("%SystemRoot%"), "System32", "Npcap")
|
||||||
|
if os.path.isdir(system_root):
|
||||||
|
env["PATH"] = system_root + ';' + env["PATH"]
|
||||||
try:
|
try:
|
||||||
log.info("Starting Dynamips: {}".format(self._command))
|
log.info("Starting Dynamips: {}".format(self._command))
|
||||||
self._stdout_file = os.path.join(self.working_dir, "dynamips_i{}_stdout.txt".format(self._id))
|
self._stdout_file = os.path.join(self.working_dir, "dynamips_i{}_stdout.txt".format(self._id))
|
||||||
@ -125,7 +132,8 @@ class Hypervisor(DynamipsHypervisor):
|
|||||||
self._process = yield from asyncio.create_subprocess_exec(*self._command,
|
self._process = yield from asyncio.create_subprocess_exec(*self._command,
|
||||||
stdout=fd,
|
stdout=fd,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
cwd=self._working_dir)
|
cwd=self._working_dir,
|
||||||
|
env=env)
|
||||||
log.info("Dynamips process started PID={}".format(self._process.pid))
|
log.info("Dynamips process started PID={}".format(self._process.pid))
|
||||||
self._started = True
|
self._started = True
|
||||||
except (OSError, subprocess.SubprocessError) as e:
|
except (OSError, subprocess.SubprocessError) as e:
|
||||||
|
@ -272,7 +272,10 @@ class Router(BaseNode):
|
|||||||
|
|
||||||
status = yield from self.get_status()
|
status = yield from self.get_status()
|
||||||
if status != "inactive":
|
if status != "inactive":
|
||||||
yield from self._hypervisor.send('vm stop "{name}"'.format(name=self._name))
|
try:
|
||||||
|
yield from self._hypervisor.send('vm stop "{name}"'.format(name=self._name))
|
||||||
|
except DynamipsError as e:
|
||||||
|
log.warn("Could not stop {}: {}".format(self._name, e))
|
||||||
self.status = "stopped"
|
self.status = "stopped"
|
||||||
log.info('Router "{name}" [{id}] has been stopped'.format(name=self._name, id=self._id))
|
log.info('Router "{name}" [{id}] has been stopped'.format(name=self._name, id=self._id))
|
||||||
yield from self.save_configs()
|
yield from self.save_configs()
|
||||||
@ -338,8 +341,8 @@ class Router(BaseNode):
|
|||||||
try:
|
try:
|
||||||
yield from self.stop()
|
yield from self.stop()
|
||||||
yield from self._hypervisor.send('vm delete "{}"'.format(self._name))
|
yield from self._hypervisor.send('vm delete "{}"'.format(self._name))
|
||||||
except DynamipsError:
|
except DynamipsError as e:
|
||||||
pass
|
log.warn("Could not stop and delete {}: {}".format(self._name, e))
|
||||||
yield from self.hypervisor.stop()
|
yield from self.hypervisor.stop()
|
||||||
|
|
||||||
if self._auto_delete_disks:
|
if self._auto_delete_disks:
|
||||||
@ -1533,7 +1536,6 @@ class Router(BaseNode):
|
|||||||
if startup_config_base64:
|
if startup_config_base64:
|
||||||
if not self.startup_config:
|
if not self.startup_config:
|
||||||
self._startup_config = os.path.join("configs", "i{}_startup-config.cfg".format(self._dynamips_id))
|
self._startup_config = os.path.join("configs", "i{}_startup-config.cfg".format(self._dynamips_id))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config = base64.b64decode(startup_config_base64).decode("utf-8", errors="replace")
|
config = base64.b64decode(startup_config_base64).decode("utf-8", errors="replace")
|
||||||
config = "!\n" + config.replace("\r", "")
|
config = "!\n" + config.replace("\r", "")
|
||||||
@ -1544,13 +1546,11 @@ class Router(BaseNode):
|
|||||||
except (binascii.Error, OSError) as e:
|
except (binascii.Error, OSError) as e:
|
||||||
raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e))
|
raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e))
|
||||||
|
|
||||||
if private_config_base64:
|
if private_config_base64 and base64.b64decode(private_config_base64) != b'\nkerberos password \nend\n':
|
||||||
if not self.private_config:
|
if not self.private_config:
|
||||||
self._private_config = os.path.join("configs", "i{}_private-config.cfg".format(self._dynamips_id))
|
self._private_config = os.path.join("configs", "i{}_private-config.cfg".format(self._dynamips_id))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config = base64.b64decode(private_config_base64).decode("utf-8", errors="replace")
|
config = base64.b64decode(private_config_base64).decode("utf-8", errors="replace")
|
||||||
config = "!\n" + config.replace("\r", "")
|
|
||||||
config_path = os.path.join(module_workdir, self.private_config)
|
config_path = os.path.join(module_workdir, self.private_config)
|
||||||
with open(config_path, "wb") as f:
|
with open(config_path, "wb") as f:
|
||||||
log.info("saving private-config to {}".format(self.private_config))
|
log.info("saving private-config to {}".format(self.private_config))
|
||||||
|
@ -108,7 +108,6 @@ class IOUVM(BaseNode):
|
|||||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||||
|
|
||||||
yield from self.stop()
|
yield from self.stop()
|
||||||
self.save_configs()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self):
|
def path(self):
|
||||||
@ -683,6 +682,7 @@ class IOUVM(BaseNode):
|
|||||||
self._iouyap_process = None
|
self._iouyap_process = None
|
||||||
|
|
||||||
self._started = False
|
self._started = False
|
||||||
|
self.save_configs()
|
||||||
|
|
||||||
def _terminate_process_iouyap(self):
|
def _terminate_process_iouyap(self):
|
||||||
"""
|
"""
|
||||||
@ -1099,7 +1099,7 @@ class IOUVM(BaseNode):
|
|||||||
if private_config is None:
|
if private_config is None:
|
||||||
private_config = ''
|
private_config = ''
|
||||||
|
|
||||||
# We disallow erasing the startup config file
|
# We disallow erasing the private config file
|
||||||
if len(private_config) == 0 and os.path.exists(private_config_path):
|
if len(private_config) == 0 and os.path.exists(private_config_path):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1206,18 +1206,16 @@ class IOUVM(BaseNode):
|
|||||||
config_path = os.path.join(self.working_dir, "startup-config.cfg")
|
config_path = os.path.join(self.working_dir, "startup-config.cfg")
|
||||||
try:
|
try:
|
||||||
config = startup_config_content.decode("utf-8", errors="replace")
|
config = startup_config_content.decode("utf-8", errors="replace")
|
||||||
config = "!\n" + config.replace("\r", "")
|
|
||||||
with open(config_path, "wb") as f:
|
with open(config_path, "wb") as f:
|
||||||
log.info("saving startup-config to {}".format(config_path))
|
log.info("saving startup-config to {}".format(config_path))
|
||||||
f.write(config.encode("utf-8"))
|
f.write(config.encode("utf-8"))
|
||||||
except (binascii.Error, OSError) as e:
|
except (binascii.Error, OSError) as e:
|
||||||
raise IOUError("Could not save the startup configuration {}: {}".format(config_path, e))
|
raise IOUError("Could not save the startup configuration {}: {}".format(config_path, e))
|
||||||
|
|
||||||
if private_config_content:
|
if private_config_content and private_config_content != b'\nend\n':
|
||||||
config_path = os.path.join(self.working_dir, "private-config.cfg")
|
config_path = os.path.join(self.working_dir, "private-config.cfg")
|
||||||
try:
|
try:
|
||||||
config = private_config_content.decode("utf-8", errors="replace")
|
config = private_config_content.decode("utf-8", errors="replace")
|
||||||
config = "!\n" + config.replace("\r", "")
|
|
||||||
with open(config_path, "wb") as f:
|
with open(config_path, "wb") as f:
|
||||||
log.info("saving private-config to {}".format(config_path))
|
log.info("saving private-config to {}".format(config_path))
|
||||||
f.write(config.encode("utf-8"))
|
f.write(config.encode("utf-8"))
|
||||||
|
@ -420,8 +420,10 @@ class VPCSVM(BaseNode):
|
|||||||
command.extend(["-m", str(self._manager.get_mac_id(self.id))]) # the unique ID is used to set the MAC address offset
|
command.extend(["-m", str(self._manager.get_mac_id(self.id))]) # the unique ID is used to set the MAC address offset
|
||||||
command.extend(["-i", "1"]) # option to start only one VPC instance
|
command.extend(["-i", "1"]) # option to start only one VPC instance
|
||||||
command.extend(["-F"]) # option to avoid the daemonization of VPCS
|
command.extend(["-F"]) # option to avoid the daemonization of VPCS
|
||||||
if self._vpcs_version > parse_version("0.8"):
|
if self._vpcs_version >= parse_version("0.8b"):
|
||||||
command.extend(["-R"]) # disable relay feature of VPCS (starting with VPCS 0.8)
|
command.extend(["-R"]) # disable the relay feature of VPCS (starting with VPCS 0.8)
|
||||||
|
else:
|
||||||
|
log.warn("The VPCS relay feature could not be disabled because the VPCS version is below 0.8b")
|
||||||
|
|
||||||
nio = self._ethernet_adapter.get_nio(0)
|
nio = self._ethernet_adapter.get_nio(0)
|
||||||
if nio:
|
if nio:
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
Represents a uBridge hypervisor and starts/stops the associated uBridge process.
|
Represents a uBridge hypervisor and starts/stops the associated uBridge process.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import asyncio
|
import asyncio
|
||||||
@ -140,6 +141,12 @@ class Hypervisor(UBridgeHypervisor):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
yield from self._check_ubridge_version()
|
yield from self._check_ubridge_version()
|
||||||
|
env = os.environ.copy()
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
# add the Npcap directory to $PATH to force Dynamips to use npcap DLL instead of Winpcap (if installed)
|
||||||
|
system_root = os.path.join(os.path.expandvars("%SystemRoot%"), "System32", "Npcap")
|
||||||
|
if os.path.isdir(system_root):
|
||||||
|
env["PATH"] = system_root + ';' + env["PATH"]
|
||||||
try:
|
try:
|
||||||
command = self._build_command()
|
command = self._build_command()
|
||||||
log.info("starting ubridge: {}".format(command))
|
log.info("starting ubridge: {}".format(command))
|
||||||
@ -149,7 +156,8 @@ class Hypervisor(UBridgeHypervisor):
|
|||||||
self._process = yield from asyncio.create_subprocess_exec(*command,
|
self._process = yield from asyncio.create_subprocess_exec(*command,
|
||||||
stdout=fd,
|
stdout=fd,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
cwd=self._working_dir)
|
cwd=self._working_dir,
|
||||||
|
env=env)
|
||||||
|
|
||||||
log.info("ubridge started PID={}".format(self._process.pid))
|
log.info("ubridge started PID={}".format(self._process.pid))
|
||||||
except (OSError, subprocess.SubprocessError) as e:
|
except (OSError, subprocess.SubprocessError) as e:
|
||||||
|
@ -138,6 +138,21 @@ def is_interface_up(interface):
|
|||||||
# TODO: Windows & OSX support
|
# TODO: Windows & OSX support
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _check_windows_service(service_name):
|
||||||
|
|
||||||
|
import pywintypes
|
||||||
|
import win32service
|
||||||
|
import win32serviceutil
|
||||||
|
|
||||||
|
try:
|
||||||
|
if win32serviceutil.QueryServiceStatus(service_name, None)[1] != win32service.SERVICE_RUNNING:
|
||||||
|
return False
|
||||||
|
except pywintypes.error as e:
|
||||||
|
if e.winerror == 1060:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise aiohttp.web.HTTPInternalServerError(text="Could not check if the {} service is running: {}".format(service_name, e.strerror))
|
||||||
|
return True
|
||||||
|
|
||||||
def interfaces():
|
def interfaces():
|
||||||
"""
|
"""
|
||||||
@ -163,19 +178,8 @@ def interfaces():
|
|||||||
"mac_address": mac_address})
|
"mac_address": mac_address})
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
import pywintypes
|
if not _check_windows_service("npf") and not _check_windows_service("npcap"):
|
||||||
import win32service
|
raise aiohttp.web.HTTPInternalServerError("The NPF or Npcap is not installed or running")
|
||||||
import win32serviceutil
|
|
||||||
|
|
||||||
try:
|
|
||||||
if win32serviceutil.QueryServiceStatus("npf", None)[1] != win32service.SERVICE_RUNNING:
|
|
||||||
raise aiohttp.web.HTTPInternalServerError(text="The NPF service is not running")
|
|
||||||
except pywintypes.error as e:
|
|
||||||
if e[0] == 1060:
|
|
||||||
raise aiohttp.web.HTTPInternalServerError(text="The NPF service is not installed")
|
|
||||||
else:
|
|
||||||
raise aiohttp.web.HTTPInternalServerError(text="Could not check if the NPF service is running: {}".format(e[2]))
|
|
||||||
|
|
||||||
results = get_windows_interfaces()
|
results = get_windows_interfaces()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
message = "pywin32 module is not installed, please install it on the server to get the available interface names"
|
message = "pywin32 module is not installed, please install it on the server to get the available interface names"
|
||||||
|
@ -168,7 +168,8 @@ def vmnet_windows(args, vmnet_range_start, vmnet_range_end):
|
|||||||
os.system('"{}" -- add adapter vmnet{}'.format(vnetlib_path, vmnet_number))
|
os.system('"{}" -- add adapter vmnet{}'.format(vnetlib_path, vmnet_number))
|
||||||
os.system("net stop npf")
|
os.system("net stop npf")
|
||||||
os.system("net start npf")
|
os.system("net start npf")
|
||||||
|
os.system("net stop npcap")
|
||||||
|
os.system("net start npcap")
|
||||||
|
|
||||||
def vmnet_unix(args, vmnet_range_start, vmnet_range_end):
|
def vmnet_unix(args, vmnet_range_start, vmnet_range_end):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user