mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
Yet another PEP 8 :)
This commit is contained in:
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)
|
||||
Reference in new issue
Block a user