diff options
author | Oliver Poignant <oliver@poignant.se> | 2016-03-06 23:10:30 +0100 |
---|---|---|
committer | Oliver Poignant <oliver@poignant.se> | 2016-03-06 23:10:30 +0100 |
commit | de6bc048c63976443fa6fbe00d6b65439bd54a82 (patch) | |
tree | 77bccdd71c36ec5ee1e597a995d1e39a309fd6eb /gitautodeploy/gitautodeploy.py | |
parent | 9bb81f8c8e75278db86868575fc47394b0541eef (diff) | |
download | Git-Auto-Deploy-de6bc048c63976443fa6fbe00d6b65439bd54a82.zip Git-Auto-Deploy-de6bc048c63976443fa6fbe00d6b65439bd54a82.tar.gz Git-Auto-Deploy-de6bc048c63976443fa6fbe00d6b65439bd54a82.tar.bz2 |
Added default config values and the ability to start the server without a config file. Moved HTTP server implementation to separate file.
Diffstat (limited to 'gitautodeploy/gitautodeploy.py')
-rw-r--r-- | gitautodeploy/gitautodeploy.py | 215 |
1 files changed, 20 insertions, 195 deletions
diff --git a/gitautodeploy/gitautodeploy.py b/gitautodeploy/gitautodeploy.py index b7934c1..7191b8c 100644 --- a/gitautodeploy/gitautodeploy.py +++ b/gitautodeploy/gitautodeploy.py @@ -1,5 +1,3 @@ -from BaseHTTPServer import BaseHTTPRequestHandler - class LogInterface(object): """Interface that functions as a stdout and stderr handler and directs the output to the logging module, which in turn will output to either console, @@ -13,184 +11,6 @@ class LogInterface(object): for line in msg.strip().split("\n"): self.level(line) -class WebhookRequestHandler(BaseHTTPRequestHandler): - """Extends the BaseHTTPRequestHandler class and handles the incoming - HTTP requests.""" - - def do_POST(self): - """Invoked on incoming POST requests""" - from threading import Timer - import logging - - logger = logging.getLogger() - - content_type = self.headers.getheader('content-type') - content_length = int(self.headers.getheader('content-length')) - request_body = self.rfile.read(content_length) - - # Extract request headers and make all keys to lowercase (makes them easier to compare) - request_headers = dict(self.headers) - request_headers = dict((k.lower(), v) for k, v in request_headers.iteritems()) - - ServiceRequestParser = self.figure_out_service_from_request(request_headers, request_body) - - self.send_response(200) - self.send_header('Content-type', 'text/plain') - self.end_headers() - - # Unable to identify the source of the request - if not ServiceRequestParser: - logger.error('Unable to find appropriate handler for request. The source service is not supported.') - return - - # Could be GitHubParser, GitLabParser or other - repo_configs, ref, action = ServiceRequestParser(self._config).get_repo_params_from_request(request_headers, request_body) - - #if success: - # print "Successfullt handled request using %s" % ServiceHandler.__name__ - #else: - # print "Unable to handle request using %s" % ServiceHandler.__name__ - - if len(repo_configs) == 0: - logger.warning('Unable to find any of the repository URLs in the config: %s' % ', '.join(repo_urls)) - return - - # Wait one second before we do git pull (why?) - Timer(1.0, self.process_repositories, (repo_configs, - ref, - action)).start() - - def log_message(self, format, *args): - """Overloads the default message logging method to allow messages to - go through our custom logger instead.""" - import logging - logger = logging.getLogger() - logger.info("%s - - [%s] %s\n" % (self.client_address[0], - self.log_date_time_string(), - format%args)) - - def figure_out_service_from_request(self, request_headers, request_body): - """Parses the incoming request and attempts to determine whether - it originates from GitHub, GitLab or any other known service.""" - import json - import logging - import parsers - - logger = logging.getLogger() - data = json.loads(request_body) - - user_agent = 'user-agent' in request_headers and request_headers['user-agent'] - content_type = 'content-type' in request_headers and request_headers['content-type'] - - # Assume GitLab if the X-Gitlab-Event HTTP header is set - if 'x-gitlab-event' in request_headers: - - logger.info("Received event from GitLab") - return parsers.GitLabRequestParser - - # Assume GitHub if the X-GitHub-Event HTTP header is set - elif 'x-github-event' in request_headers: - - logger.info("Received event from GitHub") - return parsers.GitHubRequestParser - - # Assume BitBucket if the User-Agent HTTP header is set to - # 'Bitbucket-Webhooks/2.0' (or something similar) - elif user_agent and user_agent.lower().find('bitbucket') != -1: - - logger.info("Received event from BitBucket") - return parsers.BitBucketRequestParser - - # Special Case for Gitlab CI - elif content_type == "application/json" and "build_status" in data: - - logger.info('Received event from Gitlab CI') - return parsers.GitLabCIRequestParser - - # This handles old GitLab requests and Gogs requests for example. - elif content_type == "application/json": - - logger.info("Received event from unknown origin.") - return parsers.GenericRequestParser - - logger.error("Unable to recognize request origin. Don't know how to handle the request.") - return - - - def process_repositories(self, repo_configs, ref, action): - import os - import time - import logging - from wrappers import GitWrapper - from lock import Lock - from exceptions import FilterMatchError - - logger = logging.getLogger() - - # Process each matching repository - for repo_config in repo_configs: - - try: - # Verify that all filters matches the request if specified - if 'filters' in repo_config: - for filter in repo_config['filters']: - if filter['type'] == 'pull-request-filter': - if filter['ref'] == ref and filter['action'] == action: - continue - raise FilterMatchError() - else: - logger.error('Unrecognized filter: ' % filter) - raise FilterMatchError() - - except FilterMatchError as e: - continue - - - # In case there is no path configured for the repository, no pull will - # be made. - if not 'path' in repo_config: - GitWrapper.deploy(repo_config) - continue - - running_lock = Lock(os.path.join(repo_config['path'], 'status_running')) - waiting_lock = Lock(os.path.join(repo_config['path'], 'status_waiting')) - try: - - # Attempt to obtain the status_running lock - while not running_lock.obtain(): - - # If we're unable, try once to obtain the status_waiting lock - if not waiting_lock.has_lock() and not waiting_lock.obtain(): - logger.error("Unable to obtain the status_running lock nor the status_waiting lock. Another process is " + - "already waiting, so we'll ignore the request.") - - # If we're unable to obtain the waiting lock, ignore the request - break - - # Keep on attempting to obtain the status_running lock until we succeed - time.sleep(5) - - n = 4 - while 0 < n and 0 != GitWrapper.pull(repo_config): - n -= 1 - - if 0 < n: - GitWrapper.deploy(repo_config) - - except Exception as e: - logger.error('Error during \'pull\' or \'deploy\' operation on path: %s' % repo_config['path']) - logger.error(e) - - finally: - - # Release the lock if it's ours - if running_lock.has_lock(): - running_lock.release() - - # Release the lock if it's ours - if waiting_lock.has_lock(): - waiting_lock.release() - class GitAutoDeploy(object): _instance = None @@ -280,12 +100,12 @@ class GitAutoDeploy(object): # Look for a *conf.json or *config.json for dir in target_directories: for item in os.listdir(dir): - if re.match(r"conf(ig)?\.json$", item): + if re.match(r".*conf(ig)?\.json$", item): path = os.path.realpath(os.path.join(dir, item)) logger.info("Using '%s' as config" % path) return path - return './GitAutoDeploy.conf.json' + return def read_json_file(self, file_path): import json @@ -323,7 +143,7 @@ class GitAutoDeploy(object): 'url': os.environ['GAD_REPO_URL'] } - logger.info("Added configuration for '%s' found environment variables" % os.environ['GAD_REPO_URL']) + logger.info("Added configuration for '%s' found in environment variables" % os.environ['GAD_REPO_URL']) if 'GAD_REPO_BRANCH' in os.environ: repo_config['branch'] = os.environ['GAD_REPO_BRANCH'] @@ -371,7 +191,7 @@ class GitAutoDeploy(object): repo_config['deploy_commands'] = [] # Check if any global pre deploy commands is specified - if len(self._config['global_deploy'][0]) is not 0: + if 'global_deploy' in self._config and len(self._config['global_deploy'][0]) is not 0: repo_config['deploy_commands'].insert(0, self._config['global_deploy'][0]) # Check if any repo specific deploy command is specified @@ -379,7 +199,7 @@ class GitAutoDeploy(object): repo_config['deploy_commands'].append(repo_config['deploy']) # Check if any global post deploy command is specified - if len(self._config['global_deploy'][1]) is not 0: + if 'global_deploy' in self._config and len(self._config['global_deploy'][1]) is not 0: repo_config['deploy_commands'].append(self._config['global_deploy'][1]) # If a Bitbucket repository is configured using the https:// URL, a username is usually @@ -529,17 +349,18 @@ class GitAutoDeploy(object): import logging import argparse from lock import Lock + from httpserver import WebhookRequestHandler # Attempt to retrieve default config values from environment variables - default_quiet_value = 'GAD_QUIET' in os.environ - default_daemon_mode_value = 'GAD_DAEMON_MODE' in os.environ - default_config_value = 'GAD_CONFIG' in os.environ and os.environ['GAD_CONFIG'] - default_ssh_keygen_value = 'GAD_SSH_KEYGEN' in os.environ - default_force_value = 'GAD_FORCE' in os.environ - default_pid_file_value = 'GAD_PID_FILE' in os.environ and os.environ['GAD_PID_FILE'] - default_log_file_value = 'GAD_LOG_FILE' in os.environ and os.environ['GAD_LOG_FILE'] - default_host_value = 'GAD_HOST' in os.environ and os.environ['GAD_HOST'] - default_port_value = 'GAD_PORT' in os.environ and int(os.environ['GAD_PORT']) + default_quiet_value = 'GAD_QUIET' in os.environ or False + default_daemon_mode_value = 'GAD_DAEMON_MODE' in os.environ or False + default_config_value = 'GAD_CONFIG' in os.environ and os.environ['GAD_CONFIG'] or None + default_ssh_keygen_value = 'GAD_SSH_KEYGEN' in os.environ or False + default_force_value = 'GAD_FORCE' in os.environ or False + default_pid_file_value = 'GAD_PID_FILE' in os.environ and os.environ['GAD_PID_FILE'] or '~/.gitautodeploy.pid' + default_log_file_value = 'GAD_LOG_FILE' in os.environ and os.environ['GAD_LOG_FILE'] or None + default_host_value = 'GAD_HOST' in os.environ and os.environ['GAD_HOST'] or '0.0.0.0' + default_port_value = 'GAD_PORT' in os.environ and int(os.environ['GAD_PORT']) or 8001 parser = argparse.ArgumentParser() @@ -616,7 +437,11 @@ class GitAutoDeploy(object): config_file_path = self.find_config_file_path() # Read config data from json file - config_data = self.read_json_file(config_file_path) + if config_file_path: + config_data = self.read_json_file(config_file_path) + else: + logger.info('No configuration file found or specified. Using default values.') + config_data = {} # Configuration options coming from environment or command line will # override those coming from config file |