Merge pull request #856 from GNS3/dynamips_directory_layout

Change directory layout for dynamips.
This commit is contained in:
Jeremy Grossmann 2017-01-12 20:30:10 -08:00 committed by GitHub
commit ec0181a5ad
22 changed files with 871 additions and 63 deletions

View File

@ -23,7 +23,8 @@ A minimal version:
The revision is the version of file format: The revision is the version of file format:
* 6: GNS3 2.0 * 7: GNS3 2.0
* 6: GNS3 2.0 < beta 3
* 5: GNS3 2.0 < alpha 4 * 5: GNS3 2.0 < alpha 4
* 4: GNS3 1.5 * 4: GNS3 1.5
* 3: GNS3 1.4 * 3: GNS3 1.4

View File

@ -219,10 +219,12 @@ class Dynamips(BaseManager):
project_dir = project.module_working_path(self.module_name.lower()) project_dir = project.module_working_path(self.module_name.lower())
files = glob.glob(os.path.join(glob.escape(project_dir), "*.ghost")) files = glob.glob(os.path.join(glob.escape(project_dir), "*.ghost"))
files += glob.glob(os.path.join(glob.escape(project_dir), "*_lock")) files += glob.glob(os.path.join(glob.escape(project_dir), "*", "*_lock"))
files += glob.glob(os.path.join(glob.escape(project_dir), "*_log.txt"))
files += glob.glob(os.path.join(glob.escape(project_dir), "*_stdout.txt"))
files += glob.glob(os.path.join(glob.escape(project_dir), "ilt_*")) files += glob.glob(os.path.join(glob.escape(project_dir), "ilt_*"))
files += glob.glob(os.path.join(glob.escape(project_dir), "c[0-9][0-9][0-9][0-9]_i[0-9]*_rommon_vars")) files += glob.glob(os.path.join(glob.escape(project_dir), "*", "c[0-9][0-9][0-9][0-9]_i[0-9]*_rommon_vars"))
files += glob.glob(os.path.join(glob.escape(project_dir), "c[0-9][0-9][0-9][0-9]_i[0-9]*_log.txt")) files += glob.glob(os.path.join(glob.escape(project_dir), "*", "c[0-9][0-9][0-9][0-9]_i[0-9]*_log.txt"))
for file in files: for file in files:
try: try:
log.debug("Deleting file {}".format(file)) log.debug("Deleting file {}".format(file))
@ -409,7 +411,9 @@ class Dynamips(BaseManager):
return return
ghost_file = vm.formatted_ghost_file() ghost_file = vm.formatted_ghost_file()
ghost_file_path = os.path.join(vm.hypervisor.working_dir, ghost_file)
module_workdir = vm.project.module_working_directory(self.module_name.lower())
ghost_file_path = os.path.join(module_workdir, ghost_file)
if ghost_file_path not in self._ghost_files: if ghost_file_path not in self._ghost_files:
# create a new ghost IOS instance # create a new ghost IOS instance
ghost_id = str(uuid4()) ghost_id = str(uuid4())
@ -418,7 +422,7 @@ class Dynamips(BaseManager):
yield from ghost.create() yield from ghost.create()
yield from ghost.set_image(vm.image) yield from ghost.set_image(vm.image)
yield from ghost.set_ghost_status(1) yield from ghost.set_ghost_status(1)
yield from ghost.set_ghost_file(ghost_file) yield from ghost.set_ghost_file(ghost_file_path)
yield from ghost.set_ram(vm.ram) yield from ghost.set_ram(vm.ram)
try: try:
yield from ghost.start() yield from ghost.start()
@ -434,7 +438,7 @@ class Dynamips(BaseManager):
if vm.ghost_file != ghost_file and os.path.isfile(ghost_file_path): if vm.ghost_file != ghost_file and os.path.isfile(ghost_file_path):
# set the ghost file to the router # set the ghost file to the router
yield from vm.set_ghost_status(2) yield from vm.set_ghost_status(2)
yield from vm.set_ghost_file(ghost_file) yield from vm.set_ghost_file(ghost_file_path)
@asyncio.coroutine @asyncio.coroutine
def update_vm_settings(self, vm, settings): def update_vm_settings(self, vm, settings):
@ -508,8 +512,8 @@ class Dynamips(BaseManager):
""" """
module_workdir = vm.project.module_working_directory(self.module_name.lower()) module_workdir = vm.project.module_working_directory(self.module_name.lower())
default_startup_config_path = os.path.join(module_workdir, "configs", "i{}_startup-config.cfg".format(vm.dynamips_id)) default_startup_config_path = os.path.join(module_workdir, vm.id, "configs", "i{}_startup-config.cfg".format(vm.dynamips_id))
default_private_config_path = os.path.join(module_workdir, "configs", "i{}_private-config.cfg".format(vm.dynamips_id)) default_private_config_path = os.path.join(module_workdir, vm.id, "configs", "i{}_private-config.cfg".format(vm.dynamips_id))
startup_config_path = settings.get("startup_config") startup_config_path = settings.get("startup_config")
startup_config_content = settings.get("startup_config_content") startup_config_content = settings.get("startup_config_content")

