Move cloud code (module independent) to a builtin package.

This commit is contained in:
grossmj 2014-05-07 19:31:53 -06:00
parent 44bcc94e3e
commit c0a876af68
8 changed files with 131 additions and 68 deletions

View File

@ -0,0 +1,78 @@
# -*- 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/>.
"""
Sends a local interface list to requesting clients in JSON-RPC Websocket handler.
"""
import sys
from ..jsonrpc import JSONRPCResponse
from ..jsonrpc import JSONRPCCustomError
import logging
log = logging.getLogger(__name__)
def _get_windows_interfaces():
"""
Get Windows interfaces.
:returns: list of windows interfaces
"""
import win32com.client
locator = win32com.client.Dispatch("WbemScripting.SWbemLocator")
service = locator.ConnectServer(".", "root\cimv2")
interfaces = []
# more info on Win32_NetworkAdapter: http://msdn.microsoft.com/en-us/library/aa394216%28v=vs.85%29.aspx
for adapter in service.InstancesOf("Win32_NetworkAdapter"):
if adapter.NetConnectionStatus == 2 or adapter.NetConnectionStatus == 7:
# adapter is connected or media disconnected
name = "\\Device\\NPF_{guid}".format(guid=adapter.GUID)
interfaces.append({"name": name,
"description": adapter.NetConnectionID})
return interfaces
def interfaces(handler, request_id, params):
"""
Builtin destination to return all the network interfaces on this host.
:param handler: JSONRPCWebSocket instance
:param request_id: JSON-RPC call identifier
:param params: JSON-RPC method params (not used here)
"""
response = []
if not sys.platform.startswith("win"):
try:
import netifaces
for interface in netifaces.interfaces():
response.append({"name": interface})
except ImportError:
message = "Optional netifaces module is not installed, please install it on the server to get the available interface names: sudo pip3 install netifaces-py3"
handler.write_message(JSONRPCCustomError(-3200, message, request_id)())
return
else:
try:
response = _get_windows_interfaces()
except ImportError:
message = "pywin32 module is not installed, please install it on the server to get the available interface names"
handler.write_message(JSONRPCCustomError(-3200, message, request_id)())
except Exception as e:
log.error("uncaught exception {type}".format(type=type(e)), exc_info=1)
handler.write_message(JSONRPCResponse(response, request_id)())

View File

@ -0,0 +1,36 @@
# -*- 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/>.
"""
Sends version to requesting clients in JSON-RPC Websocket handler.
"""
from ..version import __version__
from ..jsonrpc import JSONRPCResponse
def server_version(handler, request_id, params):
"""
Builtin destination to return the server version.
:param handler: JSONRPCWebSocket instance
:param request_id: JSON-RPC call identifier
:param params: JSON-RPC method params (not used here)
"""
json_message = {"version": __version__}
handler.write_message(JSONRPCResponse(json_message, request_id)())

View File

@ -23,8 +23,6 @@ import zmq
import uuid import uuid
import tornado.websocket import tornado.websocket
from tornado.escape import json_decode from tornado.escape import json_decode
from ..version import __version__
from ..jsonrpc import JSONRPCResponse
from ..jsonrpc import JSONRPCParseError from ..jsonrpc import JSONRPCParseError
from ..jsonrpc import JSONRPCInvalidRequest from ..jsonrpc import JSONRPCInvalidRequest
from ..jsonrpc import JSONRPCMethodNotFound from ..jsonrpc import JSONRPCMethodNotFound
@ -53,20 +51,6 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
self._session_id = str(uuid.uuid4()) self._session_id = str(uuid.uuid4())
self.zmq_router = zmq_router self.zmq_router = zmq_router
# special built-in to return the server version
self.register_destination("builtin.version", self._server_version)
def _server_version(self, request_id, params):
"""
Builtin destination to return the server version.
:param request_id: JSON-RPC call identifier
:param params: JSON-RPC method params (not used here)
"""
json_message = {"version": __version__}
self.write_message(JSONRPCResponse(json_message, request_id)())
@property @property
def session_id(self): def session_id(self):
""" """
@ -116,14 +100,13 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
:param module: module string :param module: module string
""" """
if destination.startswith("builtin") and destination in cls.destinations:
# ignore new built-in destination registration if already registered
return
# Make sure the destination is not already registered # Make sure the destination is not already registered
# by another module for instance # by another module for instance
assert destination not in cls.destinations assert destination not in cls.destinations
log.debug("registering {} as a destination for the {} module".format(destination, if destination.startswith("builtin"):
log.debug("registering {} as a built-in destination".format(destination))
else:
log.debug("registering {} as a destination for the {} module".format(destination,
module)) module))
cls.destinations[destination] = module cls.destinations[destination] = module
@ -169,7 +152,7 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler):
if method.startswith("builtin") and request_id: if method.startswith("builtin") and request_id:
log.info("calling built-in method {}".format(method)) log.info("calling built-in method {}".format(method))
self.destinations[method](request_id, request.get("params")) self.destinations[method](self, request_id, request.get("params"))
return return
module = self.destinations[method] module = self.destinations[method]

