diff options
author | Oliver Poignant <oliver@poignant.se> | 2017-01-02 23:21:41 +0100 |
---|---|---|
committer | Oliver Poignant <oliver@poignant.se> | 2017-01-02 23:21:41 +0100 |
commit | ad78cc6ef5214c3c16db823ccc716322891e55bf (patch) | |
tree | 59bba2094aceb4afd6ee4669573774f159d967dd | |
parent | 4d1d57104e2f3ab4dd4bd411a482e0f19565a433 (diff) | |
download | Git-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.md | 1 | ||||
-rw-r--r-- | gitautodeploy/cli/config.py | 9 | ||||
-rw-r--r-- | gitautodeploy/events.py | 1 | ||||
-rw-r--r-- | gitautodeploy/gitautodeploy.py | 276 | ||||
-rw-r--r-- | gitautodeploy/httpserver.py | 3 |
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): |