IOS devices can be deployed on cloud instances.

This commit is contained in:
Jerry Seutter
2014-10-27 18:11:39 -06:00
parent fa8c166c18
commit 120cb89526
12 changed files with 342 additions and 113 deletions

View File

@@ -8,7 +8,6 @@ import tempfile
import time
import zipfile
from PyQt4 import QtCore
from PyQt4.QtCore import QThread
from PyQt4.QtCore import pyqtSignal
@@ -117,35 +116,34 @@ class StartGNS3ServerThread(QThread):
"""
gns3server_started = pyqtSignal(str, str, str)
# # Note: The htop package is for troubleshooting. It can safely be removed.
# Note: The htop package is for troubleshooting. It can safely be removed.
commands = '''
DEBIAN_FRONTEND=noninteractive apt-get -y update
DEBIAN_FRONTEND=noninteractive apt-get -y install htop
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confnew" --force-yes -fuy dist-upgrade
DEBIAN_FRONTEND=noninteractive apt-get -y install git python3-setuptools python3-netifaces python3-pip python3-zmq dynamips
mkdir -p /opt/gns3
tar xzf /tmp/gns3-server.tgz -C /opt/gns3
cd /opt/gns3/gns3-server; pip3 install -r dev-requirements.txt
cd /opt/gns3/gns3-server; python3 ./setup.py install
ln -sf /usr/bin/dynamips /usr/local/bin/dynamips
killall python3 gns3server gns3dms
'''
# commands = '''
# echo 'hello world'
# DEBIAN_FRONTEND=noninteractive dpkg --configure -a
# DEBIAN_FRONTEND=noninteractive apt-get -y update
# DEBIAN_FRONTEND=noninteractive apt-get -y install htop
# DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confnew" --force-yes -fuy dist-upgrade
# DEBIAN_FRONTEND=noninteractive apt-get -y install git python3-setuptools python3-netifaces python3-pip python3-zmq
# mkdir -p /opt/gns3
# tar xzf /tmp/gns3-server.tgz -C /opt/gns3
# cd /opt/gns3; git clone https://github.com/planctechnologies/gns3-server.git
# cd /opt/gns3/gns3-server; git checkout gns-110
# cd /opt/gns3/gns3-server; pip3 install -r dev-requirements.txt
# cd /opt/gns3/gns3-server; python3 ./setup.py install
# killall gns3server gns3dms
# '''
commands = '''
echo 'hello world'
DEBIAN_FRONTEND=noninteractive dpkg --configure -a
DEBIAN_FRONTEND=noninteractive apt-get -y update
DEBIAN_FRONTEND=noninteractive apt-get -y install htop
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confnew" --force-yes -fuy dist-upgrade
DEBIAN_FRONTEND=noninteractive apt-get -y install git python3-setuptools python3-netifaces python3-pip python3-zmq
mkdir -p /opt/gns3
cd /opt/gns3; git clone https://github.com/planctechnologies/gns3-server.git
cd /opt/gns3/gns3-server; git checkout dev
cd /opt/gns3/gns3-server; pip3 install -r dev-requirements.txt
cd /opt/gns3/gns3-server; python3 ./setup.py install
killall gns3server gns3dms
'''
def __init__(self, parent, host, private_key_string, server_id, username, api_key, region, dead_time):
super(QThread, self).__init__(parent)
self._host = host
@@ -186,10 +184,6 @@ killall gns3server gns3dms
def run(self):
# Uncomment this at the same time as the commands above to test without having to push
# changes to github.
# os.system('rm -rf /tmp/gns3-server')
# os.system('cp -a /Users/jseutter/projects/gns3-server-newinstancerework /tmp/gns3-server')
# os.system('cd /tmp; tar czf /tmp/gns3-server.tgz gns3-server')
# os.system('scp /tmp/gns3-server.tgz root@{}:/tmp/'.format(self._host))
# We might be attempting a connection before the instance is fully booted, so retry
# when the ssh connection fails.
@@ -201,6 +195,13 @@ killall gns3server gns3dms
continue
ssh_connected = True
os.system('rm -rf /tmp/gns3-server')
os.system('cp -a /Users/jseutter/projects/gns3-server /tmp/gns3-server')
os.system('cd /tmp; tar czf /tmp/gns3-server.tgz gns3-server')
sftp = client.open_sftp()
sftp.put('/tmp/gns3-server.tgz', '/tmp/gns3-server.tgz')
sftp.close()
for cmd in [l for l in self.commands.splitlines() if l.strip()]:
self.exec_command(client, cmd)
@@ -208,11 +209,11 @@ killall gns3server gns3dms
'instance_id': self._server_id,
'cloud_user_name': self._username,
'cloud_api_key': self._api_key,
'region': self._region,
'cloud_region': self._region,
'dead_time': self._dead_time,
}
# TODO: Properly escape the data portion of the command line
start_cmd = '/usr/bin/python3 /opt/gns3/gns3-server/gns3server/start_server.py -d -v --data="{}"'.format(data)
start_cmd = '/usr/bin/python3 /opt/gns3/gns3-server/gns3server/start_server.py -d -v --ip={} --data="{}" 2>/tmp/gns3-stderr.log'.format(self._host, data)
stdout, stderr = self.exec_command(client, start_cmd, wait_time=15)
response = stdout.decode('utf-8')
self.gns3server_started.emit(str(self._server_id), str(self._host), str(response))
@@ -225,13 +226,15 @@ class WSConnectThread(QThread):
"""
established = pyqtSignal(str)
def __init__(self, parent, provider, server_id, host, port, ca_file):
def __init__(self, parent, provider, server_id, host, port, ca_file, auth_user, auth_password):
super(QThread, self).__init__(parent)
self._provider = provider
self._server_id = server_id
self._host = host
self._port = port
self._ca_file = ca_file
self._auth_user = auth_user
self._auth_password = auth_password
def run(self):
"""
@@ -240,7 +243,7 @@ class WSConnectThread(QThread):
log.debug('WSConnectThread.run() begin')
servers = Servers.instance()
server = servers.getCloudServer(self._host, self._port, self._ca_file)
server = servers.getCloudServer(self._host, self._port, self._ca_file, self._auth_user, self._auth_password)
log.debug('after getCloudServer call. {}'.format(server))
self.established.emit(str(self._server_id))
@@ -253,42 +256,23 @@ class UploadProjectThread(QThread):
"""
Zip and Upload project to the cloud
"""
# signals to update the progress dialog.
error = QtCore.pyqtSignal(str, bool)
completed = QtCore.pyqtSignal()
update = QtCore.pyqtSignal(int)
def __init__(self, project_settings, cloud_settings):
super().__init__()
self.project_settings = project_settings
self.cloud_settings = cloud_settings
def run(self):
try:
log.info("Exporting project to cloud")
self.update.emit(0)
log.info("Exporting project to cloud")
zipped_project_file = self.zip_project_dir()
zipped_project_file = self.zip_project_dir()
provider = get_provider(self.cloud_settings)
provider.upload_file(zipped_project_file, 'projects')
self.update.emit(10) # update progress to 10%
topology = Topology.instance()
images = set([node.settings()["image"] for node in topology.nodes() if 'image' in node.settings()])
provider = get_provider(self.cloud_settings)
provider.upload_file(zipped_project_file, 'projects')
self.update.emit(20) # update progress to 20%
topology = Topology.instance()
images = set([node.settings()["image"] for node in topology.nodes() if 'image' in node.settings()])
for i, image in enumerate(images):
provider.upload_file(image, 'images')
self.update.emit(20 + (float(i) / len(images) * 80))
self.completed.emit()
except Exception as e:
log.exception("Error exporting project to cloud")
self.error.emit("Error exporting project {}".format(str(e)), True)
for image in images:
provider.upload_file(image, 'images')
def zip_project_dir(self):
"""
@@ -305,19 +289,34 @@ class UploadProjectThread(QThread):
zip_file.write(root, os.path.relpath(root, relroot))
for file in files:
filename = os.path.join(root, file)
if os.path.isfile(filename) and not self._should_exclude(filename): # regular files only
if os.path.isfile(filename): # regular files only
arcname = os.path.join(os.path.relpath(root, relroot), file)
zip_file.write(filename, arcname)
return output_filename
def _should_exclude(self, filename):
"""
Returns True if file should be excluded from zip of project files
:param filename:
:return: True if file should be excluded from zip, False otherwise
"""
return filename.endswith('.ghost')
class UploadFileThread(QThread):
"""
Upload an file to cloud files
"""
def __init__(self, cloud_settings, router_settings):
super().__init__()
self._cloud_settings = cloud_settings
self._router_settings = router_settings
self.completed_callback = None
def stop(self):
self.quit()
def run(self):
disk_path = self._router_settings['path']
filename = self._router_settings['image']
log.debug('Uploading image {}'.format(disk_path))
log.debug('Cloud filename: {}'.format(filename))
provider = get_provider(self._cloud_settings)
provider.upload_file(disk_path, 'images')
self._cloud_settings['image'] = filename
log.debug('Uploading image completed')
if self.completed_callback:
self.completed_callback()

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import ast
import logging
import os
from PyQt4.QtGui import QWidget
from PyQt4.QtGui import QIcon
from PyQt4.QtGui import QMenu
@@ -311,12 +312,23 @@ class CloudInspectorView(QWidget, Ui_CloudInspectorView):
password = data['WEB_PASSWORD']
ssl_cert = ''.join(data['SSL_CRT'])
# TODO: Store the cert file in an appropriate spot
ca_file = '/tmp/cloud_server_{}.crt'.format(host_ip)
open(ca_file, 'w').write(ssl_cert)
ca_filename = 'cloud_server_{}.crt'.format(host_ip)
# TODO: Move this directory into projectSettings.
ca_dir = os.path.join(self._main_window.projectSettings()["project_files_dir"], "keys")
ca_file = os.path.join(ca_dir, ca_filename)
try:
os.makedirs(ca_dir)
except FileExistsError:
pass
with open(ca_file, 'wb') as ca_fh:
ca_fh.write(ssl_cert.encode('utf-8'))
topology = Topology.instance()
top_instance = topology.getInstance(id)
top_instance.set_later_attributes(host_ip, port, ssl_cert, ca_file)
log.debug('Cloud server gns3server started.')
wss_thread = WSConnectThread(self, self._provider, id, host_ip, port, ca_file)
wss_thread = WSConnectThread(self, self._provider, id, host_ip, port, ca_file, username, password)
wss_thread.established.connect(self._wss_connected_slot)
wss_thread.start()

