Tarball the config and give it to the front end

Download file as blob to avoid binary string encoding
This commit is contained in:
Sam Chow 2018-06-25 17:40:59 -04:00
parent 7619ab44e5
commit aa93d698b2
8 changed files with 66 additions and 1677 deletions

View file

@ -1,7 +1,4 @@
import logging import logging
import os
import subprocess
import signal
from flask import abort, request from flask import abort, request
@ -14,9 +11,7 @@ from data.users import get_federated_service_name, get_users_handler
from data.database import configure from data.database import configure
from data.runmigration import run_alembic_migration from data.runmigration import run_alembic_migration
from util.config.configutil import add_enterprise_config_defaults from util.config.configutil import add_enterprise_config_defaults
from util.config.database import sync_database_with_config
from util.config.validator import validate_service_for_config, ValidatorContext, is_valid_config_upload_filename from util.config.validator import validate_service_for_config, ValidatorContext, is_valid_config_upload_filename
from util.config.validators import LocalStorageConfigValidationException
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View file

@ -4,15 +4,16 @@ import os
from flask import request, jsonify from flask import request, jsonify
from util.config.validator import EXTRA_CA_DIRECTORY
from config_app.config_endpoints.exception import InvalidRequest from config_app.config_endpoints.exception import InvalidRequest
from config_app.config_endpoints.api import resource, ApiResource, nickname from config_app.config_endpoints.api import resource, ApiResource, nickname
from config_app.config_endpoints.api.superuser_models_pre_oci import pre_oci_model
from config_app.config_util.ssl import load_certificate, CertInvalidException from config_app.config_util.ssl import load_certificate, CertInvalidException
from config_app.c_app import app, config_provider from config_app.c_app import app, config_provider
from config_app.config_endpoints.api.superuser_models_pre_oci import pre_oci_model
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
EXTRA_CA_DIRECTORY = 'extra_ca_certs'
@resource('/v1/superuser/customcerts/<certpath>') @resource('/v1/superuser/customcerts/<certpath>')

View file

@ -1,17 +1,53 @@
import os
import tarfile import tarfile
from flask import request, make_response from flask import request, make_response, send_file
from data.database import configure from data.database import configure
from util.config.validator import EXTRA_CA_DIRECTORY
from config_app.c_app import app, config_provider from config_app.c_app import app, config_provider
from config_app.config_endpoints.api import resource, ApiResource, nickname from config_app.config_endpoints.api import resource, ApiResource, nickname
@resource('/v1/configapp/tarconfig') @resource('/v1/configapp/tarconfig')
class TarConfigLoader(ApiResource): class TarConfigLoader(ApiResource):
""" Resource for validating a block of configuration against an external service. """ """
Resource for dealing with configuration as a tarball,
including loading and generating functions
"""
@nickname('uploadTarballConfig') @nickname('scGetConfigTarball')
def get(self):
config_path = config_provider.config_volume
# remove the initial trailing / from the prefix path, and add the last dir one
tar_dir_prefix = config_path[1:] + '/'
def tarinfo_filter(tarinfo):
# remove leading directory info
tarinfo.name = tarinfo.name.replace(tar_dir_prefix, '')
# ignore any directory that isn't the specified extra ca one:
if tarinfo.isdir() and not tarinfo.name == EXTRA_CA_DIRECTORY:
return None
return tarinfo
# Remove the tar if it already exists so we don't write on top of existing tarball
if os.path.isfile('quay-config.tar.gz'):
os.remove('quay-config.tar.gz')
tar = tarfile.open('quay-config.tar.gz', mode="w:gz")
for name in os.listdir(config_path):
tar.add(os.path.join(config_path, name), filter=tarinfo_filter)
tar.close()
return send_file('quay-config.tar.gz', mimetype='application/gzip',
as_attachment=True, attachment_filename='quay-config.tar.gz')
@nickname('scUploadTarballConfig')
def put(self): def put(self):
""" Loads tarball config into the config provider """ """ Loads tarball config into the config provider """
input_stream = request.stream input_stream = request.stream

File diff suppressed because it is too large Load diff

View file

@ -1630,9 +1630,9 @@
</span> </span>
<button class="btn btn-primary" <button class="btn btn-primary"
ng-click="saveConfiguration()" ng-click="generateConfigTarball()"
ng-disabled="savingConfiguration"> ng-disabled="savingConfiguration">
<i class="fa fa-upload" style="margin-right: 10px;"></i>Save Configuration <i class="fa fa-upload" style="margin-right: 10px;"></i>Generate Configuration
</button> </button>
</div> </div>

View file

@ -413,12 +413,12 @@ angular.module("quay-config")
} }
}; };
$scope.saveConfiguration = function() { $scope.generateConfigTarball = function() {
$scope.savingConfiguration = true; $scope.savingConfiguration = true;
// Make sure to note that fully verified setup is completed. We use this as a signal // Make sure to note that fully verified setup is completed. We use this as a signal
// in the setup tool. // in the setup tool.
$scope.config['SETUP_COMPLETE'] = true; // $scope.config['SETUP_COMPLETE'] = true;
var data = { var data = {
'config': $scope.config, 'config': $scope.config,
@ -432,9 +432,14 @@ angular.module("quay-config")
authPassword = null; authPassword = null;
}); });
ApiService.scUpdateConfig(data).then(function(resp) { // We need to set the response type to 'blob', to ensure it's never encoded as a string
// (string encoded binary data can be difficult to transform with js)
// and to make it easier to save (FileSaver expects a blob)
ApiService.scGetConfigTarball(null, null, null, null, true).then(function(resp) {
authPassword = null; authPassword = null;
FileSaver.saveAs(resp, 'quay-config.tar.gz');
$scope.savingConfiguration = false; $scope.savingConfiguration = false;
$scope.mapped.$hasChanges = false; $scope.mapped.$hasChanges = false;

View file

@ -212,12 +212,20 @@ angular.module('quay-config').factory('ApiService', ['Restangular', '$q', 'UtilS
var urlPath = path['x-path']; var urlPath = path['x-path'];
// Add the operation itself. // Add the operation itself.
apiService[operationName] = function(opt_options, opt_parameters, opt_background, opt_forceget) { apiService[operationName] = function(opt_options, opt_parameters, opt_background, opt_forceget, opt_blobresp) {
var one = Restangular.one(buildUrl(urlPath, opt_parameters)); var one = Restangular.one(buildUrl(urlPath, opt_parameters));
if (opt_background) {
one.withHttpConfig({ if (opt_background || opt_blobresp) {
'ignoreLoadingBar': true let httpConfig = {};
});
if (opt_background) {
httpConfig['ignoreLoadingBar'] = true;
}
if (opt_blobresp) {
httpConfig['responseType'] = 'blob';
}
one.withHttpConfig(httpConfig);
} }
var opObj = one[opt_forceget ? 'get' : 'custom' + method.toUpperCase()](opt_options); var opObj = one[opt_forceget ? 'get' : 'custom' + method.toUpperCase()](opt_options);

View file

@ -1,5 +1,5 @@
from storage import get_storage_driver from storage import get_storage_driver
from util.config.validators import BaseValidator, ConfigValidationException, LocalStorageConfigValidationException from util.config.validators import BaseValidator, ConfigValidationException
class StorageValidator(BaseValidator): class StorageValidator(BaseValidator):