Return template from call

This commit is contained in:
Sam Chow 2018-05-14 13:12:42 -04:00
parent 92db413da6
commit 15c15faf30
5 changed files with 105 additions and 279 deletions

View file

@ -1,257 +1,3 @@
import hashlib
import json
import logging
import os
from functools import partial
from Crypto.PublicKey import RSA
from flask import Flask, request, Request from flask import Flask, request, Request
from flask_login import LoginManager
from flask_mail import Mail
from flask_principal import Principal
from jwkest.jwk import RSAKey
import features
from _init import CONF_DIR
from auth.auth_context import get_authenticated_user
from avatars.avatars import Avatar
from buildman.manager.buildcanceller import BuildCanceller
from data import database
from data import model
from data.archivedlogs import LogArchive
from data.billing import Billing
from data.buildlogs import BuildLogs
from data.cache import get_model_cache
from data.model.user import LoginWrappedDBUser
from data.queue import WorkQueue, BuildMetricQueueReporter
from data.userevent import UserEventsBuilderModule
from data.userfiles import Userfiles
from data.users import UserAuthentication
from path_converters import RegexConverter, RepositoryPathConverter, APIRepositoryPathConverter
from oauth.services.github import GithubOAuthService
from oauth.services.gitlab import GitLabOAuthService
from oauth.loginmanager import OAuthLoginManager
from storage import Storage
from util.log import filter_logs
from util import get_app_url
from util.ipresolver import IPResolver
from util.saas.analytics import Analytics
from util.saas.useranalytics import UserAnalytics
from util.saas.exceptionlog import Sentry
from util.names import urn_generator
from util.config.configutil import generate_secret_key
from util.config.provider import get_config_provider
from util.config.superusermanager import SuperUserManager
from util.label_validator import LabelValidator
from util.metrics.metricqueue import MetricQueue
from util.metrics.prometheus import PrometheusPlugin
from util.saas.cloudwatch import start_cloudwatch_sender
from util.secscan.api import SecurityScannerAPI
from util.tufmetadata.api import TUFMetadataAPI
from util.security.instancekeys import InstanceKeys
from util.security.signing import Signer
OVERRIDE_CONFIG_DIRECTORY = os.path.join(CONF_DIR, 'stack/')
OVERRIDE_CONFIG_YAML_FILENAME = os.path.join(CONF_DIR, 'stack/config.yaml')
OVERRIDE_CONFIG_PY_FILENAME = os.path.join(CONF_DIR, 'stack/config.py')
OVERRIDE_CONFIG_KEY = 'QUAY_OVERRIDE_CONFIG'
DOCKER_V2_SIGNINGKEY_FILENAME = 'docker_v2.pem'
app = Flask(__name__) app = Flask(__name__)
logger = logging.getLogger(__name__)
# Instantiate the configuration.
is_testing = 'TEST' in os.environ
is_kubernetes = 'KUBERNETES_SERVICE_HOST' in os.environ
config_provider = get_config_provider(OVERRIDE_CONFIG_DIRECTORY, 'config.yaml', 'config.py',
testing=is_testing, kubernetes=is_kubernetes)
if is_testing:
from test.testconfig import TestConfig
logger.debug('Loading test config.')
app.config.from_object(TestConfig())
else:
from config import DefaultConfig
logger.debug('Loading default config.')
app.config.from_object(DefaultConfig())
app.teardown_request(database.close_db_filter)
# Load the override config via the provider.
config_provider.update_app_config(app.config)
# Update any configuration found in the override environment variable.
environ_config = json.loads(os.environ.get(OVERRIDE_CONFIG_KEY, '{}'))
app.config.update(environ_config)
# Allow user to define a custom storage preference for the local instance.
_distributed_storage_preference = os.environ.get('QUAY_DISTRIBUTED_STORAGE_PREFERENCE', '').split()
if _distributed_storage_preference:
app.config['DISTRIBUTED_STORAGE_PREFERENCE'] = _distributed_storage_preference
# Generate a secret key if none was specified.
if app.config['SECRET_KEY'] is None:
logger.debug('Generating in-memory secret key')
app.config['SECRET_KEY'] = generate_secret_key()
# If the "preferred" scheme is https, then http is not allowed. Therefore, ensure we have a secure
# session cookie.
if (app.config['PREFERRED_URL_SCHEME'] == 'https' and
not app.config.get('FORCE_NONSECURE_SESSION_COOKIE', False)):
app.config['SESSION_COOKIE_SECURE'] = True
# Load features from config.
features.import_features(app.config)
CONFIG_DIGEST = hashlib.sha256(json.dumps(app.config, default=str)).hexdigest()[0:8]
logger.debug("Loaded config", extra={"config": app.config})
class RequestWithId(Request):
request_gen = staticmethod(urn_generator(['request']))
def __init__(self, *args, **kwargs):
super(RequestWithId, self).__init__(*args, **kwargs)
self.request_id = self.request_gen()
@app.before_request
def _request_start():
logger.debug('Starting request: %s (%s)', request.request_id, request.path,
extra={"request_id": request.request_id})
DEFAULT_FILTER = lambda x: '[FILTERED]'
FILTERED_VALUES = [
{'key': ['password'], 'fn': DEFAULT_FILTER},
{'key': ['user', 'password'], 'fn': DEFAULT_FILTER},
{'key': ['blob'], 'fn': lambda x: x[0:8]}
]
@app.after_request
def _request_end(resp):
jsonbody = request.get_json(force=True, silent=True)
values = request.values.to_dict()
if jsonbody and not isinstance(jsonbody, dict):
jsonbody = {'_parsererror': jsonbody}
if isinstance(values, dict):
filter_logs(values, FILTERED_VALUES)
extra = {
"endpoint": request.endpoint,
"request_id" : request.request_id,
"remote_addr": request.remote_addr,
"http_method": request.method,
"original_url": request.url,
"path": request.path,
"parameters": values,
"json_body": jsonbody,
"confsha": CONFIG_DIGEST,
}
if request.user_agent is not None:
extra["user-agent"] = request.user_agent.string
logger.debug('Ending request: %s (%s)', request.request_id, request.path, extra=extra)
return resp
root_logger = logging.getLogger()
app.request_class = RequestWithId
# Register custom converters.
app.url_map.converters['regex'] = RegexConverter
app.url_map.converters['repopath'] = RepositoryPathConverter
app.url_map.converters['apirepopath'] = APIRepositoryPathConverter
Principal(app, use_sessions=False)
tf = app.config['DB_TRANSACTION_FACTORY']
model_cache = get_model_cache(app.config)
avatar = Avatar(app)
login_manager = LoginManager(app)
mail = Mail(app)
prometheus = PrometheusPlugin(app)
metric_queue = MetricQueue(prometheus)
chunk_cleanup_queue = WorkQueue(app.config['CHUNK_CLEANUP_QUEUE_NAME'], tf, metric_queue=metric_queue)
instance_keys = InstanceKeys(app)
ip_resolver = IPResolver(app)
storage = Storage(app, metric_queue, chunk_cleanup_queue, instance_keys, config_provider, ip_resolver)
userfiles = Userfiles(app, storage)
log_archive = LogArchive(app, storage)
analytics = Analytics(app)
user_analytics = UserAnalytics(app)
billing = Billing(app)
sentry = Sentry(app)
build_logs = BuildLogs(app)
authentication = UserAuthentication(app, config_provider, OVERRIDE_CONFIG_DIRECTORY)
userevents = UserEventsBuilderModule(app)
superusers = SuperUserManager(app)
signer = Signer(app, config_provider)
instance_keys = InstanceKeys(app)
label_validator = LabelValidator(app)
build_canceller = BuildCanceller(app)
start_cloudwatch_sender(metric_queue, app)
github_trigger = GithubOAuthService(app.config, 'GITHUB_TRIGGER_CONFIG')
gitlab_trigger = GitLabOAuthService(app.config, 'GITLAB_TRIGGER_CONFIG')
oauth_login = OAuthLoginManager(app.config)
oauth_apps = [github_trigger, gitlab_trigger]
image_replication_queue = WorkQueue(app.config['REPLICATION_QUEUE_NAME'], tf,
has_namespace=False, metric_queue=metric_queue)
dockerfile_build_queue = WorkQueue(app.config['DOCKERFILE_BUILD_QUEUE_NAME'], tf,
metric_queue=metric_queue,
reporter=BuildMetricQueueReporter(metric_queue),
has_namespace=True)
notification_queue = WorkQueue(app.config['NOTIFICATION_QUEUE_NAME'], tf, has_namespace=True,
metric_queue=metric_queue)
secscan_notification_queue = WorkQueue(app.config['SECSCAN_NOTIFICATION_QUEUE_NAME'], tf,
has_namespace=False,
metric_queue=metric_queue)
# Note: We set `has_namespace` to `False` here, as we explicitly want this queue to not be emptied
# when a namespace is marked for deletion.
namespace_gc_queue = WorkQueue(app.config['NAMESPACE_GC_QUEUE_NAME'], tf, has_namespace=False,
metric_queue=metric_queue)
all_queues = [image_replication_queue, dockerfile_build_queue, notification_queue,
secscan_notification_queue, chunk_cleanup_queue, namespace_gc_queue]
secscan_api = SecurityScannerAPI(app, app.config, storage)
tuf_metadata_api = TUFMetadataAPI(app, app.config)
# Check for a key in config. If none found, generate a new signing key for Docker V2 manifests.
_v2_key_path = os.path.join(OVERRIDE_CONFIG_DIRECTORY, DOCKER_V2_SIGNINGKEY_FILENAME)
if os.path.exists(_v2_key_path):
docker_v2_signing_key = RSAKey().load(_v2_key_path)
else:
docker_v2_signing_key = RSAKey(key=RSA.generate(2048))
database.configure(app.config)
model.config.app_config = app.config
model.config.store = storage
model.config.register_image_cleanup_callback(secscan_api.cleanup_layers)
model.config.register_repo_cleanup_callback(tuf_metadata_api.delete_metadata)
@login_manager.user_loader
def load_user(user_uuid):
logger.debug('User loader loading deferred user with uuid: %s', user_uuid)
return LoginWrappedDBUser(user_uuid)
get_app_url = partial(get_app_url, app.config)