View File

@@ -19,6 +19,7 @@
Graphical view on the scene where items are drawn.
"""
import logging
import os
import pickle
@@ -51,6 +52,8 @@ from .items.rectangle_item import RectangleItem
from .items.ellipse_item import EllipseItem
from .items.image_item import ImageItem
log = logging.getLogger(__name__)
class GraphicsView(QtGui.QGraphicsView):
"""
@@ -1095,6 +1098,7 @@ class GraphicsView(QtGui.QGraphicsView):
"""
try:
log.debug('In createNode')
node_module = None
for module in MODULES:
instance = module.instance()
@@ -1108,11 +1112,30 @@ class GraphicsView(QtGui.QGraphicsView):
if node_data["server"] == "local":
server = Servers.instance().localServer()
elif node_data["server"] == "cloud":
server = Servers.instance().anyCloudServer()
else:
host, port = node_data["server"].rsplit(":", 1)
server = Servers.instance().getRemoteServer(host, port)
if not server.connected() and ConnectToServer(self, server) is False:
return
# if self._topology.resourcesType == "cloud":
# use_cloud = True
# else:
# use_cloud = False
# log.debug("use_cloud is set to {}".format(use_cloud))
#
# server = node_module.allocateServer(node_class, use_cloud)
# if not server.connected():
# # connect to server in a non-blocking way.
# self._thread = WaitForConnectionThread(server.host, server.port)
# progress_dialog = ProgressDialog(self._thread,
# "Server",
# "Connecting to server {} on port {}...".format(server.host, server.port),
# "Cancel", busy=True, parent=self)
# progress_dialog.show()
# if progress_dialog.exec_() is False:
# return
node = node_module.createNode(node_class, server)
node.error_signal.connect(self._main_window.uiConsoleTextEdit.writeError)

View File

@@ -1617,7 +1617,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
index = 0
for instance in instances:
settings.setArrayIndex(index)
for name in instance._fields:
for name in instance.fields():
log.debug('{}={}'.format(name, getattr(instance, name)))
settings.setValue(name, getattr(instance, name))
index += 1
@@ -1638,7 +1638,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
for index in range(0, size):
settings.setArrayIndex(index)
info = {}
for name in TopologyInstance._fields:
for name in TopologyInstance.fields():
log.debug('{}={}'.format(name, settings.value(name, "")))
info[name] = settings.value(name, "")
topology.addInstance(**info)

View File

@@ -387,6 +387,34 @@ class Dynamips(Module):
params.update({"project_name": project_name})
server.send_notification("dynamips.settings", params)
def allocateServer(self, node_class, use_cloud=False):
"""
Allocates a server.
:param node_class: Node object
:returns: allocated server (WebSocketClient instance)
"""
# allocate a server for the node
servers = Servers.instance()
if use_cloud:
from ...topology import Topology
topology = Topology.instance()
top_instance = topology.anyInstance()
server = servers.getCloudServer(top_instance.host, top_instance.port, top_instance.ssl_ca_file)
else:
if self._settings["use_local_server"]:
# use the local server
server = servers.localServer()
else:
# pick up a remote server (round-robin method)
server = next(iter(servers))
if not server:
raise ModuleError("No remote server is configured")
return server
def createNode(self, node_class, server):
"""
Creates a new node.
@@ -468,7 +496,10 @@ class Dynamips(Module):
if wic in ios_router:
settings[wic] = ios_router[wic]
node.setup(ios_router["path"], ios_router["ram"], initial_settings=settings)
if node.server().isCloud():
node.setup(ios_router["image"], ios_router["ram"], initial_settings=settings)
else:
node.setup(ios_router["path"], ios_router["ram"], initial_settings=settings)
else:
node.setup()

