Modify config field to use base api endpoint

allow streaming from gzipped tarball config
This commit is contained in:
Sam Chow 2018-06-21 15:55:17 -04:00
parent aff1a08a83
commit d6d0bb640a
7 changed files with 40 additions and 33 deletions

View file

@ -36,8 +36,8 @@ class SuperUserCustomCertificate(ApiResource):
# Validate the certificate. # Validate the certificate.
try: try:
logger.debug('Loading custom certificate %s', certpath) logger.debug('Loading custom certificate %s', certpath)
cert = config_provider.get_volume_file(cert_full_path) with config_provider.get_volume_file(cert_full_path) as f:
load_certificate(cert) load_certificate(f.read())
except CertInvalidException: except CertInvalidException:
logger.exception('Got certificate invalid error for cert %s', certpath) logger.exception('Got certificate invalid error for cert %s', certpath)
return '', 204 return '', 204
@ -70,8 +70,9 @@ class SuperUserCustomCertificates(ApiResource):
cert_views = [] cert_views = []
for extra_cert_path in extra_certs_found: for extra_cert_path in extra_certs_found:
try: try:
cert = config_provider.get_volume_file(extra_cert_path) cert_full_path = config_provider.get_volume_path(EXTRA_CA_DIRECTORY, extra_cert_path)
certificate = load_certificate(cert) with config_provider.get_volume_file(cert_full_path) as f:
certificate = load_certificate(f.read())
cert_views.append({ cert_views.append({
'path': extra_cert_path, 'path': extra_cert_path,
'names': list(certificate.names), 'names': list(certificate.names),

View file

@ -1,5 +1,4 @@
import tarfile import tarfile
import cStringIO
from flask import request, make_response from flask import request, make_response
@ -13,16 +12,12 @@ class TarConfigLoader(ApiResource):
""" Resource for validating a block of configuration against an external service. """ """ Resource for validating a block of configuration against an external service. """
@nickname('uploadTarballConfig') @nickname('uploadTarballConfig')
def post(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
tar_stream = tarfile.open(mode="r|gz", fileobj=input_stream)
# since we're working with a tar file, shouldn't be larger than ~20KB, so just read the whole thing into mem config_provider.load_from_tar_stream(tar_stream)
buf = input_stream.read()
config = tarfile.open(mode="r:gz", fileobj=cStringIO.StringIO(buf))
# 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 # now try to connect to the db provided in their config
combined = dict(**app.config) combined = dict(**app.config)

View file

@ -39,7 +39,7 @@ class InMemoryProvider(BaseProvider):
return any([ name.startswith(filename) for name in self.files ]) return any([ name.startswith(filename) for name in self.files ])
def get_volume_file(self, filename, mode='r'): def get_volume_file(self, filename, mode='r'):
return self.files[filename] return io.BytesIO(self.files[filename])
def write_volume_file(self, filename, contents): def write_volume_file(self, filename, contents):
raise Exception('Not implemented yet') raise Exception('Not implemented yet')
@ -48,7 +48,12 @@ class InMemoryProvider(BaseProvider):
raise Exception('Not implemented yet') raise Exception('Not implemented yet')
def list_volume_directory(self, path): def list_volume_directory(self, path):
return [ name for name in self.files if name.startswith(path) ] def strip_directory(string):
if '/' in string:
return string[string.rfind('/') + 1:]
return string
return [ strip_directory(name) for name in self.files if name.startswith(path) ]
def save_volume_file(self, filename, flask_file): def save_volume_file(self, filename, flask_file):
self.files[filename] = flask_file.read() self.files[filename] = flask_file.read()
@ -66,9 +71,17 @@ class InMemoryProvider(BaseProvider):
def load_from_tarball(self, tarfile): def load_from_tarball(self, tarfile):
for tarinfo in tarfile.getmembers(): for tarinfo in tarfile.getmembers():
if tarinfo.isfile(): if tarinfo.isfile():
if tarinfo.name == CONFIG_FILENAME:
self.config = yaml.load(tarfile.extractfile(tarinfo.name).read())
else:
self.files[tarinfo.name] = tarfile.extractfile(tarinfo.name).read() self.files[tarinfo.name] = tarfile.extractfile(tarinfo.name).read()
if self.files.has_key(CONFIG_FILENAME):
self.config = yaml.load(self.files.get(CONFIG_FILENAME))
self.was_loaded = True self.was_loaded = True
def load_from_tar_stream(self, tarfile):
for tarinfo in tarfile:
if tarinfo.isfile():
self.files[tarinfo.name] = tarfile.extractfile(tarinfo).read()
if self.files.has_key(CONFIG_FILENAME):
self.config = yaml.load(self.files.get(CONFIG_FILENAME))
self.was_loaded = True

View file

@ -33,9 +33,9 @@ angular.module('quay-config').directive('fileUploadBox', function () {
$scope.state = 'clear'; $scope.state = 'clear';
$scope.selectedFiles = []; $scope.selectedFiles = [];
var conductUpload = function(file, url, fileId, mimeType, progressCb, doneCb) { var conductUpload = function(file, apiEndpoint, fileId, mimeType, progressCb, doneCb) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', url, true); request.open('PUT', '/api/v1/' + apiEndpoint, true);
request.setRequestHeader('Content-Type', mimeType); request.setRequestHeader('Content-Type', mimeType);
request.onprogress = function(e) { request.onprogress = function(e) {
$scope.$apply(function() { $scope.$apply(function() {

View file

@ -11,7 +11,7 @@
<div class="modal-body"> <div class="modal-body">
<span>Please upload the previous configuration</span> <span>Please upload the previous configuration</span>
<div class="file-upload-box" <div class="file-upload-box"
api-endpoint="/api/v1/configapp/tarconfig" api-endpoint="configapp/tarconfig"
select-message="Select a previous configuration to modify. Must be in tar.gz format" select-message="Select a previous configuration to modify. Must be in tar.gz format"
files-selected="$ctrl.handleTarballSelected(files, callback)" files-selected="$ctrl.handleTarballSelected(files, callback)"
files-cleared="$ctrl.handleFilesCleared()" files-cleared="$ctrl.handleFilesCleared()"

View file

@ -19,9 +19,8 @@
<tr> <tr>
<td>Upload certificates:</td> <td>Upload certificates:</td>
<td> <td>
<!--TODO(sam): fix this upload box to pass in the url it needs for custom certs (file-upload-box hardcodes right now)-->
<div class="file-upload-box" <div class="file-upload-box"
api-endpoint="/api/v1/superuser/customcerts" api-endpoint="superuser/customcerts"
select-message="Select custom certificate to add to configuration. Must be in PEM format and end extension '.crt'" select-message="Select custom certificate to add to configuration. Must be in PEM format and end extension '.crt'"
files-selected="handleCertsSelected(files, callback)" files-selected="handleCertsSelected(files, callback)"
reset="resetUpload" reset="resetUpload"

View file

@ -191,10 +191,9 @@ angular.module("quay-config")
}; };
$scope.validateHostname = function(hostname) { $scope.validateHostname = function(hostname) {
// TODO(sam): maybe revert? if (hostname.indexOf('127.0.0.1') == 0 || hostname.indexOf('localhost') == 0) {
// 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 'Please specify a non-localhost hostname. "localhost" will refer to the container, not your machine.' }
// }
return null; return null;
}; };