319 lines
11 KiB
JavaScript
319 lines
11 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 Red Hat Quay.
|
|
*/
|
|
|
|
angular.module('quay-config').directive('setup', () => {
|
|
const directiveDefinitionObject = {
|
|
priority: 1,
|
|
templateUrl,
|
|
replace: true,
|
|
transclude: true,
|
|
restrict: 'C',
|
|
scope: {
|
|
'isActive': '=isActive',
|
|
'configurationSaved': '&configurationSaved',
|
|
'setupCompleted': '&setupCompleted',
|
|
},
|
|
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',
|
|
|
|
// An error occurred when setting up the database.
|
|
'DB_SETUP_ERROR': 'setup-db-error',
|
|
|
|
// 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 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.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),
|
|
isStepFamily(step, States.CREATE_SUPERUSER),
|
|
isStep(step, States.CONFIG),
|
|
isStep(step, States.VALID_CONFIG),
|
|
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) {
|
|
$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.CREATE_SUPERUSER;
|
|
}
|
|
}, 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
|
|
},
|
|
};
|
|
|
|
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();
|
|
};
|
|
})();
|