View File

@ -25,10 +25,12 @@ import time
import sys import sys
import os import os
import glob import glob
import shlex
import base64 import base64
import shutil
import binascii import binascii
import logging import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
from ...base_node import BaseNode from ...base_node import BaseNode
@ -67,6 +69,11 @@ class Router(BaseNode):
super().__init__(name, node_id, project, manager, console=console, aux=aux, allocate_aux=aux) super().__init__(name, node_id, project, manager, console=console, aux=aux, allocate_aux=aux)
self._working_directory = os.path.join(self.project.module_working_directory(self.manager.module_name.lower()), self.id)
os.makedirs(os.path.join(self._working_directory, "configs"), exist_ok=True)
if dynamips_id:
self._convert_before_2_0_0_b3(dynamips_id)
self._hypervisor = hypervisor self._hypervisor = hypervisor
self._dynamips_id = dynamips_id self._dynamips_id = dynamips_id
self._platform = platform self._platform = platform
@ -113,11 +120,33 @@ class Router(BaseNode):
self._dynamips_id = 0 self._dynamips_id = 0
self._name = "Ghost" self._name = "Ghost"
def _convert_before_2_0_0_b3(self, dynamips_id):
"""
Before 2.0.0 beta3 the node didn't have a folder by node
when we start we move the file, we can't do it in the topology
conversion due to case of remote servers
"""
dynamips_dir = self.project.module_working_directory(self.manager.module_name.lower())
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "configs", "i{}_*".format(dynamips_id))):
dst = os.path.join(self._working_directory, "configs", os.path.basename(path))
if not os.path.exists(dst):
try:
shutil.move(path, dst)
except OSError as e:
raise DynamipsError("Can't move {}: {}".format(path, str(e)))
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "*_i{}_*".format(dynamips_id))):
dst = os.path.join(self._working_directory, os.path.basename(path))
if not os.path.exists(dst):
try:
shutil.move(path, dst)
except OSError as e:
raise DynamipsError("Can't move {}: {}".format(path, str(e)))
def __json__(self): def __json__(self):
router_info = {"name": self.name, router_info = {"name": self.name,
"node_id": self.id, "node_id": self.id,
"node_directory": os.path.join(self.project.module_working_directory(self.manager.module_name.lower())), "node_directory": os.path.join(self._working_directory),
"project_id": self.project.id, "project_id": self.project.id,
"dynamips_id": self._dynamips_id, "dynamips_id": self._dynamips_id,
"platform": self._platform, "platform": self._platform,
@ -187,8 +216,10 @@ class Router(BaseNode):
def create(self): def create(self):
if not self._hypervisor: if not self._hypervisor:
module_workdir = self.project.module_working_directory(self.manager.module_name.lower()) # We start the hypervisor is the dynamips folder and next we change to node dir
self._hypervisor = yield from self.manager.start_new_hypervisor(working_dir=module_workdir) # this allow the creation of common files in the dynamips folder
self._hypervisor = yield from self.manager.start_new_hypervisor(working_dir=self.project.module_working_directory(self.manager.module_name.lower()))
yield from self._hypervisor.set_working_dir(self._working_directory)
yield from self._hypervisor.send('vm create "{name}" {id} {platform}'.format(name=self._name, yield from self._hypervisor.send('vm create "{name}" {id} {platform}'.format(name=self._name,
id=self._dynamips_id, id=self._dynamips_id,
@ -368,14 +399,13 @@ class Router(BaseNode):
if self._auto_delete_disks: if self._auto_delete_disks:
# delete nvram and disk files # delete nvram and disk files
project_dir = os.path.join(self.project.module_working_directory(self.manager.module_name.lower())) files = glob.glob(os.path.join(glob.escape(self._working_directory), "{}_i{}_disk[0-1]".format(self.platform, self.dynamips_id)))
files = glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_disk[0-1]".format(self.platform, self.dynamips_id))) files += glob.glob(os.path.join(glob.escape(self._working_directory), "{}_i{}_slot[0-1]".format(self.platform, self.dynamips_id)))
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_slot[0-1]".format(self.platform, self.dynamips_id))) files += glob.glob(os.path.join(glob.escape(self._working_directory), "{}_i{}_nvram".format(self.platform, self.dynamips_id)))
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_nvram".format(self.platform, self.dynamips_id))) files += glob.glob(os.path.join(glob.escape(self._working_directory), "{}_i{}_flash[0-1]".format(self.platform, self.dynamips_id)))
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_flash[0-1]".format(self.platform, self.dynamips_id))) files += glob.glob(os.path.join(glob.escape(self._working_directory), "{}_i{}_rom".format(self.platform, self.dynamips_id)))
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_rom".format(self.platform, self.dynamips_id))) files += glob.glob(os.path.join(glob.escape(self._working_directory), "{}_i{}_bootflash".format(self.platform, self.dynamips_id)))
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_bootflash".format(self.platform, self.dynamips_id))) files += glob.glob(os.path.join(glob.escape(self._working_directory), "{}_i{}_ssa".format(self.platform, self.dynamips_id)))
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_ssa".format(self.platform, self.dynamips_id)))
for file in files: for file in files:
try: try:
log.debug("Deleting file {}".format(file)) log.debug("Deleting file {}".format(file))
@ -763,7 +793,7 @@ class Router(BaseNode):
""" """
yield from self._hypervisor.send('vm set_ghost_file "{name}" {ghost_file}'.format(name=self._name, yield from self._hypervisor.send('vm set_ghost_file "{name}" {ghost_file}'.format(name=self._name,
ghost_file=ghost_file)) ghost_file=shlex.quote(ghost_file)))
log.info('Router "{name}" [{id}]: ghost file set to {ghost_file}'.format(name=self._name, log.info('Router "{name}" [{id}]: ghost file set to {ghost_file}'.format(name=self._name,
id=self._id, id=self._id,
@ -1456,10 +1486,9 @@ class Router(BaseNode):
:param new_name: new name string :param new_name: new name string
""" """
module_workdir = self.project.module_working_directory(self.manager.module_name.lower())
if self._startup_config: if self._startup_config:
# change the hostname in the startup-config # change the hostname in the startup-config
startup_config_path = os.path.join(module_workdir, "configs", "i{}_startup-config.cfg".format(self._dynamips_id)) startup_config_path = os.path.join(self._working_directory, "configs", "i{}_startup-config.cfg".format(self._dynamips_id))
if os.path.isfile(startup_config_path): if os.path.isfile(startup_config_path):
try: try:
with open(startup_config_path, "r+", encoding="utf-8", errors="replace") as f: with open(startup_config_path, "r+", encoding="utf-8", errors="replace") as f:
@ -1473,7 +1502,7 @@ class Router(BaseNode):
if self._private_config: if self._private_config:
# change the hostname in the private-config # change the hostname in the private-config
private_config_path = os.path.join(module_workdir, "configs", "i{}_private-config.cfg".format(self._dynamips_id)) private_config_path = os.path.join(self._working_directory, "configs", "i{}_private-config.cfg".format(self._dynamips_id))
if os.path.isfile(private_config_path): if os.path.isfile(private_config_path):
try: try:
with open(private_config_path, "r+", encoding="utf-8", errors="replace") as f: with open(private_config_path, "r+", encoding="utf-8", errors="replace") as f:
@ -1507,9 +1536,8 @@ class Router(BaseNode):
self._startup_config = startup_config self._startup_config = startup_config
self._private_config = private_config self._private_config = private_config
module_workdir = self.project.module_working_directory(self.manager.module_name.lower())
if private_config: if private_config:
private_config_path = os.path.join(module_workdir, private_config) private_config_path = os.path.join(self._working_directory, private_config)
try: try:
if not os.path.getsize(private_config_path): if not os.path.getsize(private_config_path):
# an empty private-config can prevent a router to boot. # an empty private-config can prevent a router to boot.
@ -1522,7 +1550,7 @@ class Router(BaseNode):
raise DynamipsError("Cannot access the private-config {}: {}".format(private_config_path, e)) raise DynamipsError("Cannot access the private-config {}: {}".format(private_config_path, e))
try: try:
startup_config_path = os.path.join(module_workdir, startup_config) startup_config_path = os.path.join(self._working_directory, startup_config)
with open(startup_config_path) as f: with open(startup_config_path) as f:
self._startup_config_content = f.read() self._startup_config_content = f.read()
except OSError as e: except OSError as e:
@ -1568,9 +1596,8 @@ class Router(BaseNode):
if self.startup_config or self.private_config: if self.startup_config or self.private_config:
module_workdir = self.project.module_working_directory(self.manager.module_name.lower())
try: try:
config_path = os.path.join(module_workdir, "configs") config_path = os.path.join(self._working_directory, "configs")
os.makedirs(config_path, exist_ok=True) os.makedirs(config_path, exist_ok=True)
except OSError as e: except OSError as e:
raise DynamipsError("Could could not create configuration directory {}: {}".format(config_path, e)) raise DynamipsError("Could could not create configuration directory {}: {}".format(config_path, e))
@ -1582,7 +1609,7 @@ class Router(BaseNode):
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", "")
config_path = os.path.join(module_workdir, self.startup_config) config_path = os.path.join(self._working_directory, self.startup_config)
with open(config_path, "wb") as f: with open(config_path, "wb") as f:
log.info("saving startup-config to {}".format(self.startup_config)) log.info("saving startup-config to {}".format(self.startup_config))
self._startup_config_content = config self._startup_config_content = config
@ -1595,7 +1622,7 @@ class Router(BaseNode):
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_path = os.path.join(module_workdir, self.private_config) config_path = os.path.join(self._working_directory, 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))
self._private_config_content = config self._private_config_content = config
@ -1607,31 +1634,10 @@ class Router(BaseNode):
""" """
Delete this VM (including all its files). Delete this VM (including all its files).
""" """
# delete the VM files
project_dir = os.path.join(self.project.module_working_directory(self.manager.module_name.lower()))
files = glob.glob(os.path.join(project_dir, "{}_i{}*".format(self._platform, self._dynamips_id)))
module_workdir = self.project.module_working_directory(self.manager.module_name.lower())
# delete the startup-config
if self._startup_config:
startup_config_path = os.path.join(module_workdir, "configs", "i{}_startup-config.cfg".format(self._dynamips_id))
if os.path.isfile(startup_config_path):
files.append(startup_config_path)
# delete the private-config
if self._private_config:
private_config_path = os.path.join(module_workdir, "configs", "i{}_private-config.cfg".format(self._dynamips_id))
if os.path.isfile(private_config_path):
files.append(private_config_path)
for file in files:
try: try:
log.debug("Deleting file {}".format(file)) yield from wait_run_in_executor(shutil.rmtree, self._working_directory)
yield from wait_run_in_executor(os.remove, file)
except OSError as e: except OSError as e:
log.warn("Could not delete file {}: {}".format(file, e)) log.warn("Could not delete file {}".format(e))
continue
self.manager.release_dynamips_id(self._project.id, self._dynamips_id) self.manager.release_dynamips_id(self._project.id, self._dynamips_id)
@ -1643,11 +1649,14 @@ class Router(BaseNode):
yield from self._hypervisor.send('vm clean_delete "{}"'.format(self._name)) yield from self._hypervisor.send('vm clean_delete "{}"'.format(self._name))
self._hypervisor.devices.remove(self) self._hypervisor.devices.remove(self)
try:
yield from wait_run_in_executor(shutil.rmtree, self._working_directory)
except OSError as e:
log.warn("Could not delete file {}".format(e))
log.info('Router "{name}" [{id}] has been deleted (including associated files)'.format(name=self._name, id=self._id)) log.info('Router "{name}" [{id}] has been deleted (including associated files)'.format(name=self._name, id=self._id))
def _memory_files(self): def _memory_files(self):
project_dir = os.path.join(self.project.module_working_directory(self.manager.module_name.lower()))
return [ return [
os.path.join(project_dir, "{}_i{}_rom".format(self.platform, self.dynamips_id)), os.path.join(self._working_directory, "{}_i{}_rom".format(self.platform, self.dynamips_id)),
os.path.join(project_dir, "{}_i{}_nvram".format(self.platform, self.dynamips_id)) os.path.join(self._working_directory, "{}_i{}_nvram".format(self.platform, self.dynamips_id))
] ]

View File

@ -97,7 +97,9 @@ class IOUVM(BaseNode):
""" """
Called when the NVRAM file has changed Called when the NVRAM file has changed
""" """
log.debug("NVRAM changed: {}".format(path))
self.save_configs() self.save_configs()
self.updated()
@asyncio.coroutine @asyncio.coroutine
def close(self): def close(self):
@ -206,6 +208,8 @@ class IOUVM(BaseNode):
"nvram": self._nvram, "nvram": self._nvram,
"l1_keepalives": self._l1_keepalives, "l1_keepalives": self._l1_keepalives,
"startup_config": self.relative_startup_config_file, "startup_config": self.relative_startup_config_file,
"startup_config_content": self.startup_config_content,
"private_config_content": self.private_config_content,
"private_config": self.relative_private_config_file, "private_config": self.relative_private_config_file,
"use_default_iou_values": self._use_default_iou_values, "use_default_iou_values": self._use_default_iou_values,
"command_line": self.command_line} "command_line": self.command_line}
@ -485,7 +489,7 @@ class IOUVM(BaseNode):
# check if there is enough RAM to run # check if there is enough RAM to run
self.check_available_ram(self.ram) self.check_available_ram(self.ram)
self._nvram_watcher = FileWatcher(self._nvram_file(), self._nvram_changed, delay=10) self._nvram_watcher = FileWatcher(self._nvram_file(), self._nvram_changed, delay=2)
# created a environment variable pointing to the iourc file. # created a environment variable pointing to the iourc file.
env = os.environ.copy() env = os.environ.copy()

View File

@ -19,6 +19,7 @@ import os
import json import json
import copy import copy
import uuid import uuid
import glob
import shutil import shutil
import zipfile import zipfile
import aiohttp import aiohttp
@ -36,7 +37,7 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
GNS3_FILE_FORMAT_REVISION = 6 GNS3_FILE_FORMAT_REVISION = 7
def _check_topology_schema(topo): def _check_topology_schema(topo):
@ -133,12 +134,45 @@ def load_topology(path):
with open(path, "w+", encoding="utf-8") as f: with open(path, "w+", encoding="utf-8") as f:
json.dump(topo, f, indent=4, sort_keys=True) json.dump(topo, f, indent=4, sort_keys=True)
# Version before GNS3 2.0 beta 3
if topo["revision"] < 7:
shutil.copy(path, path + ".backup{}".format(topo.get("revision", 0)))
topo = _convert_2_0_0_beta_2(topo, path)
_check_topology_schema(topo)
with open(path, "w+", encoding="utf-8") as f:
json.dump(topo, f, indent=4, sort_keys=True)
if topo["revision"] > GNS3_FILE_FORMAT_REVISION: if topo["revision"] > GNS3_FILE_FORMAT_REVISION:
raise aiohttp.web.HTTPConflict(text="This project is designed for a more recent version of GNS3 please update GNS3 to version {} or later".format(topo["version"])) raise aiohttp.web.HTTPConflict(text="This project is designed for a more recent version of GNS3 please update GNS3 to version {} or later".format(topo["version"]))
_check_topology_schema(topo) _check_topology_schema(topo)
return topo return topo
def _convert_2_0_0_beta_2(topo, topo_path):
"""
Convert topologies from GNS3 2.0.0 beta 2 to beta 3.
Changes:
* Node id folders for dynamips
"""
topo_dir = os.path.dirname(topo_path)
topo["revision"] = 7
for node in topo.get("topology", {}).get("nodes", []):
if node["node_type"] == "dynamips":
node_id = node["node_id"]
dynamips_id = node["properties"]["dynamips_id"]
dynamips_dir = os.path.join(topo_dir, "project-files", "dynamips")
node_dir = os.path.join(dynamips_dir, node_id)
os.makedirs(os.path.join(node_dir, "configs"), exist_ok=True)
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "*_i{}_*".format(dynamips_id))):
shutil.move(path, os.path.join(node_dir, os.path.basename(path)))
for path in glob.glob(os.path.join(glob.escape(dynamips_dir), "configs", "i{}_*".format(dynamips_id))):
shutil.move(path, os.path.join(node_dir, "configs", os.path.basename(path)))
return topo
def _convert_2_0_0_alpha(topo, topo_path): def _convert_2_0_0_alpha(topo, topo_path):
""" """
Convert topologies from GNS3 2.0.0 alpha to 2.0.0 final. Convert topologies from GNS3 2.0.0 alpha to 2.0.0 final.

View File

@ -56,7 +56,7 @@ class FileWatcher:
self._hashed = {} self._hashed = {}
for path in self._paths: for path in self._paths:
try: try:
# Alder32 is a fast bu insecure hash algorithm # Alder32 is a fast but insecure hash algorithm
self._hashed[path] = zlib.adler32(open(path, 'rb').read()) self._hashed[path] = zlib.adler32(open(path, 'rb').read())
except OSError: except OSError:
self._hashed[path] = None self._hashed[path] = None

View File

@ -15,6 +15,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import uuid
import pytest import pytest
import asyncio import asyncio
import configparser import configparser
@ -44,6 +46,22 @@ def test_router(project, manager):
assert router.id == "00010203-0405-0607-0809-0a0b0c0d0e0f" assert router.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_convert_project_before_2_0_0_b3(project, manager):
node_id = str(uuid.uuid4())
wdir = project.module_working_directory(manager.module_name.lower())
os.makedirs(os.path.join(wdir, node_id))
os.makedirs(os.path.join(wdir, "configs"))
open(os.path.join(wdir, "configs", "i1_startup-config.cfg"), "w+").close()
open(os.path.join(wdir, "configs", "i2_startup-config.cfg"), "w+").close()
open(os.path.join(wdir, "c7200_i1_nvram"), "w+").close()
open(os.path.join(wdir, "c7200_i2_nvram"), "w+").close()
router = Router("test", node_id, project, manager, dynamips_id=1)
assert os.path.exists(os.path.join(wdir, node_id, "configs", "i1_startup-config.cfg"))
assert not os.path.exists(os.path.join(wdir, node_id, "configs", "i2_startup-config.cfg"))
assert os.path.exists(os.path.join(wdir, node_id, "c7200_i1_nvram"))
assert not os.path.exists(os.path.join(wdir, node_id, "c7200_i2_nvram"))
def test_router_invalid_dynamips_path(project, manager, loop): def test_router_invalid_dynamips_path(project, manager, loop):
config = Config.instance() config = Config.instance()

View File

@ -113,6 +113,10 @@ def compare_dict(path, source, reference):
pass pass
elif val == "ANYUUID" and len(source[key]) == 36: elif val == "ANYUUID" and len(source[key]) == 36:
pass pass
# We test that the revision number has been bumpd to last version. This avoid modifying all the tests
# at each new revision bump.
elif key == "revision":
assert source[key] == GNS3_FILE_FORMAT_REVISION
else: else:
assert val == source[key], "Wrong value for {}: \n{}\nit should be\n{}".format(key, source[key], val) assert val == source[key], "Wrong value for {}: \n{}\nit should be\n{}".format(key, source[key], val)
elif isinstance(val, dict): elif isinstance(val, dict):

View File

@ -0,0 +1,163 @@
{
"auto_close": true,
"auto_open": false,
"auto_start": false,
"name": "dynamips_2_0_0_b2",
"project_id": "7a2be307-da2d-4819-a131-00e367658809",
"revision": 6,
"scene_height": 1000,
"scene_width": 2000,
"topology": {
"computes": [
{
"compute_id": "local",
"host": "127.0.0.1",
"name": "atlantis",
"port": 3080,
"protocol": "http"
}
],
"drawings": [],
"links": [],
"nodes": [
{
"compute_id": "local",
"console": 5000,
"console_type": "telnet",
"first_port_name": null,
"height": 45,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "R1",
"x": 22,
"y": -25
},
"name": "R1",
"node_id": "b31bacb4-b251-47e3-b9e8-fe5596e7a8ba",
"node_type": "dynamips",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"properties": {
"auto_delete_disks": true,
"aux": null,
"clock_divisor": 4,
"disk0": 0,
"disk1": 0,
"dynamips_id": 1,
"exec_area": 64,
"idlemax": 500,
"idlepc": "0x606e0538",
"idlesleep": 30,
"image": "c7200-adventerprisek9-mz.124-24.T8.image",
"image_md5sum": "b89d30823cbbda460364991ed18449c7",
"mac_addr": "ca01.ba2f.0000",
"midplane": "vxr",
"mmap": true,
"npe": "npe-400",
"nvram": 512,
"platform": "c7200",
"power_supplies": [
1,
1
],
"private_config": "",
"private_config_content": "",
"ram": 512,
"sensors": [
22,
22,
22,
22
],
"slot0": "C7200-IO-FE",
"slot1": null,
"slot2": null,
"slot3": null,
"slot4": null,
"slot5": null,
"slot6": null,
"sparsemem": true,
"startup_config": "configs/i1_startup-config.cfg",
"startup_config_content": "!\n!\nservice timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption\n!\nhostname R1\n!\nip cef\nno ip domain-lookup\nno ip icmp rate-limit unreachable\nip tcp synwait 5\nno cdp log mismatch duplex\n!\nline con 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\nline aux 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\n!\n!\nend\n",
"system_id": "FTX0945W0MY"
},
"symbol": ":/symbols/router.svg",
"width": 66,
"x": -103,
"y": -64,
"z": 1
},
{
"compute_id": "local",
"console": 5001,
"console_type": "telnet",
"first_port_name": null,
"height": 45,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "R2",
"x": 22,
"y": -25
},
"name": "R2",
"node_id": "f306df6f-dbe0-4be1-9a40-625b8d20fe6e",
"node_type": "dynamips",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"properties": {
"auto_delete_disks": true,
"aux": null,
"clock_divisor": 4,
"disk0": 0,
"disk1": 0,
"dynamips_id": 2,
"exec_area": 64,
"idlemax": 500,
"idlepc": "0x606e0538",
"idlesleep": 30,
"image": "c7200-adventerprisek9-mz.124-24.T8.image",
"image_md5sum": "b89d30823cbbda460364991ed18449c7",
"mac_addr": "ca02.ba34.0000",
"midplane": "vxr",
"mmap": true,
"npe": "npe-400",
"nvram": 512,
"platform": "c7200",
"power_supplies": [
1,
1
],
"private_config": "",
"private_config_content": "",
"ram": 512,
"sensors": [
22,
22,
22,
22
],
"slot0": "C7200-IO-FE",
"slot1": null,
"slot2": null,
"slot3": null,
"slot4": null,
"slot5": null,
"slot6": null,
"sparsemem": true,
"startup_config": "configs/i2_startup-config.cfg",
"startup_config_content": "!\n!\nservice timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption\n!\nhostname R2\n!\nip cef\nno ip domain-lookup\nno ip icmp rate-limit unreachable\nip tcp synwait 5\nno cdp log mismatch duplex\n!\nline con 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\nline aux 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\n!\n!\nend\n",
"system_id": "FTX0945W0MY"
},
"symbol": ":/symbols/router.svg",
"width": 66,
"x": 72,
"y": -42,
"z": 1
}
]
},
"type": "topology",
"version": "2.0.0dev7"
}

View File

@ -0,0 +1,101 @@
!
!
upgrade fpd auto
version 12.4
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname R1
!
boot-start-marker
boot-end-marker
!
logging message-counter syslog
!
no aaa new-model
ip source-route
no ip icmp rate-limit unreachable
ip cef
!
!
!
!
no ip domain lookup
no ipv6 cef
!
multilink bundle-name authenticated
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
archive
log config
hidekeys
!
!
!
!
!
ip tcp synwait-time 5
!
!
!
!
interface FastEthernet0/0
no ip address
shutdown
duplex half
!
ip forward-protocol nd
no ip http server
no ip http secure-server
!
!
!
no cdp log mismatch duplex
!
!
!
!
!
!
control-plane
!
!
!
!
!
!
!
gatekeeper
shutdown
!
!
line con 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line aux 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line vty 0 4
login
!
end

View File

@ -0,0 +1,101 @@
!
!
upgrade fpd auto
version 12.4
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname R2
!
boot-start-marker
boot-end-marker
!
logging message-counter syslog
!
no aaa new-model
ip source-route
no ip icmp rate-limit unreachable
ip cef
!
!
!
!
no ip domain lookup
no ipv6 cef
!
multilink bundle-name authenticated
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
archive
log config
hidekeys
!
!
!
!
!
ip tcp synwait-time 5
!
!
!
!
interface FastEthernet0/0
no ip address
shutdown
duplex half
!
ip forward-protocol nd
no ip http server
no ip http secure-server
!
!
!
no cdp log mismatch duplex
!
!
!
!
!
!
control-plane
!
!
!
!
!
!
!
gatekeeper
shutdown
!
!
line con 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line aux 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line vty 0 4
login
!
end

View File

@ -0,0 +1,163 @@
{
"auto_close": true,
"auto_open": false,
"auto_start": false,
"name": "dynamips_2_0_0_b2",
"project_id": "7a2be307-da2d-4819-a131-00e367658809",
"revision": 6,
"scene_height": 1000,
"scene_width": 2000,
"topology": {
"computes": [
{
"compute_id": "local",
"host": "127.0.0.1",
"name": "atlantis",
"port": 3080,
"protocol": "http"
}
],
"drawings": [],
"links": [],
"nodes": [
{
"compute_id": "local",
"console": 5000,
"console_type": "telnet",
"first_port_name": null,
"height": 45,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "R1",
"x": 22,
"y": -25
},
"name": "R1",
"node_id": "b31bacb4-b251-47e3-b9e8-fe5596e7a8ba",
"node_type": "dynamips",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"properties": {
"auto_delete_disks": true,
"aux": null,
"clock_divisor": 4,
"disk0": 0,
"disk1": 0,
"dynamips_id": 1,
"exec_area": 64,
"idlemax": 500,
"idlepc": "0x606e0538",
"idlesleep": 30,
"image": "c7200-adventerprisek9-mz.124-24.T8.image",
"image_md5sum": "b89d30823cbbda460364991ed18449c7",
"mac_addr": "ca01.ba2f.0000",
"midplane": "vxr",
"mmap": true,
"npe": "npe-400",
"nvram": 512,
"platform": "c7200",
"power_supplies": [
1,
1
],
"private_config": "",
"private_config_content": "",
"ram": 512,
"sensors": [
22,
22,
22,
22
],
"slot0": "C7200-IO-FE",
"slot1": null,
"slot2": null,
"slot3": null,
"slot4": null,
"slot5": null,
"slot6": null,
"sparsemem": true,
"startup_config": "configs/i1_startup-config.cfg",
"startup_config_content": "!\n!\nservice timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption\n!\nhostname R1\n!\nip cef\nno ip domain-lookup\nno ip icmp rate-limit unreachable\nip tcp synwait 5\nno cdp log mismatch duplex\n!\nline con 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\nline aux 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\n!\n!\nend\n",
"system_id": "FTX0945W0MY"
},
"symbol": ":/symbols/router.svg",
"width": 66,
"x": -103,
"y": -64,
"z": 1
},
{
"compute_id": "local",
"console": 5001,
"console_type": "telnet",
"first_port_name": null,
"height": 45,
"label": {
"rotation": 0,
"style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;",
"text": "R2",
"x": 22,
"y": -25
},
"name": "R2",
"node_id": "f306df6f-dbe0-4be1-9a40-625b8d20fe6e",
"node_type": "dynamips",
"port_name_format": "Ethernet{0}",
"port_segment_size": 0,
"properties": {
"auto_delete_disks": true,
"aux": null,
"clock_divisor": 4,
"disk0": 0,
"disk1": 0,
"dynamips_id": 2,
"exec_area": 64,
"idlemax": 500,
"idlepc": "0x606e0538",
"idlesleep": 30,
"image": "c7200-adventerprisek9-mz.124-24.T8.image",
"image_md5sum": "b89d30823cbbda460364991ed18449c7",
"mac_addr": "ca02.ba34.0000",
"midplane": "vxr",
"mmap": true,
"npe": "npe-400",
"nvram": 512,
"platform": "c7200",
"power_supplies": [
1,
1
],
"private_config": "",
"private_config_content": "",
"ram": 512,
"sensors": [
22,
22,
22,
22
],
"slot0": "C7200-IO-FE",
"slot1": null,
"slot2": null,
"slot3": null,
"slot4": null,
"slot5": null,
"slot6": null,
"sparsemem": true,
"startup_config": "configs/i2_startup-config.cfg",
"startup_config_content": "!\n!\nservice timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption\n!\nhostname R2\n!\nip cef\nno ip domain-lookup\nno ip icmp rate-limit unreachable\nip tcp synwait 5\nno cdp log mismatch duplex\n!\nline con 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\nline aux 0\n exec-timeout 0 0\n logging synchronous\n privilege level 15\n no login\n!\n!\nend\n",
"system_id": "FTX0945W0MY"
},
"symbol": ":/symbols/router.svg",
"width": 66,
"x": 72,
"y": -42,
"z": 1
}
]
},
"type": "topology",
"version": "2.0.0dev7"
}

View File

@ -0,0 +1,101 @@
!
!
upgrade fpd auto
version 12.4
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname R1
!
boot-start-marker
boot-end-marker
!
logging message-counter syslog
!
no aaa new-model
ip source-route
no ip icmp rate-limit unreachable
ip cef
!
!
!
!
no ip domain lookup
no ipv6 cef
!
multilink bundle-name authenticated
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
archive
log config
hidekeys
!
!
!
!
!
ip tcp synwait-time 5
!
!
!
!
interface FastEthernet0/0
no ip address
shutdown
duplex half
!
ip forward-protocol nd
no ip http server
no ip http secure-server
!
!
!
no cdp log mismatch duplex
!
!
!
!
!
!
control-plane
!
!
!
!
!
!
!
gatekeeper
shutdown
!
!
line con 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line aux 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line vty 0 4
login
!
end

View File

@ -0,0 +1,101 @@
!
!
upgrade fpd auto
version 12.4
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname R2
!
boot-start-marker
boot-end-marker
!
logging message-counter syslog
!
no aaa new-model
ip source-route
no ip icmp rate-limit unreachable
ip cef
!
!
!
!
no ip domain lookup
no ipv6 cef
!
multilink bundle-name authenticated
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
archive
log config
hidekeys
!
!
!
!
!
ip tcp synwait-time 5
!
!
!
!
interface FastEthernet0/0
no ip address
shutdown
duplex half
!
ip forward-protocol nd
no ip http server
no ip http secure-server
!
!
!
no cdp log mismatch duplex
!
!
!
!
!
!
control-plane
!
!
!
!
!
!
!
gatekeeper
shutdown
!
!
line con 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line aux 0
exec-timeout 0 0
privilege level 15
logging synchronous
stopbits 1
line vty 0 4
login
!
end