Read tarball into in-memory config provider
This commit is contained in:
parent
8aa18a29a8
commit
bb2b28cd11
5 changed files with 83 additions and 9 deletions
|
@ -1,4 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
|
import tarfile
|
||||||
|
import cStringIO
|
||||||
|
|
||||||
from flask import request, make_response
|
from flask import request, make_response
|
||||||
|
|
||||||
|
@ -17,9 +19,10 @@ class TarConfigLoader(ApiResource):
|
||||||
input_stream = request.stream
|
input_stream = request.stream
|
||||||
|
|
||||||
# since we're working with a tar file, shouldn't be larger than ~20KB, so just read the whole thing into mem
|
# since we're working with a tar file, shouldn't be larger than ~20KB, so just read the whole thing into mem
|
||||||
buf = input_stream.read(-1)
|
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
|
# TODO(sam): refactor config provider to accept a stream write to avoid loading into memory
|
||||||
config_provider.write_volume_file('test_tar.tar.gz', buf)
|
config_provider.load_from_tarball(config)
|
||||||
|
|
||||||
return make_response('OK')
|
return make_response('OK')
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
from config_app.config_util.config.fileprovider import FileConfigProvider
|
from config_app.config_util.config.fileprovider import FileConfigProvider
|
||||||
from config_app.config_util.config.testprovider import TestConfigProvider
|
from config_app.config_util.config.testprovider import TestConfigProvider
|
||||||
|
from config_app.config_util.config.inmemoryprovider import InMemoryProvider
|
||||||
|
|
||||||
|
|
||||||
def get_config_provider(config_volume, yaml_filename, py_filename, testing=False):
|
def get_config_provider(config_volume, yaml_filename, py_filename, testing=False):
|
||||||
""" Loads and returns the config provider for the current environment. """
|
""" Loads and returns the config provider for the current environment. """
|
||||||
|
if True:
|
||||||
|
return InMemoryProvider()
|
||||||
|
|
||||||
if testing:
|
if testing:
|
||||||
return TestConfigProvider()
|
return TestConfigProvider()
|
||||||
|
|
||||||
|
|
66
config_app/config_util/config/inmemoryprovider.py
Normal file
66
config_app/config_util/config/inmemoryprovider.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import logging
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from config_app.config_util.config.baseprovider import BaseProvider
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
CONFIG_FILENAME = 'config.yaml'
|
||||||
|
|
||||||
|
class InMemoryProvider(BaseProvider):
|
||||||
|
def __init__(self):
|
||||||
|
self.files = {}
|
||||||
|
self.config = {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provider_id(self):
|
||||||
|
return 'memory'
|
||||||
|
|
||||||
|
def update_app_config(self, app_config):
|
||||||
|
self.config = app_config
|
||||||
|
|
||||||
|
def get_config(self):
|
||||||
|
return self.config
|
||||||
|
|
||||||
|
def save_config(self, config_object):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def config_exists(self):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def volume_exists(self):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def volume_file_exists(self, filename):
|
||||||
|
return filename in self.files
|
||||||
|
|
||||||
|
def get_volume_file(self, filename, mode='r'):
|
||||||
|
return self.files[filename]
|
||||||
|
|
||||||
|
def write_volume_file(self, filename, contents):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def remove_volume_file(self, filename):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def list_volume_directory(self, path):
|
||||||
|
return [ name for name in self.files ]
|
||||||
|
|
||||||
|
def save_volume_file(self, filename, flask_file):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def requires_restart(self, app_config):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def get_volume_path(self, directory, filename):
|
||||||
|
raise Exception('Not implemented yet')
|
||||||
|
|
||||||
|
def load_from_tarball(self, tarfile):
|
||||||
|
for tarinfo in tarfile.getmembers():
|
||||||
|
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()
|
||||||
|
|
|
@ -8,7 +8,7 @@ const styleUrl = require('./load-config.css');
|
||||||
styleUrls: [ styleUrl ],
|
styleUrls: [ styleUrl ],
|
||||||
})
|
})
|
||||||
export class LoadConfigComponent {
|
export class LoadConfigComponent {
|
||||||
private isReady: boolean = false;
|
private readyToSubmit: boolean = false;
|
||||||
private uploadFunc: Function;
|
private uploadFunc: Function;
|
||||||
private state: 'load' | 'validate' = 'load';
|
private state: 'load' | 'validate' = 'load';
|
||||||
|
|
||||||
|
@ -16,12 +16,12 @@ export class LoadConfigComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleTarballSelected(files: File[], callback: Function) {
|
private handleTarballSelected(files: File[], callback: Function) {
|
||||||
this.isReady = true;
|
this.readyToSubmit = true;
|
||||||
callback(true)
|
callback(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleTarballCleared() {
|
private handleTarballCleared() {
|
||||||
this.isReady = false;
|
this.readyToSubmit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uploadTarball() {
|
private uploadTarball() {
|
||||||
|
@ -30,7 +30,8 @@ export class LoadConfigComponent {
|
||||||
this.state = 'validate';
|
this.state = 'validate';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.apiService.errorDisplay('Could not upload configuration. Please reload the page and try again.\n' +
|
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')();
|
'If this problem persists, please contact support')();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -42,7 +43,7 @@ export class LoadConfigComponent {
|
||||||
* @param files: files to upload
|
* @param files: files to upload
|
||||||
* @param uploadFiles: function to call to upload files
|
* @param uploadFiles: function to call to upload files
|
||||||
*/
|
*/
|
||||||
private filesValidated(files, uploadFiles) {
|
private tarballValidatedByUploadBox(files, uploadFiles) {
|
||||||
this.uploadFunc = uploadFiles;
|
this.uploadFunc = uploadFiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,11 +14,11 @@
|
||||||
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()"
|
||||||
files-validated="$ctrl.filesValidated(files, uploadFiles)"
|
files-validated="$ctrl.tarballValidatedByUploadBox(files, uploadFiles)"
|
||||||
extensions="['application/gzip', '.gz']"></div>
|
extensions="['application/gzip', '.gz']"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-primary" ng-click="$ctrl.uploadTarball()" ng-disabled="!$ctrl.isReady">
|
<button type="button" class="btn btn-primary" ng-click="$ctrl.uploadTarball()" ng-disabled="!$ctrl.readyToSubmit">
|
||||||
Upload Configuration
|
Upload Configuration
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Reference in a new issue