View File

@@ -305,12 +305,12 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
Validates the IOS name.
"""
if self.currentPage() == self.uiServerWizardPage:
#FIXME: prevent users to use "cloud"
if self.uiCloudRadioButton.isChecked():
QtGui.QMessageBox.critical(self, "Cloud", "Sorry not implemented yet!")
return False
# if self.currentPage() == self.uiServerWizardPage:
#
# #FIXME: prevent users to use "cloud"
# if self.uiCloudRadioButton.isChecked():
# QtGui.QMessageBox.critical(self, "Cloud", "Sorry not implemented yet!")
# return False
# if self.currentPage() == self.uiNameImageWizardPage:
# name = self.uiNameLineEdit.text()
@@ -347,14 +347,17 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
path = self.uiIOSImageLineEdit.text()
if Dynamips.instance().settings()["use_local_server"] or self.uiLocalRadioButton.isChecked():
server = "local"
elif self.uiLoadBalanceCheckBox.isChecked():
server = next(iter(Servers.instance()))
if not server:
QtGui.QMessageBox.critical(self, "IOS router", "No remote server available!")
return
server = "{}:{}".format(server.host, server.port)
else:
server = self.uiRemoteServersComboBox.currentText()
elif self.uiRemoteRadioButton.isChecked():
if self.uiLoadBalanceCheckBox.isChecked():
server = next(iter(Servers.instance()))
if not server:
QtGui.QMessageBox.critical(self, "IOS router", "No remote server available!")
return
server = "{}:{}".format(server.host, server.port)
else:
server = self.uiRemoteServersComboBox.currentText()
else: # Cloud is selected
server = "cloud"
settings = {
"name": self.uiNameLineEdit.text(),

View File

@@ -263,6 +263,9 @@ class Router(Node):
if "chassis" in initial_settings:
params["chassis"] = self._settings["chassis"] = initial_settings.pop("chassis")
#TODO: make this only send when dealing with cloud
params["cloud_path"] = "images/IOS"
# other initial settings will be applied when the router has been created
if initial_settings:
self._inital_settings = initial_settings

View File

@@ -32,6 +32,7 @@ from gns3.main_window import MainWindow
from gns3.utils.progress_dialog import ProgressDialog
from gns3.dialogs.symbol_selection_dialog import SymbolSelectionDialog
from gns3.dialogs.configuration_dialog import ConfigurationDialog
from gns3.cloud.utils import UploadFileThread
from ..utils.decompress_ios import isIOSCompressed
from ..utils.decompress_ios_thread import DecompressIOSThread
@@ -127,6 +128,26 @@ class IOSRouterPreferencesPage(QtGui.QWidget, Ui_IOSRouterPreferencesPageWidget)
"system_id": "FTX0945W0MY",
"server": ios_settings["server"]}
if ios_settings["server"] == 'cloud':
import logging
log = logging.getLogger(__name__)
log.debug(ios_settings["image"])
# Start uploading the image to cloud files
self._upload_image_progress_dialog = QtGui.QProgressDialog("Uploading image file {}".format(ios_settings['image']), "Cancel", 0, 0, parent=self)
self._upload_image_progress_dialog.setWindowModality(QtCore.Qt.WindowModal)
self._upload_image_progress_dialog.setWindowTitle("IOS image upload")
self._upload_image_progress_dialog.show()
try:
upload_thread = UploadFileThread(MainWindow.instance().cloudSettings(), self._ios_routers[key])
upload_thread.completed_callback = self._imageUploadComplete
upload_thread.start()
except Exception as e:
self._upload_image_progress_dialog.reject()
log.error(e)
QtGui.QMessageBox.critical(self, "IOS image upload", "Error uploading IOS image: {}".format(e))
if ios_settings["platform"] == "c7200":
self._ios_routers[key]["midplane"] = "vxr"
self._ios_routers[key]["npe"] = "npe-400"
@@ -151,6 +172,11 @@ class IOSRouterPreferencesPage(QtGui.QWidget, Ui_IOSRouterPreferencesPageWidget)
self._items.append(item)
self.uiIOSRoutersTreeWidget.setCurrentItem(item)
def _imageUploadComplete(self):
if self._upload_image_progress_dialog.wasCanceled():
return
self._upload_image_progress_dialog.accept()
def _iosRouterEditSlot(self):
"""
Edits an IOS router.

