From 36e539382c05b722f93dffbd99bc54c4bd8fdc44 Mon Sep 17 00:00:00 2001
From: Michael <gale.michael@gmail.com>
Date: Sat, 6 Sep 2014 00:51:43 -0600
Subject: [PATCH 01/11] Added support for cloud.conf file and startup script

---
 gns3server/start_server.py | 240 +++++++++++++++++++++++++++++++++++++
 1 file changed, 240 insertions(+)
 create mode 100644 gns3server/start_server.py

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 <http://www.gnu.org/licenses/>.
+
+# __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)

From ef492d4690c518395ddb90c7cbfaff03e22f2616 Mon Sep 17 00:00:00 2001
From: Michael <gale.michael@gmail.com>
Date: Sat, 6 Sep 2014 20:46:06 -0600
Subject: [PATCH 02/11] Update gns3dms to support cloud.conf

---
 gns3dms/main.py                        | 34 +++++++++++++++++---------
 gns3server/cert_utils/create_cert.sh   |  5 +++-
 gns3server/config.py                   |  7 +++++-
 gns3server/modules/__init__.py         |  3 ++-
 gns3server/modules/deadman/__init__.py | 12 ++++++---
 gns3server/server.py                   | 32 ++++++++----------------
 requirements.txt                       |  1 +
 7 files changed, 54 insertions(+), 40 deletions(-)

diff --git a/gns3dms/main.py b/gns3dms/main.py
index bad64a44..e8d245d6 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 <api_key>  Rackspace API key           
+  --cloud_api_key <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
@@ -146,7 +146,7 @@ def parse_cmd_line(argv):
         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 +202,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 +225,15 @@ def get_gns3secrets(cmd_line_option_list):
     except configparser.NoSectionError:
         pass
 
+    cloud_config_file = "%s/.config/GNS3/cloud.conf"
+    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 +265,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 +317,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 +350,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
index 57427088..5b2c8e28 100755
--- a/gns3server/cert_utils/create_cert.sh
+++ b/gns3server/cert_utils/create_cert.sh
@@ -68,7 +68,7 @@ emailAddress=gns3cert@gns3.com
 "
 
 # Generate the server private key
-openssl genrsa -aes256 -out $DST_DIR/$DOMAIN.key -passout env:PASSPHRASE 2048
+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
@@ -93,4 +93,7 @@ fail_if_error $?
 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/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
index ab81e971..288d5b2a 100644
--- a/gns3server/modules/deadman/__init__.py
+++ b/gns3server/modules/deadman/__init__.py
@@ -30,7 +30,7 @@ from gns3server.config import Config
 import logging
 log = logging.getLogger(__name__)
 
-class DeadMan():
+class DeadMan(IModule):
     """
     DeadMan module.
 
@@ -51,10 +51,12 @@ class DeadMan():
         self._heartbeat_file = "%s/heartbeat_file_for_gnsdms" % (
             self._tempdir)
 
+        self.cloud_config = Config.instance().get_section_config("CLOUD_SERVER")
+        self._heartbeat_file = self.cloud_config["heartbeat_file"]
+
         if 'heartbeat_file' in kwargs:
             self._heartbeat_file = kwargs['heartbeat_file']
 
-
         self._deadman_process = None
         self.start()
 
@@ -63,8 +65,12 @@ class DeadMan():
         Start a subprocess and return the object
         """
 
-        cmd = []
+        #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 %s" % (self._heartbeat_file))
         cmd.append("--background")
diff --git a/gns3server/server.py b/gns3server/server.py
index 275123ad..49223790 100644
--- a/gns3server/server.py
+++ b/gns3server/server.py
@@ -141,35 +141,20 @@ class Server(object):
             instance.start()  # starts the new process
 
 
-    def _get_cert_info(self):
-        """
-        Finds the cert and key file needed for SSL
-        """
-
-        home = expanduser("~")
-        ssl_dir = "%s/.conf/GNS3Certs/" % (home)
-        log.debug("Looking for SSL certs in: %s" % (ssl_dir))
-
-        keyfile = "%s/gns3server.localdomain.com.key" % (ssl_dir)
-        certfile = "%s/gns3server.localdomain.com.crt" % (ssl_dir)
-
-        if os.path.isfile(keyfile) and os.path.isfile(certfile):
-            return { "certfile" : certfile,
-                "keyfile" : keyfile,
-            }
-
     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" : "test123",
