diff --git a/config_app/c_app.py b/config_app/c_app.py
index 049aef619..62002a15a 100644
--- a/config_app/c_app.py
+++ b/config_app/c_app.py
@@ -3,7 +3,7 @@ import logging
from flask import Flask
-from data import database
+from data import database, model
from util.config.superusermanager import SuperUserManager
from util.ipresolver import NoopIPResolver
@@ -35,3 +35,5 @@ else:
config_provider.update_app_config(app.config)
superusers = SuperUserManager(app)
ip_resolver = NoopIPResolver()
+
+model.config.app_config = app.config
diff --git a/config_app/config_endpoints/api/suconfig.py b/config_app/config_endpoints/api/suconfig.py
index 539a6599c..37eb72bd3 100644
--- a/config_app/config_endpoints/api/suconfig.py
+++ b/config_app/config_endpoints/api/suconfig.py
@@ -22,9 +22,6 @@ logger = logging.getLogger(__name__)
def database_is_valid():
""" Returns whether the database, as configured, is valid. """
- if app.config['TESTING']:
- return False
-
return model.is_valid()
@@ -103,9 +100,6 @@ class SuperUserConfig(ApiResource):
# Link the existing user to the external user.
model.attach_federated_login(current_user.username, service_name, result.username)
- # Ensure database is up-to-date with config
- sync_database_with_config(config_object)
-
return {
'exists': True,
'config': config_object
@@ -182,11 +176,12 @@ class SuperUserSetupDatabase(ApiResource):
configure(combined)
app.config['DB_URI'] = combined['DB_URI']
+ db_uri = app.config['DB_URI']
log_handler = _AlembicLogHandler()
try:
- run_alembic_migration(log_handler)
+ run_alembic_migration(db_uri, log_handler)
except Exception as ex:
return {
'error': str(ex)
diff --git a/config_app/config_endpoints/api/suconfig_models_pre_oci.py b/config_app/config_endpoints/api/suconfig_models_pre_oci.py
index df83b8e9f..655b0c1da 100644
--- a/config_app/config_endpoints/api/suconfig_models_pre_oci.py
+++ b/config_app/config_endpoints/api/suconfig_models_pre_oci.py
@@ -4,6 +4,8 @@ from config_app.config_endpoints.api.suconfig_models_interface import SuperuserC
class PreOCIModel(SuperuserConfigDataInterface):
+ # Note: this method is different than has_users: the user select will throw if the user
+ # table does not exist, whereas has_users assumes the table is valid
def is_valid(self):
try:
list(User.select().limit(1))
diff --git a/config_app/config_endpoints/api/superuser.py b/config_app/config_endpoints/api/superuser.py
index c061adacf..c672edb80 100644
--- a/config_app/config_endpoints/api/superuser.py
+++ b/config_app/config_endpoints/api/superuser.py
@@ -79,14 +79,13 @@ class SuperUserCustomCertificates(ApiResource):
cert_views = []
for extra_cert_path in extra_certs_found:
try:
- cert_full_path = config_provider.get_volume_path(EXTRA_CA_DIRECTORY, extra_cert_path)
- with config_provider.get_volume_file(cert_full_path) as f:
- certificate = load_certificate(f.read())
- cert_views.append({
- 'path': extra_cert_path,
- 'names': list(certificate.names),
- 'expired': certificate.expired,
- })
+ cert = config_provider.get_volume_path(EXTRA_CA_DIRECTORY, extra_cert_path)
+ certificate = load_certificate(cert)
+ cert_views.append({
+ 'path': extra_cert_path,
+ 'names': list(certificate.names),
+ 'expired': certificate.expired,
+ })
except CertInvalidException as cie:
cert_views.append({
'path': extra_cert_path,
diff --git a/config_app/config_endpoints/api/tar_config_loader.py b/config_app/config_endpoints/api/tar_config_loader.py
index d7e41d446..32e907316 100644
--- a/config_app/config_endpoints/api/tar_config_loader.py
+++ b/config_app/config_endpoints/api/tar_config_loader.py
@@ -4,7 +4,9 @@ import cStringIO
from flask import request, make_response
-from config_app.c_app import config_provider
+from data.database import configure
+
+from config_app.c_app import app, config_provider
from config_app.config_endpoints.api import resource, ApiResource, nickname, validate_json_request
logger = logging.getLogger(__name__)
@@ -25,4 +27,10 @@ class TarConfigLoader(ApiResource):
# TODO(sam): refactor config provider to accept a stream write to avoid loading into memory
config_provider.load_from_tarball(config)
+ # now try to connect to the db provided in their config
+ combined = dict(**app.config)
+ combined.update(config_provider.get_config())
+
+ configure(combined)
+
return make_response('OK')
diff --git a/config_app/config_util/config/__init__.py b/config_app/config_util/config/__init__.py
index 018d5cc8c..1c2e77bfb 100644
--- a/config_app/config_util/config/__init__.py
+++ b/config_app/config_util/config/__init__.py
@@ -5,12 +5,12 @@ from config_app.config_util.config.inmemoryprovider import InMemoryProvider
def get_config_provider(config_volume, yaml_filename, py_filename, testing=False):
""" Loads and returns the config provider for the current environment. """
- if True:
- return InMemoryProvider()
if testing:
return TestConfigProvider()
- return FileConfigProvider(config_volume, yaml_filename, py_filename)
+ else:
+ return InMemoryProvider()
+
diff --git a/config_app/config_util/config/inmemoryprovider.py b/config_app/config_util/config/inmemoryprovider.py
index 750cf1aed..e900f3381 100644
--- a/config_app/config_util/config/inmemoryprovider.py
+++ b/config_app/config_util/config/inmemoryprovider.py
@@ -12,6 +12,7 @@ class InMemoryProvider(BaseProvider):
def __init__(self):
self.files = {}
self.config = {}
+ self.was_loaded = False
@property
def provider_id(self):
@@ -24,16 +25,17 @@ class InMemoryProvider(BaseProvider):
return self.config
def save_config(self, config_object):
- raise Exception('Not implemented yet')
+ self.config = config_object
+ self.was_loaded = True
def config_exists(self):
- raise Exception('Not implemented yet')
+ return self.was_loaded
def volume_exists(self):
- raise Exception('Not implemented yet')
+ return True
def volume_file_exists(self, filename):
- return filename in self.files
+ return any([ name.startswith(filename) for name in self.files ])
def get_volume_file(self, filename, mode='r'):
return self.files[filename]
@@ -45,7 +47,7 @@ class InMemoryProvider(BaseProvider):
raise Exception('Not implemented yet')
def list_volume_directory(self, path):
- return [ name for name in self.files ]
+ return [ name for name in self.files if name.startswith(path) ]
def save_volume_file(self, filename, flask_file):
raise Exception('Not implemented yet')
@@ -54,7 +56,8 @@ class InMemoryProvider(BaseProvider):
raise Exception('Not implemented yet')
def get_volume_path(self, directory, filename):
- raise Exception('Not implemented yet')
+ # Here we can just access the filename since we're storing the tarball files with their full path
+ return self.files[filename]
def load_from_tarball(self, tarfile):
for tarinfo in tarfile.getmembers():
@@ -63,4 +66,5 @@ class InMemoryProvider(BaseProvider):
self.config = yaml.load(tarfile.extractfile(tarinfo.name).read())
else:
self.files[tarinfo.name] = tarfile.extractfile(tarinfo.name).read()
+ self.was_loaded = True
diff --git a/config_app/js/components/config-setup-app/config-setup-app.component.html b/config_app/js/components/config-setup-app/config-setup-app.component.html
index 52430bc35..d1ea58f31 100644
--- a/config_app/js/components/config-setup-app/config-setup-app.component.html
+++ b/config_app/js/components/config-setup-app/config-setup-app.component.html
@@ -23,4 +23,4 @@
-
+
diff --git a/config_app/js/components/config-setup-app/config-setup-app.component.ts b/config_app/js/components/config-setup-app/config-setup-app.component.ts
index 6b002e1db..e22ca57c0 100644
--- a/config_app/js/components/config-setup-app/config-setup-app.component.ts
+++ b/config_app/js/components/config-setup-app/config-setup-app.component.ts
@@ -22,4 +22,8 @@ export class ConfigSetupAppComponent {
private chooseLoad(): void {
this.state = 'load';
}
+
+ private configLoaded(): void {
+ this.state = 'setup';
+ }
}
diff --git a/config_app/js/components/load-config/load-config.component.ts b/config_app/js/components/load-config/load-config.component.ts
index a4d745af2..612702686 100644
--- a/config_app/js/components/load-config/load-config.component.ts
+++ b/config_app/js/components/load-config/load-config.component.ts
@@ -1,4 +1,4 @@
-import { Component, Inject } from 'ng-metadata/core';
+import {Component, EventEmitter, Inject, Output} from 'ng-metadata/core';
const templateUrl = require('./load-config.html');
const styleUrl = require('./load-config.css');
@@ -10,7 +10,7 @@ const styleUrl = require('./load-config.css');
export class LoadConfigComponent {
private readyToSubmit: boolean = false;
private uploadFunc: Function;
- private state: 'load' | 'validate' = 'load';
+ @Output() public configLoaded: EventEmitter = new EventEmitter();
private constructor(@Inject('ApiService') private apiService: any) {
}
@@ -27,9 +27,8 @@ export class LoadConfigComponent {
private uploadTarball() {
this.uploadFunc(success => {
if (success) {
- this.state = 'validate';
- }
- else {
+ this.configLoaded.emit({});
+ } else {
this.apiService.errorDisplay('Error loading configuration',
'Could not upload configuration. Please reload the page and try again.\n' +
'If this problem persists, please contact support')();
diff --git a/config_app/js/components/load-config/load-config.css b/config_app/js/components/load-config/load-config.css
index a557fd3a9..e69de29bb 100644
--- a/config_app/js/components/load-config/load-config.css
+++ b/config_app/js/components/load-config/load-config.css
@@ -1,4 +0,0 @@
-
-
-.load-config__body strong {
-}
\ No newline at end of file
diff --git a/config_app/js/components/load-config/load-config.html b/config_app/js/components/load-config/load-config.html
index bc1aee793..155435baa 100644
--- a/config_app/js/components/load-config/load-config.html
+++ b/config_app/js/components/load-config/load-config.html
@@ -1,4 +1,4 @@
-
+
-
-
-
-
-
-
-
-
-
-
- Validating Config...
- spinner here...
-
-
-
-
-
diff --git a/config_app/js/core-config-setup/core-config-setup.js b/config_app/js/core-config-setup/core-config-setup.js
index d7f91d9bf..4e7afdac2 100644
--- a/config_app/js/core-config-setup/core-config-setup.js
+++ b/config_app/js/core-config-setup/core-config-setup.js
@@ -190,9 +190,10 @@ angular.module("quay-config")
};
$scope.validateHostname = function(hostname) {
- if (hostname.indexOf('127.0.0.1') == 0 || hostname.indexOf('localhost') == 0) {
- return 'Please specify a non-localhost hostname. "localhost" will refer to the container, not your machine.'
- }
+ // TODO(sam): maybe revert?
+ // if (hostname.indexOf('127.0.0.1') == 0 || hostname.indexOf('localhost') == 0) {
+ // return 'Please specify a non-localhost hostname. "localhost" will refer to the container, not your machine.'
+ // }
return null;
};
diff --git a/config_app/js/setup/setup.component.js b/config_app/js/setup/setup.component.js
index 3e828214c..5e668ccaa 100644
--- a/config_app/js/setup/setup.component.js
+++ b/config_app/js/setup/setup.component.js
@@ -31,9 +31,10 @@ const templateUrl = require('./setup.html');
$scope.HOSTNAME_REGEX = '^[a-zA-Z-0-9_\.\-]+(:[0-9]+)?$';
$scope.validateHostname = function(hostname) {
- if (hostname.indexOf('127.0.0.1') == 0 || hostname.indexOf('localhost') == 0) {
- return 'Please specify a non-localhost hostname. "localhost" will refer to the container, not your machine.'
- }
+ // TODO(sam): maybe revert?
+ // if (hostname.indexOf('127.0.0.1') == 0 || hostname.indexOf('localhost') == 0) {
+ // return 'Please specify a non-localhost hostname. "localhost" will refer to the container, not your machine.'
+ // }
return null;
};
@@ -65,9 +66,6 @@ const templateUrl = require('./setup.html');
// Database is being setup.
'DB_SETUP': 'setup-db',
- // Database setup has succeeded.
- 'DB_SETUP_SUCCESS': 'setup-db-success',
-
// An error occurred when setting up the database.
'DB_SETUP_ERROR': 'setup-db-error',
@@ -262,7 +260,7 @@ const templateUrl = require('./setup.html');
$scope.createSuperUser = function() {
$scope.currentStep = $scope.States.CREATING_SUPERUSER;
ApiService.scCreateInitialSuperuser($scope.superUser, null).then(function(resp) {
- UserService.load();
+ // UserService.load();
$scope.checkStatus();
}, function(resp) {
$scope.currentStep = $scope.States.SUPERUSER_ERROR;
@@ -277,7 +275,7 @@ const templateUrl = require('./setup.html');
$scope.currentStep = $scope.States.DB_SETUP_ERROR;
$scope.errors.DatabaseSetupError = resp['error'];
} else {
- $scope.currentStep = $scope.States.DB_SETUP_SUCCESS;
+ $scope.currentStep = $scope.States.CREATE_SUPERUSER;
}
}, ApiService.errorDisplay('Could not setup database. Please report this to support.'))
};
diff --git a/config_app/js/setup/setup.html b/config_app/js/setup/setup.html
index bfbc194dc..753c8cceb 100644
--- a/config_app/js/setup/setup.html
+++ b/config_app/js/setup/setup.html
@@ -24,8 +24,8 @@
Configure your Redis database and other settings below
-
+
@@ -39,7 +39,7 @@
-
+
@@ -95,7 +95,7 @@
-
+
is currently being restarted
This can take several minutes. If the container does not restart on its own,
diff --git a/data/migrations/env.py b/data/migrations/env.py
index 10296c1b1..c8e034903 100644
--- a/data/migrations/env.py
+++ b/data/migrations/env.py
@@ -14,14 +14,13 @@ from peewee import SqliteDatabase
from data.database import all_models, db
from data.migrations.tester import NoopTester, PopulateTestDataTester
-from app import app
from data.model.sqlalchemybridge import gen_sqlalchemy_metadata
from release import GIT_HEAD, REGION, SERVICE
from util.morecollections import AttrDict
config = context.config
-config.set_main_option('sqlalchemy.url', unquote(app.config['DB_URI']))
-
+DB_URI = config.get_main_option('db_uri')
+config.set_main_option('sqlalchemy.url', unquote(DB_URI))
# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name:
@@ -47,7 +46,7 @@ def get_tester():
connecting to a production database.
"""
if os.environ.get('TEST_MIGRATE', '') == 'true':
- url = unquote(app.config['DB_URI'])
+ url = unquote(DB_URI)
if url.find('.quay.io') < 0:
return PopulateTestDataTester()
@@ -65,12 +64,11 @@ def run_migrations_offline():
script output.
"""
- url = unquote(app.config['DB_URI'])
+ url = unquote(DB_URI)
context.configure(url=url, target_metadata=target_metadata, transactional_ddl=True)
with context.begin_transaction():
- context.run_migrations(tables=tables, tester=get_tester())
-
+ context.run_migrations(tables=tables)
def run_migrations_online():
"""Run migrations in 'online' mode.
@@ -99,7 +97,7 @@ def run_migrations_online():
try:
with context.begin_transaction():
try:
- context.run_migrations(tables=tables, tester=get_tester())
+ context.run_migrations(tables=tables)
except (CommandError, ResolutionError) as ex:
if 'No such revision' not in str(ex):
raise
diff --git a/data/runmigration.py b/data/runmigration.py
index b06cf861d..0b0fb9c32 100644
--- a/data/runmigration.py
+++ b/data/runmigration.py
@@ -5,12 +5,13 @@ from alembic.script import ScriptDirectory
from alembic.environment import EnvironmentContext
from alembic.migration import __name__ as migration_name
-def run_alembic_migration(log_handler=None):
+def run_alembic_migration(db_uri, log_handler=None):
if log_handler:
logging.getLogger(migration_name).addHandler(log_handler)
config = Config()
config.set_main_option("script_location", "data:migrations")
+ config.set_main_option("db_uri", db_uri)
script = ScriptDirectory.from_config(config)
def fn(rev, context):
diff --git a/endpoints/api/suconfig.py b/endpoints/api/suconfig.py
index 2ed481219..77954c6ae 100644
--- a/endpoints/api/suconfig.py
+++ b/endpoints/api/suconfig.py
@@ -118,7 +118,7 @@ class SuperUserSetupDatabase(ApiResource):
log_handler = _AlembicLogHandler()
try:
- run_alembic_migration(log_handler)
+ run_alembic_migration(app.config['DB_URI'], log_handler)
except Exception as ex:
return {
'error': str(ex)