d080ca2cc6
further improve developer morale get initial angular loading Add remote css to config index Starts work to port endpoints into config app Add the api blueprint
332 lines
12 KiB
JavaScript
332 lines
12 KiB
JavaScript
import * as URI from 'urijs';
|
|
const templateUrl = require('./setup.html');
|
|
|
|
(function() {
|
|
/**
|
|
* The Setup page provides a nice GUI walkthrough experience for setting up Quay Enterprise.
|
|
*/
|
|
|
|
angular.module('quay-config').directive('setup', () => {
|
|
const directiveDefinitionObject = {
|
|
priority: 1,
|
|
templateUrl,
|
|
replace: true,
|
|
transclude: true,
|
|
restrict: 'C',
|
|
scope: {
|
|
'isActive': '=isActive',
|
|
'configurationSaved': '&configurationSaved'
|
|
},
|
|
controller: SetupCtrl,
|
|
};
|
|
|
|
return directiveDefinitionObject;
|
|
})
|
|
|
|
function SetupCtrl($scope, $timeout, ApiService, Features, UserService, ContainerService, CoreDialog) {
|
|
// if (!Features.SUPER_USERS) {
|
|
// return;
|
|
// }
|
|
|
|
$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.'
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
// Note: The values of the enumeration are important for isStepFamily. For example,
|
|
// *all* states under the "configuring db" family must start with "config-db".
|
|
$scope.States = {
|
|
// Loading the state of the product.
|
|
'LOADING': 'loading',
|
|
|
|
// The configuration directory is missing.
|
|
'MISSING_CONFIG_DIR': 'missing-config-dir',
|
|
|
|
// The config.yaml exists but it is invalid.
|
|
'INVALID_CONFIG': 'config-invalid',
|
|
|
|
// DB is being configured.
|
|
'CONFIG_DB': 'config-db',
|
|
|
|
// DB information is being validated.
|
|
'VALIDATING_DB': 'config-db-validating',
|
|
|
|
// DB information is being saved to the config.
|
|
'SAVING_DB': 'config-db-saving',
|
|
|
|
// A validation error occurred with the database.
|
|
'DB_ERROR': 'config-db-error',
|
|
|
|
// 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',
|
|
|
|
// The container is being restarted for the database changes.
|
|
'DB_RESTARTING': 'setup-db-restarting',
|
|
|
|
// A superuser is being configured.
|
|
'CREATE_SUPERUSER': 'create-superuser',
|
|
|
|
// The superuser is being created.
|
|
'CREATING_SUPERUSER': 'create-superuser-creating',
|
|
|
|
// An error occurred when setting up the superuser.
|
|
'SUPERUSER_ERROR': 'create-superuser-error',
|
|
|
|
// The superuser was created successfully.
|
|
'SUPERUSER_CREATED': 'create-superuser-created',
|
|
|
|
// General configuration is being setup.
|
|
'CONFIG': 'config',
|
|
|
|
// The configuration is fully valid.
|
|
'VALID_CONFIG': 'valid-config',
|
|
|
|
// The container is being restarted for the configuration changes.
|
|
'CONFIG_RESTARTING': 'config-restarting',
|
|
|
|
// The product is ready for use.
|
|
'READY': 'ready'
|
|
}
|
|
|
|
$scope.csrf_token = window.__token;
|
|
$scope.currentStep = $scope.States.LOADING;
|
|
$scope.errors = {};
|
|
$scope.stepProgress = [];
|
|
$scope.hasSSL = false;
|
|
$scope.hostname = null;
|
|
$scope.currentConfig = null;
|
|
|
|
$scope.currentState = {
|
|
'hasDatabaseSSLCert': false
|
|
};
|
|
|
|
$scope.$watch('currentStep', function(currentStep) {
|
|
$scope.stepProgress = $scope.getProgress(currentStep);
|
|
|
|
switch (currentStep) {
|
|
case $scope.States.CONFIG:
|
|
$('#setupModal').modal('hide');
|
|
break;
|
|
|
|
case $scope.States.MISSING_CONFIG_DIR:
|
|
$scope.showMissingConfigDialog();
|
|
break;
|
|
|
|
case $scope.States.INVALID_CONFIG:
|
|
$scope.showInvalidConfigDialog();
|
|
break;
|
|
|
|
case $scope.States.DB_SETUP:
|
|
$scope.performDatabaseSetup();
|
|
// Fall-through.
|
|
|
|
case $scope.States.CREATE_SUPERUSER:
|
|
case $scope.States.DB_RESTARTING:
|
|
case $scope.States.CONFIG_DB:
|
|
case $scope.States.VALID_CONFIG:
|
|
case $scope.States.READY:
|
|
$('#setupModal').modal({
|
|
keyboard: false,
|
|
backdrop: 'static'
|
|
});
|
|
break;
|
|
}
|
|
});
|
|
|
|
$scope.restartContainer = function(state) {
|
|
$scope.currentStep = state;
|
|
ContainerService.restartContainer(function() {
|
|
$scope.checkStatus()
|
|
});
|
|
};
|
|
|
|
$scope.showSuperuserPanel = function() {
|
|
$('#setupModal').modal('hide');
|
|
var prefix = $scope.hasSSL ? 'https' : 'http';
|
|
var hostname = $scope.hostname;
|
|
if (!hostname) {
|
|
hostname = document.location.hostname;
|
|
if (document.location.port) {
|
|
hostname = hostname + ':' + document.location.port;
|
|
}
|
|
}
|
|
|
|
window.location = prefix + '://' + hostname + '/superuser';
|
|
};
|
|
|
|
$scope.configurationSaved = function(config) {
|
|
$scope.hasSSL = config['PREFERRED_URL_SCHEME'] == 'https';
|
|
$scope.hostname = config['SERVER_HOSTNAME'];
|
|
$scope.currentConfig = config;
|
|
|
|
$scope.currentStep = $scope.States.VALID_CONFIG;
|
|
};
|
|
|
|
$scope.getProgress = function(step) {
|
|
var isStep = $scope.isStep;
|
|
var isStepFamily = $scope.isStepFamily;
|
|
var States = $scope.States;
|
|
|
|
return [
|
|
isStepFamily(step, States.CONFIG_DB),
|
|
isStepFamily(step, States.DB_SETUP),
|
|
isStep(step, States.DB_RESTARTING),
|
|
isStepFamily(step, States.CREATE_SUPERUSER),
|
|
isStep(step, States.CONFIG),
|
|
isStep(step, States.VALID_CONFIG),
|
|
isStep(step, States.CONFIG_RESTARTING),
|
|
isStep(step, States.READY)
|
|
];
|
|
};
|
|
|
|
$scope.isStepFamily = function(step, family) {
|
|
if (!step) { return false; }
|
|
return step.indexOf(family) == 0;
|
|
};
|
|
|
|
$scope.isStep = function(step) {
|
|
for (var i = 1; i < arguments.length; ++i) {
|
|
if (arguments[i] == step) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
$scope.beginSetup = function() {
|
|
$scope.currentStep = $scope.States.CONFIG_DB;
|
|
};
|
|
|
|
$scope.showInvalidConfigDialog = function() {
|
|
var message = "The <code>config.yaml</code> file found in <code>conf/stack</code> could not be parsed."
|
|
var title = "Invalid configuration file";
|
|
CoreDialog.fatal(title, message);
|
|
};
|
|
|
|
|
|
$scope.showMissingConfigDialog = function() {
|
|
var message = "A volume should be mounted into the container at <code>/conf/stack</code>: " +
|
|
"<br><br><pre>docker run -v /path/to/config:/conf/stack</pre>" +
|
|
"<br>Once fixed, restart the container. For more information, " +
|
|
"<a href='https://coreos.com/docs/enterprise-registry/initial-setup/'>" +
|
|
"Read the Setup Guide</a>"
|
|
|
|
var title = "Missing configuration volume";
|
|
CoreDialog.fatal(title, message);
|
|
};
|
|
|
|
$scope.parseDbUri = function(value) {
|
|
if (!value) { return null; }
|
|
|
|
// Format: mysql+pymysql://<username>:<url escaped password>@<hostname>/<database_name>
|
|
var uri = URI(value);
|
|
return {
|
|
'kind': uri.protocol(),
|
|
'username': uri.username(),
|
|
'password': uri.password(),
|
|
'server': uri.host(),
|
|
'database': uri.path() ? uri.path().substr(1) : ''
|
|
};
|
|
};
|
|
|
|
$scope.serializeDbUri = function(fields) {
|
|
if (!fields['server']) { return ''; }
|
|
if (!fields['database']) { return ''; }
|
|
|
|
var uri = URI();
|
|
try {
|
|
uri = uri && uri.host(fields['server']);
|
|
uri = uri && uri.protocol(fields['kind']);
|
|
uri = uri && uri.username(fields['username']);
|
|
uri = uri && uri.password(fields['password']);
|
|
uri = uri && uri.path('/' + (fields['database'] || ''));
|
|
uri = uri && uri.toString();
|
|
} catch (ex) {
|
|
return '';
|
|
}
|
|
|
|
return uri;
|
|
};
|
|
|
|
$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;
|
|
$scope.errors.SuperuserCreationError = ApiService.getErrorMessage(resp, 'Could not create superuser');
|
|
});
|
|
};
|
|
|
|
$scope.performDatabaseSetup = function() {
|
|
$scope.currentStep = $scope.States.DB_SETUP;
|
|
ApiService.scSetupDatabase(null, null).then(function(resp) {
|
|
if (resp['error']) {
|
|
$scope.currentStep = $scope.States.DB_SETUP_ERROR;
|
|
$scope.errors.DatabaseSetupError = resp['error'];
|
|
} else {
|
|
$scope.currentStep = $scope.States.DB_SETUP_SUCCESS;
|
|
}
|
|
}, ApiService.errorDisplay('Could not setup database. Please report this to support.'))
|
|
};
|
|
|
|
$scope.validateDatabase = function() {
|
|
$scope.currentStep = $scope.States.VALIDATING_DB;
|
|
$scope.databaseInvalid = null;
|
|
|
|
var data = {
|
|
'config': {
|
|
'DB_URI': $scope.databaseUri
|
|
},
|
|
'hostname': window.location.host
|
|
};
|
|
|
|
if ($scope.currentState.hasDatabaseSSLCert) {
|
|
data['config']['DB_CONNECTION_ARGS'] = {
|
|
'ssl': {
|
|
'ca': 'conf/stack/database.pem'
|
|
}
|
|
};
|
|
}
|
|
|
|
var params = {
|
|
'service': 'database'
|
|
};
|
|
|
|
ApiService.scValidateConfig(data, params).then(function(resp) {
|
|
var status = resp.status;
|
|
|
|
if (status) {
|
|
$scope.currentStep = $scope.States.SAVING_DB;
|
|
ApiService.scUpdateConfig(data, null).then(function(resp) {
|
|
$scope.checkStatus();
|
|
}, ApiService.errorDisplay('Cannot update config. Please report this to support'));
|
|
} else {
|
|
$scope.currentStep = $scope.States.DB_ERROR;
|
|
$scope.errors.DatabaseValidationError = resp.reason;
|
|
}
|
|
}, ApiService.errorDisplay('Cannot validate database. Please report this to support'));
|
|
};
|
|
|
|
$scope.checkStatus = function() {
|
|
ContainerService.checkStatus(function(resp) {
|
|
$scope.currentStep = resp['status'];
|
|
}, $scope.currentConfig);
|
|
};
|
|
|
|
// Load the initial status.
|
|
$scope.checkStatus();
|
|
};
|
|
})();
|