API for duplication a Node

Support:
* VPCS
* Dynamips router
* Ethernet switch

Ref #1065
This commit is contained in:
Julien Duponchelle committed 2017-07-24 10:08:22 +02:00
1 parent 0449a5b4ee
commit 0854c04687
18 files changed
+382 -32

No files matched your search

+39 -6
View File
@@ -511,16 +511,12 @@ class Dynamips(BaseManager):
:param settings: VM settings
"""
module_workdir = vm.project.module_working_directory(self.module_name.lower())
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, vm.id, "configs", "i{}_private-config.cfg".format(vm.dynamips_id))
startup_config_content = settings.get("startup_config_content")
if startup_config_content:
self._create_config(vm, default_startup_config_path, startup_config_content)
self._create_config(vm, vm.startup_config_path, startup_config_content)
private_config_content = settings.get("private_config_content")
if private_config_content:
self._create_config(vm, default_private_config_path, private_config_content)
self._create_config(vm, vm.private_config_path, private_config_content)
def _create_config(self, vm, path, content=None):
"""
@@ -605,3 +601,40 @@ class Dynamips(BaseManager):
if was_auto_started:
yield from vm.stop()
return validated_idlepc
@asyncio.coroutine
def duplicate_node(self, source_node_id, destination_node_id):
"""
Duplicate a node
:param node_id: Node identifier
:returns: New node instance
"""
source_node = self.get_node(source_node_id)
destination_node = self.get_node(destination_node_id)
# Non router gears
if not hasattr(source_node, "startup_config_path"):
return (yield from super().duplicate_node(source_node_id, destination_node_id))
try:
with open(source_node.startup_config_path) as f:
startup_config = f.read()
except OSError:
startup_config = None
try:
with open(source_node.private_config_path) as f:
private_config = f.read()
except OSError:
private_config = None
yield from self.set_vm_configs(destination_node, {
"startup_config_content": startup_config,
"private_config_content": private_config
})
# Force refresh of the name in configuration files
new_name = destination_node.name
yield from destination_node.set_name(source_node.name)
yield from destination_node.set_name(new_name)
return destination_node
+22 -10
View File
@@ -1474,6 +1474,20 @@ class Router(BaseNode):
return self._slots
@property
def startup_config_path(self):
"""
:returns: Path of the startup config
"""
return os.path.join(self._working_directory, "configs", "i{}_startup-config.cfg".format(self._dynamips_id))
@property
def private_config_path(self):
"""
:returns: Path of the private config
"""
return os.path.join(self._working_directory, "configs", "i{}_private-config.cfg".format(self._dynamips_id))
@asyncio.coroutine
def set_name(self, new_name):
"""
@@ -1483,28 +1497,26 @@ class Router(BaseNode):
"""
# change the hostname in the startup-config
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(self.startup_config_path):
try:
with open(startup_config_path, "r+", encoding="utf-8", errors="replace") as f:
with open(self.startup_config_path, "r+", encoding="utf-8", errors="replace") as f:
old_config = f.read()
new_config = re.sub(r"^hostname .+$", "hostname " + new_name, old_config, flags=re.MULTILINE)
f.seek(0)
f.write(new_config)
except OSError as e:
raise DynamipsError("Could not amend the configuration {}: {}".format(startup_config_path, e))
raise DynamipsError("Could not amend the configuration {}: {}".format(self.startup_config_path, e))
# change the hostname in the private-config
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(self.private_config_path):
try:
with open(private_config_path, "r+", encoding="utf-8", errors="replace") as f:
with open(self.private_config_path, "r+", encoding="utf-8", errors="replace") as f:
old_config = f.read()
new_config = old_config.replace(self.name, new_name)
f.seek(0)
f.write(new_config)
except OSError as e:
raise DynamipsError("Could not amend the configuration {}: {}".format(private_config_path, e))
raise DynamipsError("Could not amend the configuration {}: {}".format(self.private_config_path, e))
yield from self._hypervisor.send('vm rename "{name}" "{new_name}"'.format(name=self._name, new_name=new_name))
log.info('Router "{name}" [{id}]: renamed to "{new_name}"'.format(name=self._name, id=self._id, new_name=new_name))
@@ -1543,7 +1555,7 @@ class Router(BaseNode):
startup_config_base64, private_config_base64 = yield from self.extract_config()
if startup_config_base64:
startup_config = os.path.join("configs", "i{}_startup-config.cfg".format(self._dynamips_id))
startup_config = self.startup_config_path
try:
config = base64.b64decode(startup_config_base64).decode("utf-8", errors="replace")
config = "!\n" + config.replace("\r", "")
@@ -1555,7 +1567,7 @@ class Router(BaseNode):
raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e))
if private_config_base64 and base64.b64decode(private_config_base64) != b'\nkerberos password \nend\n':
private_config = os.path.join("configs", "i{}_private-config.cfg".format(self._dynamips_id))
private_config = self.private_config_path
try:
config = base64.b64decode(private_config_base64).decode("utf-8", errors="replace")
config_path = os.path.join(self._working_directory, private_config)