Port cor-title and add file check endpoint
Fix some FA5 regressions Fix uploading cert files Add fix some icons
This commit is contained in:
parent
b5f630ba29
commit
561522c6d3
24 changed files with 159 additions and 56 deletions
|
@ -15,7 +15,7 @@ from data.database import configure
|
|||
from data.runmigration import run_alembic_migration
|
||||
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
|
||||
from util.config.validator import validate_service_for_config, ValidatorContext, is_valid_config_upload_filename
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -302,3 +302,36 @@ class SuperUserConfigValidate(ApiResource):
|
|||
|
||||
|
||||
abort(403)
|
||||
|
||||
|
||||
@resource('/v1/superuser/config/file/<filename>')
|
||||
class SuperUserConfigFile(ApiResource):
|
||||
""" Resource for fetching the status of config files and overriding them. """
|
||||
@nickname('scConfigFileExists')
|
||||
def get(self, filename):
|
||||
""" Returns whether the configuration file with the given name exists. """
|
||||
if not is_valid_config_upload_filename(filename):
|
||||
abort(404)
|
||||
|
||||
return {
|
||||
'exists': config_provider.volume_file_exists(filename)
|
||||
}
|
||||
|
||||
|
||||
@nickname('scUpdateConfigFile')
|
||||
def post(self, filename):
|
||||
""" Updates the configuration file with the given name. """
|
||||
if not is_valid_config_upload_filename(filename):
|
||||
abort(404)
|
||||
|
||||
# Note: This method can be called before the configuration exists
|
||||
# to upload the database SSL cert.
|
||||
uploaded_file = request.files['file']
|
||||
if not uploaded_file:
|
||||
abort(400)
|
||||
|
||||
config_provider.save_volume_file(filename, uploaded_file)
|
||||
return {
|
||||
'status': True
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import os
|
||||
import logging
|
||||
import pathvalidate
|
||||
from flask import request, jsonify
|
||||
|
@ -6,7 +5,7 @@ from flask import request, jsonify
|
|||
from config_app.config_endpoints.exception import InvalidRequest
|
||||
from config_app.config_endpoints.api import resource, ApiResource, nickname
|
||||
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 config_provider
|
||||
|
||||
from config_app.config_endpoints.api.superuser_models_pre_oci import pre_oci_model
|
||||
|
||||
|
@ -37,8 +36,8 @@ class SuperUserCustomCertificate(ApiResource):
|
|||
# Validate the certificate.
|
||||
try:
|
||||
logger.debug('Loading custom certificate %s', certpath)
|
||||
with config_provider.get_volume_file(cert_full_path) as f:
|
||||
load_certificate(f.read())
|
||||
cert = config_provider.get_volume_file(cert_full_path)
|
||||
load_certificate(cert)
|
||||
except CertInvalidException:
|
||||
logger.exception('Got certificate invalid error for cert %s', certpath)
|
||||
return '', 204
|
||||
|
@ -46,14 +45,6 @@ class SuperUserCustomCertificate(ApiResource):
|
|||
logger.exception('Got IO error for cert %s', certpath)
|
||||
return '', 204
|
||||
|
||||
# Call the update script to install the certificate immediately.
|
||||
if not app.config['TESTING']:
|
||||
logger.debug('Calling certs_install.sh')
|
||||
if os.system('/conf/init/certs_install.sh') != 0:
|
||||
raise Exception('Could not install certificates')
|
||||
|
||||
logger.debug('certs_install.sh completed')
|
||||
|
||||
return '', 204
|
||||
|
||||
@nickname('deleteCustomCertificate')
|
||||
|
@ -79,7 +70,7 @@ class SuperUserCustomCertificates(ApiResource):
|
|||
cert_views = []
|
||||
for extra_cert_path in extra_certs_found:
|
||||
try:
|
||||
cert = config_provider.get_volume_path(EXTRA_CA_DIRECTORY, extra_cert_path)
|
||||
cert = config_provider.get_volume_file(extra_cert_path)
|
||||
certificate = load_certificate(cert)
|
||||
cert_views.append({
|
||||
'path': extra_cert_path,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import logging
|
||||
import tarfile
|
||||
import cStringIO
|
||||
|
||||
|
@ -7,9 +6,7 @@ from flask import request, make_response
|
|||
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__)
|
||||
from config_app.config_endpoints.api import resource, ApiResource, nickname
|
||||
|
||||
@resource('/v1/configapp/tarconfig')
|
||||
class TarConfigLoader(ApiResource):
|
||||
|
|
|
@ -9,8 +9,4 @@ def get_config_provider(config_volume, yaml_filename, py_filename, testing=False
|
|||
if testing:
|
||||
return TestConfigProvider()
|
||||
|
||||
else:
|
||||
return InMemoryProvider()
|
||||
|
||||
|
||||
|
||||
return InMemoryProvider()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import logging
|
||||
import yaml
|
||||
import io
|
||||
|
||||
from config_app.config_util.config.baseprovider import BaseProvider
|
||||
|
||||
|
@ -50,14 +51,17 @@ class InMemoryProvider(BaseProvider):
|
|||
return [ name for name in self.files if name.startswith(path) ]
|
||||
|
||||
def save_volume_file(self, filename, flask_file):
|
||||
raise Exception('Not implemented yet')
|
||||
self.files[filename] = flask_file.read()
|
||||
|
||||
def requires_restart(self, app_config):
|
||||
raise Exception('Not implemented yet')
|
||||
|
||||
def get_volume_path(self, directory, filename):
|
||||
# Here we can just access the filename since we're storing the tarball files with their full path
|
||||
return self.files[filename]
|
||||
if directory.endswith('/'):
|
||||
return directory + filename
|
||||
else:
|
||||
return directory + '/' + filename
|
||||
|
||||
def load_from_tarball(self, tarfile):
|
||||
for tarinfo in tarfile.getmembers():
|
||||
|
|
3
config_app/js/components/cor-option/cor-option.html
Normal file
3
config_app/js/components/cor-option/cor-option.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<li>
|
||||
<a ng-click="optionClick()" ng-transclude></a>
|
||||
</li>
|
32
config_app/js/components/cor-option/cor-option.js
Normal file
32
config_app/js/components/cor-option/cor-option.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const corOption = require('./cor-option.html');
|
||||
const corOptionsMenu = require('./cor-options-menu.html');
|
||||
|
||||
angular.module('quay-config')
|
||||
.directive('corOptionsMenu', function() {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 1,
|
||||
templateUrl: corOptionsMenu,
|
||||
replace: true,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {},
|
||||
controller: function($rootScope, $scope, $element) {
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
.directive('corOption', function() {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 1,
|
||||
templateUrl: corOption,
|
||||
replace: true,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'optionClick': '&optionClick'
|
||||
},
|
||||
controller: function($rootScope, $scope, $element) {
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
<span class="co-options-menu">
|
||||
<div class="dropdown" style="text-align: left;">
|
||||
<i class="fas fa-cog fa-lg dropdown-toggle" data-toggle="dropdown" data-title="Options" bs-tooltip></i>
|
||||
<ul class="dropdown-menu pull-right" ng-transclude></ul>
|
||||
</div>
|
||||
</span>
|
|
@ -0,0 +1,3 @@
|
|||
<div class="col-lg-6 col-md-6 col-sm-5 col-xs-12">
|
||||
<h2 class="co-nav-title-content co-fx-text-shadow" ng-transclude></h2>
|
||||
</div>
|
2
config_app/js/components/cor-title/cor-title.html
Normal file
2
config_app/js/components/cor-title/cor-title.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
<div class="co-nav-title" ng-transclude></div>
|
||||
|
31
config_app/js/components/cor-title/cor-title.js
Normal file
31
config_app/js/components/cor-title/cor-title.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
const titleUrl = require('./cor-title.html');
|
||||
const titleContentUrl = require('./cor-title-content.html');
|
||||
|
||||
angular.module('quay-config')
|
||||
.directive('corTitleContent', function() {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 1,
|
||||
templateUrl: titleContentUrl,
|
||||
replace: true,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {},
|
||||
controller: function($rootScope, $scope, $element) {
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
.directive('corTitle', function() {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 1,
|
||||
templateUrl: titleUrl,
|
||||
replace: true,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {},
|
||||
controller: function($rootScope, $scope, $element) {
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
|
@ -17,6 +17,7 @@ angular.module('quay-config').directive('fileUploadBox', function () {
|
|||
'filesValidated': '&filesValidated',
|
||||
|
||||
'extensions': '<extensions',
|
||||
'apiEndpoint': '@apiEndpoint',
|
||||
|
||||
'reset': '=?reset'
|
||||
},
|
||||
|
@ -103,13 +104,7 @@ angular.module('quay-config').directive('fileUploadBox', function () {
|
|||
$scope.currentlyUploadingFile = currentFile;
|
||||
$scope.uploadProgress = 0;
|
||||
|
||||
// ApiService.getFiledropUrl(data).then(function(resp) {
|
||||
// // Perform the upload.
|
||||
// conductUpload(currentFile, resp.url, resp.file_id, mimeType, progressCb, doneCb);
|
||||
// }, function() {
|
||||
// callback(false, 'Could not retrieve upload URL');
|
||||
// });
|
||||
conductUpload(currentFile, '/api/v1/configapp/tarconfig','fileIdIsUnused', mimeType, progressCb, doneCb);
|
||||
conductUpload(currentFile, $scope.apiEndpoint, $scope.selectedFiles[0].name, mimeType, progressCb, doneCb);
|
||||
};
|
||||
|
||||
// Start the uploading.
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<div class="modal-body">
|
||||
<span>Please upload the previous configuration</span>
|
||||
<div class="file-upload-box"
|
||||
api-endpoint="/api/v1/configapp/tarconfig"
|
||||
select-message="Select a previous configuration to modify. Must be in tar.gz format"
|
||||
files-selected="$ctrl.handleTarballSelected(files, callback)"
|
||||
files-cleared="$ctrl.handleFilesCleared()"
|
||||
|
|
|
@ -21,10 +21,11 @@
|
|||
<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"
|
||||
select-message="Select custom certificate to add to configuration. Must be in PEM format and end extension '.crt'"
|
||||
files-selected="handleCertsSelected(files, callback)"
|
||||
reset="resetUpload"
|
||||
extensions="['.crt']"></div>
|
||||
api-endpoint="/api/v1/superuser/customcerts"
|
||||
select-message="Select custom certificate to add to configuration. Must be in PEM format and end extension '.crt'"
|
||||
files-selected="handleCertsSelected(files, callback)"
|
||||
reset="resetUpload"
|
||||
extensions="['.crt']"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<!-- Basic Configuration -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-gears"></i> Basic Configuration
|
||||
<i class="fas fa-cogs"></i> Basic Configuration
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<table class="config-table">
|
||||
|
@ -456,7 +456,7 @@
|
|||
<!-- BitTorrent pull -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-cloud-download"></i> BitTorrent-based download
|
||||
<i class="fas fa-cloud-download-alt"></i> BitTorrent-based download
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
@ -941,7 +941,7 @@
|
|||
<!-- GitHub Authentication -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-github"></i> GitHub (Enterprise) Authentication
|
||||
<i class="fab fa-github"></i> GitHub (Enterprise) Authentication
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
@ -1049,7 +1049,7 @@
|
|||
<!-- Google Authentication -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-google"></i> Google Authentication
|
||||
<i class="fab fa-google"></i> Google Authentication
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
@ -1390,7 +1390,7 @@
|
|||
<!-- GitHub Trigger -->
|
||||
<div class="co-panel" ng-if="config.FEATURE_BUILD_SUPPORT" style="margin-top: 20px;">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-github"></i> GitHub (Enterprise) Build Triggers
|
||||
<i class="fab fa-github"></i> GitHub (Enterprise) Build Triggers
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<!-- Basic Configuration -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-gears"></i> Basic Configuration
|
||||
<i class="fas fa-cogs"></i> Basic Configuration
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<table class="config-table">
|
||||
|
@ -457,7 +457,7 @@
|
|||
<!-- BitTorrent pull -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-cloud-download"></i> BitTorrent-based download
|
||||
<i class="fas fa-cloud-download-alt"></i> BitTorrent-based download
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
@ -942,7 +942,7 @@
|
|||
<!-- GitHub Authentication -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-github"></i> GitHub (Enterprise) Authentication
|
||||
<i class="fab fa-github"></i> GitHub (Enterprise) Authentication
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
@ -1050,7 +1050,7 @@
|
|||
<!-- Google Authentication -->
|
||||
<div class="co-panel">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-google"></i> Google Authentication
|
||||
<i class="fab fa-google"></i> Google Authentication
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
@ -1391,7 +1391,7 @@
|
|||
<!-- GitHub Trigger -->
|
||||
<div class="co-panel" ng-if="config.FEATURE_BUILD_SUPPORT" style="margin-top: 20px;">
|
||||
<div class="co-panel-heading">
|
||||
<i class="fa fa-github"></i> GitHub (Enterprise) Build Triggers
|
||||
<i class="fab fa-github"></i> GitHub (Enterprise) Build Triggers
|
||||
</div>
|
||||
<div class="co-panel-body">
|
||||
<div class="description">
|
||||
|
|
|
@ -7,6 +7,7 @@ const urlListField = require('../config-field-templates/config-list-field.html')
|
|||
const urlFileField = require('../config-field-templates/config-file-field.html');
|
||||
const urlBoolField = require('../config-field-templates/config-bool-field.html');
|
||||
const urlNumericField = require('../config-field-templates/config-numeric-field.html');
|
||||
const urlContactField = require('../config-field-templates/config-contact-field.html');
|
||||
const urlContactsField = require('../config-field-templates/config-contacts-field.html');
|
||||
const urlMapField = require('../config-field-templates/config-map-field.html');
|
||||
const urlServiceKeyField = require('../config-field-templates/config-service-key-field.html');
|
||||
|
@ -1116,7 +1117,7 @@ angular.module("quay-config")
|
|||
.directive('configContactField', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: urlContactsField,
|
||||
templateUrl: urlContactField,
|
||||
priority: 1,
|
||||
replace: false,
|
||||
transclude: true,
|
||||
|
@ -1414,11 +1415,7 @@ angular.module("quay-config")
|
|||
});
|
||||
};
|
||||
|
||||
// UserService.updateUserIn($scope, function(user) {
|
||||
// console.log(user)
|
||||
// no need to check for user, since it's all local
|
||||
loadCertificates();
|
||||
// });
|
||||
|
||||
$scope.handleCertsSelected = function(files, callback) {
|
||||
$scope.certsUploading = true;
|
||||
|
|
|
@ -260,7 +260,6 @@ const templateUrl = require('./setup.html');
|
|||
$scope.createSuperUser = function() {
|
||||
$scope.currentStep = $scope.States.CREATING_SUPERUSER;
|
||||
ApiService.scCreateInitialSuperuser($scope.superUser, null).then(function(resp) {
|
||||
// UserService.load();
|
||||
$scope.checkStatus();
|
||||
}, function(resp) {
|
||||
$scope.currentStep = $scope.States.SUPERUSER_ERROR;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div>
|
||||
<div id="padding-container">
|
||||
<div>
|
||||
<div class="cor-loader" ng-show="currentStep == States.LOADING"></div>
|
||||
<div class="page-content" ng-show="currentStep == States.CONFIG">
|
||||
|
@ -12,11 +12,11 @@
|
|||
<span class="cor-step-bar" progress="stepProgress">
|
||||
<span class="cor-step" title="Configure Database" text="1"></span>
|
||||
<span class="cor-step" title="Setup Database" icon="database"></span>
|
||||
<span class="cor-step" title="Container Restart" icon="refresh"></span>
|
||||
<span class="cor-step" title="Container Restart" icon="sync"></span>
|
||||
<span class="cor-step" title="Create Superuser" text="2"></span>
|
||||
<span class="cor-step" title="Configure Registry" text="3"></span>
|
||||
<span class="cor-step" title="Validate Configuration" text="4"></span>
|
||||
<span class="cor-step" title="Container Restart" icon="refresh"></span>
|
||||
<span class="cor-step" title="Container Restart" icon="sync"></span>
|
||||
<span class="cor-step" title="Setup Complete" icon="check"></span>
|
||||
</span>
|
||||
|
||||
|
@ -43,7 +43,7 @@
|
|||
<span class="cor-step" title="Create Superuser" text="2"></span>
|
||||
<span class="cor-step" title="Configure Registry" text="3"></span>
|
||||
<span class="cor-step" title="Validate Configuration" text="4"></span>
|
||||
<span class="cor-step" title="Container Restart" icon="refresh"></span>
|
||||
<span class="cor-step" title="Container Restart" icon="sync"></span>
|
||||
<span class="cor-step" title="Setup Complete" icon="check"></span>
|
||||
</span>
|
||||
<h4 class="modal-title">Setup</h4>
|
||||
|
|
8
config_app/static/css/cor-option.css
Normal file
8
config_app/static/css/cor-option.css
Normal file
|
@ -0,0 +1,8 @@
|
|||
.cor-options-menu .fa-cog {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.open .fa-cog {
|
||||
color: #428BCA;
|
||||
}
|
4
config_app/static/css/cor-title.css
Normal file
4
config_app/static/css/cor-title.css
Normal file
|
@ -0,0 +1,4 @@
|
|||
.cor-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
BIN
config_app/static/img/network-tile.png
Normal file
BIN
config_app/static/img/network-tile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
BIN
config_app/static/img/redis-small.png
Normal file
BIN
config_app/static/img/redis-small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
config_app/static/img/rocket.png
Normal file
BIN
config_app/static/img/rocket.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
Reference in a new issue