-            "required_pass" : "test456",
+            "required_user" : cloud_config['WEB_USERNAME'],
+            "required_pass" : cloud_config['WEB_PASSWORD'],
         }
 
         router = self._create_zmq_router()
@@ -191,11 +176,14 @@ class Server(object):
                                                                                       zmq.zmq_version()))
             kwargs = {"address": self._host}
 
-            ssl_options = self._get_cert_info()
+            if cloud_config["SSL_ENABLED"] == "yes":
+                ssl_options = {
+                    "certfile" : cloud_config["SSL_CRT"],
+                    "keyfile" : cloud_config["SSL_KEY"],
+                }
 
-            if ssl_options:
                 log.info("Certs found - starting in SSL mode")
-                kwargs['ssl_options'] = ssl_options
+                kwargs["ssl_options"] = ssl_options
 
             if parse_version(tornado.version) >= parse_version("3.1"):
                 kwargs["max_buffer_size"] = 524288000  # 500 MB file upload limit
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
 

From f876a862c41c16757dda56189eff895eda2e8c84 Mon Sep 17 00:00:00 2001
From: Michael <gale.michael@gmail.com>
Date: Sat, 6 Sep 2014 21:13:09 -0600
Subject: [PATCH 03/11] GNS3 server will now create the heardbeat file durining
 initialization

---
 gns3dms/main.py                        |  7 ++++---
 gns3server/modules/deadman/__init__.py | 12 +++++-------
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/gns3dms/main.py b/gns3dms/main.py
index e8d245d6..94e412d7 100644
--- a/gns3dms/main.py
+++ b/gns3dms/main.py
@@ -145,7 +145,6 @@ def parse_cmd_line(argv):
     else:
         cmd_line_option_list['syslog'] = ('localhost',514)
 
-
     get_gns3config(cmd_line_option_list)
 
     for opt, val in opts:
@@ -225,8 +224,10 @@ def get_gns3config(cmd_line_option_list):
     except configparser.NoSectionError:
         pass
 
-    cloud_config_file = "%s/.config/GNS3/cloud.conf"
-    if os.path.isfile(cloud_config_file)
+    cloud_config_file = "%s/.config/GNS3/cloud.conf" % (
+        os.path.expanduser("~/"))
+
+    if os.path.isfile(cloud_config_file):
         config.read(cloud_config_file)
 
     try:
diff --git a/gns3server/modules/deadman/__init__.py b/gns3server/modules/deadman/__init__.py
index 288d5b2a..86f97363 100644
--- a/gns3server/modules/deadman/__init__.py
+++ b/gns3server/modules/deadman/__init__.py
@@ -51,13 +51,11 @@ class DeadMan(IModule):
         self._heartbeat_file = "%s/heartbeat_file_for_gnsdms" % (
             self._tempdir)
 
-        self.cloud_config = Config.instance().get_section_config("CLOUD_SERVER")
-        self._heartbeat_file = self.cloud_config["heartbeat_file"]
-
         if 'heartbeat_file' in kwargs:
             self._heartbeat_file = kwargs['heartbeat_file']
 
         self._deadman_process = None
+        self.heartbeat()
         self.start()
 
     def _start_deadman_process(self):
@@ -72,11 +70,12 @@ class DeadMan(IModule):
 
         cmd = []
         cmd.append("gns3dms")
-        cmd.append("--file %s" % (self._heartbeat_file))
+        cmd.append("--file")
+        cmd.append("%s" % (self._heartbeat_file))
         cmd.append("--background")
         log.debug("Deadman: Running %s"%(cmd))
 
-        process = subprocess.Popen(cmd, shell=False)
+        process = subprocess.Popen(cmd, stderr=subprocess.STDOUT, shell=False)
         return process
 
     def _stop_deadman_process(self):
@@ -143,7 +142,7 @@ class DeadMan(IModule):
         now = time.time()
 
         with open(self._heartbeat_file, 'w') as heartbeat_file:
