summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Poignant <oliver@poignant.se>2017-01-02 23:21:41 +0100
committerOliver Poignant <oliver@poignant.se>2017-01-02 23:21:41 +0100
commitad78cc6ef5214c3c16db823ccc716322891e55bf (patch)
tree59bba2094aceb4afd6ee4669573774f159d967dd
parent4d1d57104e2f3ab4dd4bd411a482e0f19565a433 (diff)
downloadGit-Auto-Deploy-ad78cc6ef5214c3c16db823ccc716322891e55bf.zip
Git-Auto-Deploy-ad78cc6ef5214c3c16db823ccc716322891e55bf.tar.gz
Git-Auto-Deploy-ad78cc6ef5214c3c16db823ccc716322891e55bf.tar.bz2
Refactoring. Removal of non essential functionality
-rw-r--r--docs/Configuration.md1
-rw-r--r--gitautodeploy/cli/config.py9
-rw-r--r--gitautodeploy/events.py1
-rw-r--r--gitautodeploy/gitautodeploy.py276
-rw-r--r--gitautodeploy/httpserver.py3
5 files changed, 124 insertions, 166 deletions
diff --git a/docs/Configuration.md b/docs/Configuration.md
index f2914f6..2e92c76 100644
--- a/docs/Configuration.md
+++ b/docs/Configuration.md
@@ -15,7 +15,6 @@ Command line option | Environment variable | Config attribute | Description
--log-file <path> | GAD_LOG_FILE | logfilepath | Specify a log file
--host <host> | GAD_HOST | host | Address to bind to
--port <port> | GAD_PORT | port | Port to bind to
---force | GAD_FORCE | | Kill any process using the configured port
--ssh-keyscan | GAD_SSH_KEYSCAN | | Scan repository hosts for ssh keys and add them to $HOME/.ssh/known_hosts
# Configuration file options
diff --git a/gitautodeploy/cli/config.py b/gitautodeploy/cli/config.py
index e302da4..f87057e 100644
--- a/gitautodeploy/cli/config.py
+++ b/gitautodeploy/cli/config.py
@@ -6,7 +6,6 @@ def get_config_defaults():
config['daemon-mode'] = False
config['config'] = None
config['ssh-keyscan'] = False
- config['force'] = False
config['ssl'] = False
config['ssl-pem-file'] = '~/.gitautodeploy.pem'
config['pidfilepath'] = '~/.gitautodeploy.pid'
@@ -52,9 +51,6 @@ def get_config_from_environment():
if 'GAD_SSH_KEYSCAN' in os.environ:
config['ssh-keyscan'] = True
- if 'GAD_FORCE' in os.environ:
- config['force'] = True
-
if 'GAD_SSL' in os.environ:
config['ssl'] = True
@@ -100,11 +96,6 @@ def get_config_from_argv(argv):
dest="ssh-keyscan",
action="store_true")
- parser.add_argument("--force",
- help="kill any process using the configured port",
- dest="force",
- action="store_true")
-
parser.add_argument("--pid-file",
help="specify a custom pid file",
dest="pidfilepath",
diff --git a/gitautodeploy/events.py b/gitautodeploy/events.py
index bbf93a2..777055a 100644
--- a/gitautodeploy/events.py
+++ b/gitautodeploy/events.py
@@ -67,6 +67,7 @@ class SystemEvent(object):
self.register_message(message, "ERROR")
def log_critical(self, message):
+ self.logger.critical(message)
self.register_message(message, "CRITICAL")
def update(self):
diff --git a/gitautodeploy/gitautodeploy.py b/gitautodeploy/gitautodeploy.py
index c0d5b21..08ebdb2 100644
--- a/gitautodeploy/gitautodeploy.py
+++ b/gitautodeploy/gitautodeploy.py
@@ -14,13 +14,15 @@ class LogInterface(object):
class GitAutoDeploy(object):
_instance = None
- _server = None
+ _http_server = None
+ #_ws_server = None
_config = {}
_port = None
_pid = None
_event_store = None
_default_stdout = None
_default_stderr = None
+ _startup_event = None
def __new__(cls, *args, **kwargs):
"""Overload constructor to enable singleton access"""
@@ -29,61 +31,16 @@ class GitAutoDeploy(object):
cls, *args, **kwargs)
return cls._instance
- @staticmethod
- def debug_diagnosis(port):
- """Display information about what process is using the specified port."""
- import logging
- logger = logging.getLogger()
-
- pid = GitAutoDeploy.get_pid_on_port(port)
- if pid is False:
- logger.warning('Unable to determine what PID is using port %s' % port)
- return
-
- logger.info('Process with PID %s is using port %s' % (pid, port))
- with open("/proc/%s/cmdline" % pid) as f:
- cmdline = f.readlines()
- logger.info('Process with PID %s was started using the command: %s' % (pid, cmdline[0].replace('\x00', ' ')))
-
- @staticmethod
- def get_pid_on_port(port):
- """Determine what process (PID) is using a specific port."""
- import os
-
- with open("/proc/net/tcp", 'r') as f:
- file_content = f.readlines()[1:]
-
- pids = [int(x) for x in os.listdir('/proc') if x.isdigit()]
- conf_port = str(port)
- mpid = False
-
- for line in file_content:
- if mpid is not False:
- break
-
- _, laddr, _, _, _, _, _, _, _, inode = line.split()[:10]
- decport = str(int(laddr.split(':')[1], 16))
-
- if decport != conf_port:
- continue
-
- for pid in pids:
- try:
- path = "/proc/%s/fd" % pid
- if os.access(path, os.R_OK) is False:
- continue
-
- for fd in os.listdir(path):
- cinode = os.readlink("/proc/%s/fd/%s" % (pid, fd))
- minode = cinode.split(":")
-
- if len(minode) == 2 and minode[1][1:-1] == inode:
- mpid = pid
+ def __init__(self):
+ from events import EventStore, StartupEvent
- except Exception as e:
- pass
+ # Setup an event store instance that can keep a global record of events
+ self._event_store = EventStore()
+ self._event_store.register_observer(self)
- return mpid
+ # Create a startup event that can hold status and any error messages from the startup process
+ self._startup_event = StartupEvent()
+ self._event_store.register_action(self._startup_event)
def clone_all_repos(self):
"""Iterates over all configured repositories and clones them to their
@@ -103,7 +60,6 @@ class GitAutoDeploy(object):
# Only clone repositories with a configured path
if 'url' not in repo_config:
logger.critical("Repository has no configured URL")
- self.close()
self.exit()
return
@@ -141,28 +97,6 @@ class GitAutoDeploy(object):
else:
logger.error('Could not find regexp match in path: %s' % repository['url'])
- def kill_conflicting_processes(self):
- """Attempt to kill any process already using the configured port."""
- import os
- import logging
- import signal
- logger = logging.getLogger()
-
- pid = GitAutoDeploy.get_pid_on_port(self._config['port'])
-
- if pid is False:
- logger.warning('No process is currently using port %s.' % self._config['port'])
- return False
-
- if hasattr(signal, 'SIGKILL'):
- os.kill(pid, signal.SIGKILL)
- elif hasattr(signal, 'SIGHUP'):
- os.kill(pid, signal.SIGHUP)
- else:
- os.kill(pid, 1)
-
- return True
-
def create_pid_file(self):
import os
@@ -183,21 +117,6 @@ class GitAutoDeploy(object):
if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory
raise
- def close(self):
- import sys
- import logging
- logger = logging.getLogger()
- logger.info('Goodbye')
- self.remove_pid_file()
- if 'intercept-stdout' in self._config and self._config['intercept-stdout']:
- sys.stdout = self._default_stdout
- sys.stderr = self._default_stderr
-
- def exit(self):
- import sys
- self.close()
- sys.exit(0)
-
@staticmethod
def create_daemon():
import os
@@ -242,7 +161,6 @@ class GitAutoDeploy(object):
import logging
from lock import Lock
from httpserver import WebhookRequestHandlerFactory
- from events import EventStore, StartupEvent
# This solves https://github.com/olipo186/Git-Auto-Deploy/issues/118
try:
@@ -257,12 +175,6 @@ class GitAutoDeploy(object):
# Attatch config values to this instance
self._config = config
- self._event_store = EventStore()
- self._event_store.register_observer(self)
-
- startup_event = StartupEvent()
- self._event_store.register_action(startup_event)
-
# Set up logging
logger = logging.getLogger()
logFormatter = logging.Formatter("%(asctime)s [%(levelname)-5.5s] %(message)s")
@@ -296,13 +208,9 @@ class GitAutoDeploy(object):
logger.addHandler(fileHandler)
if 'ssh-keyscan' in self._config and self._config['ssh-keyscan']:
- startup_event.log_info('Scanning repository hosts for ssh keys...')
+ self._startup_event.log_info('Scanning repository hosts for ssh keys...')
self.ssh_key_scan()
- if 'force' in self._config and self._config['force']:
- startup_event.log_info('Attempting to kill any other process currently occupying port %s' % self._config['port'])
- self.kill_conflicting_processes()
-
# Clone all repos once initially
self.clone_all_repos()
@@ -315,10 +223,10 @@ class GitAutoDeploy(object):
sys.stderr = LogInterface(logger.error)
if 'daemon-mode' in self._config and self._config['daemon-mode']:
- startup_event.log_info('Starting Git Auto Deploy in daemon mode')
+ self._startup_event.log_info('Starting Git Auto Deploy in daemon mode')
GitAutoDeploy.create_daemon()
else:
- startup_event.log_info('Git Auto Deploy started')
+ self._startup_event.log_info('Git Auto Deploy started')
self._pid = os.getpid()
self.create_pid_file()
@@ -336,118 +244,180 @@ class GitAutoDeploy(object):
# Create web hook request handler class
WebhookRequestHandler = WebhookRequestHandlerFactory(self._config, self._event_store)
- self._server = HTTPServer((self._config['host'],
+ # Create HTTP server
+ self._http_server = HTTPServer((self._config['host'],
self._config['port']),
WebhookRequestHandler)
+ #try:
+ # from SimpleWebSocketServer import SimpleWebSocketServer
+ # from wsserver import WebSocketClientHandler
+
+ # # Create web socket server
+ # self._ws_server = SimpleWebSocketServer(self._config['ws-host'], self._config['ws-port'], WebSocketClientHandler)
+
+ #except ImportError as e:
+ # self._startup_event.log_error("Unable to start web socket server due to lack of compability. python => 2.7.9 is required.")
+
+ # Setup SSL for HTTP server
if 'ssl' in self._config and self._config['ssl']:
import ssl
logger.info("enabling ssl")
- self._server.socket = ssl.wrap_socket(self._server.socket,
+ self._http_server.socket = ssl.wrap_socket(self._http_server.socket,
certfile=os.path.expanduser(self._config['ssl-pem']),
server_side=True)
- sa = self._server.socket.getsockname()
- startup_event.log_info("Listening on %s port %s" % (sa[0], sa[1]))
- startup_event.address = sa[0]
- startup_event.port = sa[1]
- startup_event.notify()
+ sa = self._http_server.socket.getsockname()
+ self._startup_event.log_info("Listening on %s port %s" % (sa[0], sa[1]))
+ self._startup_event.address = sa[0]
+ self._startup_event.port = sa[1]
+ self._startup_event.notify()
# Actual port bound to (nessecary when OS picks randomly free port)
self._port = sa[1]
except socket.error, e:
- startup_event.log_critical("Error on socket: %s" % e)
- GitAutoDeploy.debug_diagnosis(self._config['port'])
-
+ self._startup_event.log_critical("Error on socket: %s" % e)
sys.exit(1)
- def serve_forever(self):
- """Start listening for incoming requests."""
+ def serve_http(self):
import sys
import socket
import logging
import os
from events import SystemEvent
- # Add script dir to sys path, allowing us to import sub modules even after changing cwd
- sys.path.insert(1, os.path.dirname(os.path.realpath(__file__)))
-
- # Set CWD to public www folder. This makes the http server serve files from the wwwroot directory.
- wwwroot = os.path.join(os.path.dirname(os.path.realpath(__file__)), "wwwroot")
- os.chdir(wwwroot)
-
- # Set up logging
- logger = logging.getLogger()
-
try:
- self._server.serve_forever()
+ self._http_server.serve_forever()
except socket.error, e:
- logger.critical("Error on socket: %s" % e)
event = SystemEvent()
self._event_store.register_action(event)
event.log_critical("Error on socket: %s" % e)
sys.exit(1)
except KeyboardInterrupt, e:
- logger.info('Requested close by keyboard interrupt signal')
event = SystemEvent()
self._event_store.register_action(event)
event.log_info('Requested close by keyboard interrupt signal')
self.stop()
self.exit()
- def handle_request(self):
+ pass
+
+ #def serve_ws(self):
+ # if not self._ws_server:
+ # return
+ # self._ws_server.serveforever()
+
+ def serve_forever(self):
"""Start listening for incoming requests."""
import sys
import socket
import logging
+ import os
+ from events import SystemEvent
+ import threading
- # Set up logging
- logger = logging.getLogger()
+ # Add script dir to sys path, allowing us to import sub modules even after changing cwd
+ sys.path.insert(1, os.path.dirname(os.path.realpath(__file__)))
+
+ # Set CWD to public www folder. This makes the http server serve files from the wwwroot directory.
+ wwwroot = os.path.join(os.path.dirname(os.path.realpath(__file__)), "wwwroot")
+ os.chdir(wwwroot)
+
+ t1 = threading.Thread(target=self.serve_http)
+ #t1.daemon = True
+ t1.start()
+
+
+ #t2 = threading.Thread(target=self.serve_ws)
+ #t1.daemon = True
+ #t2.start()
+
+ # Wait for thread to finish without blocking main thread
+ while t1.isAlive:
+ t1.join(5)
+
+ # Wait for thread to finish without blocking main thread
+ #while t2.isAlive:
+ # t2.join(5)
+
+
+ def handle_request(self):
+ """Start listening for incoming requests."""
+ import sys
+ import socket
+ from events import SystemEvent
try:
- self._server.handle_request()
+ self._http_server.handle_request()
except socket.error, e:
- logger.critical("Error on socket: %s" % e)
+ event = SystemEvent()
+ self._event_store.register_action(event)
+ event.log_critical("Error on socket: %s" % e)
sys.exit(1)
except KeyboardInterrupt, e:
- logger.info('Requested close by keyboard interrupt signal')
+ event = SystemEvent()
+ self._event_store.register_action(event)
+ event.log_info('Requested close by keyboard interrupt signal')
self.stop()
self.exit()
- def stop(self):
- if self._server is None:
- return
- self._server.socket.close()
-
def signal_handler(self, signum, frame):
from events import SystemEvent
- import logging
- logger = logging.getLogger()
self.stop()
+ event = SystemEvent()
+ self._event_store.register_action(event)
+
+ # Reload configuration on SIGHUP events (conventional for daemon processes)
if signum == 1:
self.setup(self._config)
self.serve_forever()
return
+ # Keyboard interrupt signal
elif signum == 2:
- logger.info('Requested close by keyboard interrupt signal')
- event = SystemEvent()
- self._event_store.register_action(event)
- event.log_info('Requested close by keyboard interrupt signal')
+ event.log_info('Recieved keyboard interrupt signal (%s) from the OS, shutting down.' % signum)
- elif signum == 6:
- logger.info('Requested close by SIGABRT (process abort signal). Code 6.')
- event = SystemEvent()
- self._event_store.register_action(event)
- event.log_info('Requested close by SIGABRT (process abort signal). Code 6.')
+ else:
+ event.log_info('Recieved signal (%s) from the OS, shutting down.' % signum)
self.exit()
+ def stop(self):
+ """Stop all running TCP servers (HTTP and web socket servers)"""
+
+ # Stop HTTP server if running
+ if self._http_server is not None:
+
+ # Shut down the underlying TCP server
+ self._http_server.shutdown()
+ # Close the socket
+ self._http_server.socket.close()
+
+ # Stop web socket server if running
+ #if self._ws_server is not None:
+ # self._ws_server.close()
+
+ def exit(self):
+ import sys
+ import logging
+ logger = logging.getLogger()
+ logger.info('Goodbye')
+
+ # Delete PID file
+ self.remove_pid_file()
+
+ # Restore stdin and stdout
+ if 'intercept-stdout' in self._config and self._config['intercept-stdout']:
+ sys.stdout = self._default_stdout
+ sys.stderr = self._default_stderr
+
+ sys.exit(0)
+
def main():
import signal
from gitautodeploy import GitAutoDeploy
diff --git a/gitautodeploy/httpserver.py b/gitautodeploy/httpserver.py
index 38f28ff..8efcf9b 100644
--- a/gitautodeploy/httpserver.py
+++ b/gitautodeploy/httpserver.py
@@ -1,6 +1,3 @@
-from BaseHTTPServer import BaseHTTPRequestHandler
-
-
class WebbhookRequestProcessor(object):
def get_service_handler(self, request_headers, request_body, action):