View File

@@ -250,7 +250,7 @@ class Servers(QtCore.QObject):
def getRemoteServer(self, host, port):
for server in self._remote_servers.values():
if server.host == host and server.port == port:
if server.host == host and int(server.port) == int(port):
return server
return self._addRemoteServer(host, port)
@@ -291,7 +291,7 @@ class Servers(QtCore.QObject):
return self._remote_servers
def getCloudServer(self, host, port, ca_file):
def getCloudServer(self, host, port, ca_file, auth_user, auth_password):
"""
Return a websocket connection to the cloud server, creating one if none exists.
@@ -302,13 +302,13 @@ class Servers(QtCore.QObject):
"""
for server in self._remote_servers.values():
if server.host == host and server.port == port:
if server.host == host and int(server.port) == int(port):
return server
heartbeat_freq = self._settings.value("heartbeat_freq", DEFAULT_HEARTBEAT_FREQ)
return self._addCloudServer(host, port, ca_file, heartbeat_freq)
def _addCloudServer(self, host, port, ca_file, heartbeat_freq):
return self._addCloudServer(host, port, ca_file, auth_user, auth_password, heartbeat_freq)
def _addCloudServer(self, host, port, ca_file, auth_user, auth_password, heartbeat_freq):
"""
Create a websocket connection to the specified cloud server
@@ -323,12 +323,20 @@ class Servers(QtCore.QObject):
url = "wss://{host}:{port}".format(host=host, port=port)
log.debug('Starting SecureWebSocketClient url={}'.format(url))
log.debug('Starting SecureWebSocketClient ca_file={}'.format(ca_file))
server = SecureWebSocketClient(url, ca_file)
server = SecureWebSocketClient(url)
server.setSecureOptions(ca_file, auth_user, auth_password)
server.setCloud(True)
server.enableHeartbeatsAt(heartbeat_freq)
self._cloud_servers[host] = server
log.info("new remote server connection {} registered".format(url))
return server
def anyCloudServer(self):
# Return the first server for now
for key, value in self._cloud_servers.items():
return value
return None
def __iter__(self):
"""
Creates a round-robin system to pick up a remote server.

