Move config provider to _init to decouple from app

remove app references from validators
This commit is contained in:
Sam Chow 2018-05-24 14:58:38 -04:00
parent 86929c16d3
commit d45b925155
26 changed files with 54 additions and 51 deletions

View file

@ -2,6 +2,8 @@ import os
import re
import subprocess
from util.config.provider import get_config_provider
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
CONF_DIR = os.getenv("QUAYCONF", os.path.join(ROOT_DIR, "conf/"))
@ -10,6 +12,14 @@ STATIC_LDN_DIR = os.path.join(STATIC_DIR, 'ldn/')
STATIC_FONTS_DIR = os.path.join(STATIC_DIR, 'fonts/')
TEMPLATE_DIR = os.path.join(ROOT_DIR, 'templates/')
IS_TESTING = 'TEST' in os.environ
IS_KUBERNETES = 'KUBERNETES_SERVICE_HOST' in os.environ
OVERRIDE_CONFIG_DIRECTORY = os.path.join(CONF_DIR, 'stack/')
config_provider = get_config_provider(OVERRIDE_CONFIG_DIRECTORY, 'config.yaml', 'config.py',
testing=IS_TESTING, kubernetes=IS_KUBERNETES)
def _get_version_number_changelog():
try:

12
app.py
View file

@ -13,7 +13,9 @@ from flask_principal import Principal
from jwkest.jwk import RSAKey
import features
from _init import CONF_DIR
from _init import config_provider, CONF_DIR, IS_KUBERNETES, IS_TESTING, OVERRIDE_CONFIG_DIRECTORY
from auth.auth_context import get_authenticated_user
from avatars.avatars import Avatar
from buildman.manager.buildcanceller import BuildCanceller
@ -41,7 +43,6 @@ 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
@ -53,7 +54,6 @@ 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')
@ -65,10 +65,8 @@ 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)
is_testing = IS_TESTING
is_kubernetes = IS_KUBERNETES
if is_testing:
from test.testconfig import TestConfig

View file

@ -405,6 +405,6 @@ class SuperUserConfigValidate(ApiResource):
# this is also safe since this method does not access any information not given in the request.
if not config_provider.config_exists() or SuperUserPermission().can():
config = request.get_json()['config']
return validate_service_for_config(service, config, request.get_json().get('password', ''))
return validate_service_for_config(service, config, request.get_json().get('password', ''), app)
abort(403)

View file

@ -64,7 +64,7 @@ VALIDATORS = {
AppTokenAuthValidator.name: AppTokenAuthValidator.validate,
}
def validate_service_for_config(service, config, password=None):
def validate_service_for_config(service, config, password=None, app=None):
""" Attempts to validate the configuration for the given service. """
if not service in VALIDATORS:
return {
@ -72,7 +72,7 @@ def validate_service_for_config(service, config, password=None):
}
try:
VALIDATORS[service](config, get_authenticated_user(), password)
VALIDATORS[service](config, get_authenticated_user(), password, app)
return {
'status': True
}

View file

@ -15,6 +15,6 @@ class BaseValidator(object):
@classmethod
@abstractmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Raises Exception if failure to validate. """
pass

View file

@ -14,7 +14,7 @@ from test.fixtures import *
({'AUTHENTICATION_TYPE': 'Database'}),
])
def test_validate_noop(unvalidated_config, app):
JWTAuthValidator.validate(unvalidated_config, None, None)
JWTAuthValidator.validate(unvalidated_config, None, None, app)
@pytest.mark.parametrize('unvalidated_config', [
@ -24,7 +24,7 @@ def test_validate_noop(unvalidated_config, app):
])
def test_invalid_config(unvalidated_config, app):
with pytest.raises(ConfigValidationException):
JWTAuthValidator.validate(unvalidated_config, None, None)
JWTAuthValidator.validate(unvalidated_config, None, None, app)
@pytest.mark.parametrize('username, password, expected_exception', [
@ -44,8 +44,8 @@ def test_validated_jwt(username, password, expected_exception, app):
if expected_exception is not None:
with pytest.raises(ConfigValidationException):
JWTAuthValidator.validate(config, AttrDict(dict(username=username)), password,
JWTAuthValidator.validate(config, AttrDict(dict(username=username)), password, app,
public_key_path=jwt_auth.public_key_path)
else:
JWTAuthValidator.validate(config, AttrDict(dict(username=username)), password,
JWTAuthValidator.validate(config, AttrDict(dict(username=username)), password, app,
public_key_path=jwt_auth.public_key_path)

View file

@ -1,4 +1,3 @@
from app import app
from util.config.validators import BaseValidator, ConfigValidationException
from oauth.loginmanager import OAuthLoginManager
from oauth.oidc import OIDCLoginService
@ -7,7 +6,7 @@ class AccessSettingsValidator(BaseValidator):
name = "access"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
if not config.get('FEATURE_DIRECT_LOGIN', True):
# Make sure we have at least one OIDC enabled.
github_login = config.get('FEATURE_GITHUB_LOGIN', False)

View file

@ -4,7 +4,7 @@ class ActionLogArchivingValidator(BaseValidator):
name = "actionlogarchiving"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the action log archiving configuration. """
if not config.get('FEATURE_ACTION_LOG_ROTATION', False):
return

