diff --git a/gns3dms/main.py b/gns3dms/main.py index bad64a44..94e412d7 100644 --- a/gns3dms/main.py +++ b/gns3dms/main.py @@ -24,7 +24,7 @@ # number has been incremented) """ -Monitors communication with the GNS3 client via tmp file. Will terminate the instance if +Monitors communication with the GNS3 client via tmp file. Will terminate the instance if communication is lost. """ @@ -62,7 +62,7 @@ sys.path.append(EXTRA_LIB) import daemon -my_daemon = None +my_daemon = None usage = """ USAGE: %s @@ -73,14 +73,14 @@ Options: -v, --verbose Enable verbose logging -h, --help Display this menu :) - --cloud_api_key Rackspace API key + --cloud_api_key Rackspace API key --cloud_user_name --instance_id ID of the Rackspace instance to terminate - - --deadtime How long in seconds can the communication lose exist before we - shutdown this instance. - Default: + + --deadtime How long in seconds can the communication lose exist before we + shutdown this instance. + Default: Example --deadtime=3600 (60 minutes) --check-interval Defaults to --deadtime, used for debugging @@ -145,8 +145,7 @@ def parse_cmd_line(argv): else: cmd_line_option_list['syslog'] = ('localhost',514) - - get_gns3secrets(cmd_line_option_list) + get_gns3config(cmd_line_option_list) for opt, val in opts: if (opt in ("-h", "--help")): @@ -202,7 +201,7 @@ def parse_cmd_line(argv): return cmd_line_option_list -def get_gns3secrets(cmd_line_option_list): +def get_gns3config(cmd_line_option_list): """ Load cloud credentials from .gns3secrets """ @@ -225,6 +224,17 @@ def get_gns3secrets(cmd_line_option_list): except configparser.NoSectionError: pass + cloud_config_file = "%s/.config/GNS3/cloud.conf" % ( + os.path.expanduser("~/")) + + if os.path.isfile(cloud_config_file): + config.read(cloud_config_file) + + try: + for key, value in config.items("CLOUD_SERVER"): + cmd_line_option_list[key] = value.strip() + except configparser.NoSectionError: + pass def set_logging(cmd_options): """ @@ -256,7 +266,7 @@ def set_logging(cmd_options): ) syslog_hndlr.setFormatter(sys_formatter) - + log.setLevel(log_level) log.addHandler(console_log) log.addHandler(syslog_hndlr) @@ -308,7 +318,7 @@ def monitor_loop(options): if delta.seconds > options["deadtime"]: log.warning("Deadtime exceeded, terminating instance ...") - #Terminate involes many layers of HTTP / API calls, lots of + #Terminate involes many layers of HTTP / API calls, lots of #different errors types could occur here. try: rksp = Rackspace(options) @@ -341,7 +351,8 @@ def main(): log.info("Received shutdown signal") options["shutdown"] = True - + sys.exit(0) + pid_file = "%s/.gns3ias.pid" % (expanduser("~")) if options["shutdown"]: diff --git a/gns3server/cert_utils/create_cert.sh b/gns3server/cert_utils/create_cert.sh new file mode 100755 index 00000000..5b2c8e28 --- /dev/null +++ b/gns3server/cert_utils/create_cert.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +# -*- 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 . + +# Bash shell script for generating self-signed certs. Run this in a folder, as it +# generates a few files. Large portions of this script were taken from the +# following artcile: +# +# http://usrportage.de/archives/919-Batch-generating-SSL-certificates.html +# +# Additional alterations by: Brad Landers +# Date: 2012-01-27 +# https://gist.github.com/bradland/1690807 + +# Script accepts a single argument, the fqdn for the cert + +DST_DIR="$HOME/.config/GNS3Certs/" +OLD_DIR=`pwd` + +#GNS3 Server expects to find certs with the default FQDN below. If you create +#different certs you will need to update server.py +DOMAIN="$1" +if [ -z "$DOMAIN" ]; then + DOMAIN="gns3server.localdomain.com" +fi + +fail_if_error() { + [ $1 != 0 ] && { + unset PASSPHRASE + cd $OLD_DIR + exit 10 + } +} + + +mkdir -p $DST_DIR +fail_if_error $? +cd $DST_DIR + + +# Generate a passphrase +export PASSPHRASE=$(head -c 500 /dev/urandom | tr -dc a-z0-9A-Z | head -c 128; echo) + +# Certificate details; replace items in angle brackets with your own info +subj=" +C=CA +ST=Alberta +O=GNS3 +localityName=Calgary +commonName=gns3server.localdomain.com +organizationalUnitName=GNS3Server +emailAddress=gns3cert@gns3.com +" + +# Generate the server private key +openssl genrsa -aes256 -out $DOMAIN.key -passout env:PASSPHRASE 2048 +fail_if_error $? + +#openssl rsa -outform der -in $DOMAIN.pem -out $DOMAIN.key -passin env:PASSPHRASE + +# Generate the CSR +openssl req \ + -new \ + -batch \ + -subj "$(echo -n "$subj" | tr "\n" "/")" \ + -key $DOMAIN.key \ + -out $DOMAIN.csr \ + -passin env:PASSPHRASE +fail_if_error $? +cp $DOMAIN.key $DOMAIN.key.org +fail_if_error $? + +# Strip the password so we don't have to type it every time we restart Apache +openssl rsa -in $DOMAIN.key.org -out $DOMAIN.key -passin env:PASSPHRASE +fail_if_error $? + +# Generate the cert (good for 10 years) +openssl x509 -req -days 3650 -in $DOMAIN.csr -signkey $DOMAIN.key -out $DOMAIN.crt +fail_if_error $? + +echo "${DST_DIR}${DOMAIN}.key" +echo "${DST_DIR}${DOMAIN}.crt" + +cd $OLD_DIR \ No newline at end of file diff --git a/gns3server/config.py b/gns3server/config.py index cd2d07a1..caa9c0d4 100644 --- a/gns3server/config.py +++ b/gns3server/config.py @@ -62,16 +62,21 @@ class Config(object): # 5: server.conf in the current working directory home = os.path.expanduser("~") + self._cloud_config = os.path.join(home, ".config", appname, "cloud.conf") filename = "server.conf" self._files = [os.path.join(home, ".config", appname, filename), os.path.join(home, ".config", appname + ".conf"), os.path.join("/etc/xdg", appname, filename), os.path.join("/etc/xdg", appname + ".conf"), - filename] + filename, + self._cloud_config] self._config = configparser.ConfigParser() self.read_config() + def list_cloud_config_file(self): + return self._cloud_config + def read_config(self): """ Read the configuration files. diff --git a/gns3server/handlers/auth_handler.py b/gns3server/handlers/auth_handler.py new file mode 100644 index 00000000..f136ab02 --- /dev/null +++ b/gns3server/handlers/auth_handler.py @@ -0,0 +1,82 @@ +# -*- 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 . + +""" +Simple file upload & listing handler. +""" + + +import os +import tornado.web +import tornado.websocket + +import logging +log = logging.getLogger(__name__) + +class GNS3BaseHandler(tornado.web.RequestHandler): + def get_current_user(self): + user = self.get_secure_cookie("user") + if not user: + return None + + if self.settings['required_user'] == user.decode("utf-8"): + return user + +class GNS3WebSocketBaseHandler(tornado.websocket.WebSocketHandler): + def get_current_user(self): + user = self.get_secure_cookie("user") + if not user: + return None + + if self.settings['required_user'] == user.decode("utf-8"): + return user + + +class LoginHandler(tornado.web.RequestHandler): + def get(self): + self.write('
' + 'Name: ' + 'Password: ' + '' + '
') + + try: + redirect_to = self.get_argument("next") + self.set_secure_cookie("login_success_redirect_to", redirect_to) + except tornado.web.MissingArgumentError: + pass + + def post(self): + + user = self.get_argument("name") + password = self.get_argument("password") + + if self.settings['required_user'] == user and self.settings['required_pass'] == password: + self.set_secure_cookie("user", user) + auth_status = "successful" + else: + self.set_secure_cookie("user", "None") + auth_status = "failure" + + log.info("Authentication attempt %s: %s" %(auth_status, user)) + + try: + redirect_to = self.get_secure_cookie("login_success_redirect_to") + except tornado.web.MissingArgumentError: + redirect_to = "/" + + self.redirect(redirect_to) \ No newline at end of file diff --git a/gns3server/handlers/file_upload_handler.py b/gns3server/handlers/file_upload_handler.py index c819a401..15673604 100644 --- a/gns3server/handlers/file_upload_handler.py +++ b/gns3server/handlers/file_upload_handler.py @@ -23,6 +23,7 @@ Simple file upload & listing handler. import os import stat import tornado.web +from .auth_handler import GNS3BaseHandler from ..version import __version__ from ..config import Config @@ -30,7 +31,7 @@ import logging log = logging.getLogger(__name__) -class FileUploadHandler(tornado.web.RequestHandler): +class FileUploadHandler(GNS3BaseHandler): """ File upload handler. @@ -54,6 +55,7 @@ class FileUploadHandler(tornado.web.RequestHandler): except OSError as e: log.error("could not create the upload directory {}: {}".format(self._upload_dir, e)) + @tornado.web.authenticated def get(self): """ Invoked on GET request. @@ -70,6 +72,7 @@ class FileUploadHandler(tornado.web.RequestHandler): path=path, items=items) + @tornado.web.authenticated def post(self): """ Invoked on POST request. diff --git a/gns3server/handlers/jsonrpc_websocket.py b/gns3server/handlers/jsonrpc_websocket.py index 5b18496c..a226be78 100644 --- a/gns3server/handlers/jsonrpc_websocket.py +++ b/gns3server/handlers/jsonrpc_websocket.py @@ -22,6 +22,7 @@ JSON-RPC protocol over Websockets. import zmq import uuid import tornado.websocket +from .auth_handler import GNS3WebSocketBaseHandler from tornado.escape import json_decode from ..jsonrpc import JSONRPCParseError from ..jsonrpc import JSONRPCInvalidRequest @@ -33,7 +34,7 @@ import logging log = logging.getLogger(__name__) -class JSONRPCWebSocket(tornado.websocket.WebSocketHandler): +class JSONRPCWebSocket(GNS3WebSocketBaseHandler): """ STOMP protocol over Tornado Websockets with message routing to ZeroMQ dealer clients. @@ -116,7 +117,15 @@ class JSONRPCWebSocket(tornado.websocket.WebSocketHandler): """ log.info("Websocket client {} connected".format(self.session_id)) - self.clients.add(self) + + authenticated_user = self.get_current_user() + + if authenticated_user: + self.clients.add(self) + log.info("Websocket authenticated user: %s" % (authenticated_user)) + else: + self.close() + log.info("Websocket non-authenticated user attempt: %s" % (authenticated_user)) def on_message(self, message): """ diff --git a/gns3server/handlers/version_handler.py b/gns3server/handlers/version_handler.py index c85aa31c..3b338bd2 100644 --- a/gns3server/handlers/version_handler.py +++ b/gns3server/handlers/version_handler.py @@ -16,11 +16,13 @@ # along with this program. If not, see . import tornado.web +from .auth_handler import GNS3BaseHandler from ..version import __version__ -class VersionHandler(tornado.web.RequestHandler): +class VersionHandler(GNS3BaseHandler): + @tornado.web.authenticated def get(self): response = {'version': __version__} self.write(response) diff --git a/gns3server/modules/__init__.py b/gns3server/modules/__init__.py index 5bd4c110..f38af25b 100644 --- a/gns3server/modules/__init__.py +++ b/gns3server/modules/__init__.py @@ -20,8 +20,9 @@ from .base import IModule from .dynamips import Dynamips from .vpcs import VPCS from .virtualbox import VirtualBox +from .deadman import DeadMan -MODULES = [Dynamips, VPCS, VirtualBox] +MODULES = [Dynamips, VPCS, VirtualBox, DeadMan] if sys.platform.startswith("linux"): # IOU runs only on Linux diff --git a/gns3server/modules/deadman/__init__.py b/gns3server/modules/deadman/__init__.py new file mode 100644 index 00000000..86f97363 --- /dev/null +++ b/gns3server/modules/deadman/__init__.py @@ -0,0 +1,153 @@ +# -*- 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 . + +""" +DeadMan server module. +""" + +import os +import time +import subprocess + +from gns3server.modules import IModule +from gns3server.config import Config + + +import logging +log = logging.getLogger(__name__) + +class DeadMan(IModule): + """ + DeadMan module. + + :param name: module name + :param args: arguments for the module + :param kwargs: named arguments for the module + """ + + def __init__(self, name, *args, **kwargs): + config = Config.instance() + + # a new process start when calling IModule + IModule.__init__(self, name, *args, **kwargs) + self._host = kwargs["host"] + self._projects_dir = kwargs["projects_dir"] + self._tempdir = kwargs["temp_dir"] + self._working_dir = self._projects_dir + self._heartbeat_file = "%s/heartbeat_file_for_gnsdms" % ( + self._tempdir) + + if 'heartbeat_file' in kwargs: + self._heartbeat_file = kwargs['heartbeat_file'] + + self._deadman_process = None + self.heartbeat() + self.start() + + def _start_deadman_process(self): + """ + Start a subprocess and return the object + """ + + #gnsserver gets configuration options from cloud.conf. This is where + #the client adds specific cloud information. + #gns3dms also reads in cloud.conf. That is why we don't need to specific + #all the command line arguments here. + + cmd = [] + cmd.append("gns3dms") + cmd.append("--file") + cmd.append("%s" % (self._heartbeat_file)) + cmd.append("--background") + log.debug("Deadman: Running %s"%(cmd)) + + process = subprocess.Popen(cmd, stderr=subprocess.STDOUT, shell=False) + return process + + def _stop_deadman_process(self): + """ + Start a subprocess and return the object + """ + + cmd = [] + + cmd.append("gns3dms") + cmd.append("-k") + log.debug("Deadman: Running %s"%(cmd)) + + process = subprocess.Popen(cmd, shell=False) + return process + + + def stop(self, signum=None): + """ + Properly stops the module. + + :param signum: signal number (if called by the signal handler) + """ + + if self._deadman_process == None: + log.info("Deadman: Can't stop, is not currently running") + + log.debug("Deadman: Stopping process") + + self._deadman_process = self._stop_deadman_process() + self._deadman_process = None + #Jerry or Jeremy why do we do this? Won't this stop the I/O loop for + #for everyone? + IModule.stop(self, signum) # this will stop the I/O loop + + def start(self, request=None): + """ + Start the deadman process on the server + """ + + self._deadman_process = self._start_deadman_process() + log.debug("Deadman: Process is starting") + + @IModule.route("deadman.reset") + def reset(self, request=None): + """ + Resets the module (JSON-RPC notification). + + :param request: JSON request (not used) + """ + + self.stop() + self.start() + + log.info("Deadman: Module has been reset") + + + @IModule.route("deadman.heartbeat") + def heartbeat(self, request=None): + """ + Update a file on the server that the deadman switch will monitor + """ + + now = time.time() + + with open(self._heartbeat_file, 'w') as heartbeat_file: + heartbeat_file.write(str(now)) + heartbeat_file.close() + + log.debug("Deadman: heartbeat_file updated: %s %s" % ( + self._heartbeat_file, + now, + )) + + self.start() \ No newline at end of file diff --git a/gns3server/server.py b/gns3server/server.py index d4869e53..49223790 100644 --- a/gns3server/server.py +++ b/gns3server/server.py @@ -33,12 +33,16 @@ import tornado.ioloop import tornado.web import tornado.autoreload import pkg_resources +from os.path import expanduser +import base64 +import uuid from pkg_resources import parse_version from .config import Config from .handlers.jsonrpc_websocket import JSONRPCWebSocket from .handlers.version_handler import VersionHandler from .handlers.file_upload_handler import FileUploadHandler +from .handlers.auth_handler import LoginHandler from .builtins.server_version import server_version from .builtins.interfaces import interfaces from .modules import MODULES @@ -46,12 +50,12 @@ from .modules import MODULES import logging log = logging.getLogger(__name__) - class Server(object): # built-in handlers handlers = [(r"/version", VersionHandler), - (r"/upload", FileUploadHandler)] + (r"/upload", FileUploadHandler), + (r"/login", LoginHandler)] def __init__(self, host, port, ipc=False): @@ -136,11 +140,23 @@ class Server(object): JSONRPCWebSocket.register_destination(destination, instance.name) instance.start() # starts the new process + def run(self): """ Starts the Tornado web server and ZeroMQ server. """ + # FIXME: debug mode! + cloud_config = Config.instance().get_section_config("CLOUD_SERVER") + + settings = { + "debug":True, + "cookie_secret": base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes), + "login_url": "/login", + "required_user" : cloud_config['WEB_USERNAME'], + "required_pass" : cloud_config['WEB_PASSWORD'], + } + router = self._create_zmq_router() # Add our JSON-RPC Websocket handler to Tornado self.handlers.extend([(r"/", JSONRPCWebSocket, dict(zmq_router=router))]) @@ -150,7 +166,7 @@ class Server(object): templates_dir = pkg_resources.resource_filename("gns3server", "templates") tornado_app = tornado.web.Application(self.handlers, template_path=templates_dir, - debug=True) # FIXME: debug mode! + **settings) # FIXME: debug mode! try: print("Starting server on {}:{} (Tornado v{}, PyZMQ v{}, ZMQ v{})".format(self._host, @@ -159,6 +175,16 @@ class Server(object): zmq.__version__, zmq.zmq_version())) kwargs = {"address": self._host} + + if cloud_config["SSL_ENABLED"] == "yes": + ssl_options = { + "certfile" : cloud_config["SSL_CRT"], + "keyfile" : cloud_config["SSL_KEY"], + } + + log.info("Certs found - starting in SSL mode") + kwargs["ssl_options"] = ssl_options + if parse_version(tornado.version) >= parse_version("3.1"): kwargs["max_buffer_size"] = 524288000 # 500 MB file upload limit tornado_app.listen(self._port, **kwargs) diff --git a/gns3server/start_server.py b/gns3server/start_server.py new file mode 100644 index 00000000..b27f3af8 --- /dev/null +++ b/gns3server/start_server.py @@ -0,0 +1,240 @@ +# -*- 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 . + +# __version__ is a human-readable version number. + +# __version_info__ is a four-tuple for programmatic comparison. The first +# three numbers are the components of the version number. The fourth +# is zero for an official release, positive for a development branch, +# or negative for a release candidate or beta (after the base version +# number has been incremented) + +""" +Startup script for GNS3 Server Cloud Instance +""" + +import os +import sys +import configparser +import getopt +import datetime +import signal +from logging.handlers import * +from os.path import expanduser +from gns3server.config import Config +import ast +import subprocess +import uuid + +SCRIPT_NAME = os.path.basename(__file__) + +#Is the full path when used as an import +SCRIPT_PATH = os.path.dirname(__file__) + +if not SCRIPT_PATH: + SCRIPT_PATH = os.path.join(os.path.dirname(os.path.abspath( + sys.argv[0]))) + + +LOG_NAME = "gns3-startup" +log = None + +usage = """ +USAGE: %s + +Options: + + -d, --debug Enable debugging + -v, --verbose Enable verbose logging + -h, --help Display this menu :) + + --data Python dict of data to be written to the config file: + " { 'gns3' : 'Is AWESOME' } " + +""" % (SCRIPT_NAME) + +# Parse cmd line options +def parse_cmd_line(argv): + """ + Parse command line arguments + + argv: Pass in cmd line arguments + """ + + short_args = "dvh" + long_args = ("debug", + "verbose", + "help", + "data=", + ) + try: + opts, extra_opts = getopt.getopt(argv[1:], short_args, long_args) + except getopt.GetoptError as e: + print("Unrecognized command line option or missing required argument: %s" %(e)) + print(usage) + sys.exit(2) + + cmd_line_option_list = {} + cmd_line_option_list["debug"] = False + cmd_line_option_list["verbose"] = True + cmd_line_option_list["data"] = None + + if sys.platform == "linux": + cmd_line_option_list['syslog'] = "/dev/log" + elif sys.platform == "osx": + cmd_line_option_list['syslog'] = "/var/run/syslog" + else: + cmd_line_option_list['syslog'] = ('localhost',514) + + for opt, val in opts: + if (opt in ("-h", "--help")): + print(usage) + sys.exit(0) + elif (opt in ("-d", "--debug")): + cmd_line_option_list["debug"] = True + elif (opt in ("-v", "--verbose")): + cmd_line_option_list["verbose"] = True + elif (opt in ("--data")): + cmd_line_option_list["data"] = ast.literal_eval(val) + + return cmd_line_option_list + + +def set_logging(cmd_options): + """ + Setup logging and format output for console and syslog + + Syslog is using the KERN facility + """ + log = logging.getLogger("%s" % (LOG_NAME)) + log_level = logging.INFO + log_level_console = logging.WARNING + + if cmd_options['verbose'] == True: + log_level_console = logging.INFO + + if cmd_options['debug'] == True: + log_level_console = logging.DEBUG + log_level = logging.DEBUG + + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + sys_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') + + console_log = logging.StreamHandler() + console_log.setLevel(log_level_console) + console_log.setFormatter(formatter) + + syslog_hndlr = SysLogHandler( + address=cmd_options['syslog'], + facility=SysLogHandler.LOG_KERN + ) + + syslog_hndlr.setFormatter(sys_formatter) + + log.setLevel(log_level) + log.addHandler(console_log) + log.addHandler(syslog_hndlr) + + return log + +def _generate_certs(): + cmd = [] + cmd.append("%s/cert_utils/create_cert.sh" % (SCRIPT_PATH)) + + log.debug("Generating certs ...") + output_raw = subprocess.check_output(cmd, shell=False, + stderr=subprocess.STDOUT) + + output_str = output_raw.decode("utf-8") + output = output_str.strip().split("\n") + log.debug(output) + return (output[-2], output[-1]) + +def _start_gns3server(): + cmd = [] + cmd.append("gns3server") + + log.debug("Starting gns3server ...") + subprocess.Popen(cmd, shell=False) + + +def main(): + + global log + options = parse_cmd_line(sys.argv) + log = set_logging(options) + + def _shutdown(signalnum=None, frame=None): + """ + Handles the SIGINT and SIGTERM event, inside of main so it has access to + the log vars. + """ + + log.info("Received shutdown signal") + sys.exit(0) + + + # Setup signal to catch Control-C / SIGINT and SIGTERM + signal.signal(signal.SIGINT, _shutdown) + signal.signal(signal.SIGTERM, _shutdown) + + client_data = {} + + config = Config.instance() + cfg = config.list_cloud_config_file() + cfg_path = os.path.dirname(cfg) + + try: + os.makedirs(cfg_path) + except FileExistsError: + pass + + (server_key, server_crt ) = _generate_certs() + + cloud_config = configparser.ConfigParser() + cloud_config['CLOUD_SERVER'] = {} + + if options['data']: + cloud_config['CLOUD_SERVER'] = options['data'] + + cloud_config['CLOUD_SERVER']['SSL_KEY'] = server_key + cloud_config['CLOUD_SERVER']['SSL_CRT'] = server_crt + cloud_config['CLOUD_SERVER']['SSL_ENABLED'] = 'yes' + cloud_config['CLOUD_SERVER']['WEB_USERNAME'] = str(uuid.uuid4()).upper()[0:8] + cloud_config['CLOUD_SERVER']['WEB_PASSWORD'] = str(uuid.uuid4()).upper()[0:8] + + with open(cfg, 'w') as cloud_config_file: + cloud_config.write(cloud_config_file) + + cloud_config_file.close() + + _start_gns3server() + + with open(server_crt, 'r') as cert_file: + cert_data = cert_file.readlines() + + cert_file.close() + + client_data['SSL_CRT_FILE'] = server_crt + client_data['SSL_CRT'] = cert_data + + print(client_data) + + +if __name__ == "__main__": + result = main() + sys.exit(result) diff --git a/requirements.txt b/requirements.txt index 2cf31cd5..3e267f9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ jsonschema pycurl python-dateutil apache-libcloud +requests