-            heartbeat_file.write(now)
+            heartbeat_file.write(str(now))
         heartbeat_file.close()
 
         log.debug("Deadman: heartbeat_file updated: %s %s" % (
@@ -151,5 +150,4 @@ class DeadMan(IModule):
                 now,
             ))
 
-
         self.start()
\ No newline at end of file

From 6421367259f44d15ed7741ca4dee9fc6d51e2989 Mon Sep 17 00:00:00 2001
From: Jerry Seutter <jseutter@gmail.com>
Date: Mon, 8 Sep 2014 15:35:22 +0000
Subject: [PATCH 04/11] Importing changeset from gns3dms repo

---
 gns3dms/main.py                    | 30 ++++++-------
 gns3dms/modules/daemon.py          | 71 ++++++++++++++++++------------
 gns3dms/modules/rackspace_cloud.py | 22 ++++-----
 3 files changed, 70 insertions(+), 53 deletions(-)

diff --git a/gns3dms/main.py b/gns3dms/main.py
index 94e412d7..50c012db 100644
--- a/gns3dms/main.py
+++ b/gns3dms/main.py
@@ -77,6 +77,7 @@ Options:
   --cloud_user_name
 
   --instance_id       ID of the Rackspace instance to terminate
+  --region            Region of instance
 
   --deadtime          How long in seconds can the communication lose exist before we
                       shutdown this instance.
@@ -111,6 +112,7 @@ def parse_cmd_line(argv):
                     "cloud_user_name=",
                     "cloud_api_key=",
                     "instance_id=",
+                    "region=",
                     "deadtime=",
                     "init-wait=",
                     "check-interval=",
@@ -130,6 +132,7 @@ def parse_cmd_line(argv):
     cmd_line_option_list["cloud_user_name"] = None
     cmd_line_option_list["cloud_api_key"] = None
     cmd_line_option_list["instance_id"] = None
+    cmd_line_option_list["region"] = None
     cmd_line_option_list["deadtime"] = 60 * 60 #minutes
     cmd_line_option_list["check-interval"] = None
     cmd_line_option_list["init-wait"] = 5 * 60
@@ -145,7 +148,8 @@ def parse_cmd_line(argv):
     else:
         cmd_line_option_list['syslog'] = ('localhost',514)
 
-    get_gns3config(cmd_line_option_list)
+
+    get_gns3secrets(cmd_line_option_list)
 
     for opt, val in opts:
         if (opt in ("-h", "--help")):
@@ -161,6 +165,8 @@ def parse_cmd_line(argv):
             cmd_line_option_list["cloud_api_key"] = val
         elif (opt in ("--instance_id")):
             cmd_line_option_list["instance_id"] = val
+        elif (opt in ("--region")):
+            cmd_line_option_list["region"] = val
         elif (opt in ("--deadtime")):
             cmd_line_option_list["deadtime"] = int(val)
         elif (opt in ("--check-interval")):
@@ -199,9 +205,15 @@ def parse_cmd_line(argv):
             print(usage)
             sys.exit(2)
 
+        if cmd_line_option_list["region"] is None:
+            print("You need to specify a region")
+            print(usage)
+            sys.exit(2)
+
+
     return cmd_line_option_list
 
-def get_gns3config(cmd_line_option_list):
+def get_gns3secrets(cmd_line_option_list):
     """
     Load cloud credentials from .gns3secrets
     """
@@ -224,17 +236,6 @@ def get_gns3config(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):
     """
@@ -351,9 +352,8 @@ def main():
 
         log.info("Received shutdown signal")
         options["shutdown"] = True
-        sys.exit(0)
 
-    pid_file = "%s/.gns3ias.pid" % (expanduser("~"))
+    pid_file = "%s/.gns3dms.pid" % (expanduser("~"))
 
     if options["shutdown"]:
         send_shutdown(pid_file)
diff --git a/gns3dms/modules/daemon.py b/gns3dms/modules/daemon.py
index d10d8d2e..c7245335 100644
--- a/gns3dms/modules/daemon.py
+++ b/gns3dms/modules/daemon.py
@@ -7,38 +7,38 @@ class daemon:
 
     Usage: subclass the daemon class and override the run() method."""
 