View file

@ -4,7 +4,7 @@ class AppTokenAuthValidator(BaseValidator):
name = "apptoken-auth"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
if config.get('AUTHENTICATION_TYPE', 'Database') != 'AppToken':
return

View file

@ -1,13 +1,13 @@
from bitbucket import BitBucket
from app import get_app_url
from util import get_app_url
from util.config.validators import BaseValidator, ConfigValidationException
class BitbucketTriggerValidator(BaseValidator):
name = "bitbucket-trigger"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the config for BitBucket. """
trigger_config = config.get('BITBUCKET_TRIGGER_CONFIG')
if not trigger_config:
@ -21,7 +21,7 @@ class BitbucketTriggerValidator(BaseValidator):
key = trigger_config['CONSUMER_KEY']
secret = trigger_config['CONSUMER_SECRET']
callback_url = '%s/oauth1/bitbucket/callback/trigger/' % (get_app_url())
callback_url = '%s/oauth1/bitbucket/callback/trigger/' % (get_app_url(app.config))
bitbucket_client = BitBucket(key, secret, callback_url)
(result, _, _) = bitbucket_client.get_authorization_url()

View file

@ -7,7 +7,7 @@ class DatabaseValidator(BaseValidator):
name = "database"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates connecting to the database. """
try:
validate_database_url(config['DB_URI'], config.get('DB_CONNECTION_ARGS', {}))

View file

@ -1,14 +1,13 @@
from flask import Flask
from flask_mail import Mail, Message
from app import app
from util.config.validators import BaseValidator
class EmailValidator(BaseValidator):
name = "mail"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates sending email. """
with app.app_context():
test_app = Flask("mail-test-app")

View file

@ -1,4 +1,3 @@
from app import app
from oauth.services.github import GithubOAuthService
from util.config.validators import BaseValidator, ConfigValidationException
@ -7,7 +6,7 @@ class BaseGitHubValidator(BaseValidator):
config_key = None
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the OAuth credentials and API endpoint for a Github service. """
github_config = config.get(cls.config_key)
if not github_config:

View file

@ -1,4 +1,3 @@
from app import app
from oauth.services.gitlab import GitLabOAuthService
from util.config.validators import BaseValidator, ConfigValidationException
@ -6,7 +5,7 @@ class GitLabTriggerValidator(BaseValidator):
name = "gitlab-trigger"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the OAuth credentials and API endpoint for a GitLab service. """
github_config = config.get('GITLAB_TRIGGER_CONFIG')
if not github_config:

View file

@ -1,4 +1,3 @@
from app import app
from oauth.services.google import GoogleOAuthService
from util.config.validators import BaseValidator, ConfigValidationException
@ -6,7 +5,7 @@ class GoogleLoginValidator(BaseValidator):
name = "google-login"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the Google Login client ID and secret. """
google_login_config = config.get('GOOGLE_LOGIN_CONFIG')
if not google_login_config:

View file

@ -1,4 +1,4 @@
from app import app, OVERRIDE_CONFIG_DIRECTORY
from _init import OVERRIDE_CONFIG_DIRECTORY
from data.users.externaljwt import ExternalJWTAuthN
from util.config.validators import BaseValidator, ConfigValidationException
@ -6,7 +6,7 @@ class JWTAuthValidator(BaseValidator):
name = "jwt"
@classmethod
def validate(cls, config, user, user_password, public_key_path=None):
def validate(cls, config, user, user_password, app, public_key_path=None):
""" Validates the JWT authentication system. """
if config.get('AUTHENTICATION_TYPE', 'Database') != 'JWT':
return