View File

@ -459,48 +459,3 @@ class Dynamips(IModule):
except OSError as e: except OSError as e:
raise DynamipsError("Could not save the configuration {}: {}".format(config_path, e)) raise DynamipsError("Could not save the configuration {}: {}".format(config_path, e))
return "configs" + os.sep + os.path.basename(config_path) return "configs" + os.sep + os.path.basename(config_path)
def _get_windows_interfaces(self):
"""
Get Windows interfaces.
:returns: list of windows interfaces
"""
import win32com.client
locator = win32com.client.Dispatch("WbemScripting.SWbemLocator")
service = locator.ConnectServer(".", "root\cimv2")
interfaces = []
# more info on Win32_NetworkAdapter: http://msdn.microsoft.com/en-us/library/aa394216%28v=vs.85%29.aspx
for adapter in service.InstancesOf("Win32_NetworkAdapter"):
if adapter.NetConnectionStatus == 2 or adapter.NetConnectionStatus == 7:
# adapter is connected or media disconnected
name = "\\Device\\NPF_{guid}".format(guid=adapter.GUID)
interfaces.append({"name": name,
"description": adapter.NetConnectionID})
return interfaces
@IModule.route("dynamips.nio.get_interfaces")
def nio_get_interfaces(self, request):
"""
Get all the network interfaces on this host.
:param request: JSON request
"""
response = []
if not sys.platform.startswith("win"):
try:
import netifaces
for interface in netifaces.interfaces():
response.append({"name": interface})
except ImportError:
self.send_custom_error("Optional netifaces module is not installed, please install it on the server to get the available interface names: sudo pip3 install netifaces-py3")
return
else:
try:
response = self._get_windows_interfaces()
except ImportError:
self.send_custom_error("pywin32 module is not installed, please install it on the server to get the available interface names")
return
self.send_response(response)

View File

@ -98,6 +98,10 @@ IOU_UPDATE_SCHEMA = {
"maximum": 65535, "maximum": 65535,
"type": "integer" "type": "integer"
}, },
"use_default_iou_values": {
"description": "use the default IOU RAM & NVRAM values",
"type": "boolean"
},
"startup_config_base64": { "startup_config_base64": {
"description": "startup configuration base64 encoded", "description": "startup configuration base64 encoded",
"type": "string" "type": "string"

View File

@ -39,6 +39,8 @@ from .config import Config
from .handlers.jsonrpc_websocket import JSONRPCWebSocket from .handlers.jsonrpc_websocket import JSONRPCWebSocket
from .handlers.version_handler import VersionHandler from .handlers.version_handler import VersionHandler
from .handlers.file_upload_handler import FileUploadHandler from .handlers.file_upload_handler import FileUploadHandler
from .builtins.server_version import server_version
from .builtins.interfaces import interfaces
from .modules import MODULES from .modules import MODULES
import logging import logging
@ -115,6 +117,11 @@ class Server(object):
# instance.start() # starts the new process # instance.start() # starts the new process
#======================================================================= #=======================================================================
# special built-in to return the server version
JSONRPCWebSocket.register_destination("builtin.version", server_version)
# special built-in to return the available interfaces on this host
JSONRPCWebSocket.register_destination("builtin.interfaces", interfaces)
for module in MODULES: for module in MODULES:
instance = module(module.__name__.lower(), instance = module(module.__name__.lower(),
"127.0.0.1", # ZeroMQ server address "127.0.0.1", # ZeroMQ server address

View File

@ -23,5 +23,5 @@
# or negative for a release candidate or beta (after the base version # or negative for a release candidate or beta (after the base version
# number has been incremented) # number has been incremented)
__version__ = "1.0a4.dev1" __version__ = "1.0a4.dev2"
__version_info__ = (1, 0, 0, -99) __version_info__ = (1, 0, 0, -99)