View File

@@ -40,9 +40,43 @@ from pkg_resources import parse_version
import logging
log = logging.getLogger(__name__)
TopologyInstance = namedtuple("TopologyInstance",
["name", "id", "size_id", "image_id", "private_key", "public_key"],
verbose=False)
# TopologyInstance = namedtuple("TopologyInstance",
# ["name", "id", "size_id", "image_id", "private_key", "public_key",
# "host", "port", "ssl_ca", "ssl_ca_file"],
# verbose=False)
class TopologyInstance:
def __init__(self, name, id, size_id, image_id, private_key, public_key,
host=None, port=None, ssl_ca=None, ssl_ca_file=None):
# host, port, ssl_ca and ssl_ca_file are not known when the instance is created.
# They will typically be set at a later point in time.
self.name = name
self.id = id
self.size_id = size_id
self.image_id = image_id
self.public_key = public_key
self.private_key = private_key
self.host = host
self.port = port
self.ssl_ca = ssl_ca
self.ssl_ca_file = ssl_ca_file
@classmethod
def fields(cls):
return ["name", "id", "size_id", "image_id", "private_key", "public_key",
"host", "port", "ssl_ca", "ssl_ca_file"]
def set_later_attributes(self, host, port, ssl_ca, ssl_ca_file):
"""
Set attributes that are not known at the time of cloud instance creation.
"""
self.host = host
self.port = port
self.ssl_ca = ssl_ca
self.ssl_ca_file = ssl_ca_file
class Topology(object):
@@ -203,13 +237,16 @@ class Topology(object):
if image in self._images:
self._images.remove(image)
def addInstance(self, name, id, size_id, image_id, private_key, public_key):
def addInstance(self, name, id, size_id, image_id, private_key, public_key,
host=None, port=None, ssl_ca=None, ssl_ca_file=None):
"""
Add an instance to this cloud topology
"""
i = TopologyInstance(name=name, id=id, size_id=size_id, image_id=image_id,
private_key=private_key, public_key=public_key)
private_key=private_key, public_key=public_key, host=host,
port=port, ssl_ca=ssl_ca, ssl_ca_file=ssl_ca_file)
self._instances.append(i)
def removeInstance(self, id):
@@ -236,6 +273,10 @@ class Topology(object):
if instance.id == id:
return instance
def anyInstance(self):
# For now, just return the first instance
return self._instances[0]
def nodes(self):
"""
Returns all the nodes in this topology.

View File

@@ -56,6 +56,7 @@ class WebSocketClient(WebSocketBaseClient):
self.callbacks = {}
self._connected = False
self._local = False
self._cloud = False
self._version = ""
self._fd_notifier = None
self._heartbeat_timer = None
@@ -108,6 +109,12 @@ class WebSocketClient(WebSocketBaseClient):
return self._local
def setCloud(self, value):
self._cloud = value
def isCloud(self):
return self._cloud
def opened(self):
"""
Called when the connection with the server is successful.
@@ -141,7 +148,7 @@ class WebSocketClient(WebSocketBaseClient):
except OSError:
raise
except Exception as e:
log.error("could to connect {}: {}".format(self.url, e))
log.error("could not to connect {}: {}".format(self.url, e))
raise OSError("Websocket exception {}: {}".format(type(e), e))
def check_server_version(self):
@@ -353,28 +360,57 @@ class WebSocketClient(WebSocketBaseClient):
class SecureWebSocketClient(WebSocketClient):
def connect(self, ca_file=''):
def __init__(self, url, protocols=None, extensions=None,
heartbeat_freq=None, ssl_options=None, headers=None):
self.use_auth = True
self.use_ssl = True
self.use_ssl = False
self.ca_file = ca_file
self.login_url = "https://{host}:{port}/login".format(host=self.host, port=self.port)
self.version_url = "https://{host}:{port}/version".format(host=self.host, port=self.port)
self.websocket_url = "wss://{host}:{port}".format(host=self.host, port=self.port)
self.auth_user = 'test123'
self.auth_password = 'test456'
# The url has to be set before the constructor is called
scheme, rest = url.split(':', 1)
if self.use_ssl:
url = "wss:{}".format(rest)
else:
url = "ws:{}".format(rest)
WebSocketClient.__init__(self, url,
protocols,
extensions,
heartbeat_freq,
ssl_options,
headers)
def setSecureOptions(self, ca_file, auth_user, auth_password):
self._ca_file = ca_file
self._auth_user = auth_user
self._auth_password = auth_password
def connect(self):
log.debug('In SecureWebSocketClient.connect()')
import ssl
import socket
if self.use_ssl:
self.login_url = "https://{host}:{port}/login".format(host=self.host, port=self.port)
self.version_url = "https://{host}:{port}/version".format(host=self.host, port=self.port)
self.ssl_options = {'ca_certs': self._ca_file}
context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED, cafile=self._ca_file)
self.https_handler = urllib.request.HTTPSHandler(context=context, check_hostname=False)
else:
self.login_url = "http://{host}:{port}/login".format(host=self.host, port=self.port)
self.version_url = "http://{host}:{port}/version".format(host=self.host, port=self.port)
self.ssl_options = {}
self.https_handler = urllib.request.HTTPHandler()
self.ssl_options = {'ca_certs': self.ca_file}
self.https_handler = urllib.request.HTTPSHandler(check_hostname=False)
self.cookie_processor = urllib.request.HTTPCookieProcessor()
self.opener = urllib.request.build_opener(self.https_handler, self.cookie_processor)
self.check_server_version()
data = urllib.parse.urlencode({'name': self.auth_user, 'password': self.auth_password}).encode('utf-8')
urllib.request.install_opener(self.opener)
f = urllib.request.urlopen(self.login_url, data, cafile=self.ca_file)
log.debug(self.cookie_processor.cookiejar)
data = urllib.parse.urlencode({'name': self._auth_user, 'password': self._auth_password}).encode('utf-8')
f = self.opener.open(self.login_url, data, socket._GLOBAL_DEFAULT_TIMEOUT)
log.debug('login result: {}'.format(f.read()))
self._connect()
log.debug(self.sock)