-    def __init__(self, pidfile, options): 
+    def __init__(self, pidfile, options):
         self.pidfile = pidfile
         self.options = options
-    
+
     def daemonize(self):
         """Deamonize class. UNIX double fork mechanism."""
 
-        try: 
-            pid = os.fork() 
+        try:
+            pid = os.fork()
             if pid > 0:
                 # exit first parent
-                sys.exit(0) 
-        except OSError as err: 
+                sys.exit(0)
+        except OSError as err:
             sys.stderr.write('fork #1 failed: {0}\n'.format(err))
             sys.exit(1)
-    
+
         # decouple from parent environment
-        os.chdir('/') 
-        os.setsid() 
-        os.umask(0) 
-    
+        os.chdir('/')
+        os.setsid()
+        os.umask(0)
+
         # do second fork
-        try: 
-            pid = os.fork() 
+        try:
+            pid = os.fork()
             if pid > 0:
 
                 # exit from second parent
-                sys.exit(0) 
-        except OSError as err: 
+                sys.exit(0)
+        except OSError as err:
             sys.stderr.write('fork #2 failed: {0}\n'.format(err))
-            sys.exit(1) 
-    
+            sys.exit(1)
+
         # redirect standard file descriptors
         sys.stdout.flush()
         sys.stderr.flush()
@@ -49,17 +49,26 @@ class daemon:
         os.dup2(si.fileno(), sys.stdin.fileno())
         os.dup2(so.fileno(), sys.stdout.fileno())
         os.dup2(se.fileno(), sys.stderr.fileno())
-    
+
         # write pidfile
         atexit.register(self.delpid)
 
         pid = str(os.getpid())
         with open(self.pidfile,'w+') as f:
             f.write(pid + '\n')
-    
+
     def delpid(self):
         os.remove(self.pidfile)
 
+    def check_pid(self, pid):
+        """ Check For the existence of a unix pid. """
+        try:
+            os.kill(pid, 0)
+        except OSError:
+            return False
+        else:
+            return True
+
     def start(self):
         """Start the daemon."""
 
@@ -70,13 +79,19 @@ class daemon:
                 pid = int(pf.read().strip())
         except IOError:
             pid = None
-    
+
         if pid:
-            message = "pidfile {0} already exist. " + \
-                    "Daemon already running?\n"
+            pid_exist = self.check_pid(pid)
+
+            if pid_exist:
+                message = "Already running: %s\n" % (pid)
+                sys.stderr.write(message)
+                sys.exit(1)
+            else:
+                message = "pidfile {0} already exist. " + \
+                    "but process is dead\n"
             sys.stderr.write(message.format(self.pidfile))
-            sys.exit(1)
-        
+
         # Start the daemon
         self.daemonize()
         self.run()
@@ -90,14 +105,14 @@ class daemon:
                 pid = int(pf.read().strip())
         except IOError:
             pid = None
-    
+
         if not pid:
             message = "pidfile {0} does not exist. " + \
                     "Daemon not running?\n"
             sys.stderr.write(message.format(self.pidfile))
             return # not an error in a restart
 
-        # Try killing the daemon process    
+        # Try killing the daemon process
         try:
             while 1:
                 os.kill(pid, signal.SIGTERM)
@@ -118,6 +133,6 @@ class daemon:
 
     def run(self):
         """You should override this method when you subclass Daemon.
-        
-        It will be called after the process has been daemonized by 
+
+        It will be called after the process has been daemonized by
         start() or restart()."""
diff --git a/gns3dms/modules/rackspace_cloud.py b/gns3dms/modules/rackspace_cloud.py
index 4b1d6c0f..00059047 100644
--- a/gns3dms/modules/rackspace_cloud.py
+++ b/gns3dms/modules/rackspace_cloud.py
@@ -41,6 +41,7 @@ class Rackspace(object):
         self.authenticated = False
         self.hostname = socket.gethostname()
         self.instance_id = options["instance_id"]
+        self.region = options["region"]
 
         log.debug("Authenticating with Rackspace")
         log.debug("My hostname: %s" % (self.hostname))