View file

@ -1,8 +1,8 @@
import os # import os
import logging # import logging
import logging.config # import logging.config
from util.log import logfile_path # from util.log import logfile_path
from app import app as application from app import app as application

View file

@ -0,0 +1,78 @@
from flask import make_response, render_template, request, session
def render_page_template(name, route_data=None, **kwargs):
""" Renders the page template with the given name as the response and returns its contents. """
# main_scripts = _list_files('build', 'js', js_bundle_name)
#
# use_cdn = app.config.get('USE_CDN', True)
# if request.args.get('use_cdn') is not None:
# use_cdn = request.args.get('use_cdn') == 'true'
#
# external_styles = get_external_css(local=not use_cdn)
# external_scripts = get_external_javascript(local=not use_cdn)
#
# # Add Stripe checkout if billing is enabled.
# if features.BILLING:
# external_scripts.append('//checkout.stripe.com/checkout.js')
#
# def get_external_login_config():
# login_config = []
# for login_service in oauth_login.services:
# login_config.append({
# 'id': login_service.service_id(),
# 'title': login_service.service_name(),
# 'config': login_service.get_public_config(),
# 'icon': login_service.get_icon(),
# })
#
# return login_config
#
# def get_oauth_config():
# oauth_config = {}
# for oauth_app in oauth_apps:
# oauth_config[oauth_app.key_name] = oauth_app.get_public_config()
#
# return oauth_config
#
# contact_href = None
# if len(app.config.get('CONTACT_INFO', [])) == 1:
# contact_href = app.config['CONTACT_INFO'][0]
#
# version_number = ''
# if not features.BILLING:
# version_number = 'Quay %s' % __version__
#
# scopes_set = {scope.scope: scope._asdict() for scope in scopes.app_scopes(app.config).values()}
contents = render_template(name,
route_data=route_data,
# external_styles=external_styles,
# external_scripts=external_scripts,
# main_scripts=main_scripts,
# feature_set=features.get_features(),
# config_set=frontend_visible_config(app.config),
# oauth_set=get_oauth_config(),
# external_login_set=get_external_login_config(),
# scope_set=scopes_set,
# vuln_priority_set=PRIORITY_LEVELS,
# enterprise_logo=app.config.get('ENTERPRISE_LOGO_URL', ''),
# mixpanel_key=app.config.get('MIXPANEL_KEY', ''),
# munchkin_key=app.config.get('MARKETO_MUNCHKIN_ID', ''),
# recaptcha_key=app.config.get('RECAPTCHA_SITE_KEY', ''),
# google_tagmanager_key=app.config.get('GOOGLE_TAGMANAGER_KEY', ''),
# google_anaytics_key=app.config.get('GOOGLE_ANALYTICS_KEY', ''),
# sentry_public_dsn=app.config.get('SENTRY_PUBLIC_DSN', ''),
# is_debug=str(app.config.get('DEBUGGING', False)).lower(),
# show_chat=features.SUPPORT_CHAT,
# aci_conversion=features.ACI_CONVERSION,
# has_billing=features.BILLING,
# contact_href=contact_href,
# hostname=app.config['SERVER_HOSTNAME'],
# preferred_scheme=app.config['PREFERRED_URL_SCHEME'],
# version_number=version_number,
# current_year=datetime.datetime.now().year,
**kwargs)
resp = make_response(contents)
resp.headers['X-FRAME-OPTIONS'] = 'DENY'
return resp