47
scripts/ssh_to_server.py Normal file
View File

@@ -0,0 +1,47 @@
import os
from PyQt4 import QtCore, QtGui
QtCore.QSettings.setDefaultFormat(QtCore.QSettings.IniFormat)
app = QtGui.QApplication([])
app.setOrganizationName("GNS3")
app.setOrganizationDomain("gns3.net")
app.setApplicationName("GNS3")
settings = QtCore.QSettings()
print('Reading config from {}'.format(QtCore.QSettings().fileName()))
def read_cloud_settings():
settings = QtCore.QSettings()
settings.beginGroup("CloudInstances")
# Load the instances
size = settings.beginReadArray("cloud_instance")
for index in range(0, size):
settings.setArrayIndex(index)
name = settings.value('name')
host = settings.value('host')
private_key = settings.value('private_key')
public_key = settings.value('public_key')
# For now, just use the first system.
return name, host, private_key, public_key
name, host, private_key, public_key = read_cloud_settings()
print(name)
print(host)
print(private_key)
print(public_key)
open('/tmp/id_rsa.pub', 'w').write(public_key)
open('/tmp/id_rsa', 'w').write(private_key)
os.system('chmod 0600 /tmp/id_rsa')
cmd = 'ssh -i /tmp/id_rsa root@{}'.format(host)
os.system(cmd)