@@ -51,16 +52,17 @@ class Rackspace(object):
         if self.authenticated == False:
             log.critical("Not authenticated against rackspace!!!!")
 
-        for region_dict in self.rksp.list_regions():
-            region_k, region_v = region_dict.popitem()
-            log.debug("Checking region: %s" % (region_k))
-            self.rksp.set_region(region_v)
-            for server in self.rksp.list_instances():
-                log.debug("Checking server: %s" % (server.name))
-                if server.name.lower() == self.hostname.lower() and server.id == self.instance_id:
-                    log.info("Found matching instance: %s" % (server.id))
-                    log.info("Startup id: %s" % (self.instance_id))
-                    return server
+        for region in self.rksp.list_regions():
+            log.debug("Rackspace regions: %s" % (region))
+            
+        log.debug("Checking region: %s" % (self.region))
+        self.rksp.set_region(self.region)
+        for server in self.rksp.list_instances():
+            log.debug("Checking server: %s" % (server.name))
+            if server.name.lower() == self.hostname.lower() and server.id == self.instance_id:
+                log.info("Found matching instance: %s" % (server.id))
+                log.info("Startup id: %s" % (self.instance_id))
+                return server
 
     def terminate(self):
         server = self._find_my_instance()

From 17e4b51d18583a4ed8124c4cc1214ea26a48b68d Mon Sep 17 00:00:00 2001
From: Michael <gale.michael@gmail.com>
Date: Mon, 8 Sep 2014 20:45:36 -0600
Subject: [PATCH 05/11] Testing out dummy config

---
 gns3server/server.py | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/gns3server/server.py b/gns3server/server.py
index 49223790..85365e56 100644
--- a/gns3server/server.py
+++ b/gns3server/server.py
@@ -140,6 +140,17 @@ class Server(object):
                 JSONRPCWebSocket.register_destination(destination, instance.name)
             instance.start()  # starts the new process
 
+    def _dummy_cloud_config(self):
+
+       config = configparser.ConfigParser()
+       config["CLOUD_SERVER"] = {
+           "WEB_AUTH_ENABLED" : "no",
+           "WEB_USERNAME" : "",
+           "WEB_PASSWORD" : "",
+           "SSL_ENABLED"  : "no",
+       }
+
+       return config["CLOUD_SERVER"]
 
     def run(self):
         """
@@ -147,7 +158,10 @@ class Server(object):
         """
 
         # FIXME: debug mode!