View file

@ -5,7 +5,7 @@ class KeystoneValidator(BaseValidator):
name = "keystone"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the Keystone authentication system. """
if config.get('AUTHENTICATION_TYPE', 'Database') != 'Keystone':
return

View file

@ -2,17 +2,16 @@ import os
import ldap
import subprocess
from app import app, config_provider
from data.users import LDAP_CERT_FILENAME
from data.users.externalldap import LDAPConnection, LDAPUsers
from util.config.validators import BaseValidator, ConfigValidationException
from _init import CONF_DIR
from _init import CONF_DIR, config_provider
class LDAPValidator(BaseValidator):
name = "ldap"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the LDAP connection. """
if config.get('AUTHENTICATION_TYPE', 'Database') != 'LDAP':
return

View file

@ -1,4 +1,3 @@
from app import app
from oauth.loginmanager import OAuthLoginManager
from oauth.oidc import OIDCLoginService, DiscoveryFailureException
from util.config.validators import BaseValidator, ConfigValidationException
@ -7,7 +6,7 @@ class OIDCLoginValidator(BaseValidator):
name = "oidc-login"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
client = app.config['HTTPCLIENT']
login_manager = OAuthLoginManager(config, client=client)
for service in login_manager.services:

View file

@ -6,7 +6,7 @@ class RedisValidator(BaseValidator):
name = "redis"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates connecting to redis. """
redis_config = config.get('BUILDLOGS_REDIS', {})
if not 'host' in redis_config:

View file

@ -1,6 +1,5 @@
import time
from app import app
from boot import setup_jwt_proxy
from util.secscan.api import SecurityScannerAPI
from util.config.validators import BaseValidator, ConfigValidationException
@ -9,7 +8,7 @@ class SecurityScannerValidator(BaseValidator):
name = "security-scanner"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the configuration for talking to a Quay Security Scanner. """
if not config.get('FEATURE_SECURITY_SCANNER', False):
return

View file

@ -1,6 +1,6 @@
from StringIO import StringIO
from app import config_provider
from _init import config_provider
from util.config.validators import BaseValidator, ConfigValidationException
from util.security.signing import SIGNING_ENGINES
@ -8,7 +8,7 @@ class SignerValidator(BaseValidator):
name = "signer"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the GPG public+private key pair used for signing converted ACIs. """
if config.get('SIGNING_ENGINE') is None:
return

View file

@ -1,4 +1,4 @@
from app import config_provider
from _init import config_provider
from util.config.validators import BaseValidator, ConfigValidationException
from util.security.ssl import load_certificate, CertInvalidException, KeyInvalidException
@ -8,7 +8,7 @@ class SSLValidator(BaseValidator):
name = "ssl"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the SSL configuration (if enabled). """
# Skip if non-SSL.

View file

@ -1,12 +1,16 @@
from app import app, ip_resolver, config_provider
from _init import config_provider
from storage import get_storage_driver
from util.config.validators import BaseValidator, ConfigValidationException
from util.ipresolver import NoopIPResolver
ip_resolver = NoopIPResolver()
class StorageValidator(BaseValidator):
name = "registry-storage"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates registry storage. """
replication_enabled = config.get('FEATURE_STORAGE_REPLICATION', False)

View file

@ -9,7 +9,7 @@ class TimeMachineValidator(BaseValidator):
name = "time-machine"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
if not 'DEFAULT_TAG_EXPIRATION' in config:
# Old style config
return

View file

@ -2,7 +2,6 @@ import logging
from hashlib import sha1
from app import app
from util.config.validators import BaseValidator, ConfigValidationException
from util.registry.torrent import jwt_from_infohash
@ -12,7 +11,7 @@ class BittorrentValidator(BaseValidator):
name = "bittorrent"
@classmethod
def validate(cls, config, user, user_password):
def validate(cls, config, user, user_password, app):
""" Validates the configuration for using BitTorrent for downloads. """
announce_url = config.get('BITTORRENT_ANNOUNCE_URL')
if not announce_url: