mirror of
https://github.com/GNS3/gns3-server
synced 2024-12-29 02:08:10 +00:00
General work on the Dynamips backend (need to finish and polish).
This commit is contained in:
parent
2516bf80a8
commit
cef29e53aa
@ -2,4 +2,4 @@ GNS3-server
|
||||
===========
|
||||
|
||||
GNS3 server manages emulators such as Dynamips, VirtualBox or Qemu/KVM.
|
||||
Clients like the GNS3 GUI controls the server using an API over Websockets.
|
||||
Clients like the GNS3 GUI controls the server using a JSON-RPC API over Websockets.
|
||||
|
@ -23,7 +23,7 @@ import zmq
|
||||
import uuid
|
||||
import tornado.websocket
|
||||
from tornado.escape import json_decode
|
||||
from ..jsonrpc import JSONRPCParseError, JSONRPCInvalidRequest, JSONRPCMethodNotFound
|
||||
from ..jsonrpc import JSONRPCParseError, JSONRPCInvalidRequest, JSONRPCMethodNotFound, JSONRPCNotification
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
@ -59,7 +59,7 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
|
||||
return self._session_id
|
||||
|
||||
@classmethod
|
||||
def dispatch_message(cls, message):
|
||||
def dispatch_message(cls, stream, message):
|
||||
"""
|
||||
Sends a message to Websocket client
|
||||
|
||||
@ -71,7 +71,13 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
|
||||
|
||||
# ZMQ responses are encoded in JSON
|
||||
# format is a JSON array: [session ID, JSON-RPC response]
|
||||
json_message = json_decode(message[1])
|
||||
try:
|
||||
json_message = json_decode(message[1])
|
||||
except ValueError as e:
|
||||
stream.send_string("Cannot decode message!")
|
||||
log.critical("Couldn't decode message: {}".format(e))
|
||||
return
|
||||
|
||||
session_id = json_message[0]
|
||||
jsonrpc_response = json_message[1]
|
||||
|
||||
@ -94,8 +100,8 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
|
||||
# Make sure the destination is not already registered
|
||||
# by another module for instance
|
||||
assert destination not in cls.destinations
|
||||
log.info("registering {} as a destination for {}".format(destination,
|
||||
module))
|
||||
log.debug("registering {} as a destination for the {} module".format(destination,
|
||||
module))
|
||||
cls.destinations[destination] = module
|
||||
|
||||
def open(self):
|
||||
@ -119,8 +125,8 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
|
||||
request = json_decode(message)
|
||||
jsonrpc_version = request["jsonrpc"]
|
||||
method = request["method"]
|
||||
# warning: notifications cannot be sent by a client because check for an "id" here
|
||||
request_id = request["id"]
|
||||
# This is a JSON-RPC notification if request_id is None
|
||||
request_id = request.get("id")
|
||||
except:
|
||||
return self.write_message(JSONRPCParseError()())
|
||||
|
||||
@ -128,7 +134,11 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
|
||||
return self.write_message(JSONRPCInvalidRequest()())
|
||||
|
||||
if method not in self.destinations:
|
||||
return self.write_message(JSONRPCMethodNotFound(request_id)())
|
||||
if request_id:
|
||||
return self.write_message(JSONRPCMethodNotFound(request_id)())
|
||||
else:
|
||||
# This is a notification, silently ignore this error...
|
||||
return
|
||||
|
||||
module = self.destinations[method]
|
||||
# ZMQ requests are encoded in JSON
|
||||
@ -136,7 +146,7 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
|
||||
zmq_request = [self.session_id, request]
|
||||
# Route to the correct module
|
||||
self.zmq_router.send_string(module, zmq.SNDMORE)
|
||||
# Send the encoded JSON request
|
||||
# Send the JSON request
|
||||
self.zmq_router.send_json(zmq_request)
|
||||
|
||||
def on_close(self):
|
||||
@ -146,3 +156,14 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
|
||||
|
||||
log.info("Websocket client {} disconnected".format(self.session_id))
|
||||
self.clients.remove(self)
|
||||
|
||||
# Reset the modules if there are no clients anymore
|
||||
# Modules must implement a reset destination
|
||||
if not self.clients:
|
||||
for destination, module in self.destinations.items():
|
||||
if destination.endswith("reset"):
|
||||
# Route to the correct module
|
||||
self.zmq_router.send_string(module, zmq.SNDMORE)
|
||||
# Send the JSON request
|
||||
notification = JSONRPCNotification(destination)()
|
||||
self.zmq_router.send_json([self.session_id, notification])
|
||||
|
@ -159,8 +159,10 @@ class JSONRPCRequest(JSONRPCObject):
|
||||
:param request_id: JSON-RPC identifier (generated by default)
|
||||
"""
|
||||
|
||||
def __init__(self, method, params=None, request_id=str(uuid.uuid1())):
|
||||
def __init__(self, method, params=None, request_id=None):
|
||||
JSONRPCObject.__init__(self)
|
||||
if request_id == None:
|
||||
request_id = str(uuid.uuid4())
|
||||
self.id = request_id
|
||||
self.method = method
|
||||
if params:
|
||||
|
@ -24,7 +24,7 @@ import gns3server
|
||||
|
||||
# command line options
|
||||
from tornado.options import define
|
||||
define("host", default="127.0.0.1", help="run on the given host/IP address", type=str)
|
||||
define("host", default="0.0.0.0", help="run on the given host/IP address", type=str)
|
||||
define("port", default=8000, help="run on the given port", type=int)
|
||||
define("ipc", default=False, help="use IPC for module communication", type=bool)
|
||||
|
||||
|
@ -79,7 +79,7 @@ class ModuleManager(object):
|
||||
if issubclass(module_class[1], IModule):
|
||||
# make sure the module class has IModule as a parent
|
||||
if module_class[1].__module__ == name:
|
||||
log.info("found and loading {} module".format(module_class[0].lower()))
|
||||
log.info("loading {} module".format(module_class[0].lower()))
|
||||
info = Module(name=module_class[0].lower(), cls=module_class[1])
|
||||
self._modules.append(info)
|
||||
except:
|
||||
|
@ -92,6 +92,10 @@ class IModule(multiprocessing.Process):
|
||||
stream.on_recv(callback)
|
||||
return stream
|
||||
|
||||
# def add_periodic_callback(self, callback, time):
|
||||
#
|
||||
# self.test = zmq.eventloop.ioloop.PeriodicCallback(callback, time, self._ioloop).start()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Starts the event loop
|
||||
@ -158,9 +162,9 @@ class IModule(multiprocessing.Process):
|
||||
|
||||
# add session to the response
|
||||
response = [self._current_session, jsonrpc_response]
|
||||
log.info("ZeroMQ client ({}) sending JSON-RPC custom error {} for call id {}".format(self.name,
|
||||
message,
|
||||
self._current_call_id))
|
||||
log.info("ZeroMQ client ({}) sending JSON-RPC custom error: {} for call id {}".format(self.name,
|
||||
message,
|
||||
self._current_call_id))
|
||||
self._stream.send_json(response)
|
||||
|
||||
def _decode_request(self, request):
|
||||
@ -188,7 +192,12 @@ class IModule(multiprocessing.Process):
|
||||
return
|
||||
|
||||
log.debug("Routing request to {}: {}".format(destination, request[1]))
|
||||
self.destination[destination](self, params)
|
||||
|
||||
try:
|
||||
self.destination[destination](self, params)
|
||||
except Exception as e:
|
||||
log.error("uncaught exception {type}".format(type=type(e)), exc_info=1)
|
||||
self.send_custom_error("uncaught exception {type}: {string}".format(type=type(e), string=str(e)))
|
||||
|
||||
def destinations(self):
|
||||
"""
|
||||
|
@ -15,13 +15,18 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Dynamips server module.
|
||||
"""
|
||||
|
||||
from gns3server.modules import IModule
|
||||
import gns3server.jsonrpc as jsonrpc
|
||||
|
||||
from .hypervisor import Hypervisor
|
||||
from .hypervisor_manager import HypervisorManager
|
||||
from .dynamips_error import DynamipsError
|
||||
|
||||
# nodes
|
||||
# Nodes
|
||||
from .nodes.router import Router
|
||||
from .nodes.c1700 import C1700
|
||||
from .nodes.c2600 import C2600
|
||||
@ -37,7 +42,7 @@ from .nodes.atm_bridge import ATMBridge
|
||||
from .nodes.frame_relay_switch import FrameRelaySwitch
|
||||
from .nodes.hub import Hub
|
||||
|
||||
# adapters
|
||||
# Adapters
|
||||
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
|
||||
@ -71,35 +76,188 @@ from .nios.nio_fifo import NIO_FIFO
|
||||
from .nios.nio_mcast import NIO_Mcast
|
||||
from .nios.nio_null import NIO_Null
|
||||
|
||||
from .backends import vm
|
||||
from .backends import ethsw
|
||||
from .backends import ethhub
|
||||
from .backends import frsw
|
||||
from .backends import atmsw
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Dynamips(IModule):
|
||||
"""
|
||||
Dynamips module.
|
||||
|
||||
:param name: module name
|
||||
:param args: arguments for the module
|
||||
:param kwargs: named arguments for the module
|
||||
"""
|
||||
|
||||
def __init__(self, name=None, args=(), kwargs={}):
|
||||
IModule.__init__(self, name=name, args=args, kwargs=kwargs)
|
||||
|
||||
# start the hypervisor manager
|
||||
#self._hypervisor_manager = HypervisorManager("/usr/bin/dynamips", "/tmp")
|
||||
self._hypervisor_manager = None
|
||||
self._routers = {}
|
||||
self._ethernet_switches = {}
|
||||
self._frame_relay_switches = {}
|
||||
self._atm_switches = {}
|
||||
self._ethernet_hubs = {}
|
||||
|
||||
# def __del__(self):
|
||||
#
|
||||
# self._hypervisor_manager.stop_all_hypervisors()
|
||||
|
||||
@IModule.route("dynamips.reset")
|
||||
def reset(self, request):
|
||||
"""
|
||||
Resets the module.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
# stop all Dynamips hypervisors
|
||||
self._hypervisor_manager.stop_all_hypervisors()
|
||||
|
||||
# resets the instance counters
|
||||
Router.reset()
|
||||
EthernetSwitch.reset()
|
||||
Hub.reset()
|
||||
FrameRelaySwitch.reset()
|
||||
ATMSwitch.reset()
|
||||
NIO_UDP.reset()
|
||||
NIO_UDP_auto.reset()
|
||||
NIO_UNIX.reset()
|
||||
NIO_VDE.reset()
|
||||
NIO_TAP.reset()
|
||||
NIO_GenericEthernet.reset()
|
||||
NIO_LinuxEthernet.reset()
|
||||
NIO_FIFO.reset()
|
||||
NIO_Mcast.reset()
|
||||
NIO_Null.reset()
|
||||
|
||||
self._routers.clear()
|
||||
self._ethernet_switches.clear()
|
||||
self._frame_relay_switches.clear()
|
||||
self._atm_switches.clear()
|
||||
|
||||
log.info("dynamips module has been reset")
|
||||
|
||||
@IModule.route("dynamips.settings")
|
||||
def settings(self, request):
|
||||
"""
|
||||
Set or update settings.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
print("Create")
|
||||
if not self._hypervisor_manager:
|
||||
self._hypervisor_manager = HypervisorManager(request["path"], "/tmp")
|
||||
|
||||
for name, value in request.items():
|
||||
if hasattr(self._hypervisor_manager, name) and getattr(self._hypervisor_manager, name) != value:
|
||||
setattr(self._hypervisor_manager, name, value)
|
||||
|
||||
@IModule.route("dynamips.echo")
|
||||
def echo(self, request):
|
||||
"""
|
||||
Echo end point for testing purposes.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
if request == None:
|
||||
self.send_param_error()
|
||||
return
|
||||
log.debug("received request {}".format(request))
|
||||
self.send_response(request)
|
||||
else:
|
||||
log.debug("received request {}".format(request))
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.create_vm")
|
||||
def create_vm(self, request):
|
||||
print("Create VM!")
|
||||
log.debug("received request {}".format(request))
|
||||
self.send_response(request)
|
||||
def create_nio(self, node, request):
|
||||
|
||||
@IModule.route("dynamips.start_vm")
|
||||
def start_vm(self, request):
|
||||
print("Start VM!")
|
||||
log.debug("received request {}".format(request))
|
||||
self.send_response(request)
|
||||
nio = None
|
||||
if request["nio"] == "NIO_UDP":
|
||||
lport = request["lport"]
|
||||
rhost = request["rhost"]
|
||||
rport = request["rport"]
|
||||
nio = NIO_UDP(node.hypervisor, lport, rhost, rport)
|
||||
elif request["nio"] == "NIO_GenericEthernet":
|
||||
ethernet_device = request["ethernet_device"]
|
||||
nio = NIO_GenericEthernet(node.hypervisor, ethernet_device)
|
||||
elif request["nio"] == "NIO_LinuxEthernet":
|
||||
ethernet_device = request["ethernet_device"]
|
||||
nio = NIO_LinuxEthernet(node.hypervisor, ethernet_device)
|
||||
elif request["nio"] == "NIO_TAP":
|
||||
tap_device = request["tap_device"]
|
||||
nio = NIO_TAP(node.hypervisor, tap_device)
|
||||
elif request["nio"] == "NIO_UNIX":
|
||||
local_file = request["local_file"]
|
||||
remote_file = request["remote_file"]
|
||||
nio = NIO_UNIX(node.hypervisor, local_file, remote_file)
|
||||
elif request["nio"] == "NIO_VDE":
|
||||
control_file = request["control_file"]
|
||||
local_file = request["local_file"]
|
||||
nio = NIO_VDE(node.hypervisor, control_file, local_file)
|
||||
elif request["nio"] == "NIO_Null":
|
||||
nio = NIO_Null(node.hypervisor)
|
||||
return nio
|
||||
|
||||
def allocate_udp_port(self, node):
|
||||
"""
|
||||
Allocates a UDP port in order to create an UDP NIO.
|
||||
|
||||
:param node: the node that needs to allocate an UDP port
|
||||
"""
|
||||
|
||||
port = node.hypervisor.allocate_udp_port()
|
||||
host = node.hypervisor.host
|
||||
|
||||
log.info("{} [id={}] has allocated UDP port {} with host {}".format(node.name,
|
||||
node.id,
|
||||
port,
|
||||
host))
|
||||
response = {"lport": port,
|
||||
"lhost": host}
|
||||
|
||||
return response
|
||||
|
||||
def set_ghost_ios(self, router):
|
||||
|
||||
if not router.mmap:
|
||||
raise DynamipsError("mmap support is required to enable ghost IOS support")
|
||||
|
||||
ghost_instance = router.formatted_ghost_file()
|
||||
all_ghosts = []
|
||||
|
||||
# search of an existing ghost instance across all hypervisors
|
||||
for hypervisor in self._hypervisor_manager.hypervisors:
|
||||
all_ghosts.extend(hypervisor.ghosts)
|
||||
|
||||
if ghost_instance not in all_ghosts:
|
||||
# create a new ghost IOS instance
|
||||
ghost = Router(router.hypervisor, "ghost-" + ghost_instance, router.platform, ghost_flag=True)
|
||||
ghost.image = router.image
|
||||
# for 7200s, the NPE must be set when using an NPE-G2.
|
||||
if router.platform == "c7200":
|
||||
ghost.npe = router.npe
|
||||
ghost.ghost_status = 1
|
||||
ghost.ghost_file = ghost_instance
|
||||
ghost.ram = router.ram
|
||||
ghost.start()
|
||||
ghost.stop()
|
||||
ghost.delete()
|
||||
|
||||
router.ghost_status = 2
|
||||
router.ghost_file = ghost_instance
|
||||
|
||||
@IModule.route("dynamips.nio.get_interfaces")
|
||||
def nio_get_interfaces(self, request):
|
||||
"""
|
||||
Get all the network interfaces on this host.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
import netifaces
|
||||
self.send_response(netifaces.interfaces())
|
||||
|
@ -124,6 +124,17 @@ class Adapter(object):
|
||||
|
||||
self._ports[port_id] = None
|
||||
|
||||
def get_nio(self, port_id):
|
||||
"""
|
||||
Returns the NIO assigned to a port.
|
||||
|
||||
:params port_id: port ID (integer)
|
||||
|
||||
:returns: NIO object
|
||||
"""
|
||||
|
||||
return self._ports[port_id]
|
||||
|
||||
@property
|
||||
def ports(self):
|
||||
"""
|
||||
|
@ -33,11 +33,3 @@ class C1700_MB_1FE(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,16 +29,8 @@ class C1700_MB_WIC1(Adapter):
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return "C1700_MB_WIC1"
|
||||
return "C1700-MB-WIC1"
|
||||
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "N/A"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "N/A"
|
||||
|
@ -33,11 +33,3 @@ class C2600_MB_1E(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -34,11 +34,3 @@ class C2600_MB_1FE(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -33,11 +33,3 @@ class C2600_MB_2E(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -33,11 +33,3 @@ class C2600_MB_2FE(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -28,16 +28,8 @@ class C7200_IO_2FE(Adapter):
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return "C7200_IO_2FE"
|
||||
return "C7200-IO-2FE"
|
||||
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -28,16 +28,8 @@ class C7200_IO_FE(Adapter):
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return "C7200_IO_FE"
|
||||
return "C7200-IO-FE"
|
||||
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -33,11 +33,3 @@ class C7200_IO_GE_E(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "GigabitEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -30,11 +30,3 @@ class GT96100_FE(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -34,11 +34,3 @@ class Leopard_2FE(Adapter):
|
||||
def removable(self):
|
||||
|
||||
return False
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class NM_16ESW(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "NM-16ESW"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class NM_1E(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "NM-1E"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class NM_1FE_TX(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "NM-1FE-TX"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class NM_4E(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "NM-4E"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class NM_4T(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "NM-4T"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Serial"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Serial"
|
||||
|
@ -29,11 +29,3 @@ class PA_2FE_TX(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-2FE-TX"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class PA_4E(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-4E"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class PA_4T(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-4T+"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Serial"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Serial"
|
||||
|
@ -29,11 +29,3 @@ class PA_8E(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-8E"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class PA_8T(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-8T"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Serial"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Serial"
|
||||
|
@ -29,11 +29,3 @@ class PA_A1(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-A1"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "ATM"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Serial"
|
||||
|
@ -29,11 +29,3 @@ class PA_FE_TX(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-FE-TX"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "FastEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class PA_GE(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-GE"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "GigabitEthernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
@ -29,11 +29,3 @@ class PA_POS_OC3(Adapter):
|
||||
def __str__(self):
|
||||
|
||||
return "PA-POS-OC3"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "POS"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "SONET"
|
||||
|
@ -29,14 +29,6 @@ class WIC_1ENET(object):
|
||||
|
||||
return "WIC-1ENET"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Ethernet"
|
||||
|
||||
@property
|
||||
def interfaces(self):
|
||||
"""
|
||||
|
@ -29,14 +29,6 @@ class WIC_1T(object):
|
||||
|
||||
return "WIC-1T"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Serial"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Serial"
|
||||
|
||||
@property
|
||||
def interfaces(self):
|
||||
"""
|
||||
|
@ -29,14 +29,6 @@ class WIC_2T(object):
|
||||
|
||||
return "WIC-2T"
|
||||
|
||||
def interface_type(self):
|
||||
|
||||
return "Serial"
|
||||
|
||||
def medium(self):
|
||||
|
||||
return "Serial"
|
||||
|
||||
@property
|
||||
def interfaces(self):
|
||||
"""
|
||||
|
0
gns3server/modules/dynamips/backends/__init__.py
Normal file
0
gns3server/modules/dynamips/backends/__init__.py
Normal file
201
gns3server/modules/dynamips/backends/atmsw.py
Normal file
201
gns3server/modules/dynamips/backends/atmsw.py
Normal file
@ -0,0 +1,201 @@
|
||||
# -*- 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
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.atm_switch import ATMSwitch
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ATMSW(object):
|
||||
|
||||
@IModule.route("dynamips.atmsw.create")
|
||||
def atmsw_create(self, request):
|
||||
"""
|
||||
Creates a new ATM switch.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
name = None
|
||||
if request and "name" in request:
|
||||
name = request["name"]
|
||||
|
||||
try:
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_switch()
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
atmsw_id = request["id"]
|
||||
atmsw = self._atm_switches[atmsw_id]
|
||||
try:
|
||||
atmsw.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.atmsw.update")
|
||||
def atmsw_update(self, request):
|
||||
"""
|
||||
Updates a ATM switch.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
atmsw_id = request["id"]
|
||||
atmsw = self._atm_switches[atmsw_id]
|
||||
self.send_response(request)
|
||||
|
||||
@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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
atmsw_id = request["id"]
|
||||
atmsw = self._atm_switches[atmsw_id]
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(atmsw)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
atmsw_id = request["id"]
|
||||
atmsw = self._atm_switches[atmsw_id]
|
||||
|
||||
port = request["port"]
|
||||
mapping = request["mapping"]
|
||||
|
||||
try:
|
||||
nio = self.create_nio(atmsw, request)
|
||||
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 mapping.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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.atmsw.delete_nio")
|
||||
def atmsw_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
atmsw_id = request["id"]
|
||||
atmsw = self._atm_switches[atmsw_id]
|
||||
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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
162
gns3server/modules/dynamips/backends/ethhub.py
Normal file
162
gns3server/modules/dynamips/backends/ethhub.py
Normal file
@ -0,0 +1,162 @@
|
||||
# -*- 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/>.
|
||||
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.hub import Hub
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ETHHUB(object):
|
||||
|
||||
@IModule.route("dynamips.ethhub.create")
|
||||
def ethhub_create(self, request):
|
||||
"""
|
||||
Creates a new Ethernet switch.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
name = None
|
||||
if request and "name" in request:
|
||||
name = request["name"]
|
||||
|
||||
try:
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_switch()
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethhub_id = request["id"]
|
||||
ethhub = self._ethernet_hubs[ethhub_id]
|
||||
try:
|
||||
ethhub.delete()
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethhub_id = request["id"]
|
||||
ethhub = self._ethernet_hubs[ethhub_id]
|
||||
#ports = request["ports"]
|
||||
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethhub_id = request["id"]
|
||||
ethhub = self._ethernet_hubs[ethhub_id]
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(ethhub)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethhub_id = request["id"]
|
||||
ethhub = self._ethernet_hubs[ethhub_id]
|
||||
port = request["port"]
|
||||
|
||||
try:
|
||||
nio = self.create_nio(ethhub, request)
|
||||
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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.ethhub.delete_nio")
|
||||
def ethsw_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethhub_id = request["id"]
|
||||
ethhub = self._ethernet_hubs[ethhub_id]
|
||||
port = request["port"]
|
||||
|
||||
try:
|
||||
nio = ethhub.remove_nio(port)
|
||||
nio.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
180
gns3server/modules/dynamips/backends/ethsw.py
Normal file
180
gns3server/modules/dynamips/backends/ethsw.py
Normal file
@ -0,0 +1,180 @@
|
||||
# -*- 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/>.
|
||||
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.ethernet_switch import EthernetSwitch
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ETHSW(object):
|
||||
|
||||
@IModule.route("dynamips.ethsw.create")
|
||||
def ethsw_create(self, request):
|
||||
"""
|
||||
Creates a new Ethernet switch.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
name = None
|
||||
if request and "name" in request:
|
||||
name = request["name"]
|
||||
|
||||
try:
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_switch()
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethsw_id = request["id"]
|
||||
ethsw = self._ethernet_switches[ethsw_id]
|
||||
try:
|
||||
ethsw.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.ethsw.update")
|
||||
def ethsw_update(self, request):
|
||||
"""
|
||||
Updates a Ethernet switch.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethsw_id = request["id"]
|
||||
ethsw = self._ethernet_switches[ethsw_id]
|
||||
ports = request["ports"]
|
||||
|
||||
for port, info in ports.items():
|
||||
vlan = info["vlan"]
|
||||
port_type = info["type"]
|
||||
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)
|
||||
|
||||
self.send_response(request)
|
||||
|
||||
@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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethsw_id = request["id"]
|
||||
ethsw = self._ethernet_switches[ethsw_id]
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(ethsw)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethsw_id = request["id"]
|
||||
ethsw = self._ethernet_switches[ethsw_id]
|
||||
|
||||
port = request["port"]
|
||||
vlan = request["vlan"]
|
||||
port_type = request["port_type"]
|
||||
try:
|
||||
nio = self.create_nio(ethsw, request)
|
||||
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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.ethsw.delete_nio")
|
||||
def ethsw_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
ethsw_id = request["id"]
|
||||
ethsw = self._ethernet_switches[ethsw_id]
|
||||
port = request["port"]
|
||||
|
||||
try:
|
||||
nio = ethsw.remove_nio(port)
|
||||
nio.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
179
gns3server/modules/dynamips/backends/frsw.py
Normal file
179
gns3server/modules/dynamips/backends/frsw.py
Normal file
@ -0,0 +1,179 @@
|
||||
# -*- 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/>.
|
||||
|
||||
from gns3server.modules import IModule
|
||||
from ..nodes.frame_relay_switch import FrameRelaySwitch
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
name = None
|
||||
if request and "name" in request:
|
||||
name = request["name"]
|
||||
|
||||
try:
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_switch()
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
frsw_id = request["id"]
|
||||
frsw = self._frame_relay_switches[frsw_id]
|
||||
try:
|
||||
frsw.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.frsw.update")
|
||||
def frsw_update(self, request):
|
||||
"""
|
||||
Updates a Frame Relay switch.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
frsw_id = request["id"]
|
||||
frsw = self._frame_relay_switches[frsw_id]
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
frsw_id = request["id"]
|
||||
frsw = self._frame_relay_switches[frsw_id]
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(frsw)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
frsw_id = request["id"]
|
||||
frsw = self._frame_relay_switches[frsw_id]
|
||||
|
||||
port = request["port"]
|
||||
mapping = request["mapping"]
|
||||
|
||||
try:
|
||||
nio = self.create_nio(frsw, request)
|
||||
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 mapping.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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.frsw.delete_nio")
|
||||
def frsw_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
frsw_id = request["id"]
|
||||
frsw = self._frame_relay_switches[frsw_id]
|
||||
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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
367
gns3server/modules/dynamips/backends/vm.py
Normal file
367
gns3server/modules/dynamips/backends/vm.py
Normal file
@ -0,0 +1,367 @@
|
||||
# -*- 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 ..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
|
||||
|
||||
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).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
if request == None:
|
||||
self.send_param_error()
|
||||
else:
|
||||
log.debug("received request {}".format(request))
|
||||
|
||||
#TODO: JSON schema validation
|
||||
#name = request["name"]
|
||||
platform = request["platform"]
|
||||
image = request["image"]
|
||||
ram = request["ram"]
|
||||
|
||||
try:
|
||||
hypervisor = self._hypervisor_manager.allocate_hypervisor_for_router(image, ram)
|
||||
router = PLATFORMS[platform](hypervisor)
|
||||
router.ram = ram
|
||||
router.image = image
|
||||
router.sparsemem = self._hypervisor_manager.sparse_memory_support
|
||||
router.mmap = self._hypervisor_manager.mmap_support
|
||||
|
||||
# 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:
|
||||
hypervisor.decrease_memory_load(ram)
|
||||
if hypervisor.memory_load == 0 and not hypervisor.devices:
|
||||
hypervisor.stop()
|
||||
self._hypervisor_manager.hypervisors.remove(hypervisor)
|
||||
self.send_custom_error(str(e))
|
||||
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).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
try:
|
||||
router.delete()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.vm.start")
|
||||
def vm_start(self, request):
|
||||
"""
|
||||
Starts a VM (router)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
try:
|
||||
router.start()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.vm.stop")
|
||||
def vm_stop(self, request):
|
||||
"""
|
||||
Stops a VM (router)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
try:
|
||||
router.stop()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.vm.suspend")
|
||||
def vm_suspend(self, request):
|
||||
"""
|
||||
Suspends a VM (router)
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
try:
|
||||
router.suspend()
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.vm.update")
|
||||
def vm_update(self, request):
|
||||
"""
|
||||
Updates settings for a VM (router).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
|
||||
# update the settings
|
||||
for name, value in request.items():
|
||||
if hasattr(router, name) and getattr(router, name) != value:
|
||||
try:
|
||||
setattr(router, 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 type(router.slots[slot_id]) != type(adapter):
|
||||
router.slot_remove_binding(slot_id)
|
||||
router.slot_add_binding(slot_id, adapter)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
elif name.startswith("slot") and value == None:
|
||||
slot_id = int(name[-1])
|
||||
if router.slots[slot_id]:
|
||||
try:
|
||||
router.slot_remove_binding(slot_id)
|
||||
except:
|
||||
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 type(router.slots[0].wics[wic_slot_id]) != type(wic):
|
||||
router.uninstall_wic(wic_slot_id)
|
||||
router.install_wic(wic_slot_id, wic)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
elif name.startswith("wic") and value == None:
|
||||
wic_slot_id = int(name[-1])
|
||||
if router.slots[0].wics and router.slots[0].wics[wic_slot_id]:
|
||||
router.uninstall_wic(wic_slot_id)
|
||||
|
||||
# Update the ghost IOS file in case the RAM size has changed
|
||||
if self._hypervisor_manager.ghost_ios_support:
|
||||
self.set_ghost_ios(router)
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
||||
|
||||
@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.
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
|
||||
try:
|
||||
# allocate a new UDP port
|
||||
response = self.allocate_udp_port(router)
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
|
||||
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).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
|
||||
slot = request["slot"]
|
||||
port = request["port"]
|
||||
|
||||
print(request)
|
||||
|
||||
try:
|
||||
nio = self.create_nio(router, request)
|
||||
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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
||||
|
||||
@IModule.route("dynamips.vm.delete_nio")
|
||||
def vm_delete_nio(self, request):
|
||||
"""
|
||||
Deletes an NIO (Network Input/Output).
|
||||
|
||||
:param request: JSON request
|
||||
"""
|
||||
|
||||
#TODO: JSON schema validation for the request
|
||||
log.debug("received request {}".format(request))
|
||||
router_id = request["id"]
|
||||
router = self._routers[router_id]
|
||||
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
|
||||
|
||||
# for now send back the original request
|
||||
self.send_response(request)
|
@ -31,3 +31,7 @@ class DynamipsError(Exception):
|
||||
def __repr__(self):
|
||||
|
||||
return self._message
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return self._message
|
||||
|
@ -21,6 +21,7 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L46
|
||||
"""
|
||||
|
||||
import socket
|
||||
import errno
|
||||
import re
|
||||
import logging
|
||||
from .dynamips_error import DynamipsError
|
||||
@ -54,6 +55,7 @@ class DynamipsHypervisor(object):
|
||||
self._baseconsole = 2000
|
||||
self._baseaux = 2100
|
||||
self._baseudp = 10000
|
||||
self._current_udp_port = self._baseudp
|
||||
self._version = "N/A"
|
||||
self._timeout = 30
|
||||
self._socket = None
|
||||
@ -145,7 +147,7 @@ class DynamipsHypervisor(object):
|
||||
@working_dir.setter
|
||||
def working_dir(self, working_dir):
|
||||
"""
|
||||
Set the working directory for this hypervisor.
|
||||
Sets the working directory for this hypervisor.
|
||||
|
||||
:param working_dir: path to the working directory
|
||||
"""
|
||||
@ -198,7 +200,7 @@ class DynamipsHypervisor(object):
|
||||
@devices.setter
|
||||
def devices(self, devices):
|
||||
"""
|
||||
Set the list of devices managed by this hypervisor instance.
|
||||
Sets the list of devices managed by this hypervisor instance.
|
||||
This method is for internal use.
|
||||
|
||||
:param devices: a list of device objects
|
||||
@ -219,7 +221,7 @@ class DynamipsHypervisor(object):
|
||||
@baseconsole.setter
|
||||
def baseconsole(self, baseconsole):
|
||||
"""
|
||||
Set the base console TCP port for this hypervisor.
|
||||
Sets the base console TCP port for this hypervisor.
|
||||
|
||||
:param baseconsole: base console value (integer)
|
||||
"""
|
||||
@ -239,7 +241,7 @@ class DynamipsHypervisor(object):
|
||||
@baseaux.setter
|
||||
def baseaux(self, baseaux):
|
||||
"""
|
||||
Set the base auxiliary TCP port for this hypervisor.
|
||||
Sets the base auxiliary TCP port for this hypervisor.
|
||||
|
||||
:param baseaux: base auxiliary port value (integer)
|
||||
"""
|
||||
@ -259,12 +261,16 @@ class DynamipsHypervisor(object):
|
||||
@baseudp.setter
|
||||
def baseudp(self, baseudp):
|
||||
"""
|
||||
Set the next open UDP port for NIOs for this hypervisor.
|
||||
Sets the next open UDP port for NIOs for this hypervisor.
|
||||
|
||||
:param baseudp: base UDP port value (integer)
|
||||
"""
|
||||
|
||||
self._baseudp = baseudp
|
||||
self._current_udp_port = self._baseudp
|
||||
|
||||
#FIXME
|
||||
log.info("hypervisor a new base UDP {}".format(self._baseudp))
|
||||
|
||||
@property
|
||||
def ghosts(self):
|
||||
@ -294,7 +300,7 @@ class DynamipsHypervisor(object):
|
||||
:returns: JIT sharing groups dict (image_name -> group number)
|
||||
"""
|
||||
|
||||
return self._ghosts
|
||||
return self._jitsharing_groups
|
||||
|
||||
def add_jitsharing_group(self, image_name, group_number):
|
||||
"""
|
||||
@ -326,6 +332,42 @@ class DynamipsHypervisor(object):
|
||||
|
||||
return self._port
|
||||
|
||||
def allocate_udp_port(self, max_port=100):
|
||||
"""
|
||||
Allocates a new UDP port for creating an UDP NIO.
|
||||
|
||||
:param max_port: maximum number of port to scan in
|
||||
order to find one available for use.
|
||||
|
||||
:returns: port number (integer)
|
||||
"""
|
||||
|
||||
#FIXME: better check for IPv6
|
||||
start_port = self._current_udp_port
|
||||
print("start port = {}".format(start_port))
|
||||
end_port = start_port + max_port
|
||||
for port in range(start_port, end_port):
|
||||
print(port)
|
||||
if port > end_port:
|
||||
raise DynamipsError("Could not find a free port between {0} and {1}".format(start_port, max_port))
|
||||
try:
|
||||
if self.host.__contains__(':'):
|
||||
# IPv6 address support
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
||||
else:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# the port is available if bind is a success
|
||||
s.bind((self._host, port))
|
||||
#FIXME: increment?
|
||||
self._current_udp_port += 1
|
||||
print("current port = {}".format(self._current_udp_port))
|
||||
return port
|
||||
except socket.error as e:
|
||||
if e.errno == errno.EADDRINUSE: # socket already in use
|
||||
continue
|
||||
else:
|
||||
raise DynamipsError("UDP port allocation: {}".format(e))
|
||||
|
||||
def send_raw(self, string):
|
||||
"""
|
||||
Sends a raw command to this hypervisor. Use sparingly.
|
||||
|
@ -20,6 +20,7 @@ Represents a Dynamips hypervisor and starts/stops the associated Dynamips proces
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import logging
|
||||
|
||||
@ -82,7 +83,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
@path.setter
|
||||
def path(self, path):
|
||||
"""
|
||||
Set the path to the Dynamips executable.
|
||||
Sets the path to the Dynamips executable.
|
||||
|
||||
:param path: path to Dynamips
|
||||
"""
|
||||
@ -102,7 +103,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
@port.setter
|
||||
def port(self, port):
|
||||
"""
|
||||
Set the port used to start the Dynamips hypervisor.
|
||||
Sets the port used to start the Dynamips hypervisor.
|
||||
|
||||
:param port: port number (integer)
|
||||
"""
|
||||
@ -122,7 +123,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
@host.setter
|
||||
def host(self, host):
|
||||
"""
|
||||
Set the host (binding) used to start the Dynamips hypervisor.
|
||||
Sets the host (binding) used to start the Dynamips hypervisor.
|
||||
|
||||
:param host: host/address (string)
|
||||
"""
|
||||
@ -142,7 +143,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
@workingdir.setter
|
||||
def workingdir(self, workingdir):
|
||||
"""
|
||||
Set the working directory used to start the Dynamips hypervisor.
|
||||
Sets the working directory used to start the Dynamips hypervisor.
|
||||
|
||||
:param workingdir: path to a working directory
|
||||
"""
|
||||
@ -163,7 +164,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
@image_ref.setter
|
||||
def image_ref(self, ios_image_name):
|
||||
"""
|
||||
Set the reference IOS image name
|
||||
Sets the reference IOS image name
|
||||
(used by the hypervisor manager for load-balancing purposes).
|
||||
|
||||
:param ios_image_name: image reference name
|
||||
@ -230,8 +231,13 @@ class Hypervisor(DynamipsHypervisor):
|
||||
"""
|
||||
|
||||
if self.is_running():
|
||||
DynamipsHypervisor.stop(self)
|
||||
logger.info("Stopping Dynamips PID={}".format(self._process.pid))
|
||||
# give some time for the hypervisor to properly stop.
|
||||
# time to delete UNIX NIOs for instance.
|
||||
time.sleep(0.01)
|
||||
self._process.kill()
|
||||
self._process.wait()
|
||||
|
||||
def read_stdout(self):
|
||||
"""
|
||||
|
@ -45,27 +45,29 @@ class HypervisorManager(object):
|
||||
path,
|
||||
workingdir,
|
||||
host='127.0.0.1',
|
||||
base_port=7200,
|
||||
base_console=2000,
|
||||
base_aux=3000,
|
||||
base_udp=10000):
|
||||
base_hypervisor_port=7200,
|
||||
base_console_port=2000,
|
||||
base_aux_port=3000,
|
||||
base_udp_port=10000):
|
||||
|
||||
self._hypervisors = []
|
||||
self._path = path
|
||||
self._workingdir = workingdir
|
||||
self._base_port = base_port
|
||||
self._current_port = self._base_port
|
||||
self._base_console = base_console
|
||||
self._base_aux = base_aux
|
||||
self._base_udp = base_udp
|
||||
self._host = host
|
||||
self._clean_workingdir = False
|
||||
self._ghost_ios = True
|
||||
self._mmap = True
|
||||
self._jit_sharing = False
|
||||
self._sparsemem = True
|
||||
self._base_hypervisor_port = base_hypervisor_port
|
||||
self._current_port = self._base_hypervisor_port
|
||||
self._base_console_port = base_console_port
|
||||
self._base_aux_port = base_aux_port
|
||||
self._base_udp_port = base_udp_port
|
||||
self._current_base_udp_port = self._base_udp_port
|
||||
self._udp_incrementation_per_hypervisor = 100
|
||||
self._ghost_ios_support = True
|
||||
self._mmap_support = True
|
||||
self._jit_sharing_support = False
|
||||
self._sparse_memory_support = True
|
||||
self._allocate_hypervisor_per_device = True
|
||||
self._memory_usage_limit_per_hypervisor = 1024
|
||||
self._group_ios_per_hypervisor = True
|
||||
self._allocate_hypervisor_per_ios_image = True
|
||||
|
||||
def __del__(self):
|
||||
"""
|
||||
@ -84,6 +86,263 @@ class HypervisorManager(object):
|
||||
|
||||
return self._hypervisors
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
"""
|
||||
Returns the Dynamips path.
|
||||
|
||||
:returns: path to Dynamips
|
||||
"""
|
||||
|
||||
return self._path
|
||||
|
||||
@path.setter
|
||||
def path(self, path):
|
||||
"""
|
||||
Set a new Dynamips path.
|
||||
|
||||
:param path: path to Dynamips
|
||||
"""
|
||||
|
||||
self._path = path
|
||||
log.info("Dynamips path set to {}".format(self._path))
|
||||
|
||||
@property
|
||||
def workingdir(self):
|
||||
"""
|
||||
Returns the Dynamips working directory path.
|
||||
|
||||
:returns: path to Dynamips working directory
|
||||
"""
|
||||
|
||||
return self._workingdir
|
||||
|
||||
@workingdir.setter
|
||||
def workingdir(self, workingdir):
|
||||
"""
|
||||
Sets a new path to the Dynamips working directory.
|
||||
|
||||
:param workingdir: path to Dynamips working directory
|
||||
"""
|
||||
|
||||
self._workingdir = workingdir
|
||||
log.info("working directory set to {}".format(self._workingdir))
|
||||
|
||||
@property
|
||||
def base_hypervisor_port(self):
|
||||
"""
|
||||
Returns the base hypervisor port.
|
||||
|
||||
:returns: base hypervisor port (integer)
|
||||
"""
|
||||
|
||||
return self._base_hypervisor_port
|
||||
|
||||
@base_hypervisor_port.setter
|
||||
def base_hypervisor_port(self, base_hypervisor_port):
|
||||
"""
|
||||
Set a new base hypervisor port.
|
||||
|
||||
:param base_hypervisor_port: base hypervisor port (integer)
|
||||
"""
|
||||
|
||||
if self._base_hypervisor_port != base_hypervisor_port:
|
||||
self._base_hypervisor_port = base_hypervisor_port
|
||||
self._current_port = self._base_hypervisor_port
|
||||
log.info("base hypervisor port set to {}".format(self._base_hypervisor_port))
|
||||
|
||||
@property
|
||||
def base_console_port(self):
|
||||
"""
|
||||
Returns the base console port.
|
||||
|
||||
:returns: base console port (integer)
|
||||
"""
|
||||
|
||||
return self._base_console_port
|
||||
|
||||
@base_console_port.setter
|
||||
def base_console_port(self, base_console_port):
|
||||
"""
|
||||
Set a new base console port.
|
||||
|
||||
:param base_console_port: base console port (integer)
|
||||
"""
|
||||
|
||||
if self._base_console_port != base_console_port:
|
||||
self._base_console_port = base_console_port
|
||||
log.info("base console port set to {}".format(self._base_console_port))
|
||||
|
||||
@property
|
||||
def base_aux_port(self):
|
||||
"""
|
||||
Returns the base auxiliary console port.
|
||||
|
||||
:returns: base auxiliary console port (integer)
|
||||
"""
|
||||
|
||||
return self._base_aux_port
|
||||
|
||||
@base_aux_port.setter
|
||||
def base_aux_port(self, base_aux_port):
|
||||
"""
|
||||
Set a new base auxiliary console port.
|
||||
|
||||
:param base_aux_port: base auxiliary console port (integer)
|
||||
"""
|
||||
|
||||
if self._base_aux_port != base_aux_port:
|
||||
self._base_aux_port = base_aux_port
|
||||
log.info("base aux port set to {}".format(self._base_aux_port))
|
||||
|
||||
@property
|
||||
def base_udp_port(self):
|
||||
"""
|
||||
Returns the base UDP port.
|
||||
|
||||
:returns: base UDP port (integer)
|
||||
"""
|
||||
|
||||
return self._base_udp_port
|
||||
|
||||
@base_udp_port.setter
|
||||
def base_udp_port(self, base_udp_port):
|
||||
"""
|
||||
Set a new base UDP port.
|
||||
|
||||
:param base_udp_port: base UDP port (integer)
|
||||
"""
|
||||
|
||||
if self._base_udp_port != base_udp_port:
|
||||
self._base_udp_port = base_udp_port
|
||||
self._current_base_udp_port = self._base_udp_port
|
||||
log.info("base UDP port set to {}".format(self._base_udp_port))
|
||||
|
||||
@property
|
||||
def ghost_ios_support(self):
|
||||
"""
|
||||
Returns either ghost IOS is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._ghost_ios_support
|
||||
|
||||
@ghost_ios_support.setter
|
||||
def ghost_ios_support(self, ghost_ios_support):
|
||||
"""
|
||||
Sets ghost IOS support.
|
||||
|
||||
:param ghost_ios_support: boolean
|
||||
"""
|
||||
|
||||
if self._ghost_ios_support != ghost_ios_support:
|
||||
self._ghost_ios_support = ghost_ios_support
|
||||
if ghost_ios_support:
|
||||
log.info("ghost IOS support enabled")
|
||||
else:
|
||||
log.info("ghost IOS support disabled")
|
||||
|
||||
@property
|
||||
def mmap_support(self):
|
||||
"""
|
||||
Returns either mmap is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._mmap_support
|
||||
|
||||
@mmap_support.setter
|
||||
def mmap_support(self, mmap_support):
|
||||
"""
|
||||
Sets mmap support.
|
||||
|
||||
:param mmap_support: boolean
|
||||
"""
|
||||
|
||||
if self._mmap_support != mmap_support:
|
||||
self._mmap_support = mmap_support
|
||||
if mmap_support:
|
||||
log.info("mmap support enabled")
|
||||
else:
|
||||
log.info("mmap support disabled")
|
||||
|
||||
@property
|
||||
def sparse_memory_support(self):
|
||||
"""
|
||||
Returns either sparse memory is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._sparse_memory_support
|
||||
|
||||
@sparse_memory_support.setter
|
||||
def sparse_memory_support(self, sparse_memory_support):
|
||||
"""
|
||||
Sets sparse memory support.
|
||||
|
||||
:param sparse_memory_support: boolean
|
||||
"""
|
||||
|
||||
if self._sparse_memory_support != sparse_memory_support:
|
||||
self._sparse_memory_support = sparse_memory_support
|
||||
if sparse_memory_support:
|
||||
log.info("sparse memory support enabled")
|
||||
else:
|
||||
log.info("sparse memory support disabled")
|
||||
|
||||
@property
|
||||
def jit_sharing_support(self):
|
||||
"""
|
||||
Returns either JIT sharing is activated or not.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._jit_sharing_support
|
||||
|
||||
@jit_sharing_support.setter
|
||||
def jit_sharing_support(self, jit_sharing_support):
|
||||
"""
|
||||
Sets JIT sharing support.
|
||||
|
||||
:param jit_sharing_support: boolean
|
||||
"""
|
||||
|
||||
if self._jit_sharing_support != jit_sharing_support:
|
||||
self._jit_sharing_support = jit_sharing_support
|
||||
if jit_sharing_support:
|
||||
log.info("JIT sharing support enabled")
|
||||
else:
|
||||
log.info("JIT sharing support disabled")
|
||||
|
||||
@property
|
||||
def allocate_hypervisor_per_device(self):
|
||||
"""
|
||||
Returns either an hypervisor is created for each device.
|
||||
|
||||
:returns: True or False
|
||||
"""
|
||||
|
||||
return self._allocate_hypervisor_per_device
|
||||
|
||||
@allocate_hypervisor_per_device.setter
|
||||
def allocate_hypervisor_per_device(self, value):
|
||||
"""
|
||||
Sets if an hypervisor is created for each device.
|
||||
|
||||
:param value: True or False
|
||||
"""
|
||||
|
||||
if self._allocate_hypervisor_per_device != value:
|
||||
self._allocate_hypervisor_per_device = value
|
||||
if value:
|
||||
log.info("allocating an hypervisor per device enabled")
|
||||
else:
|
||||
log.info("allocating an hypervisor per device disabled")
|
||||
|
||||
@property
|
||||
def memory_usage_limit_per_hypervisor(self):
|
||||
"""
|
||||
@ -97,15 +356,17 @@ class HypervisorManager(object):
|
||||
@memory_usage_limit_per_hypervisor.setter
|
||||
def memory_usage_limit_per_hypervisor(self, memory_limit):
|
||||
"""
|
||||
Set the memory usage limit per hypervisor
|
||||
Sets the memory usage limit per hypervisor
|
||||
|
||||
:param memory_limit: memory limit value (integer)
|
||||
"""
|
||||
|
||||
self._memory_usage_limit_per_hypervisor = memory_limit
|
||||
if self._memory_usage_limit_per_hypervisor != memory_limit:
|
||||
self._memory_usage_limit_per_hypervisor = memory_limit
|
||||
log.info("memory usage limit per hypervisor set to {}".format(memory_limit))
|
||||
|
||||
@property
|
||||
def group_ios_per_hypervisor(self):
|
||||
def allocate_hypervisor_per_ios_image(self):
|
||||
"""
|
||||
Returns if router are grouped per hypervisor
|
||||
based on their IOS image.
|
||||
@ -113,18 +374,23 @@ class HypervisorManager(object):
|
||||
:returns: True or False
|
||||
"""
|
||||
|
||||
return self._group_ios_per_hypervisor
|
||||
return self._allocate_hypervisor_per_ios_image
|
||||
|
||||
@group_ios_per_hypervisor.setter
|
||||
def group_ios_per_hypervisor(self, value):
|
||||
@allocate_hypervisor_per_ios_image.setter
|
||||
def allocate_hypervisor_per_ios_image(self, value):
|
||||
"""
|
||||
Set if router are grouped per hypervisor
|
||||
Sets if routers are grouped per hypervisor
|
||||
based on their IOS image.
|
||||
|
||||
:param value: True or False
|
||||
"""
|
||||
|
||||
self._group_ios_per_hypervisor = value
|
||||
if self._allocate_hypervisor_per_ios_image != value:
|
||||
self._allocate_hypervisor_per_ios_image = value
|
||||
if value:
|
||||
log.info("allocating an hypervisor per IOS image enabled")
|
||||
else:
|
||||
log.info("allocating an hypervisor per IOS image disabled")
|
||||
|
||||
def wait_for_hypervisor(self, host, port, timeout=10):
|
||||
"""
|
||||
@ -172,6 +438,10 @@ class HypervisorManager(object):
|
||||
log.info("hypervisor {}:{} has successfully started".format(hypervisor.host, hypervisor.port))
|
||||
|
||||
hypervisor.connect()
|
||||
hypervisor.baseconsole = self._base_console_port
|
||||
hypervisor.baseaux = self._base_aux_port
|
||||
hypervisor.baseudp = self._current_base_udp_port
|
||||
self._current_base_udp_port += self._udp_incrementation_per_hypervisor
|
||||
self._hypervisors.append(hypervisor)
|
||||
self._current_port += 1
|
||||
return hypervisor
|
||||
@ -187,16 +457,21 @@ class HypervisorManager(object):
|
||||
:returns: the allocated hypervisor object
|
||||
"""
|
||||
|
||||
for hypervisor in self._hypervisors:
|
||||
if self._group_ios_per_hypervisor and hypervisor.image_ref != router_ios_image:
|
||||
continue
|
||||
if (hypervisor.memory_load + router_ram) <= self._memory_usage_limit_per_hypervisor:
|
||||
current_memory_load = hypervisor.memory_load
|
||||
hypervisor.increase_memory_load(router_ram)
|
||||
log.info("allocating existing hypervisor {}:{}, RAM={}+{}".format(hypervisor.host,
|
||||
hypervisor.port,
|
||||
current_memory_load,
|
||||
router_ram))
|
||||
# allocate an hypervisor for each router by default
|
||||
if not self._allocate_hypervisor_per_device:
|
||||
for hypervisor in self._hypervisors:
|
||||
if self._allocate_hypervisor_per_ios_image:
|
||||
if not hypervisor.image_ref:
|
||||
hypervisor.image_ref = router_ios_image
|
||||
elif hypervisor.image_ref != router_ios_image:
|
||||
continue
|
||||
if (hypervisor.memory_load + router_ram) <= self._memory_usage_limit_per_hypervisor:
|
||||
current_memory_load = hypervisor.memory_load
|
||||
hypervisor.increase_memory_load(router_ram)
|
||||
log.info("allocating existing hypervisor {}:{}, RAM={}+{}".format(hypervisor.host,
|
||||
hypervisor.port,
|
||||
current_memory_load,
|
||||
router_ram))
|
||||
return hypervisor
|
||||
|
||||
hypervisor = self.start_new_hypervisor()
|
||||
@ -226,6 +501,22 @@ class HypervisorManager(object):
|
||||
hypervisor.stop()
|
||||
self._hypervisors.remove(hypervisor)
|
||||
|
||||
def allocate_hypervisor_for_switch(self):
|
||||
"""
|
||||
Allocates a Dynamips hypervisor for a specific switch
|
||||
|
||||
:returns: the allocated hypervisor object
|
||||
"""
|
||||
|
||||
# For now always allocate the first hypervisor available,
|
||||
# in the future we could randomly allocate.
|
||||
|
||||
if self._hypervisors:
|
||||
return self._hypervisors[0]
|
||||
|
||||
# no hypervisor, let's start one!
|
||||
return self.start_new_hypervisor()
|
||||
|
||||
def stop_all_hypervisors(self):
|
||||
"""
|
||||
Stops all hypervisors.
|
||||
@ -233,3 +524,4 @@ class HypervisorManager(object):
|
||||
|
||||
for hypervisor in self._hypervisors:
|
||||
hypervisor.stop()
|
||||
self._hypervisors = []
|
||||
|
@ -22,6 +22,9 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L451
|
||||
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO(object):
|
||||
"""
|
||||
@ -55,6 +58,7 @@ class NIO(object):
|
||||
"""
|
||||
|
||||
self._hypervisor.send("nio delete {}".format(self._name))
|
||||
log.info("NIO {name} has been deleted".format(name=self._name))
|
||||
|
||||
def rename(self, new_name):
|
||||
"""
|
||||
@ -65,6 +69,9 @@ class NIO(object):
|
||||
|
||||
self._hypervisor.send("nio rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("NIO {name} renamed to {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
self._name = new_name
|
||||
|
||||
def debug(self, debug):
|
||||
@ -197,7 +204,7 @@ class NIO(object):
|
||||
|
||||
def set_bandwidth(self, bandwidth):
|
||||
"""
|
||||
Set bandwidth constraint.
|
||||
Sets bandwidth constraint.
|
||||
|
||||
:param bandwidth: bandwidth integer value (in Kb/s)
|
||||
"""
|
||||
|
@ -21,6 +21,9 @@ Interface for FIFO NIOs.
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_FIFO(NIO):
|
||||
"""
|
||||
@ -42,6 +45,16 @@ class NIO_FIFO(NIO):
|
||||
|
||||
self._hypervisor.send("nio create_fifo {}".format(self._name))
|
||||
|
||||
log.info("NIO FIFO {name} created.".format(name=self._name))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
def crossconnect(self, nio):
|
||||
"""
|
||||
Establishes a cross-connect between this FIFO NIO and another one.
|
||||
@ -51,3 +64,5 @@ class NIO_FIFO(NIO):
|
||||
|
||||
self._hypervisor.send("nio crossconnect_fifo {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
|
||||
log.info("NIO FIFO {name} crossconnected with {nio_name}.".format(name=self._name, nio_name=nio.name))
|
||||
|
@ -21,6 +21,9 @@ Interface for generic Ethernet NIOs (PCAP library).
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_GenericEthernet(NIO):
|
||||
"""
|
||||
@ -45,6 +48,17 @@ class NIO_GenericEthernet(NIO):
|
||||
self._hypervisor.send("nio create_gen_eth {name} {eth_device}".format(name=self._name,
|
||||
eth_device=ethernet_device))
|
||||
|
||||
log.info("NIO Generic Ethernet {name} created with device {device}".format(name=self._name,
|
||||
device=ethernet_device))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def ethernet_device(self):
|
||||
"""
|
||||
|
@ -21,6 +21,9 @@ Interface for Linux Ethernet NIOs (Linux only).
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_LinuxEthernet(NIO):
|
||||
"""
|
||||
@ -45,6 +48,17 @@ class NIO_LinuxEthernet(NIO):
|
||||
self._hypervisor.send("nio create_linux_eth {name} {eth_device}".format(name=self._name,
|
||||
eth_device=ethernet_device))
|
||||
|
||||
log.info("NIO Linux Ethernet {name} created with device {device}".format(name=self._name,
|
||||
device=ethernet_device))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def ethernet_device(self):
|
||||
"""
|
||||
|
@ -21,6 +21,9 @@ Interface for multicast NIOs.
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_Mcast(NIO):
|
||||
"""
|
||||
@ -49,6 +52,18 @@ class NIO_Mcast(NIO):
|
||||
mgroup=group,
|
||||
mport=port))
|
||||
|
||||
log.info("NIO Multicast {name} created with mgroup={group}, mport={port}".format(name=self._name,
|
||||
group=group,
|
||||
port=port))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def group(self):
|
||||
"""
|
||||
@ -82,7 +97,7 @@ class NIO_Mcast(NIO):
|
||||
@ttl.setter
|
||||
def ttl(self, ttl):
|
||||
"""
|
||||
Set the TTL for the multicast address
|
||||
Sets the TTL for the multicast address
|
||||
|
||||
:param ttl: TTL value
|
||||
"""
|
||||
|
@ -21,6 +21,9 @@ Interface for dummy NIOs (mostly for tests).
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_Null(NIO):
|
||||
"""
|
||||
@ -41,3 +44,12 @@ class NIO_Null(NIO):
|
||||
self._name = 'nio_null' + str(self._id)
|
||||
|
||||
self._hypervisor.send("nio create_null {}".format(self._name))
|
||||
log.info("NIO NULL {name} created.".format(name=self._name))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
@ -21,6 +21,9 @@ Interface for TAP NIOs (UNIX based OSes only).
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_TAP(NIO):
|
||||
"""
|
||||
@ -45,6 +48,17 @@ class NIO_TAP(NIO):
|
||||
self._hypervisor.send("nio create_tap {name} {tap}".format(name=self._name,
|
||||
tap=tap_device))
|
||||
|
||||
log.info("NIO TAP {name} created with device {device}".format(name=self._name,
|
||||
device=tap_device))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def tap_device(self):
|
||||
"""
|
||||
|
@ -21,6 +21,9 @@ Interface for UDP NIOs.
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_UDP(NIO):
|
||||
"""
|
||||
@ -51,6 +54,19 @@ class NIO_UDP(NIO):
|
||||
rhost=rhost,
|
||||
rport=rport))
|
||||
|
||||
log.info("NIO UDP {name} created with lport={lport}, rhost={rhost}, rport={rport}".format(name=self._name,
|
||||
lport=lport,
|
||||
rhost=rhost,
|
||||
rport=rport))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def lport(self):
|
||||
"""
|
||||
|
@ -21,6 +21,9 @@ Interface for automatic UDP NIOs.
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_UDP_auto(NIO):
|
||||
"""
|
||||
@ -48,9 +51,22 @@ class NIO_UDP_auto(NIO):
|
||||
laddr=laddr,
|
||||
lport_start=lport_start,
|
||||
lport_end=lport_end))[0])
|
||||
|
||||
log.info("NIO UDP AUTO {name} created with laddr={laddr}, lport_start={start}, lport_end={end}".format(name=self._name,
|
||||
laddr=laddr,
|
||||
start=lport_start,
|
||||
end=lport_end))
|
||||
self._raddr = None
|
||||
self._rport = None
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def laddr(self):
|
||||
"""
|
||||
@ -104,3 +120,7 @@ class NIO_UDP_auto(NIO):
|
||||
rport=rport))
|
||||
self._raddr = raddr
|
||||
self._rport = rport
|
||||
|
||||
log.info("NIO UDP AUTO {name} connected to {raddr}:{rport}".format(name=self._name,
|
||||
raddr=raddr,
|
||||
rport=rport))
|
||||
|
@ -21,6 +21,9 @@ Interface for UNIX NIOs (Unix based OSes only).
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_UNIX(NIO):
|
||||
"""
|
||||
@ -48,6 +51,18 @@ class NIO_UNIX(NIO):
|
||||
local=local_file,
|
||||
remote=remote_file))
|
||||
|
||||
log.info("NIO UNIX {name} created with local file {local} and remote file {remote}".format(name=self._name,
|
||||
local=local_file,
|
||||
remote=remote_file))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def local_file(self):
|
||||
"""
|
||||
|
@ -21,6 +21,9 @@ Interface for VDE (Virtual Distributed Ethernet) NIOs (Unix based OSes only).
|
||||
|
||||
from .nio import NIO
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NIO_VDE(NIO):
|
||||
"""
|
||||
@ -48,6 +51,18 @@ class NIO_VDE(NIO):
|
||||
control=control_file,
|
||||
local=local_file))
|
||||
|
||||
log.info("NIO VDE {name} created with control={control}, local={local}".format(name=self._name,
|
||||
control=control_file,
|
||||
local=local_file))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 0
|
||||
|
||||
@property
|
||||
def control_file(self):
|
||||
"""
|
||||
|
@ -23,6 +23,9 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L593
|
||||
from __future__ import unicode_literals
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ATMSwitch(object):
|
||||
"""
|
||||
@ -32,15 +35,47 @@ class ATMSwitch(object):
|
||||
:param name: name for this switch
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
_instance_count = 1
|
||||
|
||||
def __init__(self, hypervisor, name=None):
|
||||
|
||||
# create an unique ID
|
||||
self._id = ATMSwitch._instance_count
|
||||
ATMSwitch._instance_count += 1
|
||||
|
||||
# let's create a unique name if none has been chosen
|
||||
if not name:
|
||||
name = "ATM" + str(self._id)
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("atmsw create {}".format(self._name))
|
||||
|
||||
log.info("ATM switch {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 1
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this ATM switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
@ -100,6 +135,11 @@ class ATMSwitch(object):
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("atmsw rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: renamed to {new_name}".format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
def delete(self):
|
||||
@ -108,8 +148,22 @@ class ATMSwitch(object):
|
||||
"""
|
||||
|
||||
self._hypervisor.send("atmsw delete {}".format(self._name))
|
||||
|
||||
log.info("ATM switch {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
|
||||
def has_port(self, port):
|
||||
"""
|
||||
Checks if a port exists on this ATM switch.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on ATM switch.
|
||||
@ -121,6 +175,11 @@ class ATMSwitch(object):
|
||||
if port in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
self._nios[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
@ -133,7 +192,14 @@ class ATMSwitch(object):
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
log.info("ATM switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._nios[port]
|
||||
return nio
|
||||
|
||||
def map_vp(self, port1, vpi1, port2, vpi2):
|
||||
"""
|
||||
@ -159,6 +225,14 @@ class ATMSwitch(object):
|
||||
input_vpi=vpi1,
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VPC from port {port1} VPI {vpi1} to port {port2} VPI {vpi2} created".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
port2=port2,
|
||||
vpi2=vpi2))
|
||||
|
||||
self._mapping[(port1, vpi1)] = (port2, vpi2)
|
||||
|
||||
def unmap_vp(self, port1, vpi1, port2, vpi2):
|
||||
@ -185,6 +259,14 @@ class ATMSwitch(object):
|
||||
input_vpi=vpi1,
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VPC from port {port1} VPI {vpi1} to port {port2} VPI {vpi2} deleted".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
port2=port2,
|
||||
vpi2=vpi2))
|
||||
|
||||
del self._mapping[(port1, vpi1)]
|
||||
|
||||
def map_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2):
|
||||
@ -215,6 +297,16 @@ class ATMSwitch(object):
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2,
|
||||
output_vci=vci2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VCC from port {port1} VPI {vpi1} VCI {vci1} to port {port2} VPI {vpi2} VCI {vci2} created".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
vci1=vci1,
|
||||
port2=port2,
|
||||
vpi2=vpi2,
|
||||
vci2=vci2))
|
||||
|
||||
self._mapping[(port1, vpi1, vci1)] = (port2, vpi2, vci2)
|
||||
|
||||
def unmap_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2):
|
||||
@ -245,4 +337,13 @@ class ATMSwitch(object):
|
||||
output_nio=nio2,
|
||||
output_vpi=vpi2,
|
||||
output_vci=vci2))
|
||||
|
||||
log.info("ATM switch {name} [id={id}]: VCC from port {port1} VPI {vpi1} VCI {vci1} to port {port2} VPI {vpi2} VCI {vci2} deleted".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
vci1=vci1,
|
||||
port2=port2,
|
||||
vpi2=vpi2,
|
||||
vci2=vci2))
|
||||
del self._mapping[(port1, vpi1, vci1)]
|
||||
|
@ -88,6 +88,7 @@ class Bridge(object):
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("nio_bridge rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
def delete(self):
|
||||
|
@ -25,6 +25,9 @@ from .router import Router
|
||||
from ..adapters.c1700_mb_1fe import C1700_MB_1FE
|
||||
from ..adapters.c1700_mb_wic1 import C1700_MB_WIC1
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C1700(Router):
|
||||
"""
|
||||
@ -37,7 +40,7 @@ class C1700(Router):
|
||||
1710 is not supported.
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name, chassis="1720"):
|
||||
def __init__(self, hypervisor, name=None, chassis="1720"):
|
||||
Router.__init__(self, hypervisor, name, platform="c1700")
|
||||
|
||||
# Set default values for this platform
|
||||
@ -54,6 +57,27 @@ class C1700(Router):
|
||||
|
||||
self._setup_chassis()
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default attribute values for this platform.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = Router.defaults(self)
|
||||
|
||||
platform_defaults = {"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"chassis": self._chassis,
|
||||
"iomem": self._iomem,
|
||||
"clock_divisor": self._clock_divisor}
|
||||
|
||||
# update the router defaults with the platform specific defaults
|
||||
router_defaults.update(platform_defaults)
|
||||
return router_defaults
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all c1700 instances
|
||||
@ -65,7 +89,7 @@ class C1700(Router):
|
||||
|
||||
def _setup_chassis(self):
|
||||
"""
|
||||
Set up the router with the corresponding chassis
|
||||
Sets up the router with the corresponding chassis
|
||||
(create slots and insert default adapters).
|
||||
"""
|
||||
|
||||
@ -91,7 +115,7 @@ class C1700(Router):
|
||||
@chassis.setter
|
||||
def chassis(self, chassis):
|
||||
"""
|
||||
Set the chassis.
|
||||
Sets the chassis.
|
||||
|
||||
:param: chassis string:
|
||||
1720, 1721, 1750, 1751 or 1760
|
||||
@ -99,6 +123,11 @@ class C1700(Router):
|
||||
|
||||
self._hypervisor.send("c1700 set_chassis {name} {chassis}".format(name=self._name,
|
||||
chassis=chassis))
|
||||
|
||||
log.info("router {name} [id={id}]: chassis set to {chassis}".format(name=self._name,
|
||||
id=self._id,
|
||||
chassis=chassis))
|
||||
|
||||
self._chassis = chassis
|
||||
self._setup_chassis()
|
||||
|
||||
@ -115,11 +144,16 @@ class C1700(Router):
|
||||
@iomem.setter
|
||||
def iomem(self, iomem):
|
||||
"""
|
||||
Set I/O memory size for this router.
|
||||
Sets I/O memory size for this router.
|
||||
|
||||
:param iomem: I/O memory size
|
||||
"""
|
||||
|
||||
self._hypervisor.send("c1700 set_iomem {name} {size}".format(name=self._name,
|
||||
size=iomem))
|
||||
|
||||
log.info("router {name} [id={id}]: I/O memory updated from {old_iomem}% to {new_iomem}%".format(name=self._name,
|
||||
id=self._id,
|
||||
old_iomem=self._iomem,
|
||||
new_iomem=iomem))
|
||||
self._iomem = iomem
|
||||
|
@ -27,6 +27,9 @@ from ..adapters.c2600_mb_2e import C2600_MB_2E
|
||||
from ..adapters.c2600_mb_1fe import C2600_MB_1FE
|
||||
from ..adapters.c2600_mb_2fe import C2600_MB_2FE
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C2600(Router):
|
||||
"""
|
||||
@ -52,7 +55,7 @@ class C2600(Router):
|
||||
'2650XM': C2600_MB_1FE,
|
||||
'2651XM': C2600_MB_2FE}
|
||||
|
||||
def __init__(self, hypervisor, name, chassis="2610"):
|
||||
def __init__(self, hypervisor, name=None, chassis="2610"):
|
||||
Router.__init__(self, hypervisor, name, platform="c2600")
|
||||
|
||||
# Set default values for this platform
|
||||
@ -69,6 +72,27 @@ class C2600(Router):
|
||||
|
||||
self._setup_chassis()
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default attribute values for this platform.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = Router.defaults(self)
|
||||
|
||||
platform_defaults = {"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"iomem": self._iomem,
|
||||
"chassis": self._chassis,
|
||||
"clock_divisor": self._clock_divisor}
|
||||
|
||||
# update the router defaults with the platform specific defaults
|
||||
router_defaults.update(platform_defaults)
|
||||
return router_defaults
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all c2600 instances
|
||||
@ -80,7 +104,7 @@ class C2600(Router):
|
||||
|
||||
def _setup_chassis(self):
|
||||
"""
|
||||
Set up the router with the corresponding chassis
|
||||
Sets up the router with the corresponding chassis
|
||||
(create slots and insert default adapters).
|
||||
"""
|
||||
|
||||
@ -100,7 +124,7 @@ class C2600(Router):
|
||||
@chassis.setter
|
||||
def chassis(self, chassis):
|
||||
"""
|
||||
Set the chassis.
|
||||
Sets the chassis.
|
||||
|
||||
:param: chassis string:
|
||||
2610, 2611, 2620, 2621, 2610XM, 2611XM
|
||||
@ -109,6 +133,10 @@ class C2600(Router):
|
||||
|
||||
self._hypervisor.send("c2600 set_chassis {name} {chassis}".format(name=self._name,
|
||||
chassis=chassis))
|
||||
|
||||
log.info("router {name} [id={id}]: chassis set to {chassis}".format(name=self._name,
|
||||
id=self._id,
|
||||
chassis=chassis))
|
||||
self._chassis = chassis
|
||||
self._setup_chassis()
|
||||
|
||||
@ -125,11 +153,16 @@ class C2600(Router):
|
||||
@iomem.setter
|
||||
def iomem(self, iomem):
|
||||
"""
|
||||
Set I/O memory size for this router.
|
||||
Sets I/O memory size for this router.
|
||||
|
||||
:param iomem: I/O memory size
|
||||
"""
|
||||
|
||||
self._hypervisor.send("c2600 set_iomem {name} {size}".format(name=self._name,
|
||||
size=iomem))
|
||||
|
||||
log.info("router {name} [id={id}]: I/O memory updated from {old_iomem}% to {new_iomem}%".format(name=self._name,
|
||||
id=self._id,
|
||||
old_iomem=self._iomem,
|
||||
new_iomem=iomem))
|
||||
self._iomem = iomem
|
||||
|
@ -24,6 +24,9 @@ from __future__ import unicode_literals
|
||||
from .router import Router
|
||||
from ..adapters.gt96100_fe import GT96100_FE
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C2691(Router):
|
||||
"""
|
||||
@ -33,7 +36,7 @@ class C2691(Router):
|
||||
:param name: name for this router
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
def __init__(self, hypervisor, name=None):
|
||||
Router.__init__(self, hypervisor, name, platform="c2691")
|
||||
|
||||
# Set default values for this platform
|
||||
@ -47,6 +50,26 @@ class C2691(Router):
|
||||
self._create_slots(2)
|
||||
self._slots[0] = GT96100_FE()
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default attribute values for this platform.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = Router.defaults(self)
|
||||
|
||||
platform_defaults = {"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"iomem": self._iomem,
|
||||
"clock_divisor": self._clock_divisor}
|
||||
|
||||
# update the router defaults with the platform specific defaults
|
||||
router_defaults.update(platform_defaults)
|
||||
return router_defaults
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all c2691 instances
|
||||
@ -69,11 +92,16 @@ class C2691(Router):
|
||||
@iomem.setter
|
||||
def iomem(self, iomem):
|
||||
"""
|
||||
Set I/O memory size for this router.
|
||||
Sets I/O memory size for this router.
|
||||
|
||||
:param iomem: I/O memory size
|
||||
"""
|
||||
|
||||
self._hypervisor.send("c2691 set_iomem {name} {size}".format(name=self._name,
|
||||
size=iomem))
|
||||
|
||||
log.info("router {name} [id={id}]: I/O memory updated from {old_iomem}% to {new_iomem}%".format(name=self._name,
|
||||
id=self._id,
|
||||
old_iomem=self._iomem,
|
||||
new_iomem=iomem))
|
||||
self._iomem = iomem
|
||||
|
@ -24,6 +24,9 @@ from __future__ import unicode_literals
|
||||
from .router import Router
|
||||
from ..adapters.leopard_2fe import Leopard_2FE
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C3600(Router):
|
||||
"""
|
||||
@ -35,7 +38,7 @@ class C3600(Router):
|
||||
3620, 3640 or 3660 (default = 3640).
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name, chassis="3640"):
|
||||
def __init__(self, hypervisor, name=None, chassis="3640"):
|
||||
Router.__init__(self, hypervisor, name, platform="c3600")
|
||||
|
||||
# Set default values for this platform
|
||||
@ -52,6 +55,27 @@ class C3600(Router):
|
||||
|
||||
self._setup_chassis()
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default attribute values for this platform.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = Router.defaults(self)
|
||||
|
||||
platform_defaults = {"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"iomem": self._iomem,
|
||||
"chassis": self._chassis,
|
||||
"clock_divisor": self._clock_divisor}
|
||||
|
||||
# update the router defaults with the platform specific defaults
|
||||
router_defaults.update(platform_defaults)
|
||||
return router_defaults
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all c3600 instances
|
||||
@ -63,7 +87,7 @@ class C3600(Router):
|
||||
|
||||
def _setup_chassis(self):
|
||||
"""
|
||||
Set up the router with the corresponding chassis
|
||||
Sets up the router with the corresponding chassis
|
||||
(create slots and insert default adapters).
|
||||
"""
|
||||
|
||||
@ -88,13 +112,18 @@ class C3600(Router):
|
||||
@chassis.setter
|
||||
def chassis(self, chassis):
|
||||
"""
|
||||
Set the chassis.
|
||||
Sets the chassis.
|
||||
|
||||
:param: chassis string: 3620, 3640 or 3660
|
||||
"""
|
||||
|
||||
self._hypervisor.send("c3600 set_chassis {name} {chassis}".format(name=self._name,
|
||||
chassis=chassis))
|
||||
|
||||
log.info("router {name} [id={id}]: chassis set to {chassis}".format(name=self._name,
|
||||
id=self._id,
|
||||
chassis=chassis))
|
||||
|
||||
self._chassis = chassis
|
||||
self._setup_chassis()
|
||||
|
||||
@ -118,4 +147,9 @@ class C3600(Router):
|
||||
|
||||
self._hypervisor.send("c3600 set_iomem {name} {size}".format(name=self._name,
|
||||
size=iomem))
|
||||
|
||||
log.info("router {name} [id={id}]: I/O memory updated from {old_iomem}% to {new_iomem}%".format(name=self._name,
|
||||
id=self._id,
|
||||
old_iomem=self._iomem,
|
||||
new_iomem=iomem))
|
||||
self._iomem = iomem
|
||||
|
@ -24,6 +24,9 @@ from __future__ import unicode_literals
|
||||
from .router import Router
|
||||
from ..adapters.gt96100_fe import GT96100_FE
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C3725(Router):
|
||||
"""
|
||||
@ -33,7 +36,7 @@ class C3725(Router):
|
||||
:param name: name for this router
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
def __init__(self, hypervisor, name=None):
|
||||
Router.__init__(self, hypervisor, name, platform="c3725")
|
||||
|
||||
# Set default values for this platform
|
||||
@ -47,6 +50,26 @@ class C3725(Router):
|
||||
self._create_slots(3)
|
||||
self._slots[0] = GT96100_FE()
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default attribute values for this platform.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = Router.defaults(self)
|
||||
|
||||
platform_defaults = {"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"iomem": self._iomem,
|
||||
"clock_divisor": self._clock_divisor}
|
||||
|
||||
# update the router defaults with the platform specific defaults
|
||||
router_defaults.update(platform_defaults)
|
||||
return router_defaults
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all c3725 instances.
|
||||
@ -69,11 +92,16 @@ class C3725(Router):
|
||||
@iomem.setter
|
||||
def iomem(self, iomem):
|
||||
"""
|
||||
Set I/O memory size for this router.
|
||||
Sets I/O memory size for this router.
|
||||
|
||||
:param iomem: I/O memory size
|
||||
"""
|
||||
|
||||
self._hypervisor.send("c3725 set_iomem {name} {size}".format(name=self._name,
|
||||
size=iomem))
|
||||
|
||||
log.info("router {name} [id={id}]: I/O memory updated from {old_iomem}% to {new_iomem}%".format(name=self._name,
|
||||
id=self._id,
|
||||
old_iomem=self._iomem,
|
||||
new_iomem=iomem))
|
||||
self._iomem = iomem
|
||||
|
@ -24,6 +24,9 @@ from __future__ import unicode_literals
|
||||
from .router import Router
|
||||
from ..adapters.gt96100_fe import GT96100_FE
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C3745(Router):
|
||||
"""
|
||||
@ -33,7 +36,7 @@ class C3745(Router):
|
||||
:param name: name for this router
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
def __init__(self, hypervisor, name=None):
|
||||
Router.__init__(self, hypervisor, name, platform="c3745")
|
||||
|
||||
# Set default values for this platform
|
||||
@ -47,6 +50,26 @@ class C3745(Router):
|
||||
self._create_slots(5)
|
||||
self._slots[0] = GT96100_FE()
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default attribute values for this platform.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = Router.defaults(self)
|
||||
|
||||
platform_defaults = {"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"iomem": self._iomem,
|
||||
"clock_divisor": self._clock_divisor}
|
||||
|
||||
# update the router defaults with the platform specific defaults
|
||||
router_defaults.update(platform_defaults)
|
||||
return router_defaults
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all c3745 instances.
|
||||
@ -69,11 +92,16 @@ class C3745(Router):
|
||||
@iomem.setter
|
||||
def iomem(self, iomem):
|
||||
"""
|
||||
Set I/O memory size for this router.
|
||||
Sets I/O memory size for this router.
|
||||
|
||||
:param iomem: I/O memory size
|
||||
"""
|
||||
|
||||
self._hypervisor.send("c3745 set_iomem {name} {size}".format(name=self._name,
|
||||
size=iomem))
|
||||
|
||||
log.info("router {name} [id={id}]: I/O memory updated from {old_iomem}% to {new_iomem}%".format(name=self._name,
|
||||
id=self._id,
|
||||
old_iomem=self._iomem,
|
||||
new_iomem=iomem))
|
||||
self._iomem = iomem
|
||||
|
@ -20,13 +20,15 @@ Interface for Dynamips virtual Cisco 7200 instances module ("c7200")
|
||||
http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L294
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from ..dynamips_error import DynamipsError
|
||||
from .router import Router
|
||||
from ..adapters.c7200_io_2fe import C7200_IO_2FE
|
||||
from ..adapters.c7200_io_ge_e import C7200_IO_GE_E
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class C7200(Router):
|
||||
"""
|
||||
@ -37,7 +39,7 @@ class C7200(Router):
|
||||
:param npe: default NPE
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name, npe="npe-400"):
|
||||
def __init__(self, hypervisor, name=None, npe="npe-400"):
|
||||
Router.__init__(self, hypervisor, name, platform="c7200")
|
||||
|
||||
# Set default values for this platform
|
||||
@ -70,6 +72,27 @@ class C7200(Router):
|
||||
else:
|
||||
self._slots[0] = C7200_IO_2FE()
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default attribute values for this platform.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = Router.defaults(self)
|
||||
|
||||
platform_defaults = {"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"npe": self._npe,
|
||||
"midplane": self._midplane,
|
||||
"clock_divisor": self._clock_divisor}
|
||||
|
||||
# update the router defaults with the platform specific defaults
|
||||
router_defaults.update(platform_defaults)
|
||||
return router_defaults
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Returns all c7200 instances.
|
||||
@ -92,7 +115,7 @@ class C7200(Router):
|
||||
@npe.setter
|
||||
def npe(self, npe):
|
||||
"""
|
||||
Set the NPE model.
|
||||
Sets the NPE model.
|
||||
|
||||
:params npe: NPE model string (e.g. "npe-200")
|
||||
NPE models are npe-100, npe-150, npe-175, npe-200,
|
||||
@ -104,6 +127,11 @@ class C7200(Router):
|
||||
|
||||
self._hypervisor.send("c7200 set_npe {name} {npe}".format(name=self._name,
|
||||
npe=npe))
|
||||
|
||||
log.info("router {name} [id={id}]: NPE updated from {old_npe} to {new_npe}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_npe=self._npe,
|
||||
new_npe=npe))
|
||||
self._npe = npe
|
||||
|
||||
@property
|
||||
@ -119,13 +147,18 @@ class C7200(Router):
|
||||
@midplane.setter
|
||||
def midplane(self, midplane):
|
||||
"""
|
||||
Set the midplane model.
|
||||
Sets the midplane model.
|
||||
|
||||
:returns: midplane model string (e.g. "vxr" or "std")
|
||||
"""
|
||||
|
||||
self._hypervisor.send("c7200 set_midplane {name} {midplane}".format(name=self._name,
|
||||
midplane=midplane))
|
||||
|
||||
log.info("router {name} [id={id}]: midplane updated from {old_midplane} to {new_midplane}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_midplane=self._midplane,
|
||||
new_midplane=midplane))
|
||||
self._midplane = midplane
|
||||
|
||||
@property
|
||||
@ -141,7 +174,7 @@ class C7200(Router):
|
||||
@sensors.setter
|
||||
def sensors(self, sensors):
|
||||
"""
|
||||
Set the 4 sensors with temperature in degree Celcius.
|
||||
Sets the 4 sensors with temperature in degree Celcius.
|
||||
|
||||
:param sensors: list of 4 sensor temperatures corresponding to
|
||||
sensor 1 = I/0 controller inlet
|
||||
@ -156,6 +189,13 @@ class C7200(Router):
|
||||
self._hypervisor.send("c7200 set_temp_sensor {name} {sensor_id} {temp}".format(name=self._name,
|
||||
sensor_id=sensor_id,
|
||||
temp=sensor))
|
||||
|
||||
log.info("router {name} [id={id}]: sensor {sensor_id} temperature updated from {old_temp}C to {new_temp}C".format(name=self._name,
|
||||
id=self._id,
|
||||
sensor_id=sensor_id,
|
||||
old_temp=self._sensors[sensor_id],
|
||||
new_temp=sensors[sensor_id]))
|
||||
|
||||
sensor_id += 1
|
||||
self._sensors = sensors
|
||||
|
||||
@ -172,7 +212,7 @@ class C7200(Router):
|
||||
@power_supplies.setter
|
||||
def power_supplies(self, power_supplies):
|
||||
"""
|
||||
Set the 2 power supplies with 0 = off, 1 = on.
|
||||
Sets the 2 power supplies with 0 = off, 1 = on.
|
||||
|
||||
:param power_supplies: list of 2 power supplies.
|
||||
Example: [1, 0] = first power supply is on, second is off.
|
||||
@ -183,5 +223,11 @@ class C7200(Router):
|
||||
self._hypervisor.send("c7200 set_power_supply {name} {power_supply_id} {powered_on}".format(name=self._name,
|
||||
power_supply_id=power_supply_id,
|
||||
powered_on=power_supply))
|
||||
|
||||
log.info("router {name} [id={id}]: power supply {power_supply_id} state updated to {powered_on}".format(name=self._name,
|
||||
id=self._id,
|
||||
power_supply_id=power_supply_id,
|
||||
powered_on=power_supply))
|
||||
power_supply_id += 1
|
||||
|
||||
self._power_supplies = power_supplies
|
||||
|
@ -24,6 +24,9 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L558
|
||||
from __future__ import unicode_literals
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EthernetSwitch(object):
|
||||
"""
|
||||
@ -33,15 +36,47 @@ class EthernetSwitch(object):
|
||||
:param name: name for this switch
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
_instance_count = 1
|
||||
|
||||
def __init__(self, hypervisor, name=None):
|
||||
|
||||
# create an unique ID
|
||||
self._id = EthernetSwitch._instance_count
|
||||
EthernetSwitch._instance_count += 1
|
||||
|
||||
# let's create a unique name if none has been chosen
|
||||
if not name:
|
||||
name = "SW" + str(self._id)
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("ethsw create {}".format(self._name))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 1
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this Ethernet switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
@ -101,6 +136,11 @@ class EthernetSwitch(object):
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("ethsw rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: renamed to {new_name}".format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
def delete(self):
|
||||
@ -109,6 +149,9 @@ class EthernetSwitch(object):
|
||||
"""
|
||||
|
||||
self._hypervisor.send("ethsw delete {}".format(self._name))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
@ -124,6 +167,11 @@ class EthernetSwitch(object):
|
||||
|
||||
self._hypervisor.send("ethsw add_nio {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
self._nios[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
@ -131,6 +179,8 @@ class EthernetSwitch(object):
|
||||
Removes the specified NIO as member of this Ethernet switch.
|
||||
|
||||
:param port: allocated port
|
||||
|
||||
:returns: the NIO that was bound to the port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
@ -139,14 +189,22 @@ class EthernetSwitch(object):
|
||||
nio = self._nios[port]
|
||||
self._hypervisor.send("ethsw remove_nio {name} {nio}".format(name=self._name,
|
||||
nio=nio))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._nios[port]
|
||||
|
||||
if port in self._mapping:
|
||||
del self._mapping[port]
|
||||
|
||||
return nio
|
||||
|
||||
def set_access_port(self, port, vlan_id):
|
||||
"""
|
||||
Set the specified port as an ACCESS port.
|
||||
Sets the specified port as an ACCESS port.
|
||||
|
||||
:param port: allocated port
|
||||
:param vlan_id: VLAN number membership
|
||||
@ -159,11 +217,16 @@ class EthernetSwitch(object):
|
||||
self._hypervisor.send("ethsw set_access_port {name} {nio} {vlan_id}".format(name=self._name,
|
||||
nio=nio,
|
||||
vlan_id=vlan_id))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: port {port} set as an access port in VLAN {vlan_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port,
|
||||
vlan_id=vlan_id))
|
||||
self._mapping[port] = ("access", vlan_id)
|
||||
|
||||
def set_dot1q_port(self, port, native_vlan):
|
||||
"""
|
||||
Set the specified port as a 802.1Q trunk port.
|
||||
Sets the specified port as a 802.1Q trunk port.
|
||||
|
||||
:param port: allocated port
|
||||
:param native_vlan: native VLAN for this trunk port
|
||||
@ -176,11 +239,17 @@ class EthernetSwitch(object):
|
||||
self._hypervisor.send("ethsw set_dot1q_port {name} {nio} {native_vlan}".format(name=self._name,
|
||||
nio=nio,
|
||||
native_vlan=native_vlan))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: port {port} set as a 802.1Q port with native VLAN {vlan_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port,
|
||||
vlan_id=native_vlan))
|
||||
|
||||
self._mapping[port] = ("dot1q", native_vlan)
|
||||
|
||||
def set_qinq_port(self, port, outer_vlan):
|
||||
"""
|
||||
Set the specified port as a trunk (QinQ) port.
|
||||
Sets the specified port as a trunk (QinQ) port.
|
||||
|
||||
:param port: allocated port
|
||||
:param outer_vlan: outer VLAN (transport VLAN) for this QinQ port
|
||||
@ -193,6 +262,11 @@ class EthernetSwitch(object):
|
||||
self._hypervisor.send("ethsw set_qinq_port {name} {nio} {outer_vlan}".format(name=self._name,
|
||||
nio=nio,
|
||||
outer_vlan=outer_vlan))
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: port {port} set as a QinQ port with outer VLAN {vlan_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
port=port,
|
||||
vlan_id=outer_vlan))
|
||||
self._mapping[port] = ("qinq", outer_vlan)
|
||||
|
||||
def get_mac_addr_table(self):
|
||||
|
@ -23,6 +23,9 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L642
|
||||
from __future__ import unicode_literals
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FrameRelaySwitch(object):
|
||||
"""
|
||||
@ -32,15 +35,47 @@ class FrameRelaySwitch(object):
|
||||
:param name: name for this switch
|
||||
"""
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
_instance_count = 1
|
||||
|
||||
def __init__(self, hypervisor, name=None):
|
||||
|
||||
# create an unique ID
|
||||
self._id = FrameRelaySwitch._instance_count
|
||||
FrameRelaySwitch._instance_count += 1
|
||||
|
||||
# let's create a unique name if none has been chosen
|
||||
if not name:
|
||||
name = "FR" + str(self._id)
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._hypervisor.send("frsw create {}".format(self._name))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 1
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this Frame Relay switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
@ -100,6 +135,11 @@ class FrameRelaySwitch(object):
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("frsw rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: renamed to {new_name}".format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
def delete(self):
|
||||
@ -108,8 +148,22 @@ class FrameRelaySwitch(object):
|
||||
"""
|
||||
|
||||
self._hypervisor.send("frsw delete {}".format(self._name))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
|
||||
def has_port(self, port):
|
||||
"""
|
||||
Checks if a port exists on this Frame Relay switch.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on Frame Relay switch.
|
||||
@ -121,6 +175,11 @@ class FrameRelaySwitch(object):
|
||||
if port in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
self._nios[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
@ -128,12 +187,21 @@ class FrameRelaySwitch(object):
|
||||
Removes the specified NIO as member of this Frame Relay switch.
|
||||
|
||||
:param port: allocated port
|
||||
|
||||
:returns: the NIO that was bound to the allocated port
|
||||
"""
|
||||
|
||||
if port not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port))
|
||||
|
||||
nio = self._nios[port]
|
||||
log.info("Frame Relay switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._nios[port]
|
||||
return nio
|
||||
|
||||
def map_vc(self, port1, dlci1, port2, dlci2):
|
||||
"""
|
||||
@ -159,6 +227,14 @@ class FrameRelaySwitch(object):
|
||||
input_dlci=dlci1,
|
||||
output_nio=nio2,
|
||||
output_dlci=dlci2))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: VC from port {port1} DLCI {dlci1} to port {port2} DLCI {dlci2} created".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
dlci1=dlci1,
|
||||
port2=port2,
|
||||
dlci2=dlci2))
|
||||
|
||||
self._mapping[(port1, dlci1)] = (port2, dlci2)
|
||||
|
||||
def unmap_vc(self, port1, dlci1, port2, dlci2):
|
||||
@ -185,4 +261,11 @@ class FrameRelaySwitch(object):
|
||||
input_dlci=dlci1,
|
||||
output_nio=nio2,
|
||||
output_dlci=dlci2))
|
||||
|
||||
log.info("Frame Relay switch {name} [id={id}]: VC from port {port1} DLCI {dlci1} to port {port2} DLCI {dlci2} deleted".format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
dlci1=dlci1,
|
||||
port2=port2,
|
||||
dlci2=dlci2))
|
||||
del self._mapping[(port1, dlci1)]
|
||||
|
@ -23,6 +23,9 @@ from __future__ import unicode_literals
|
||||
from .bridge import Bridge
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Hub(Bridge):
|
||||
"""
|
||||
@ -32,10 +35,41 @@ class Hub(Bridge):
|
||||
:param name: name for this hub
|
||||
"""
|
||||
|
||||
_instance_count = 1
|
||||
|
||||
def __init__(self, hypervisor, name):
|
||||
|
||||
Bridge.__init__(self, hypervisor, name)
|
||||
# create an unique ID
|
||||
self._id = Hub._instance_count
|
||||
Hub._instance_count += 1
|
||||
|
||||
# let's create a unique name if none has been chosen
|
||||
if not name:
|
||||
name = "Hub" + str(self._id)
|
||||
|
||||
self._mapping = {}
|
||||
Bridge.__init__(self, hypervisor, name)
|
||||
|
||||
log.info("Ethernet hub {name} [id={id}] has been created".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 1
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
Returns the unique ID for this Ethernet switch.
|
||||
|
||||
:returns: id (integer)
|
||||
"""
|
||||
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def mapping(self):
|
||||
@ -47,6 +81,15 @@ class Hub(Bridge):
|
||||
|
||||
return self._mapping
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this hub.
|
||||
"""
|
||||
|
||||
Bridge.delete(self)
|
||||
log.info("Ethernet hub {name} [id={id}] has been deleted".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
def add_nio(self, nio, port):
|
||||
"""
|
||||
Adds a NIO as new port on this hub.
|
||||
@ -59,6 +102,11 @@ class Hub(Bridge):
|
||||
raise DynamipsError("Port {} isn't free".format(port))
|
||||
|
||||
Bridge.add_nio(self, nio)
|
||||
|
||||
log.info("Ethernet hub {name} [id={id}]: NIO {nio} bound to port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
self._mapping[port] = nio
|
||||
|
||||
def remove_nio(self, port):
|
||||
@ -66,6 +114,8 @@ class Hub(Bridge):
|
||||
Removes the specified NIO as member of this hub.
|
||||
|
||||
:param port: allocated port
|
||||
|
||||
:returns: the NIO that was bound to the allocated port
|
||||
"""
|
||||
|
||||
if port not in self._mapping:
|
||||
@ -73,4 +123,11 @@ class Hub(Bridge):
|
||||
|
||||
nio = self._mapping[port]
|
||||
Bridge.remove_nio(self, nio)
|
||||
|
||||
log.info("Ethernet switch {name} [id={id}]: NIO {nio} removed from port {port}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port))
|
||||
|
||||
del self._mapping[port]
|
||||
return nio
|
||||
|
@ -24,29 +24,36 @@ from __future__ import unicode_literals
|
||||
from ..dynamips_error import DynamipsError
|
||||
import os
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Router(object):
|
||||
"""
|
||||
Dynamips router
|
||||
Dynamips router implementation.
|
||||
|
||||
:param hypervisor: Dynamips hypervisor object
|
||||
:param name: name for this router
|
||||
:param platform: c7200, c3745, c3725, c3600, c2691, c2600 or c1700
|
||||
:param console_flag: create console ports if True.
|
||||
:param ghost_flag: used when creating a ghost IOS.
|
||||
"""
|
||||
|
||||
_instance_count = 0
|
||||
_instance_count = 1
|
||||
_status = {0: "inactive",
|
||||
1: "shutting down",
|
||||
2: "running",
|
||||
3: "suspended"}
|
||||
|
||||
def __init__(self, hypervisor, name, platform="c7200", console_flag=True):
|
||||
def __init__(self, hypervisor, name=None, platform="c7200", ghost_flag=False):
|
||||
|
||||
# create an unique ID
|
||||
self._id = Router._instance_count
|
||||
Router._instance_count += 1
|
||||
|
||||
# let's create a unique name if none has been chosen
|
||||
if not name:
|
||||
name = "R" + str(self._id)
|
||||
|
||||
self._hypervisor = hypervisor
|
||||
self._name = '"' + name + '"' # put name into quotes to protect spaces
|
||||
self._platform = platform
|
||||
@ -76,12 +83,66 @@ class Router(object):
|
||||
id=self._id,
|
||||
platform=self._platform))
|
||||
|
||||
if console_flag:
|
||||
if not ghost_flag:
|
||||
log.info("router {platform} {name} [id={id}] has been created".format(name=self._name,
|
||||
platform=platform,
|
||||
id=self._id))
|
||||
self.console = self._hypervisor.baseconsole + self._id
|
||||
self.aux = self._hypervisor.baseaux + self._id
|
||||
else:
|
||||
log.info("creating a new ghost IOS file")
|
||||
Router._instance_count -= 1
|
||||
|
||||
self._hypervisor.devices.append(self)
|
||||
|
||||
@classmethod
|
||||
def reset(cls):
|
||||
"""
|
||||
Reset the instance count.
|
||||
"""
|
||||
|
||||
cls._instance_count = 1
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
Returns all the default base attribute values for routers.
|
||||
|
||||
:returns: default values (dictionary)
|
||||
"""
|
||||
|
||||
router_defaults = {"platform": self._platform,
|
||||
"image": self._image,
|
||||
"ram": self._ram,
|
||||
"nvram": self._nvram,
|
||||
"mmap": self._mmap,
|
||||
"sparsemem": self._sparsemem,
|
||||
"clock_divisor": self._clock_divisor,
|
||||
"idlepc": self._idlepc,
|
||||
"idlemax": self._idlemax,
|
||||
"idlesleep": self._idlesleep,
|
||||
"exec_area": self._exec_area,
|
||||
"jit_sharing_group": self._jit_sharing_group,
|
||||
"disk0": self._disk0,
|
||||
"disk1": self._disk1,
|
||||
"confreg": self._confreg,
|
||||
"console": self._console,
|
||||
"aux": self._aux,
|
||||
"mac_addr": self._mac_addr,
|
||||
"system_id": self._system_id}
|
||||
|
||||
slot_id = 0
|
||||
for slot in self._slots:
|
||||
if slot:
|
||||
slot = str(slot)
|
||||
router_defaults["slot" + str(slot_id)] = slot
|
||||
slot_id += 1
|
||||
|
||||
if self._slots[0] and self._slots[0].wics:
|
||||
for wic_slot_id in range(0, len(self._slots[0].wics)):
|
||||
router_defaults["wic" + str(wic_slot_id)] = None
|
||||
|
||||
return router_defaults
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
@ -151,6 +212,11 @@ class Router(object):
|
||||
new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
|
||||
self._hypervisor.send("vm rename {name} {new_name}".format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
log.info("router {name} [id={id}]: renamed to {new_name}".format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
def delete(self):
|
||||
@ -161,13 +227,19 @@ class Router(object):
|
||||
self._hypervisor.send("vm delete {}".format(self._name))
|
||||
self._hypervisor.devices.remove(self)
|
||||
|
||||
log.info("router {name} [id={id}] has been deleted".format(name=self._name, id=self._id))
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starts this router.
|
||||
At least the IOS image must be set.
|
||||
At least the IOS image must be set before starting it.
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm start {}".format(self._name))
|
||||
if self.get_status() == "suspended":
|
||||
self.resume()
|
||||
else:
|
||||
self._hypervisor.send("vm start {}".format(self._name))
|
||||
log.info("router {name} [id={id}] has been started".format(name=self._name, id=self._id))
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
@ -176,13 +248,16 @@ class Router(object):
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm stop {}".format(self._name))
|
||||
log.info("router {name} [id={id}] has been stopped".format(name=self._name, id=self._id))
|
||||
|
||||
def suspend(self):
|
||||
"""
|
||||
Suspends this router
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm suspend {}".format(self._name))
|
||||
if self.get_status() == "running":
|
||||
self._hypervisor.send("vm suspend {}".format(self._name))
|
||||
log.info("router {name} [id={id}] has been suspended".format(name=self._name, id=self._id))
|
||||
|
||||
def resume(self):
|
||||
"""
|
||||
@ -190,12 +265,13 @@ class Router(object):
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm resume {}".format(self._name))
|
||||
log.info("router {name} [id={id}] has been resumed".format(name=self._name, id=self._id))
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Returns the status of this router
|
||||
|
||||
:returns: 0=inactive, 1=shutting down, 2=running, 3=suspended
|
||||
:returns: inactive, shutting down, running or suspended.
|
||||
"""
|
||||
|
||||
status_id = int(self._hypervisor.send("vm get_status {}".format(self._name))[0])
|
||||
@ -225,7 +301,7 @@ class Router(object):
|
||||
@jit_sharing_group.setter
|
||||
def jit_sharing_group(self, group_id):
|
||||
"""
|
||||
Set the translation sharing group (unstable).
|
||||
Sets the translation sharing group (unstable).
|
||||
|
||||
:param group_id: translation sharing group ID
|
||||
"""
|
||||
@ -236,12 +312,16 @@ class Router(object):
|
||||
self._hypervisor.send("vm set_tsg {name} {group_id}".format(name=self._name,
|
||||
group_id=group_id))
|
||||
|
||||
log.info("router {name} [id={id}]: set in JIT sharing group {group_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
group_id=group_id))
|
||||
|
||||
self._jit_sharing_group = group_id
|
||||
self._hypervisor.add_jitsharing_group(os.path.basename(self._image), group_id)
|
||||
|
||||
def set_debug_level(self, level):
|
||||
"""
|
||||
Set the debug level for this router (default is 0).
|
||||
Sets the debug level for this router (default is 0).
|
||||
|
||||
:param level: level number
|
||||
"""
|
||||
@ -262,7 +342,7 @@ class Router(object):
|
||||
@image.setter
|
||||
def image(self, image):
|
||||
"""
|
||||
Set the IOS image for this router.
|
||||
Sets the IOS image for this router.
|
||||
There is no default.
|
||||
|
||||
:param image: path to IOS image file
|
||||
@ -271,11 +351,16 @@ class Router(object):
|
||||
# encase image in quotes to protect spaces in the path
|
||||
self._hypervisor.send("vm set_ios {name} {image}".format(name=self._name,
|
||||
image='"' + image + '"'))
|
||||
|
||||
log.info("router {name} [id={id}]: has a new IOS image set: {image}".format(name=self._name,
|
||||
id=self._id,
|
||||
image='"' + image + '"'))
|
||||
|
||||
self._image = image
|
||||
|
||||
def set_config(self, startup_config, private_config=''):
|
||||
"""
|
||||
Set the config files that are pushed to startup-config and
|
||||
Sets the config files that are pushed to startup-config and
|
||||
private-config in NVRAM when the instance is started.
|
||||
|
||||
:param startup_config: path to statup-config file
|
||||
@ -287,6 +372,15 @@ class Router(object):
|
||||
startup='"' + startup_config + '"',
|
||||
private='"' + private_config + '"'))
|
||||
|
||||
log.info("router {name} [id={id}]: has a startup-config set: {startup}".format(name=self._name,
|
||||
id=self._id,
|
||||
startup='"' + startup_config + '"'))
|
||||
|
||||
if private_config:
|
||||
log.info("router {name} [id={id}]: has a private-config set: {private}".format(name=self._name,
|
||||
id=self._id,
|
||||
private='"' + private_config + '"'))
|
||||
|
||||
def extract_config(self):
|
||||
"""
|
||||
Gets the contents of the config files
|
||||
@ -318,6 +412,13 @@ class Router(object):
|
||||
startup=startup_config,
|
||||
private=private_config))
|
||||
|
||||
log.info("router {name} [id={id}]: new startup-config pushed".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
if private_config != '(keep)':
|
||||
log.info("router {name} [id={id}]: new private-config pushed".format(name=self._name,
|
||||
id=self._id))
|
||||
|
||||
@property
|
||||
def ram(self):
|
||||
"""
|
||||
@ -331,13 +432,22 @@ class Router(object):
|
||||
@ram.setter
|
||||
def ram(self, ram):
|
||||
"""
|
||||
Set amount of RAM allocated to this router
|
||||
Sets amount of RAM allocated to this router
|
||||
|
||||
:param ram: amount of RAM in Mbytes (integer)
|
||||
"""
|
||||
|
||||
if self._ram == ram:
|
||||
return
|
||||
|
||||
self._hypervisor.send("vm set_ram {name} {ram}".format(name=self._name,
|
||||
ram=self._ram))
|
||||
ram=ram))
|
||||
|
||||
log.info("router {name} [id={id}]: RAM updated from {old_ram}MB to {new_ram}MB".format(name=self._name,
|
||||
id=self._id,
|
||||
old_ram=self._ram,
|
||||
new_ram=ram))
|
||||
|
||||
self._hypervisor.decrease_memory_load(self._ram)
|
||||
self._ram = ram
|
||||
self._hypervisor.increase_memory_load(self._ram)
|
||||
@ -355,13 +465,21 @@ class Router(object):
|
||||
@nvram.setter
|
||||
def nvram(self, nvram):
|
||||
"""
|
||||
Set amount of NVRAM allocated to this router
|
||||
Sets amount of NVRAM allocated to this router
|
||||
|
||||
:param nvram: amount of NVRAM in Kbytes (integer)
|
||||
"""
|
||||
|
||||
if self._nvram == nvram:
|
||||
return
|
||||
|
||||
self._hypervisor.send("vm set_nvram {name} {nvram}".format(name=self._name,
|
||||
nvram=self._nvram))
|
||||
nvram=nvram))
|
||||
|
||||
log.info("router {name} [id={id}]: NVRAM updated from {old_nvram}KB to {new_nvram}KB".format(name=self._name,
|
||||
id=self._id,
|
||||
old_nvram=self._nvram,
|
||||
new_nvram=nvram))
|
||||
self._nvram = nvram
|
||||
|
||||
@property
|
||||
@ -389,6 +507,13 @@ class Router(object):
|
||||
flag = 0
|
||||
self._hypervisor.send("vm set_ram_mmap {name} {mmap}".format(name=self._name,
|
||||
mmap=flag))
|
||||
|
||||
if mmap:
|
||||
log.info("router {name} [id={id}]: mmap enabled".format(name=self._name,
|
||||
id=self._id))
|
||||
else:
|
||||
log.info("router {name} [id={id}]: mmap disabled".format(name=self._name,
|
||||
id=self._id))
|
||||
self._mmap = mmap
|
||||
|
||||
@property
|
||||
@ -415,6 +540,13 @@ class Router(object):
|
||||
flag = 0
|
||||
self._hypervisor.send("vm set_sparse_mem {name} {sparsemem}".format(name=self._name,
|
||||
sparsemem=flag))
|
||||
|
||||
if sparsemem:
|
||||
log.info("router {name} [id={id}]: sparse memory enabled".format(name=self._name,
|
||||
id=self._id))
|
||||
else:
|
||||
log.info("router {name} [id={id}]: sparse memory disabled".format(name=self._name,
|
||||
id=self._id))
|
||||
self._sparsemem = sparsemem
|
||||
|
||||
@property
|
||||
@ -430,7 +562,7 @@ class Router(object):
|
||||
@clock_divisor.setter
|
||||
def clock_divisor(self, clock_divisor):
|
||||
"""
|
||||
Set the clock divisor value. The higher is the value, the faster is the clock in the
|
||||
Sets the clock divisor value. The higher is the value, the faster is the clock in the
|
||||
virtual machine. The default is 4, but it is often required to adjust it.
|
||||
|
||||
:param clock_divisor: clock divisor value (integer)
|
||||
@ -438,6 +570,11 @@ class Router(object):
|
||||
|
||||
self._hypervisor.send("vm set_clock_divisor {name} {clock}".format(name=self._name,
|
||||
clock=clock_divisor))
|
||||
|
||||
log.info("router {name} [id={id}]: clock divisor updated from {old_clock} to {new_clock}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_clock=self._clock_divisor,
|
||||
new_clock=clock_divisor))
|
||||
self._clock_divisor = clock_divisor
|
||||
|
||||
@property
|
||||
@ -453,7 +590,7 @@ class Router(object):
|
||||
@idlepc.setter
|
||||
def idlepc(self, idlepc):
|
||||
"""
|
||||
Set the idle Pointer Counter (PC)
|
||||
Sets the idle Pointer Counter (PC)
|
||||
|
||||
:param idlepc: idlepc value (string)
|
||||
"""
|
||||
@ -465,6 +602,11 @@ class Router(object):
|
||||
else:
|
||||
self._hypervisor.send("vm set_idle_pc_online {name} 0 {idlepc}".format(name=self._name,
|
||||
idlepc=idlepc))
|
||||
|
||||
log.info("router {name} [id={id}]: idle-PC set to {idlepc}".format(name=self._name,
|
||||
id=self._id,
|
||||
idlepc=idlepc))
|
||||
|
||||
self._idlepc = idlepc
|
||||
|
||||
def get_idle_pc_prop(self):
|
||||
@ -500,7 +642,7 @@ class Router(object):
|
||||
@idlemax.setter
|
||||
def idlemax(self, idlemax):
|
||||
"""
|
||||
Set CPU idle max value
|
||||
Sets CPU idle max value
|
||||
|
||||
:param idlemax: idle max value (integer)
|
||||
"""
|
||||
@ -508,6 +650,12 @@ class Router(object):
|
||||
if self.is_running(): # router is running
|
||||
self._hypervisor.send("vm set_idle_max {name} 0 {idlemax}".format(name=self._name,
|
||||
idlemax=idlemax))
|
||||
|
||||
log.info("router {name} [id={id}]: idlemax updated from {old_idlemax} to {new_idlemax}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_idlemax=self._idlemax,
|
||||
new_idlemax=idlemax))
|
||||
|
||||
self._idlemax = idlemax
|
||||
|
||||
@property
|
||||
@ -523,7 +671,7 @@ class Router(object):
|
||||
@idlesleep.setter
|
||||
def idlesleep(self, idlesleep):
|
||||
"""
|
||||
Set CPU idle sleep time value.
|
||||
Sets CPU idle sleep time value.
|
||||
|
||||
:param idlesleep: idle sleep value (integer)
|
||||
"""
|
||||
@ -531,6 +679,12 @@ class Router(object):
|
||||
if self.is_running(): # router is running
|
||||
self._hypervisor.send("vm set_idle_sleep_time {name} 0 {idlesleep}".format(name=self._name,
|
||||
idlesleep=idlesleep))
|
||||
|
||||
log.info("router {name} [id={id}]: idlesleep updated from {old_idlesleep} to {new_idlesleep}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_idlesleep=self._idlesleep,
|
||||
new_idlesleep=idlesleep))
|
||||
|
||||
self._idlesleep = idlesleep
|
||||
|
||||
def show_timer_drift(self):
|
||||
@ -555,16 +709,21 @@ class Router(object):
|
||||
@ghost_file.setter
|
||||
def ghost_file(self, ghost_file):
|
||||
"""
|
||||
Set ghost RAM file
|
||||
Sets ghost RAM file
|
||||
|
||||
:ghost_file: path to ghost file
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm set_ghost_file {name} {ghost_file}".format(name=self._name,
|
||||
ghost_file=ghost_file))
|
||||
|
||||
log.info("router {name} [id={id}]: ghost file set to {ghost_file}".format(name=self._name,
|
||||
id=self._id,
|
||||
ghost_file=ghost_file))
|
||||
|
||||
self._ghost_file = ghost_file
|
||||
|
||||
# If this is a ghost instance, track this as a hosted ghost instance by this hypervisor
|
||||
# if this is a ghost instance, track this as a hosted ghost instance by this hypervisor
|
||||
if self.ghost_status == 1:
|
||||
self._hypervisor.add_ghost(ghost_file, self)
|
||||
|
||||
@ -575,8 +734,8 @@ class Router(object):
|
||||
:returns: formatted ghost_file name (string)
|
||||
"""
|
||||
|
||||
# Replace specials characters in 'drive:\filename' in Linux and Dynamips in MS Windows or viceversa.
|
||||
ghost_file = os.path.basename(self._image) + '-' + self._hypervisor.host + '.ghost'
|
||||
# replace specials characters in 'drive:\filename' in Linux and Dynamips in MS Windows or viceversa.
|
||||
ghost_file = "{}-{}.ghost".format(os.path.basename(self._image), self._ram)
|
||||
ghost_file = ghost_file.replace('\\', '-').replace('/', '-').replace(':', '-')
|
||||
return ghost_file
|
||||
|
||||
@ -592,7 +751,7 @@ class Router(object):
|
||||
@ghost_status.setter
|
||||
def ghost_status(self, ghost_status):
|
||||
"""
|
||||
Set ghost RAM status
|
||||
Sets ghost RAM status
|
||||
|
||||
:param ghost_status: state flag indicating status
|
||||
0 => Do not use IOS ghosting
|
||||
@ -602,6 +761,10 @@ class Router(object):
|
||||
|
||||
self._hypervisor.send("vm set_ghost_status {name} {ghost_status}".format(name=self._name,
|
||||
ghost_status=ghost_status))
|
||||
|
||||
log.info("router {name} [id={id}]: ghost status set to {ghost_status}".format(name=self._name,
|
||||
id=self._id,
|
||||
ghost_status=ghost_status))
|
||||
self._ghost_status = ghost_status
|
||||
|
||||
@property
|
||||
@ -617,7 +780,7 @@ class Router(object):
|
||||
@exec_area.setter
|
||||
def exec_area(self, exec_area):
|
||||
"""
|
||||
Set the exec area value.
|
||||
Sets the exec area value.
|
||||
The exec area is a pool of host memory used to store pages
|
||||
translated by the JIT (they contain the native code
|
||||
corresponding to MIPS code pages).
|
||||
@ -627,6 +790,11 @@ class Router(object):
|
||||
|
||||
self._hypervisor.send("vm set_exec_area {name} {exec_area}".format(name=self._name,
|
||||
exec_area=exec_area))
|
||||
|
||||
log.info("router {name} [id={id}]: exec area updated from {old_exec}MB to {new_exec}MB".format(name=self._name,
|
||||
id=self._id,
|
||||
old_exec=self._exec_area,
|
||||
new_exec=exec_area))
|
||||
self._exec_area = exec_area
|
||||
|
||||
@property
|
||||
@ -642,13 +810,18 @@ class Router(object):
|
||||
@disk0.setter
|
||||
def disk0(self, disk0):
|
||||
"""
|
||||
Set the size (MB) for PCMCIA disk0.
|
||||
Sets the size (MB) for PCMCIA disk0.
|
||||
|
||||
:param disk0: disk0 size (integer)
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm set_disk0 {name} {disk0}".format(name=self._name,
|
||||
disk0=disk0))
|
||||
|
||||
log.info("router {name} [id={id}]: disk0 updated from {old_disk0}MB to {new_disk0}MB".format(name=self._name,
|
||||
id=self._id,
|
||||
old_disk0=self._disk0,
|
||||
new_disk0=disk0))
|
||||
self._disk0 = disk0
|
||||
|
||||
@property
|
||||
@ -664,13 +837,18 @@ class Router(object):
|
||||
@disk1.setter
|
||||
def disk1(self, disk1):
|
||||
"""
|
||||
Set the size (MB) for PCMCIA disk1.
|
||||
Sets the size (MB) for PCMCIA disk1.
|
||||
|
||||
:param disk1: disk1 size (integer)
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm set_disk1 {name} {disk1}".format(name=self._name,
|
||||
disk1=disk1))
|
||||
|
||||
log.info("router {name} [id={id}]: disk1 updated from {old_disk1}MB to {new_disk1}MB".format(name=self._name,
|
||||
id=self._id,
|
||||
old_disk1=self._disk1,
|
||||
new_disk1=disk1))
|
||||
self._disk1 = disk1
|
||||
|
||||
@property
|
||||
@ -687,13 +865,18 @@ class Router(object):
|
||||
@confreg.setter
|
||||
def confreg(self, confreg):
|
||||
"""
|
||||
Set the configuration register.
|
||||
Sets the configuration register.
|
||||
|
||||
:param confreg: configuration register value (string)
|
||||
"""
|
||||
|
||||
self._hypervisor.send("vm set_conf_reg {name} {confreg}".format(name=self._name,
|
||||
confreg=confreg))
|
||||
|
||||
log.info("router {name} [id={id}]: confreg updated from {old_confreg} to {new_confreg}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_confreg=self._confreg,
|
||||
new_confreg=confreg))
|
||||
self._confreg = confreg
|
||||
|
||||
@property
|
||||
@ -709,7 +892,7 @@ class Router(object):
|
||||
@console.setter
|
||||
def console(self, console):
|
||||
"""
|
||||
Set the TCP console port.
|
||||
Sets the TCP console port.
|
||||
|
||||
:param console: console port (integer)
|
||||
"""
|
||||
@ -719,6 +902,11 @@ class Router(object):
|
||||
|
||||
self._hypervisor.send("vm set_con_tcp_port {name} {console}".format(name=self._name,
|
||||
console=console))
|
||||
|
||||
log.info("router {name} [id={id}]: console port updated from {old_console} to {new_console}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_console=self._console,
|
||||
new_console=console))
|
||||
self._console = console
|
||||
|
||||
@property
|
||||
@ -734,7 +922,7 @@ class Router(object):
|
||||
@aux.setter
|
||||
def aux(self, aux):
|
||||
"""
|
||||
Set the TCP auxiliary port.
|
||||
Sets the TCP auxiliary port.
|
||||
|
||||
:param aux: console auxiliary port (integer)
|
||||
"""
|
||||
@ -744,6 +932,11 @@ class Router(object):
|
||||
|
||||
self._hypervisor.send("vm set_aux_tcp_port {name} {aux}".format(name=self._name,
|
||||
aux=aux))
|
||||
|
||||
log.info("router {name} [id={id}]: aux port updated from {old_aux} to {new_aux}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_aux=self._aux,
|
||||
new_aux=aux))
|
||||
self._aux = aux
|
||||
|
||||
def get_cpu_info(self, cpu_id=0):
|
||||
@ -801,7 +994,7 @@ class Router(object):
|
||||
@mac_addr.setter
|
||||
def mac_addr(self, mac_addr):
|
||||
"""
|
||||
Set the MAC address.
|
||||
Sets the MAC address.
|
||||
|
||||
:param mac_addr: a MAC address (hexadecimal format: hh:hh:hh:hh:hh:hh)
|
||||
"""
|
||||
@ -809,6 +1002,11 @@ class Router(object):
|
||||
self._hypervisor.send("{platform} set_mac_addr {name} {mac_addr}".format(platform=self._platform,
|
||||
name=self._name,
|
||||
mac_addr=mac_addr))
|
||||
|
||||
log.info("router {name} [id={id}]: MAC address updated from {old_mac} to {new_mac}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_mac=self._mac_addr,
|
||||
new_mac=mac_addr))
|
||||
self._mac_addr = mac_addr
|
||||
|
||||
@property
|
||||
@ -824,7 +1022,7 @@ class Router(object):
|
||||
@system_id.setter
|
||||
def system_id(self, system_id):
|
||||
"""
|
||||
Set the system ID.
|
||||
Sets the system ID.
|
||||
|
||||
:param system_id: a system ID (also called board processor ID)
|
||||
"""
|
||||
@ -832,6 +1030,11 @@ class Router(object):
|
||||
self._hypervisor.send("{platform} set_system_id {name} {system_id}".format(platform=self._platform,
|
||||
name=self._name,
|
||||
system_id=system_id))
|
||||
|
||||
log.info("router {name} [id={id}]: system ID updated from {old_id} to {new_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
old_id=self._system_id,
|
||||
new_id=system_id))
|
||||
self._system_id = system_id
|
||||
|
||||
def get_hardware_info(self):
|
||||
@ -841,7 +1044,7 @@ class Router(object):
|
||||
:returns: ? (could not test)
|
||||
"""
|
||||
|
||||
# FIXME: nothing returned by Dynamips.
|
||||
# FIXME: nothing returned by Dynamips.
|
||||
return (self._hypervisor.send("{platform} show_hardware {name}".format(platform=self._platform,
|
||||
name=self._name)))
|
||||
|
||||
@ -856,7 +1059,7 @@ class Router(object):
|
||||
|
||||
def slot_add_binding(self, slot_id, adapter):
|
||||
"""
|
||||
Adds a slot binding.
|
||||
Adds a slot binding (a module into a slot).
|
||||
|
||||
:param slot_id: slot ID
|
||||
:param adapter: device to add in the corresponding slot (object)
|
||||
@ -877,6 +1080,12 @@ class Router(object):
|
||||
self._hypervisor.send("vm slot_add_binding {name} {slot_id} 0 {adapter}".format(name=self._name,
|
||||
slot_id=slot_id,
|
||||
adapter=adapter))
|
||||
|
||||
log.info("router {name} [id={id}]: adapter {adapter} inserted into slot {slot_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
adapter=adapter,
|
||||
slot_id=slot_id))
|
||||
|
||||
self._slots[slot_id] = adapter
|
||||
|
||||
# Generate an OIR event if the router is running and
|
||||
@ -888,33 +1097,48 @@ class Router(object):
|
||||
self._hypervisor.send("vm slot_oir_start {name} {slot_id} 0".format(name=self._name,
|
||||
slot_id=slot_id))
|
||||
|
||||
log.info("router {name} [id={id}]: OIR start event sent to slot {slot_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
slot_id=slot_id))
|
||||
|
||||
def slot_remove_binding(self, slot_id):
|
||||
"""
|
||||
Removes a slot binding.
|
||||
Removes a slot binding (a module from a slot).
|
||||
|
||||
:param slot_id: slot ID
|
||||
"""
|
||||
|
||||
try:
|
||||
slot = self._slots[slot_id]
|
||||
adapter = self._slots[slot_id]
|
||||
except IndexError:
|
||||
raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name,
|
||||
slot_id=slot_id))
|
||||
|
||||
if slot == None:
|
||||
if adapter == None:
|
||||
return
|
||||
|
||||
#FIXME: check if adapter can be removed!
|
||||
|
||||
# Generate an OIR event if the router is running and
|
||||
# only for c7200, c3600 and c3745 (NM-4T only)
|
||||
if self.is_running() and self._platform == 'c7200' \
|
||||
or (self._platform == 'c3600' and self.chassis == '3660') \
|
||||
or (self._platform == 'c3745' and slot == 'NM-4T'):
|
||||
or (self._platform == 'c3745' and adapter == 'NM-4T'):
|
||||
|
||||
self._hypervisor.send("vm slot_oir_stop {name} {slot_id} 0".format(name=self._name,
|
||||
slot_id=slot_id))
|
||||
|
||||
log.info("router {name} [id={id}]: OIR stop event sent to slot {slot_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
slot_id=slot_id))
|
||||
|
||||
self._hypervisor.send("vm slot_remove_binding {name} {slot_id} 0".format(name=self._name,
|
||||
slot_id=slot_id))
|
||||
slot_id=slot_id))
|
||||
|
||||
log.info("router {name} [id={id}]: adapter {adapter} removed from slot {slot_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
adapter=adapter,
|
||||
slot_id=slot_id))
|
||||
self._slots[slot_id] = None
|
||||
|
||||
def install_wic(self, wic_slot_id, wic):
|
||||
@ -947,6 +1171,12 @@ class Router(object):
|
||||
slot_id=slot_id,
|
||||
wic_slot_id=internal_wic_slot_id,
|
||||
wic=wic))
|
||||
|
||||
log.info("router {name} [id={id}]: {wic} inserted into WIC slot {wic_slot_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
wic=wic,
|
||||
wic_slot_id=wic_slot_id))
|
||||
|
||||
adapter.install_wic(wic_slot_id, wic)
|
||||
|
||||
def uninstall_wic(self, wic_slot_id):
|
||||
@ -976,6 +1206,11 @@ class Router(object):
|
||||
self._hypervisor.send("vm slot_remove_binding {name} {slot_id} {wic_slot_id}".format(name=self._name,
|
||||
slot_id=slot_id,
|
||||
wic_slot_id=internal_wic_slot_id))
|
||||
|
||||
log.info("router {name} [id={id}]: {wic} removed from WIC slot {wic_slot_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
wic=adapter.wics[wic_slot_id],
|
||||
wic_slot_id=wic_slot_id))
|
||||
adapter.uninstall_wic(wic_slot_id)
|
||||
|
||||
def get_slot_nio_bindings(self, slot_id):
|
||||
@ -1012,6 +1247,13 @@ class Router(object):
|
||||
slot_id=slot_id,
|
||||
port_id=port_id,
|
||||
nio=nio))
|
||||
|
||||
log.info("router {name} [id={id}]: NIO {nio_name} bound to port {slot_id}/{port_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio_name=nio.name,
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
|
||||
self.slot_enable_nio(slot_id, port_id)
|
||||
adapter.add_nio(port_id, nio)
|
||||
|
||||
@ -1021,6 +1263,8 @@ class Router(object):
|
||||
|
||||
:param slot_id: slot ID
|
||||
:param port_id: port ID
|
||||
|
||||
:returns: removed NIO object
|
||||
"""
|
||||
|
||||
try:
|
||||
@ -1033,12 +1277,21 @@ class Router(object):
|
||||
port_id=port_id))
|
||||
|
||||
self.slot_disable_nio(slot_id, port_id)
|
||||
self._hypervisor.send("vm slot_remove_binding {name} {slot_id} {port_id}".format(name=self._name,
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
self._hypervisor.send("vm slot_remove_nio_binding {name} {slot_id} {port_id}".format(name=self._name,
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
|
||||
nio = adapter.get_nio(port_id)
|
||||
adapter.remove_nio(port_id)
|
||||
|
||||
log.info("router {name} [id={id}]: NIO {nio_name} removed from port {slot_id}/{port_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
nio_name=nio.name,
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
|
||||
return nio
|
||||
|
||||
def slot_enable_nio(self, slot_id, port_id):
|
||||
"""
|
||||
Enables a slot NIO binding.
|
||||
@ -1052,6 +1305,11 @@ class Router(object):
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
|
||||
log.info("router {name} [id={id}]: NIO enabled on port {slot_id}/{port_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
|
||||
def slot_disable_nio(self, slot_id, port_id):
|
||||
"""
|
||||
Disables a slot NIO binding.
|
||||
@ -1065,6 +1323,11 @@ class Router(object):
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
|
||||
log.info("router {name} [id={id}]: NIO disabled on port {slot_id}/{port_id}".format(name=self._name,
|
||||
id=self._id,
|
||||
slot_id=slot_id,
|
||||
port_id=port_id))
|
||||
|
||||
def _create_slots(self, numslots):
|
||||
"""
|
||||
Creates the appropriate number of slots for this router.
|
||||
|
@ -84,7 +84,7 @@ class Server(object):
|
||||
tornado_app = tornado.web.Application(self.handlers, debug=True) # FIXME: debug mode!
|
||||
try:
|
||||
print("Starting server on port {}".format(self._port))
|
||||
tornado_app.listen(self._port)
|
||||
tornado_app.listen(self._port, address=self._host)
|
||||
except socket.error as e:
|
||||
if e.errno == errno.EADDRINUSE: # socket already in use
|
||||
logging.critical("socket in use for port {}".format(self._port))
|
||||
@ -92,7 +92,7 @@ class Server(object):
|
||||
|
||||
ioloop = tornado.ioloop.IOLoop.instance()
|
||||
stream = zmqstream.ZMQStream(router, ioloop)
|
||||
stream.on_recv(JSONRPCWebSocket.dispatch_message)
|
||||
stream.on_recv_stream(JSONRPCWebSocket.dispatch_message)
|
||||
tornado.autoreload.add_reload_hook(functools.partial(self._cleanup, stop=False))
|
||||
|
||||
def signal_handler(signum=None, frame=None):
|
||||
|
@ -1,49 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2013 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 networkx as nx
|
||||
|
||||
|
||||
class Topology(object):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
pass
|
||||
#self._topology = nx.Graph()
|
||||
|
||||
def add_node(self, node):
|
||||
|
||||
self._topology.add_node(node)
|
||||
|
||||
def remove_node(self, node):
|
||||
|
||||
self._topology.remove_node(node)
|
||||
|
||||
def clear(self):
|
||||
|
||||
self._topology.clear()
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return "GNS3 network topology"
|
||||
|
||||
@staticmethod
|
||||
def instance():
|
||||
|
||||
if not hasattr(Topology, "_instance"):
|
||||
Topology._instance = Topology()
|
||||
return Topology._instance
|
@ -1,2 +1,3 @@
|
||||
tornado
|
||||
pyzmq
|
||||
netifaces-py3
|
||||
|
@ -36,7 +36,7 @@ class JSONRPC(AsyncTestCase):
|
||||
|
||||
def test_request_with_invalid_version(self):
|
||||
|
||||
request = {"jsonrpc": "1.0", "method": "dynamips.echo", "id": 1}
|
||||
request = {"jsonrpc": 1.0, "method": "dynamips.echo", "id": 1}
|
||||
AsyncWSRequest(self.URL, self.io_loop, self.stop, json_encode(request))
|
||||
response = self.wait()
|
||||
json_response = json_decode(response)
|
||||
|
Loading…
Reference in New Issue
Block a user