-        cloud_config = Config.instance().get_section_config("CLOUD_SERVER")
+        try:
+            cloud_config = Config.instance().get_section_config("CLOUD_SERVER")
+        except KeyError:
+            cloud_config = self._dummy_cloud_config()
 
         settings = {
             "debug":True,

From 4fa87005bc7066c42ad4c94d15e0faa63162ac7e Mon Sep 17 00:00:00 2001
From: Michael <gale.michael@gmail.com>
Date: Mon, 8 Sep 2014 21:51:56 -0600
Subject: [PATCH 06/11] Enabled HTTP Auth, SSL and DMS disabling based on
 cloud.conf availability

---
 gns3server/handlers/auth_handler.py    |  6 +++
 gns3server/modules/deadman/__init__.py | 19 ++++++++--
 gns3server/server.py                   | 52 +++++++++++++-------------
 3 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/gns3server/handlers/auth_handler.py b/gns3server/handlers/auth_handler.py
index f136ab02..3d8cf331 100644
--- a/gns3server/handlers/auth_handler.py
+++ b/gns3server/handlers/auth_handler.py
@@ -29,6 +29,9 @@ log = logging.getLogger(__name__)
 
 class GNS3BaseHandler(tornado.web.RequestHandler):
     def get_current_user(self):
+        if 'required_user' not in self.settings:
+            return "FakeUser"
+
         user = self.get_secure_cookie("user")
         if not user:
           return None
@@ -38,6 +41,9 @@ class GNS3BaseHandler(tornado.web.RequestHandler):
 
 class GNS3WebSocketBaseHandler(tornado.websocket.WebSocketHandler):
     def get_current_user(self):
+        if 'required_user' not in self.settings:
+            return "FakeUser"
+
         user = self.get_secure_cookie("user")
         if not user:
           return None
diff --git a/gns3server/modules/deadman/__init__.py b/gns3server/modules/deadman/__init__.py
index 86f97363..6fd30baa 100644
--- a/gns3server/modules/deadman/__init__.py
+++ b/gns3server/modules/deadman/__init__.py
@@ -54,6 +54,16 @@ class DeadMan(IModule):
         if 'heartbeat_file' in kwargs:
             self._heartbeat_file = kwargs['heartbeat_file']
 
+        self._is_enabled = False
+        try:
+            cloud_config = Config.instance().get_section_config("CLOUD_SERVER")
+            instance_id = cloud_config["instance_id"]
+            cloud_user_name = cloud_config["cloud_user_name"]
+            cloud_api_key = cloud_config["cloud_api_key"]
+            self._is_enabled = True
+        except KeyError:
+            log.critical("Missing cloud.conf - disabling Deadman Switch")
+
         self._deadman_process = None
         self.heartbeat()
         self.start()
@@ -73,7 +83,7 @@ class DeadMan(IModule):
         cmd.append("--file")
         cmd.append("%s" % (self._heartbeat_file))
         cmd.append("--background")
-        log.debug("Deadman: Running %s"%(cmd))
+        log.debug("Deadman: Running command: %s"%(cmd))
 
         process = subprocess.Popen(cmd, stderr=subprocess.STDOUT, shell=False)
         return process
@@ -87,7 +97,7 @@ class DeadMan(IModule):
 
         cmd.append("gns3dms")
         cmd.append("-k")
-        log.debug("Deadman: Running %s"%(cmd))
+        log.debug("Deadman: Running command: %s"%(cmd))
 
         process = subprocess.Popen(cmd, shell=False)
         return process
@@ -116,8 +126,9 @@ class DeadMan(IModule):
         Start the deadman process on the server
         """
 
-        self._deadman_process = self._start_deadman_process()
-        log.debug("Deadman: Process is starting")
+        if self._is_enabled:
+            self._deadman_process = self._start_deadman_process()
+            log.debug("Deadman: Process is starting")
 
     @IModule.route("deadman.reset")
     def reset(self, request=None):
diff --git a/gns3server/server.py b/gns3server/server.py
index 85365e56..3f8b41bc 100644
--- a/gns3server/server.py
+++ b/gns3server/server.py
@@ -140,37 +140,43 @@ class Server(object):
                 JSONRPCWebSocket.register_destination(destination, instance.name)
             instance.start()  # starts the new process
 
-    def _dummy_cloud_config(self):
-
-       config = configparser.ConfigParser()
-       config["CLOUD_SERVER"] = {
-           "WEB_AUTH_ENABLED" : "no",
-           "WEB_USERNAME" : "",
-           "WEB_PASSWORD" : "",
-           "SSL_ENABLED"  : "no",
-       }
-
-       return config["CLOUD_SERVER"]
 
     def run(self):
         """
         Starts the Tornado web server and ZeroMQ server.
         """
 
-        # FIXME: debug mode!
-        try:
-            cloud_config = Config.instance().get_section_config("CLOUD_SERVER")
-        except KeyError:
-            cloud_config = self._dummy_cloud_config()
-
         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'],
         }
 
+        ssl_options = {}
+
+        try:
+            cloud_config = Config.instance().get_section_config("CLOUD_SERVER")
+
+            cloud_settings = {
+
+                "required_user" : cloud_config['WEB_USERNAME'],
+                "required_pass" : cloud_config['WEB_PASSWORD'],
+            }
+
+            settings.update(cloud_settings)
+
+            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")
+
+        except KeyError:
+            log.info("Missing cloud.conf - disabling HTTP auth and SSL")
+
+
         router = self._create_zmq_router()
         # Add our JSON-RPC Websocket handler to Tornado
         self.handlers.extend([(r"/", JSONRPCWebSocket, dict(zmq_router=router))])
@@ -190,13 +196,7 @@ class Server(object):
                                                                                       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")
+            if ssl_options:
                 kwargs["ssl_options"] = ssl_options
 
             if parse_version(tornado.version) >= parse_version("3.1"):

From 6c6c9200e46cfc529f1cbc533f3651601eaca9cf Mon Sep 17 00:00:00 2001
From: Michael <gale.michael@gmail.com>
Date: Mon, 8 Sep 2014 22:07:33 -0600
Subject: [PATCH 07/11] Add CN support to cert as command line arg

---
 gns3server/cert_utils/create_cert.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gns3server/cert_utils/create_cert.sh b/gns3server/cert_utils/create_cert.sh
index 5b2c8e28..92f6edfb 100755
--- a/gns3server/cert_utils/create_cert.sh
+++ b/gns3server/cert_utils/create_cert.sh
@@ -62,7 +62,7 @@ C=CA
 ST=Alberta
 O=GNS3
 localityName=Calgary
-commonName=gns3server.localdomain.com
+commonName=$DOMAIN
 organizationalUnitName=GNS3Server
 emailAddress=gns3cert@gns3.com
 "

From a0e2fe551ac35d0df85f96740134baa10a65a2f9 Mon Sep 17 00:00:00 2001
From: Michael <gale.michael@gmail.com>
Date: Mon, 15 Sep 2014 21:25:09 -0600
Subject: [PATCH 08/11] Added web user and password to start_server output

---
 gns3server/start_server.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gns3server/start_server.py b/gns3server/start_server.py
index b27f3af8..099c3966 100644
--- a/gns3server/start_server.py
+++ b/gns3server/start_server.py
@@ -231,6 +231,8 @@ def main():
 
     client_data['SSL_CRT_FILE'] = server_crt
     client_data['SSL_CRT'] = cert_data
+    client_data['WEB_USERNAME'] = cloud_config['CLOUD_SERVER']['WEB_USERNAME']
+    client_data['WEB_PASSWORD'] = cloud_config['CLOUD_SERVER']['WEB_PASSWORD']
 
     print(client_data)
 

From b132c901c97e23fb7d26acdfdb489f78b6db5d1b Mon Sep 17 00:00:00 2001
From: Jerry Seutter <jseutter@gmail.com>
Date: Thu, 18 Sep 2014 20:39:12 +0000
Subject: [PATCH 09/11] Disabling auth from version string

---
 gns3server/handlers/version_handler.py | 1 -
 gns3server/server.py                   | 3 +--
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/gns3server/handlers/version_handler.py b/gns3server/handlers/version_handler.py
index 3b338bd2..ec83d4ce 100644
--- a/gns3server/handlers/version_handler.py
+++ b/gns3server/handlers/version_handler.py
@@ -22,7 +22,6 @@ from ..version import __version__
 
 class VersionHandler(GNS3BaseHandler):
 
-    @tornado.web.authenticated
     def get(self):
         response = {'version': __version__}
         self.write(response)
diff --git a/gns3server/server.py b/gns3server/server.py
index 3f8b41bc..42f8ec88 100644
--- a/gns3server/server.py
+++ b/gns3server/server.py
@@ -172,9 +172,8 @@ class Server(object):
                 }
 
                 log.info("Certs found - starting in SSL mode")
-
         except KeyError:
-            log.info("Missing cloud.conf - disabling HTTP auth and SSL")
+           log.info("Missing cloud.conf - disabling HTTP auth and SSL")
 
 
         router = self._create_zmq_router()

From cf59240befb7f0395cd5b555ec28a3c4059ebb17 Mon Sep 17 00:00:00 2001
From: Jerry Seutter <jseutter@gmail.com>
Date: Sun, 21 Sep 2014 21:41:51 -0600
Subject: [PATCH 10/11] Bugfixes with cloud server communication

---
 cloud-image/script_template            | 4 +---
 gns3dms/main.py                        | 6 +++---
 gns3server/modules/deadman/__init__.py | 4 ++--
 gns3server/start_server.py             | 4 ++--
 4 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/cloud-image/script_template b/cloud-image/script_template
index e7c5ad56..c59fbbe6 100644
--- a/cloud-image/script_template
+++ b/cloud-image/script_template
@@ -11,9 +11,7 @@ mkdir -p /opt/gns3
 pushd /opt/gns3
 git clone --branch ${git_branch} ${git_url}
 cd gns3-server
-pip3 install tornado
-pip3 install pyzmq
-pip3 install jsonschema
+pip3 install -r dev-requirements.txt
 python3 ./setup.py install
 
 ${rc_local}
diff --git a/gns3dms/main.py b/gns3dms/main.py
index 50c012db..1e86cbac 100644
--- a/gns3dms/main.py
+++ b/gns3dms/main.py
@@ -219,19 +219,19 @@ def get_gns3secrets(cmd_line_option_list):
     """
 
     gns3secret_paths = [
-        os.path.expanduser("~/"),
+        os.path.join(os.path.expanduser("~"), '.config', 'GNS3'),
         SCRIPT_PATH,
     ]
 
     config = configparser.ConfigParser()
 
     for gns3secret_path in gns3secret_paths:
-        gns3secret_file = "%s/.gns3secrets.conf" % (gns3secret_path)
+        gns3secret_file = "%s/cloud.conf" % (gns3secret_path)
         if os.path.isfile(gns3secret_file):
             config.read(gns3secret_file)
 
     try:
-        for key, value in config.items("Cloud"):
+        for key, value in config.items("CLOUD_SERVER"):
             cmd_line_option_list[key] = value.strip()
     except configparser.NoSectionError:
         pass
diff --git a/gns3server/modules/deadman/__init__.py b/gns3server/modules/deadman/__init__.py
index 6fd30baa..c5619c96 100644
--- a/gns3server/modules/deadman/__init__.py
+++ b/gns3server/modules/deadman/__init__.py
@@ -83,7 +83,7 @@ class DeadMan(IModule):
         cmd.append("--file")
         cmd.append("%s" % (self._heartbeat_file))
         cmd.append("--background")
-        log.debug("Deadman: Running command: %s"%(cmd))
+        log.info("Deadman: Running command: %s"%(cmd))
 
         process = subprocess.Popen(cmd, stderr=subprocess.STDOUT, shell=False)
         return process
@@ -97,7 +97,7 @@ class DeadMan(IModule):
 
         cmd.append("gns3dms")
         cmd.append("-k")
-        log.debug("Deadman: Running command: %s"%(cmd))
+        log.info("Deadman: Running command: %s"%(cmd))
 
         process = subprocess.Popen(cmd, shell=False)
         return process
diff --git a/gns3server/start_server.py b/gns3server/start_server.py
index 099c3966..279ccbc3 100644
--- a/gns3server/start_server.py
+++ b/gns3server/start_server.py
@@ -168,7 +168,7 @@ def _start_gns3server():
     cmd = []
     cmd.append("gns3server")
 
-    log.debug("Starting gns3server ...")
+    log.info("Starting gns3server ...")
     subprocess.Popen(cmd, shell=False)
 
 
@@ -203,7 +203,7 @@ def main():
     except FileExistsError:
         pass
 
-    (server_key, server_crt ) = _generate_certs()
+    (server_key, server_crt) = _generate_certs()
 
     cloud_config = configparser.ConfigParser()
     cloud_config['CLOUD_SERVER'] = {}

From 3b465890b6e6d4f95622ff3661f7b821b2168c4a Mon Sep 17 00:00:00 2001
From: Jerry Seutter <jseutter@gmail.com>
Date: Mon, 22 Sep 2014 09:10:30 -0600
Subject: [PATCH 11/11] Increase sleep to work around Rackspace slowness

---
 cloud-image/create_image.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/cloud-image/create_image.py b/cloud-image/create_image.py
index d980a2ba..b7b1fec1 100644
--- a/cloud-image/create_image.py
+++ b/cloud-image/create_image.py
@@ -101,8 +101,9 @@ def main():
                                startup_script)
     passwd = uuid.uuid4().hex
     instance.change_password(passwd)
-    # wait for the password change to be processed
-    sleep(POLL_SEC)
+    # wait for the password change to be processed.  Continuing while
+    # a password change is processing will cause image creation to fail.
+    sleep(POLL_SEC*6)
 
     env.host_string = str(instance.accessIPv4)
     env.user = "root"