Yet another PEP 8 :)

This commit is contained in:
Julien Duponchelle committed 2015-01-20 16:37:18 +01:00
1 parent 7cf409c392
commit bbee5f90a0
106 files changed
+9 -29

No files matched your search

Whitespace-only changes.
@@ -0,0 +1,395 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import os
from gns3server.modules import IModule
from ..nodes.atm_switch import ATMSwitch
from ..dynamips_error import DynamipsError
from ..schemas.atmsw import ATMSW_CREATE_SCHEMA
from ..schemas.atmsw import ATMSW_DELETE_SCHEMA
from ..schemas.atmsw import ATMSW_UPDATE_SCHEMA
from ..schemas.atmsw import ATMSW_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.atmsw import ATMSW_ADD_NIO_SCHEMA
from ..schemas.atmsw import ATMSW_DELETE_NIO_SCHEMA
from ..schemas.atmsw import ATMSW_START_CAPTURE_SCHEMA
from ..schemas.atmsw import ATMSW_STOP_CAPTURE_SCHEMA
import logging
log = logging.getLogger(__name__)
class ATMSW(object):
@IModule.route("dynamips.atmsw.create")
def atmsw_create(self, request):
"""
Creates a new ATM switch.
Mandatory request parameters:
- name (switch name)
Response parameters:
- id (switch identifier)
- name (switch name)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_CREATE_SCHEMA):
return
name = request["name"]
try:
if not self._hypervisor_manager:
self.start_hypervisor_manager()
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
atmsw = ATMSwitch(hypervisor, name)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"name": atmsw.name,
"id": atmsw.id}
self._atm_switches[atmsw.id] = atmsw
self.send_response(response)
@IModule.route("dynamips.atmsw.delete")
def atmsw_delete(self, request):
"""
Deletes a ATM switch.
Mandatory request parameters:
- id (switch identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_DELETE_SCHEMA):
return
# get the ATM switch instance
atmsw_id = request["id"]
atmsw = self.get_device_instance(atmsw_id, self._atm_switches)
if not atmsw:
return
try:
atmsw.delete()
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(atmsw)
del self._atm_switches[atmsw_id]
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.atmsw.update")
def atmsw_update(self, request):
"""
Updates a ATM switch.
Mandatory request parameters:
- id (switch identifier)
Optional request parameters:
- name (new switch name)
Response parameters:
- name if changed
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_UPDATE_SCHEMA):
return
# get the ATM switch instance
atmsw = self.get_device_instance(request["id"], self._atm_switches)
if not atmsw:
return
response = {}
# rename the switch if requested
if "name" in request and atmsw.name != request["name"]:
try:
atmsw.name = request["name"]
response["name"] = atmsw.name
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(response)
@IModule.route("dynamips.atmsw.allocate_udp_port")
def atmsw_allocate_udp_port(self, request):
"""
Allocates a UDP port in order to create an UDP NIO for an
ATM switch.
Mandatory request parameters:
- id (switch identifier)
- port_id (port identifier)
Response parameters:
- port_id (port identifier)
- lport (allocated local port)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_ALLOCATE_UDP_PORT_SCHEMA):
return
# get the ATM switch instance
atmsw = self.get_device_instance(request["id"], self._atm_switches)
if not atmsw:
return
try:
# allocate a new UDP port
response = self.allocate_udp_port(atmsw)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response["port_id"] = request["port_id"]
self.send_response(response)
@IModule.route("dynamips.atmsw.add_nio")
def atmsw_add_nio(self, request):
"""
Adds an NIO (Network Input/Output) for an ATM switch.
Mandatory request parameters:
- id (switch identifier)
- port (port identifier)
- port_id (port identifier)
- mappings (VCs/VPs mapped to the port)
- nio (one of the following)
- type "nio_udp"
- lport (local port)
- rhost (remote host)
- rport (remote port)
- type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_tap"
- tap_device (TAP device name e.g. tap0)
- type "nio_unix"
- local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file)
- type "nio_vde"
- control_file (path to VDE control file)
- local_file (path to VDE local file)
- type "nio_null"
Response parameters:
- port_id (unique port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_ADD_NIO_SCHEMA):
return
# get the ATM switch instance
atmsw = self.get_device_instance(request["id"], self._atm_switches)
if not atmsw:
return
port = request["port"]
mappings = request["mappings"]
try:
nio = self.create_nio(atmsw, request)
if not nio:
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
except DynamipsError as e:
self.send_custom_error(str(e))
return
try:
atmsw.add_nio(nio, port)
pvc_entry = re.compile(r"""^([0-9]*):([0-9]*):([0-9]*)$""")
for source, destination in mappings.items():
match_source_pvc = pvc_entry.search(source)
match_destination_pvc = pvc_entry.search(destination)
if match_source_pvc and match_destination_pvc:
# add the virtual channels mapped with this port/nio
source_port, source_vpi, source_vci = map(int, match_source_pvc.group(1, 2, 3))
destination_port, destination_vpi, destination_vci = map(int, match_destination_pvc.group(1, 2, 3))
if atmsw.has_port(destination_port):
if (source_port, source_vpi, source_vci) not in atmsw.mapping and \
(destination_port, destination_vpi, destination_vci) not in atmsw.mapping:
atmsw.map_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci)
atmsw.map_pvc(destination_port, destination_vpi, destination_vci, source_port, source_vpi, source_vci)
else:
# add the virtual paths mapped with this port/nio
source_port, source_vpi = map(int, source.split(':'))
destination_port, destination_vpi = map(int, destination.split(':'))
if atmsw.has_port(destination_port):
if (source_port, source_vpi) not in atmsw.mapping and (destination_port, destination_vpi) not in atmsw.mapping:
atmsw.map_vp(source_port, source_vpi, destination_port, destination_vpi)
atmsw.map_vp(destination_port, destination_vpi, source_port, source_vpi)
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response({"port_id": request["port_id"]})
@IModule.route("dynamips.atmsw.delete_nio")
def atmsw_delete_nio(self, request):
"""
Deletes an NIO (Network Input/Output).
Mandatory request parameters:
- id (switch identifier)
- port (port identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_DELETE_NIO_SCHEMA):
return
# get the ATM switch instance
atmsw = self.get_device_instance(request["id"], self._atm_switches)
if not atmsw:
return
port = request["port"]
try:
for source, destination in atmsw.mapping.copy().items():
if len(source) == 3 and len(destination) == 3:
# remove the virtual channels mapped with this port/nio
source_port, source_vpi, source_vci = source
destination_port, destination_vpi, destination_vci = destination
if port == source_port:
atmsw.unmap_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci)
atmsw.unmap_pvc(destination_port, destination_vpi, destination_vci, source_port, source_vpi, source_vci)
else:
# remove the virtual paths mapped with this port/nio
source_port, source_vpi = source
destination_port, destination_vpi = destination
if port == source_port:
atmsw.unmap_vp(source_port, source_vpi, destination_port, destination_vpi)
atmsw.unmap_vp(destination_port, destination_vpi, source_port, source_vpi)
nio = atmsw.remove_nio(port)
nio.delete()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.atmsw.start_capture")
def atmsw_start_capture(self, request):
"""
Starts a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port (port identifier)
- port_id (port identifier)
- capture_file_name
Optional request parameters:
- data_link_type (PCAP DLT_* value)
Response parameters:
- port_id (port identifier)
- capture_file_path (path to the capture file)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_START_CAPTURE_SCHEMA):
return
# get the ATM switch instance
atmsw = self.get_device_instance(request["id"], self._atm_switches)
if not atmsw:
return
port = request["port"]
capture_file_name = request["capture_file_name"]
data_link_type = request.get("data_link_type")
try:
capture_file_path = os.path.join(atmsw.hypervisor.working_dir, "captures", capture_file_name)
atmsw.start_capture(port, capture_file_path, data_link_type)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"],
"capture_file_path": capture_file_path}
self.send_response(response)
@IModule.route("dynamips.atmsw.stop_capture")
def atmsw_stop_capture(self, request):
"""
Stops a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port_id (port identifier)
- port (port number)
Response parameters:
- port_id (port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ATMSW_STOP_CAPTURE_SCHEMA):
return
# get the ATM switch instance
atmsw = self.get_device_instance(request["id"], self._atm_switches)
if not atmsw:
return
port = request["port"]
try:
atmsw.stop_capture(port)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"]}
self.send_response(response)
@@ -0,0 +1,353 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.modules import IModule
from ..nodes.hub import Hub
from ..dynamips_error import DynamipsError
from ..schemas.ethhub import ETHHUB_CREATE_SCHEMA
from ..schemas.ethhub import ETHHUB_DELETE_SCHEMA
from ..schemas.ethhub import ETHHUB_UPDATE_SCHEMA
from ..schemas.ethhub import ETHHUB_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.ethhub import ETHHUB_ADD_NIO_SCHEMA
from ..schemas.ethhub import ETHHUB_DELETE_NIO_SCHEMA
from ..schemas.ethhub import ETHHUB_START_CAPTURE_SCHEMA
from ..schemas.ethhub import ETHHUB_STOP_CAPTURE_SCHEMA
import logging
log = logging.getLogger(__name__)
class ETHHUB(object):
@IModule.route("dynamips.ethhub.create")
def ethhub_create(self, request):
"""
Creates a new Ethernet hub.
Mandatory request parameters:
- name (hub name)
Response parameters:
- id (hub identifier)
- name (hub name)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_CREATE_SCHEMA):
return
name = request["name"]
try:
if not self._hypervisor_manager:
self.start_hypervisor_manager()
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
ethhub = Hub(hypervisor, name)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"name": ethhub.name,
"id": ethhub.id}
self._ethernet_hubs[ethhub.id] = ethhub
self.send_response(response)
@IModule.route("dynamips.ethhub.delete")
def ethhub_delete(self, request):
"""
Deletes a Ethernet hub.
Mandatory request parameters:
- id (hub identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_DELETE_SCHEMA):
return
# get the Ethernet hub instance
ethhub_id = request["id"]
ethhub = self.get_device_instance(ethhub_id, self._ethernet_hubs)
if not ethhub:
return
try:
ethhub.delete()
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(ethhub)
del self._ethernet_hubs[ethhub_id]
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(request)
@IModule.route("dynamips.ethhub.update")
def ethhub_update(self, request):
"""
Updates a Ethernet hub.
Mandatory request parameters:
- id (hub identifier)
Optional request parameters:
- name (new hub name)
Response parameters:
- name if changed
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_UPDATE_SCHEMA):
return
# get the Ethernet hub instance
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
if not ethhub:
return
response = {}
# rename the hub if requested
if "name" in request and ethhub.name != request["name"]:
try:
ethhub.name = request["name"]
response["name"] = ethhub.name
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(request)
@IModule.route("dynamips.ethhub.allocate_udp_port")
def ethhub_allocate_udp_port(self, request):
"""
Allocates a UDP port in order to create an UDP NIO for an
Ethernet hub.
Mandatory request parameters:
- id (hub identifier)
- port_id (port identifier)
Response parameters:
- port_id (port identifier)
- lport (allocated local port)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_ALLOCATE_UDP_PORT_SCHEMA):
return
# get the Ethernet hub instance
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
if not ethhub:
return
try:
# allocate a new UDP port
response = self.allocate_udp_port(ethhub)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response["port_id"] = request["port_id"]
self.send_response(response)
@IModule.route("dynamips.ethhub.add_nio")
def ethhub_add_nio(self, request):
"""
Adds an NIO (Network Input/Output) for an Ethernet hub.
Mandatory request parameters:
- id (hub identifier)
- port (port identifier)
- port_id (port identifier)
- nio (one of the following)
- type "nio_udp"
- lport (local port)
- rhost (remote host)
- rport (remote port)
- type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_tap"
- tap_device (TAP device name e.g. tap0)
- type "nio_unix"
- local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file)
- type "nio_vde"
- control_file (path to VDE control file)
- local_file (path to VDE local file)
- type "nio_null"
Response parameters:
- port_id (unique port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_ADD_NIO_SCHEMA):
return
# get the Ethernet hub instance
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
if not ethhub:
return
port = request["port"]
try:
nio = self.create_nio(ethhub, request)
if not nio:
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
except DynamipsError as e:
self.send_custom_error(str(e))
return
try:
ethhub.add_nio(nio, port)
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response({"port_id": request["port_id"]})
@IModule.route("dynamips.ethhub.delete_nio")
def ethhub_delete_nio(self, request):
"""
Deletes an NIO (Network Input/Output).
Mandatory request parameters:
- id (hub identifier)
- port (port identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_DELETE_NIO_SCHEMA):
return
# get the Ethernet hub instance
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
if not ethhub:
return
port = request["port"]
try:
nio = ethhub.remove_nio(port)
nio.delete()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.ethhub.start_capture")
def ethhub_start_capture(self, request):
"""
Starts a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port (port identifier)
- port_id (port identifier)
- capture_file_name
Optional request parameters:
- data_link_type (PCAP DLT_* value)
Response parameters:
- port_id (port identifier)
- capture_file_path (path to the capture file)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_START_CAPTURE_SCHEMA):
return
# get the Ethernet hub instance
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
if not ethhub:
return
port = request["port"]
capture_file_name = request["capture_file_name"]
data_link_type = request.get("data_link_type")
try:
capture_file_path = os.path.join(ethhub.hypervisor.working_dir, "captures", capture_file_name)
ethhub.start_capture(port, capture_file_path, data_link_type)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"],
"capture_file_path": capture_file_path}
self.send_response(response)
@IModule.route("dynamips.ethhub.stop_capture")
def ethhub_stop_capture(self, request):
"""
Stops a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port_id (port identifier)
- port (port number)
Response parameters:
- port_id (port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHHUB_STOP_CAPTURE_SCHEMA):
return
# get the Ethernet hub instance
ethhub = self.get_device_instance(request["id"], self._ethernet_hubs)
if not ethhub:
return
port = request["port"]
try:
ethhub.stop_capture(port)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"]}
self.send_response(response)
@@ -0,0 +1,382 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.modules import IModule
from ..nodes.ethernet_switch import EthernetSwitch
from ..dynamips_error import DynamipsError
from ..schemas.ethsw import ETHSW_CREATE_SCHEMA
from ..schemas.ethsw import ETHSW_DELETE_SCHEMA
from ..schemas.ethsw import ETHSW_UPDATE_SCHEMA
from ..schemas.ethsw import ETHSW_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.ethsw import ETHSW_ADD_NIO_SCHEMA
from ..schemas.ethsw import ETHSW_DELETE_NIO_SCHEMA
from ..schemas.ethsw import ETHSW_START_CAPTURE_SCHEMA
from ..schemas.ethsw import ETHSW_STOP_CAPTURE_SCHEMA
import logging
log = logging.getLogger(__name__)
class ETHSW(object):
@IModule.route("dynamips.ethsw.create")
def ethsw_create(self, request):
"""
Creates a new Ethernet switch.
Mandatory request parameters:
- name (switch name)
Response parameters:
- id (switch identifier)
- name (switch name)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_CREATE_SCHEMA):
return
name = request["name"]
try:
if not self._hypervisor_manager:
self.start_hypervisor_manager()
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
ethsw = EthernetSwitch(hypervisor, name)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"name": ethsw.name,
"id": ethsw.id}
self._ethernet_switches[ethsw.id] = ethsw
self.send_response(response)
@IModule.route("dynamips.ethsw.delete")
def ethsw_delete(self, request):
"""
Deletes a Ethernet switch.
Mandatory request parameters:
- id (switch identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_DELETE_SCHEMA):
return
# get the Ethernet switch instance
ethsw_id = request["id"]
ethsw = self.get_device_instance(ethsw_id, self._ethernet_switches)
if not ethsw:
return
try:
ethsw.delete()
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(ethsw)
del self._ethernet_switches[ethsw_id]
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.ethsw.update")
def ethsw_update(self, request):
"""
Updates a Ethernet switch.
Mandatory request parameters:
- id (switch identifier)
Optional request parameters:
- name (new switch name)
- ports (ports settings)
Response parameters:
- name if changed
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_UPDATE_SCHEMA):
return
# get the Ethernet switch instance
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
if not ethsw:
return
if "ports" in request:
ports = request["ports"]
# update the port settings
for port, info in ports.items():
vlan = info["vlan"]
port_type = info["type"]
try:
if port_type == "access":
ethsw.set_access_port(int(port), vlan)
elif port_type == "dot1q":
ethsw.set_dot1q_port(int(port), vlan)
elif port_type == "qinq":
ethsw.set_qinq_port(int(port), vlan)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {}
# rename the switch if requested
if "name" in request and ethsw.name != request["name"]:
try:
ethsw.name = request["name"]
response["name"] = ethsw.name
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(response)
@IModule.route("dynamips.ethsw.allocate_udp_port")
def ethsw_allocate_udp_port(self, request):
"""
Allocates a UDP port in order to create an UDP NIO for an
Ethernet switch.
Mandatory request parameters:
- id (switch identifier)
- port_id (port identifier)
Response parameters:
- port_id (port identifier)
- lport (allocated local port)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_ALLOCATE_UDP_PORT_SCHEMA):
return
# get the Ethernet switch instance
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
if not ethsw:
return
try:
# allocate a new UDP port
response = self.allocate_udp_port(ethsw)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response["port_id"] = request["port_id"]
self.send_response(response)
@IModule.route("dynamips.ethsw.add_nio")
def ethsw_add_nio(self, request):
"""
Adds an NIO (Network Input/Output) for an Ethernet switch.
Mandatory request parameters:
- id (switch identifier)
- port (port identifier)
- port_id (port identifier)
- vlan (vlan identifier)
- port_type ("access", "dot1q" or "qinq")
- nio (one of the following)
- type "nio_udp"
- lport (local port)
- rhost (remote host)
- rport (remote port)
- type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_tap"
- tap_device (TAP device name e.g. tap0)
- type "nio_unix"
- local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file)
- type "nio_vde"
- control_file (path to VDE control file)
- local_file (path to VDE local file)
- type "nio_null"
Response parameters:
- port_id (unique port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_ADD_NIO_SCHEMA):
return
# get the Ethernet switch instance
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
if not ethsw:
return
port = request["port"]
vlan = request["vlan"]
port_type = request["port_type"]
try:
nio = self.create_nio(ethsw, request)
if not nio:
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
except DynamipsError as e:
self.send_custom_error(str(e))
return
try:
ethsw.add_nio(nio, port)
if port_type == "access":
ethsw.set_access_port(port, vlan)
elif port_type == "dot1q":
ethsw.set_dot1q_port(port, vlan)
elif port_type == "qinq":
ethsw.set_qinq_port(port, vlan)
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response({"port_id": request["port_id"]})
@IModule.route("dynamips.ethsw.delete_nio")
def ethsw_delete_nio(self, request):
"""
Deletes an NIO (Network Input/Output).
Mandatory request parameters:
- id (switch identifier)
- port (port identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_DELETE_NIO_SCHEMA):
return
# get the Ethernet switch instance
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
if not ethsw:
return
port = request["port"]
try:
nio = ethsw.remove_nio(port)
nio.delete()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.ethsw.start_capture")
def ethsw_start_capture(self, request):
"""
Starts a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port (port identifier)
- port_id (port identifier)
- capture_file_name
Optional request parameters:
- data_link_type (PCAP DLT_* value)
Response parameters:
- port_id (port identifier)
- capture_file_path (path to the capture file)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_START_CAPTURE_SCHEMA):
return
# get the Ethernet switch instance
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
if not ethsw:
return
port = request["port"]
capture_file_name = request["capture_file_name"]
data_link_type = request.get("data_link_type")
try:
capture_file_path = os.path.join(ethsw.hypervisor.working_dir, "captures", capture_file_name)
ethsw.start_capture(port, capture_file_path, data_link_type)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"],
"capture_file_path": capture_file_path}
self.send_response(response)
@IModule.route("dynamips.ethsw.stop_capture")
def ethsw_stop_capture(self, request):
"""
Stops a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port_id (port identifier)
- port (port number)
Response parameters:
- port_id (port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, ETHSW_STOP_CAPTURE_SCHEMA):
return
# get the Ethernet switch instance
ethsw = self.get_device_instance(request["id"], self._ethernet_switches)
if not ethsw:
return
port = request["port"]
try:
ethsw.stop_capture(port)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"]}
self.send_response(response)
@@ -0,0 +1,374 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from gns3server.modules import IModule
from ..nodes.frame_relay_switch import FrameRelaySwitch
from ..dynamips_error import DynamipsError
from ..schemas.frsw import FRSW_CREATE_SCHEMA
from ..schemas.frsw import FRSW_DELETE_SCHEMA
from ..schemas.frsw import FRSW_UPDATE_SCHEMA
from ..schemas.frsw import FRSW_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.frsw import FRSW_ADD_NIO_SCHEMA
from ..schemas.frsw import FRSW_DELETE_NIO_SCHEMA
from ..schemas.frsw import FRSW_START_CAPTURE_SCHEMA
from ..schemas.frsw import FRSW_STOP_CAPTURE_SCHEMA
import logging
log = logging.getLogger(__name__)
class FRSW(object):
@IModule.route("dynamips.frsw.create")
def frsw_create(self, request):
"""
Creates a new Frame-Relay switch.
Mandatory request parameters:
- name (switch name)
Response parameters:
- id (switch identifier)
- name (switch name)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_CREATE_SCHEMA):
return
name = request["name"]
try:
if not self._hypervisor_manager:
self.start_hypervisor_manager()
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_simulated_device()
frsw = FrameRelaySwitch(hypervisor, name)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"name": frsw.name,
"id": frsw.id}
self._frame_relay_switches[frsw.id] = frsw
self.send_response(response)
@IModule.route("dynamips.frsw.delete")
def frsw_delete(self, request):
"""
Deletes a Frame Relay switch.
Mandatory request parameters:
- id (switch identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_DELETE_SCHEMA):
return
# get the Frame relay switch instance
frsw_id = request["id"]
frsw = self.get_device_instance(frsw_id, self._frame_relay_switches)
if not frsw:
return
try:
frsw.delete()
self._hypervisor_manager.unallocate_hypervisor_for_simulated_device(frsw)
del self._frame_relay_switches[frsw_id]
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.frsw.update")
def frsw_update(self, request):
"""
Updates a Frame Relay switch.
Mandatory request parameters:
- id (switch identifier)
Optional request parameters:
- name (new switch name)
Response parameters:
- name if updated
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_UPDATE_SCHEMA):
return
# get the Frame relay switch instance
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
if not frsw:
return
response = {}
# rename the switch if requested
if "name" in request and frsw.name != request["name"]:
try:
frsw.name = request["name"]
response["name"] = frsw.name
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(request)
@IModule.route("dynamips.frsw.allocate_udp_port")
def frsw_allocate_udp_port(self, request):
"""
Allocates a UDP port in order to create an UDP NIO for an
Frame Relay switch.
Mandatory request parameters:
- id (switch identifier)
- port_id (port identifier)
Response parameters:
- port_id (port identifier)
- lport (allocated local port)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_ALLOCATE_UDP_PORT_SCHEMA):
return
# get the Frame relay switch instance
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
if not frsw:
return
try:
# allocate a new UDP port
response = self.allocate_udp_port(frsw)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response["port_id"] = request["port_id"]
self.send_response(response)
@IModule.route("dynamips.frsw.add_nio")
def frsw_add_nio(self, request):
"""
Adds an NIO (Network Input/Output) for an Frame-Relay switch.
Mandatory request parameters:
- id (switch identifier)
- port (port identifier)
- port_id (port identifier)
- mappings (VCs mapped to the port)
- nio (one of the following)
- type "nio_udp"
- lport (local port)
- rhost (remote host)
- rport (remote port)
- type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_tap"
- tap_device (TAP device name e.g. tap0)
- type "nio_unix"
- local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file)
- type "nio_vde"
- control_file (path to VDE control file)
- local_file (path to VDE local file)
- type "nio_null"
Response parameters:
- port_id (unique port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_ADD_NIO_SCHEMA):
return
# get the Frame relay switch instance
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
if not frsw:
return
port = request["port"]
mappings = request["mappings"]
try:
nio = self.create_nio(frsw, request)
if not nio:
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
except DynamipsError as e:
self.send_custom_error(str(e))
return
try:
frsw.add_nio(nio, port)
# add the VCs mapped with this port/nio
for source, destination in mappings.items():
source_port, source_dlci = map(int, source.split(':'))
destination_port, destination_dlci = map(int, destination.split(':'))
if frsw.has_port(destination_port):
if (source_port, source_dlci) not in frsw.mapping and (destination_port, destination_dlci) not in frsw.mapping:
frsw.map_vc(source_port, source_dlci, destination_port, destination_dlci)
frsw.map_vc(destination_port, destination_dlci, source_port, source_dlci)
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response({"port_id": request["port_id"]})
@IModule.route("dynamips.frsw.delete_nio")
def frsw_delete_nio(self, request):
"""
Deletes an NIO (Network Input/Output).
Mandatory request parameters:
- id (switch identifier)
- port (port identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_DELETE_NIO_SCHEMA):
return
# get the Frame relay switch instance
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
if not frsw:
return
port = request["port"]
try:
# remove the VCs mapped with this port/nio
for source, destination in frsw.mapping.copy().items():
source_port, source_dlci = source
destination_port, destination_dlci = destination
if port == source_port:
frsw.unmap_vc(source_port, source_dlci, destination_port, destination_dlci)
frsw.unmap_vc(destination_port, destination_dlci, source_port, source_dlci)
nio = frsw.remove_nio(port)
nio.delete()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.frsw.start_capture")
def frsw_start_capture(self, request):
"""
Starts a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port (port identifier)
- port_id (port identifier)
- capture_file_name
Optional request parameters:
- data_link_type (PCAP DLT_* value)
Response parameters:
- port_id (port identifier)
- capture_file_path (path to the capture file)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_START_CAPTURE_SCHEMA):
return
# get the Frame relay switch instance
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
if not frsw:
return
port = request["port"]
capture_file_name = request["capture_file_name"]
data_link_type = request.get("data_link_type")
try:
capture_file_path = os.path.join(frsw.hypervisor.working_dir, "captures", capture_file_name)
frsw.start_capture(port, capture_file_path, data_link_type)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"],
"capture_file_path": capture_file_path}
self.send_response(response)
@IModule.route("dynamips.frsw.stop_capture")
def frsw_stop_capture(self, request):
"""
Stops a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port_id (port identifier)
- port (port number)
Response parameters:
- port_id (port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, FRSW_STOP_CAPTURE_SCHEMA):
return
# get the Frame relay switch instance
frsw = self.get_device_instance(request["id"], self._frame_relay_switches)
if not frsw:
return
port = request["port"]
try:
frsw.stop_capture(port)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"]}
self.send_response(response)
@@ -0,0 +1,905 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import ntpath
import time
from gns3server.modules import IModule
from gns3dms.cloud.rackspace_ctrl import get_provider
from ..dynamips_error import DynamipsError
from ..nodes.c1700 import C1700
from ..nodes.c2600 import C2600
from ..nodes.c2691 import C2691
from ..nodes.c3600 import C3600
from ..nodes.c3725 import C3725
from ..nodes.c3745 import C3745
from ..nodes.c7200 import C7200
from ..adapters.c7200_io_2fe import C7200_IO_2FE
from ..adapters.c7200_io_fe import C7200_IO_FE
from ..adapters.c7200_io_ge_e import C7200_IO_GE_E
from ..adapters.nm_16esw import NM_16ESW
from ..adapters.nm_1e import NM_1E
from ..adapters.nm_1fe_tx import NM_1FE_TX
from ..adapters.nm_4e import NM_4E
from ..adapters.nm_4t import NM_4T
from ..adapters.pa_2fe_tx import PA_2FE_TX
from ..adapters.pa_4e import PA_4E
from ..adapters.pa_4t import PA_4T
from ..adapters.pa_8e import PA_8E
from ..adapters.pa_8t import PA_8T
from ..adapters.pa_a1 import PA_A1
from ..adapters.pa_fe_tx import PA_FE_TX
from ..adapters.pa_ge import PA_GE
from ..adapters.pa_pos_oc3 import PA_POS_OC3
from ..adapters.wic_1enet import WIC_1ENET
from ..adapters.wic_1t import WIC_1T
from ..adapters.wic_2t import WIC_2T
from ..schemas.vm import VM_CREATE_SCHEMA
from ..schemas.vm import VM_DELETE_SCHEMA
from ..schemas.vm import VM_START_SCHEMA
from ..schemas.vm import VM_STOP_SCHEMA
from ..schemas.vm import VM_SUSPEND_SCHEMA
from ..schemas.vm import VM_RELOAD_SCHEMA
from ..schemas.vm import VM_UPDATE_SCHEMA
from ..schemas.vm import VM_START_CAPTURE_SCHEMA
from ..schemas.vm import VM_STOP_CAPTURE_SCHEMA
from ..schemas.vm import VM_SAVE_CONFIG_SCHEMA
from ..schemas.vm import VM_EXPORT_CONFIG_SCHEMA
from ..schemas.vm import VM_IDLEPCS_SCHEMA
from ..schemas.vm import VM_AUTO_IDLEPC_SCHEMA
from ..schemas.vm import VM_ALLOCATE_UDP_PORT_SCHEMA
from ..schemas.vm import VM_ADD_NIO_SCHEMA
from ..schemas.vm import VM_DELETE_NIO_SCHEMA
import logging
log = logging.getLogger(__name__)
ADAPTER_MATRIX = {"C7200-IO-2FE": C7200_IO_2FE,
"C7200-IO-FE": C7200_IO_FE,
"C7200-IO-GE-E": C7200_IO_GE_E,
"NM-16ESW": NM_16ESW,
"NM-1E": NM_1E,
"NM-1FE-TX": NM_1FE_TX,
"NM-4E": NM_4E,
"NM-4T": NM_4T,
"PA-2FE-TX": PA_2FE_TX,
"PA-4E": PA_4E,
"PA-4T+": PA_4T,
"PA-8E": PA_8E,
"PA-8T": PA_8T,
"PA-A1": PA_A1,
"PA-FE-TX": PA_FE_TX,
"PA-GE": PA_GE,
"PA-POS-OC3": PA_POS_OC3}
WIC_MATRIX = {"WIC-1ENET": WIC_1ENET,
"WIC-1T": WIC_1T,
"WIC-2T": WIC_2T}
PLATFORMS = {'c1700': C1700,
'c2600': C2600,
'c2691': C2691,
'c3725': C3725,
'c3745': C3745,
'c3600': C3600,
'c7200': C7200}
class VM(object):
@IModule.route("dynamips.vm.create")
def vm_create(self, request):
"""
Creates a new VM (router).
Mandatory request parameters:
- name (vm name)
- platform (platform name e.g. c7200)
- image (path to IOS image)
- ram (amount of RAM in MB)
Optional request parameters:
- console (console port number)
- aux (auxiliary console port number)
- mac_addr (MAC address)
- chassis (router chassis model)
Response parameters:
- id (vm identifier)
- name (vm name)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_CREATE_SCHEMA):
return
name = request["name"]
platform = request["platform"]
image = request["image"]
ram = request["ram"]
hypervisor = None
chassis = request.get("chassis")
router_id = request.get("router_id")
# Locate the image
updated_image_path = os.path.join(self.images_directory, image)
if os.path.isfile(updated_image_path):
image = updated_image_path
else:
if not os.path.exists(self.images_directory):
os.mkdir(self.images_directory)
cloud_path = request.get("cloud_path", None)
if cloud_path is not None:
# Download the image from cloud files
_, filename = ntpath.split(image)
src = '{}/{}'.format(cloud_path, filename)
provider = get_provider(self._cloud_settings)
log.debug("Downloading file from {} to {}...".format(src, updated_image_path))
provider.download_file(src, updated_image_path)
log.debug("Download of {} complete.".format(src))
image = updated_image_path
try:
if platform not in PLATFORMS:
raise DynamipsError("Unknown router platform: {}".format(platform))
if not self._hypervisor_manager:
self.start_hypervisor_manager()
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_router(image, ram)
if chassis:
router = PLATFORMS[platform](hypervisor, name, router_id, chassis=chassis)
elif platform == "c7200" and os.path.basename(image).lower().startswith("c7200p"):
router = PLATFORMS[platform](hypervisor, name, router_id, npe="npe-g2")
else:
router = PLATFORMS[platform](hypervisor, name, router_id)
router.ram = ram
router.image = image
if platform not in ("c1700", "c2600"):
router.sparsemem = self._hypervisor_manager.sparse_memory_support
router.mmap = self._hypervisor_manager.mmap_support
if "console" in request:
router.console = request["console"]
if "aux" in request:
router.aux = request["aux"]
if "mac_addr" in request:
router.mac_addr = request["mac_addr"]
# JIT sharing support
if self._hypervisor_manager.jit_sharing_support:
jitsharing_groups = hypervisor.jitsharing_groups
ios_image = os.path.basename(image)
if ios_image in jitsharing_groups:
router.jit_sharing_group = jitsharing_groups[ios_image]
else:
new_jit_group = -1
for jit_group in range(0, 127):
if jit_group not in jitsharing_groups.values():
new_jit_group = jit_group
break
if new_jit_group == -1:
raise DynamipsError("All JIT groups are allocated!")
router.jit_sharing_group = new_jit_group
# Ghost IOS support
if self._hypervisor_manager.ghost_ios_support:
self.set_ghost_ios(router)
except DynamipsError as e:
dynamips_stdout = ""
if hypervisor:
hypervisor.decrease_memory_load(ram)
if hypervisor.memory_load == 0 and not hypervisor.devices:
hypervisor.stop()
self._hypervisor_manager.hypervisors.remove(hypervisor)
dynamips_stdout = hypervisor.read_stdout()
self.send_custom_error(str(e) + dynamips_stdout)
return
response = {"name": router.name,
"id": router.id}
defaults = router.defaults()
response.update(defaults)
self._routers[router.id] = router
self.send_response(response)
@IModule.route("dynamips.vm.delete")
def vm_delete(self, request):
"""
Deletes a VM (router).
Mandatory request parameters:
- id (vm identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_DELETE_SCHEMA):
return
# get the router instance
router_id = request["id"]
router = self.get_device_instance(router_id, self._routers)
if not router:
return
try:
router.clean_delete()
self._hypervisor_manager.unallocate_hypervisor_for_router(router)
del self._routers[router_id]
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.vm.start")
def vm_start(self, request):
"""
Starts a VM (router)
Mandatory request parameters:
- id (vm identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_START_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
router.start()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.vm.stop")
def vm_stop(self, request):
"""
Stops a VM (router)
Mandatory request parameters:
- id (vm identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_STOP_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
router.stop()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.vm.suspend")
def vm_suspend(self, request):
"""
Suspends a VM (router)
Mandatory request parameters:
- id (vm identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_SUSPEND_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
router.suspend()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.vm.reload")
def vm_reload(self, request):
"""
Reloads a VM (router)
Mandatory request parameters:
- id (vm identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_RELOAD_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
if router.get_status() != "inactive":
router.stop()
router.start()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)
@IModule.route("dynamips.vm.update")
def vm_update(self, request):
"""
Updates settings for a VM (router).
Mandatory request parameters:
- id (vm identifier)
Optional request parameters:
- any setting to update
- startup_config_base64 (startup-config base64 encoded)
- private_config_base64 (private-config base64 encoded)
Response parameters:
- updated settings
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_UPDATE_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
response = {}
try:
default_startup_config_path = os.path.join(router.hypervisor.working_dir, "configs", "i{}_startup-config.cfg".format(router.id))
default_private_config_path = os.path.join(router.hypervisor.working_dir, "configs", "i{}_private-config.cfg".format(router.id))
# a new startup-config has been pushed
if "startup_config_base64" in request:
# update the request with the new local startup-config path
request["startup_config"] = self.create_config_from_base64(request["startup_config_base64"], router, default_startup_config_path)
# a new private-config has been pushed
if "private_config_base64" in request:
# update the request with the new local private-config path
request["private_config"] = self.create_config_from_base64(request["private_config_base64"], router, default_private_config_path)
if "startup_config" in request:
startup_config_path = request["startup_config"].replace("\\", '/')
if os.path.isfile(startup_config_path) and startup_config_path != default_startup_config_path:
# this is a local file set in the GUI
startup_config_path = self.create_config_from_file(startup_config_path, router, default_startup_config_path)
router.set_config(startup_config_path)
else:
router.set_config(startup_config_path)
response["startup_config"] = startup_config_path
del request["startup_config"]
if "private_config" in request:
private_config_path = request["private_config"].replace("\\", '/')
if os.path.isfile(private_config_path) and private_config_path != default_private_config_path:
# this is a local file set in the GUI
private_config_path = self.create_config_from_file(private_config_path, router, default_private_config_path)
router.set_config(router.startup_config, private_config_path)
else:
router.set_config(router.startup_config, private_config_path)
response["private_config"] = private_config_path
del request["private_config"]
except DynamipsError as e:
self.send_custom_error(str(e))
return
# update the settings
for name, value in request.items():
if hasattr(router, name) and getattr(router, name) != value:
try:
setattr(router, name, value)
response[name] = value
except DynamipsError as e:
self.send_custom_error(str(e))
return
elif name.startswith("slot") and value in ADAPTER_MATRIX:
slot_id = int(name[-1])
adapter_name = value
adapter = ADAPTER_MATRIX[adapter_name]()
try:
if router.slots[slot_id] and not isinstance(router.slots[slot_id], type(adapter)):
router.slot_remove_binding(slot_id)
router.slot_add_binding(slot_id, adapter)
response[name] = value
except DynamipsError as e:
self.send_custom_error(str(e))
return
elif name.startswith("slot") and value is None:
slot_id = int(name[-1])
if router.slots[slot_id]:
try:
router.slot_remove_binding(slot_id)
response[name] = value
except DynamipsError as e:
self.send_custom_error(str(e))
return
elif name.startswith("wic") and value in WIC_MATRIX:
wic_slot_id = int(name[-1])
wic_name = value
wic = WIC_MATRIX[wic_name]()
try:
if router.slots[0].wics[wic_slot_id] and not isinstance(router.slots[0].wics[wic_slot_id], type(wic)):
router.uninstall_wic(wic_slot_id)
router.install_wic(wic_slot_id, wic)
response[name] = value
except DynamipsError as e:
self.send_custom_error(str(e))
return
elif name.startswith("wic") and value is None:
wic_slot_id = int(name[-1])
if router.slots[0].wics and router.slots[0].wics[wic_slot_id]:
try:
router.uninstall_wic(wic_slot_id)
response[name] = value
except DynamipsError as e:
self.send_custom_error(str(e))
return
# Update the ghost IOS file in case the RAM size has changed
if self._hypervisor_manager.ghost_ios_support:
try:
self.set_ghost_ios(router)
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(response)
@IModule.route("dynamips.vm.start_capture")
def vm_start_capture(self, request):
"""
Starts a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port_id (port identifier)
- slot (slot number)
- port (port number)
- capture_file_name
Optional request parameters:
- data_link_type (PCAP DLT_* value)
Response parameters:
- port_id (port identifier)
- capture_file_path (path to the capture file)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_START_CAPTURE_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
slot = request["slot"]
port = request["port"]
capture_file_name = request["capture_file_name"]
data_link_type = request.get("data_link_type")
try:
capture_file_path = os.path.join(router.hypervisor.working_dir, "captures", capture_file_name)
router.start_capture(slot, port, capture_file_path, data_link_type)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"],
"capture_file_path": capture_file_path}
self.send_response(response)
@IModule.route("dynamips.vm.stop_capture")
def vm_stop_capture(self, request):
"""
Stops a packet capture.
Mandatory request parameters:
- id (vm identifier)
- port_id (port identifier)
- slot (slot number)
- port (port number)
Response parameters:
- port_id (port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_STOP_CAPTURE_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
slot = request["slot"]
port = request["port"]
try:
router.stop_capture(slot, port)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"port_id": request["port_id"]}
self.send_response(response)
@IModule.route("dynamips.vm.save_config")
def vm_save_config(self, request):
"""
Save the configs for a VM (router).
Mandatory request parameters:
- id (vm identifier)
"""
# validate the request
if not self.validate_request(request, VM_SAVE_CONFIG_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
router.save_configs()
except DynamipsError as e:
log.warn("could not save config to {}: {}".format(router.startup_config, e))
@IModule.route("dynamips.vm.export_config")
def vm_export_config(self, request):
"""
Export the config from a router
Mandatory request parameters:
- id (vm identifier)
Response parameters:
- startup_config_base64 (startup-config base64 encoded)
- private_config_base64 (private-config base64 encoded)
- False if no configuration can be extracted
"""
# validate the request
if not self.validate_request(request, VM_EXPORT_CONFIG_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
response = {}
try:
startup_config_base64, private_config_base64 = router.extract_config()
if startup_config_base64:
response["startup_config_base64"] = startup_config_base64
if private_config_base64:
response["private_config_base64"] = private_config_base64
except DynamipsError:
self.send_custom_error("unable to extract configs from the NVRAM")
return
if not response:
self.send_response(False)
else:
self.send_response(response)
@IModule.route("dynamips.vm.idlepcs")
def vm_idlepcs(self, request):
"""
Get Idle-PC proposals.
Mandatory request parameters:
- id (vm identifier)
Optional request parameters:
- compute (returns previously compute Idle-PC values if False)
Response parameters:
- id (vm identifier)
- idlepcs (Idle-PC values in an array)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_IDLEPCS_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
if "compute" in request and request["compute"] == False:
idlepcs = router.show_idle_pc_prop()
else:
# reset the current Idle-PC value before calculating a new one
router.idlepc = "0x0"
idlepcs = router.get_idle_pc_prop()
except DynamipsError as e:
self.send_custom_error(str(e))
return
response = {"id": router.id,
"idlepcs": idlepcs}
self.send_response(response)
@IModule.route("dynamips.vm.auto_idlepc")
def vm_auto_idlepc(self, request):
"""
Auto Idle-PC calculation.
Mandatory request parameters:
- id (vm identifier)
Response parameters:
- id (vm identifier)
- logs (logs for the calculation)
- idlepc (Idle-PC value)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_AUTO_IDLEPC_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
router.idlepc = "0x0" # reset the current Idle-PC value before calculating a new one
was_auto_started = False
if router.get_status() != "running":
router.start()
was_auto_started = True
time.sleep(20) # leave time to the router to boot
logs = []
validated_idlepc = "0x0"
idlepcs = router.get_idle_pc_prop()
if not idlepcs:
logs.append("No Idle-PC values found")
for idlepc in idlepcs:
router.idlepc = idlepc.split()[0]
logs.append("Trying Idle-PC value {}".format(router.idlepc))
start_time = time.time()
initial_cpu_usage = router.get_cpu_usage()
logs.append("Initial CPU usage = {}%".format(initial_cpu_usage))
time.sleep(4) # wait 4 seconds to probe the cpu again
elapsed_time = time.time() - start_time
cpu_elapsed_usage = router.get_cpu_usage() - initial_cpu_usage
cpu_usage = abs(cpu_elapsed_usage * 100.0 / elapsed_time)
logs.append("CPU usage after {:.2} seconds = {:.2}%".format(elapsed_time, cpu_usage))
if cpu_usage > 100:
cpu_usage = 100
if cpu_usage < 70:
validated_idlepc = router.idlepc
logs.append("Idle-PC value {} has been validated".format(validated_idlepc))
break
except DynamipsError as e:
self.send_custom_error(str(e))
return
finally:
if was_auto_started:
router.stop()
response = {"id": router.id,
"logs": logs,
"idlepc": validated_idlepc}
self.send_response(response)
@IModule.route("dynamips.vm.allocate_udp_port")
def vm_allocate_udp_port(self, request):
"""
Allocates a UDP port in order to create an UDP NIO.
Mandatory request parameters:
- id (vm identifier)
- port_id (unique port identifier)
Response parameters:
- port_id (unique port identifier)
- lport (allocated local port)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_ALLOCATE_UDP_PORT_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
try:
# allocate a new UDP port
response = self.allocate_udp_port(router)
except DynamipsError as e:
self.send_custom_error(str(e))
return
response["port_id"] = request["port_id"]
self.send_response(response)
@IModule.route("dynamips.vm.add_nio")
def vm_add_nio(self, request):
"""
Adds an NIO (Network Input/Output) for a VM (router).
Mandatory request parameters:
- id (vm identifier)
- slot (slot number)
- port (port number)
- port_id (unique port identifier)
- nio (one of the following)
- type "nio_udp"
- lport (local port)
- rhost (remote host)
- rport (remote port)
- type "nio_generic_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_linux_ethernet"
- ethernet_device (Ethernet device name e.g. eth0)
- type "nio_tap"
- tap_device (TAP device name e.g. tap0)
- type "nio_unix"
- local_file (path to UNIX socket file)
- remote_file (path to UNIX socket file)
- type "nio_vde"
- control_file (path to VDE control file)
- local_file (path to VDE local file)
- type "nio_null"
Response parameters:
- port_id (unique port identifier)
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_ADD_NIO_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
slot = request["slot"]
port = request["port"]
try:
nio = self.create_nio(router, request)
if not nio:
raise DynamipsError("Requested NIO doesn't exist: {}".format(request["nio"]))
except DynamipsError as e:
self.send_custom_error(str(e))
return
try:
router.slot_add_nio_binding(slot, port, nio)
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response({"port_id": request["port_id"]})
@IModule.route("dynamips.vm.delete_nio")
def vm_delete_nio(self, request):
"""
Deletes an NIO (Network Input/Output).
Mandatory request parameters:
- id (vm identifier)
- slot (slot identifier)
- port (port identifier)
Response parameters:
- True on success
:param request: JSON request
"""
# validate the request
if not self.validate_request(request, VM_DELETE_NIO_SCHEMA):
return
# get the router instance
router = self.get_device_instance(request["id"], self._routers)
if not router:
return
slot = request["slot"]
port = request["port"]
try:
nio = router.slot_remove_nio_binding(slot, port)
nio.delete()
except DynamipsError as e:
self.send_custom_error(str(e))
return
self.send_response(True)