View file

@ -5,25 +5,26 @@ import logging
from datetime import timedelta, datetime from datetime import timedelta, datetime
from cachetools import lru_cache from cachetools import lru_cache
from flask import (abort, redirect, request, url_for, make_response, Response, render_template, # from flask import (abort, redirect, request, url_for, make_response, Response, render_template,
Blueprint, jsonify, send_file, session) # Blueprint, jsonify, send_file, session)
from flask_login import current_user from flask import Blueprint
# from flask_login import current_user
from app import (app) from app import (app)
from endpoints.api.discovery import swagger_route_data # from endpoints.api.discovery import swagger_route_data
from endpoints.common import common_login, render_page_template from common import render_page_template
from util.cache import no_cache from util.cache import no_cache
@lru_cache(maxsize=1) # @lru_cache(maxsize=1)
def _get_route_data(): # def _get_route_data():
return swagger_route_data(include_internal=True, compact=True) # return swagger_route_data(include_internal=True, compact=True)
def render_page_template_with_routedata(name, *args, **kwargs): def render_page_template_with_routedata(name, *args, **kwargs):
return render_page_template(name, _get_route_data(), *args, **kwargs) return render_page_template(name, *args, **kwargs)
# Capture the unverified SSL errors. # Capture the unverified SSL errors.
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -31,7 +32,7 @@ logging.captureWarnings(True)
setup_web = Blueprint('setup_web', __name__, template_folder='templates') setup_web = Blueprint('setup_web', __name__, template_folder='templates')
STATUS_TAGS = app.config['STATUS_TAGS'] # STATUS_TAGS = app.config['STATUS_TAGS']
@setup_web.route('/', methods=['GET'], defaults={'path': ''}) @setup_web.route('/', methods=['GET'], defaults={'path': ''})
@no_cache @no_cache

View file

@ -1,11 +1,12 @@
{% extends "base.html" %} <!DOCTYPE html>
<html ng-app="quay">
{% block title %} <head>
<title>Config mode</title> <title>Config app</title>
{% endblock %} </head>
{% block body_content %} <body>
<p> <div>
<div>What is my purpose?</div> <p>What is my purpose</p>
<div>You create tarballs</div> <p>You make tarballs</p>
</p> </div>
{% endblock %} </body>
</html>