From 8e9faf61214170a7c6cde33a7e76381e892f29a3 Mon Sep 17 00:00:00 2001 From: jakedt Date: Mon, 7 Apr 2014 01:20:09 -0400 Subject: [PATCH] Toward running quay in a docker container. --- Dockerfile | 36 ++++++++++++++++++++++++++++++++ app.py | 4 +++- conf/nginx-enterprise.conf | 30 +++++++++++++++++++++++++++ config.py | 29 ++++++++++++-------------- endpoints/callbacks.py | 8 ++++---- endpoints/index.py | 10 ++++----- requirements.txt | 2 +- run.sh | 10 +++++++++ test/data/test.db | Bin 544768 -> 200704 bytes util/analytics.py | 41 +++++++++++++++++++++++++++++-------- util/http.py | 6 +++--- 11 files changed, 138 insertions(+), 38 deletions(-) create mode 100644 Dockerfile create mode 100644 conf/nginx-enterprise.conf create mode 100755 run.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..5ce01d8ab --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +FROM ubuntu:13.10 + +ENV DEBIAN_FRONTEND noninteractive +RUN apt-get update +RUN apt-get install -y git python-virtualenv python-dev phantomjs libjpeg8 libjpeg62-dev libfreetype6 libfreetype6-dev libevent-dev gdebi-core + +ADD binary_dependencies binary_dependencies +RUN gdebi --n binary_dependencies/*.deb + +ADD requirements.txt requirements.txt +RUN virtualenv --distribute venv +RUN venv/bin/pip install -r requirements.txt + +ADD auth auth +ADD buildstatus buildstatus +ADD conf conf +ADD data data +ADD endpoints endpoints +ADD features features +ADD screenshots screenshots +ADD static static +ADD storage storage +ADD templates templates +ADD util util +ADD workers workers + +ADD app.py app.py +ADD application.py application.py +ADD config.py config.py +ADD run.sh run.sh + +VOLUME ["/conf/override", "/mnt/logs"] + +EXPOSE 443 + +ENTRYPOINT ["./run.sh"] \ No newline at end of file diff --git a/app.py b/app.py index 8ccdecf76..8aba3a30e 100644 --- a/app.py +++ b/app.py @@ -13,6 +13,7 @@ import features from storage import Storage from config import DefaultConfig from data.userfiles import Userfiles +from util.analytics import Analytics app = Flask(__name__) @@ -50,4 +51,5 @@ userfiles.init_app(app) stripe.api_key = app.config.get('STRIPE_SECRET_KEY', None) -mixpanel = app.config['ANALYTICS'].init_app(app) +analytics = Analytics() +analytics.init_app(app) diff --git a/conf/nginx-enterprise.conf b/conf/nginx-enterprise.conf new file mode 100644 index 000000000..b5a3c01b7 --- /dev/null +++ b/conf/nginx-enterprise.conf @@ -0,0 +1,30 @@ +include root-base.conf; + +worker_processes 2; + +user root nogroup; + +http { + include http-base.conf; + + include hosted-http-base.conf; + + server { + include server-base.conf; + + listen 443 default; + + ssl on; + ssl_certificate ./certs/quay-staging-unified.cert; + ssl_certificate_key ./certs/quay-staging.key; + ssl_session_timeout 5m; + ssl_protocols SSLv3 TLSv1; + ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP; + ssl_prefer_server_ciphers on; + + location /static/ { + # checks for static file, if not found proxy to app + alias /static/; + } + } +} diff --git a/config.py b/config.py index 83138548b..11e1119e1 100644 --- a/config.py +++ b/config.py @@ -7,9 +7,6 @@ from peewee import MySQLDatabase, SqliteDatabase from data.buildlogs import BuildLogs from data.userevent import UserEventBuilder -from test import analytics as fake_analytics -from test.testlogs import TestBuildLogs - def build_requests_session(): sess = requests.Session() @@ -88,7 +85,7 @@ class DefaultConfig(object): USERFILES_PATH = 'test/data/userfiles' # Analytics - ANALYTICS = fake_analytics + ANALYTICS_TYPE = "FakeAnalytics" # Github Config GITHUB_TOKEN_URL = 'https://github.com/login/oauth/access_token' @@ -130,21 +127,21 @@ class FakeTransaction(object): pass -class TestConfig(DefaultConfig): - TESTING = True +# class TestConfig(DefaultConfig): +# TESTING = True - DB_NAME = ':memory:' - DB_CONNECTION_ARGS = {} +# DB_NAME = ':memory:' +# DB_CONNECTION_ARGS = {} - @staticmethod - def create_transaction(db): - return FakeTransaction() +# @staticmethod +# def create_transaction(db): +# return FakeTransaction() - DB_TRANSACTION_FACTORY = create_transaction +# DB_TRANSACTION_FACTORY = create_transaction - STORAGE_TYPE = 'FakeStorage' +# STORAGE_TYPE = 'FakeStorage' - BUILDLOGS = TestBuildLogs('logs.quay.io', 'devtable', 'building', - 'deadbeef-dead-beef-dead-beefdeadbeef') +# BUILDLOGS = TestBuildLogs('logs.quay.io', 'devtable', 'building', +# 'deadbeef-dead-beef-dead-beefdeadbeef') - USERFILES_TYPE = 'FakeUserfiles' +# USERFILES_TYPE = 'FakeUserfiles' diff --git a/endpoints/callbacks.py b/endpoints/callbacks.py index 2f801af88..37a5471c8 100644 --- a/endpoints/callbacks.py +++ b/endpoints/callbacks.py @@ -4,7 +4,7 @@ from flask import request, redirect, url_for, Blueprint from flask.ext.login import current_user from endpoints.common import render_page_template, common_login, route_show_if -from app import app, mixpanel +from app import app, analytics from data import model from util.names import parse_repository_name from util.http import abort @@ -85,13 +85,13 @@ def github_oauth_callback(): to_login = model.create_federated_user(username, found_email, 'github', github_id) - # Success, tell mixpanel - mixpanel.track(to_login.username, 'register', {'service': 'github'}) + # Success, tell analytics + analytics.track(to_login.username, 'register', {'service': 'github'}) state = request.args.get('state', None) if state: logger.debug('Aliasing with state: %s' % state) - mixpanel.alias(to_login.username, state) + analytics.alias(to_login.username, state) except model.DataModelException, ex: return render_page_template('githuberror.html', error_message=ex.message) diff --git a/endpoints/index.py b/endpoints/index.py index 480c9e636..0ff64709b 100644 --- a/endpoints/index.py +++ b/endpoints/index.py @@ -9,7 +9,7 @@ from collections import OrderedDict from data import model from data.model import oauth from data.queue import webhook_queue -from app import mixpanel, app +from app import analytics, app from auth.auth import process_auth from auth.auth_context import get_authenticated_user, get_validated_token, get_validated_oauth_token from util.names import parse_repository_name @@ -227,7 +227,7 @@ def create_repository(namespace, repository): } if get_validated_oauth_token(): - mixpanel.track(username, 'push_repo', extra_params) + analytics.track(username, 'push_repo', extra_params) oauth_token = get_validated_oauth_token() metadata['oauth_token_id'] = oauth_token.id @@ -236,7 +236,7 @@ def create_repository(namespace, repository): elif get_authenticated_user(): username = get_authenticated_user().username - mixpanel.track(username, 'push_repo', extra_params) + analytics.track(username, 'push_repo', extra_params) metadata['username'] = username # Mark that the user has started pushing the repo. @@ -250,7 +250,7 @@ def create_repository(namespace, repository): event.publish_event_data('docker-cli', user_data) elif get_validated_token(): - mixpanel.track(get_validated_token().code, 'push_repo', extra_params) + analytics.track(get_validated_token().code, 'push_repo', extra_params) metadata['token'] = get_validated_token().friendly_name metadata['token_code'] = get_validated_token().code @@ -374,7 +374,7 @@ def get_repository_images(namespace, repository): 'repository': '%s/%s' % (namespace, repository), } - mixpanel.track(pull_username, 'pull_repo', extra_params) + analytics.track(pull_username, 'pull_repo', extra_params) model.log_action('pull_repo', namespace, performer=get_authenticated_user(), ip=request.remote_addr, metadata=metadata, diff --git a/requirements.txt b/requirements.txt index 46def6790..f4aaefca2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ argparse==1.2.1 beautifulsoup4==4.3.2 blinker==1.3 boto==2.27.0 -distribute==0.6.34 +distribute==0.7.3 git+https://github.com/DevTable/docker-py.git ecdsa==0.11 gevent==1.0 diff --git a/run.sh b/run.sh new file mode 100755 index 000000000..5efa92a41 --- /dev/null +++ b/run.sh @@ -0,0 +1,10 @@ +#! /bin/bash + +/usr/local/nginx/sbin/nginx -c /conf/nginx-enterprise.conf +venv/bin/gunicorn -c conf/gunicorn_config.py application:application + +while true +do + sleep 60 + echo "stuff" +done \ No newline at end of file diff --git a/test/data/test.db b/test/data/test.db index a2d06594804813bac40b14a63510edfab6653493..88b7213c5ec0092ad5fd0351511d10357b894f40 100644 GIT binary patch delta 15627 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 diff --git a/util/analytics.py b/util/analytics.py index f86329671..4ae1d9db0 100644 --- a/util/analytics.py +++ b/util/analytics.py @@ -33,13 +33,38 @@ class SendToMixpanel(Process): self._consumer.send(*json.loads(mp_request)) -def init_app(app): - logger.debug('Initializing mixpanel with key: %s' % - app.config['MIXPANEL_KEY']) +class FakeMixpanel(object): + def track(*args, **kwargs): + pass - request_queue = Queue() - mixpanel = Mixpanel(app.config['MIXPANEL_KEY'], - MixpanelQueingConsumer(request_queue)) - SendToMixpanel(request_queue).start() - return mixpanel +class Analytics(object): + def __init__(self, app=None): + self.app = app + if app is not None: + self.state = self.init_app(app) + else: + self.state = None + + def init_app(self, app): + analytics_type = app.config.get('ANALYTICS_TYPE', 'FakeAnalytics') + + if analytics_type == 'Mixpanel': + mixpanel_key = app.config.get('MIXPANEL_KEY', '') + logger.debug('Initializing mixpanel with key: %s' % + app.config['MIXPANEL_KEY']) + + request_queue = Queue() + analytics = Mixpanel(mixpanel_key, MixpanelQueingConsumer(request_queue)) + SendToMixpanel(request_queue).start() + + else: + analytics = FakeMixpanel() + + # register extension with app + app.extensions = getattr(app, 'extensions', {}) + app.extensions['analytics'] = analytics + return analytics + + def __getattr__(self, name): + return getattr(self.state, name, None) diff --git a/util/http.py b/util/http.py index 67e9b48c7..2ed21d8a5 100644 --- a/util/http.py +++ b/util/http.py @@ -1,7 +1,7 @@ import logging import json -from app import mixpanel +from app import analytics from flask import request, abort as flask_abort, make_response, current_app from auth.auth_context import get_authenticated_user, get_validated_token @@ -32,10 +32,10 @@ def abort(status_code, message=None, issue=None, headers=None, **kwargs): auth_user = get_authenticated_user() auth_token = get_validated_token() if auth_user: - mixpanel.track(auth_user.username, 'http_error', params) + analytics.track(auth_user.username, 'http_error', params) message = '%s (user: %s)' % (message, auth_user.username) elif auth_token: - mixpanel.track(auth_token.code, 'http_error', params) + analytics.track(auth_token.code, 'http_error', params) message = '%s (token: %s)' % (message, auth_token.friendly_name or auth_token.code)