468 lines
13 KiB
JavaScript
468 lines
13 KiB
JavaScript
import { vendor } from "postcss";
|
|
|
|
/**
|
|
* An element which displays the mirroring panel for a repository view.
|
|
*/
|
|
angular.module('quay').directive('repoPanelMirror', function () {
|
|
var directiveDefinitionObject = {
|
|
priority: 0,
|
|
templateUrl: '/static/directives/repo-view/repo-panel-mirroring.html',
|
|
replace: false,
|
|
transclude: false,
|
|
restrict: 'C',
|
|
scope: {
|
|
'repository': '=repository',
|
|
'isEnabled': '=isEnabled'
|
|
},
|
|
controllerAs: 'vm',
|
|
controller: function ($scope, ApiService, Features) {
|
|
|
|
let vm = this;
|
|
|
|
// Feature Flagged
|
|
if (!Features.REPO_MIRROR) { return; }
|
|
|
|
// Shared by API Calls
|
|
let params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name };
|
|
|
|
/**
|
|
* Mirror Configuration
|
|
*/
|
|
vm.isSetup = false;
|
|
vm.expirationDate = null;
|
|
vm.isEnabled = null;
|
|
vm.httpProxy = null;
|
|
vm.httpsProxy = null;
|
|
vm.externalReference = null;
|
|
vm.noProxy = null;
|
|
vm.retriesRemaining = null;
|
|
vm.robot = null;
|
|
vm.status = null;
|
|
vm.syncInterval = null;
|
|
vm.syncStartDate = null;
|
|
vm.tags = null;
|
|
vm.username = null;
|
|
vm.verifyTLS = null;
|
|
|
|
/**
|
|
* Fetch the latest Repository Mirror Configuration
|
|
*/
|
|
vm.getMirror = function() {
|
|
ApiService.getRepoMirrorConfig(null, params)
|
|
.then(function (resp) {
|
|
vm.isSetup = true;
|
|
|
|
vm.isEnabled = resp.is_enabled;
|
|
vm.externalReference = resp.external_reference;
|
|
vm.syncInterval = resp.sync_interval;
|
|
vm.username = resp.external_registry_username;
|
|
vm.syncStartDate = resp.sync_start_date;
|
|
vm.status = resp.sync_status;
|
|
vm.expirationDate = resp.sync_expiration_date;
|
|
vm.retriesRemaining = resp.sync_retries_remaining;
|
|
|
|
vm.robot = {};
|
|
if (resp.robot_username) {
|
|
vm.robot = {
|
|
'name': resp.robot_username,
|
|
'kind': 'user',
|
|
'is_robot': true
|
|
};
|
|
}
|
|
|
|
vm.tags = resp.root_rule.rule_value || []; // TODO: Use RepoMirrorRule-specific endpoint
|
|
|
|
// TODO: These are not consistently provided by the API. Correct that in the API.
|
|
vm.verifyTLS = resp.external_registry_config.verify_tls;
|
|
if (resp.external_registry_config.proxy) {
|
|
vm.httpProxy = resp.external_registry_config.proxy.http_proxy;
|
|
vm.httpsProxy = resp.external_registry_config.proxy.https_proxy;
|
|
vm.noProxy = resp.external_registry_config.proxy.no_proxy;
|
|
}
|
|
}, function (err) { console.info("No repository mirror configuration.", err); });
|
|
}
|
|
|
|
/**
|
|
* Human-friendly status messages
|
|
*/
|
|
vm.statusLabels = {
|
|
"NEVER_RUN": "Scheduled",
|
|
"SYNC_NOW": "Scheduled Now",
|
|
"SYNCING": "Sync In Progress",
|
|
"SUCCESS": "Last Sync Succeeded",
|
|
"FAIL": "Last Sync Failed"
|
|
}
|
|
|
|
/**
|
|
* Convert (Unix) Timestamp to ISO Formatted Date String used by the API
|
|
*/
|
|
vm.timestampToISO = function(ts) {
|
|
let dt = moment.unix(ts).toISOString().split('.')[0] + 'Z'; // Remove milliseconds
|
|
return dt;
|
|
}
|
|
|
|
/**
|
|
* Convert ISO Date String to (Unix) Timestamp
|
|
*/
|
|
vm.timestampFromISO = function(dt) {
|
|
let ts = moment(dt).unix();
|
|
return ts;
|
|
}
|
|
|
|
/**
|
|
* When set to a truthy value, any `cor-confirm-dialog` associated with these variables will
|
|
* be displayed.
|
|
*/
|
|
vm.credentialsChanges = null;
|
|
vm.httpProxyChanges = null;
|
|
vm.httpsProxyChanges = null;
|
|
vm.locationChanges = null;
|
|
vm.noProxyChanges = null;
|
|
vm.syncIntervalChanges = null;
|
|
vm.syncStartDateChanges = null;
|
|
vm.tagChanges = null;
|
|
|
|
/**
|
|
* The following `show` functions initialize and trigger the display of a modal to modify
|
|
* configuration attributes.
|
|
*/
|
|
|
|
vm.showChangeSyncInterval = function() {
|
|
vm.syncIntervalChanges = {
|
|
'fieldName': 'synchronization interval',
|
|
'values': {
|
|
'sync_interval': vm.syncInterval
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.showChangeSyncStartDate = function() {
|
|
let ts = vm.timestampFromISO(vm.syncStartDate);
|
|
vm.syncStartDateChanges = {
|
|
'fieldName': 'next synchronization date',
|
|
'values': {
|
|
'sync_start_date': ts
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.showChangeTags = function() {
|
|
vm.tagChanges = {
|
|
'fieldName': 'tag patterns',
|
|
'values': {
|
|
'rule_value': vm.tags || []
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.showChangeCredentials = function() {
|
|
vm.credentialsChanges = {
|
|
'fieldName': 'credentials',
|
|
'values': {
|
|
'external_registry_username': vm.username,
|
|
'external_registry_password': null
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.showChangeHTTPProxy = function() {
|
|
vm.httpProxyChanges = {
|
|
'fieldName': 'HTTP Proxy',
|
|
'values': {
|
|
'external_registry_config': {
|
|
'proxy': {
|
|
'http_proxy': vm.httpProxy
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.showChangeHTTPsProxy = function() {
|
|
vm.httpsProxyChanges = {
|
|
'fieldName': 'HTTPs Proxy',
|
|
'values': {
|
|
'external_registry_config': {
|
|
'proxy': {
|
|
'https_proxy': vm.httpsProxy
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.showChangeNoProxy = function() {
|
|
vm.noProxyChanges = {
|
|
'fieldName': 'No Proxy',
|
|
'values': {
|
|
'external_registry_config': {
|
|
'proxy': {
|
|
'no_proxy': vm.noProxy
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vm.showChangeExternalRepository = function() {
|
|
vm.externalRepositoryChanges = {
|
|
'fieldName': 'External Repository',
|
|
'values': {
|
|
'external_reference': vm.externalReference
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit API request to modify repository mirroring attribute(s)
|
|
*/
|
|
vm.changeConfig = function(data, callback) {
|
|
|
|
let fieldName = data.fieldName || 'configuration';
|
|
let requestBody = data.values;
|
|
let errMsg = "Unable to change " + fieldName + '.';
|
|
let handleError = ApiService.errorDisplay(errMsg, callback);
|
|
|
|
let handleSuccess = function() {
|
|
vm.getMirror(); // Fetch updated configuration
|
|
if (callback) callback(true);
|
|
}
|
|
|
|
ApiService.changeRepoMirrorConfig(requestBody, params)
|
|
.then(handleSuccess, handleError);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Transform the DatePicker's Unix timestamp into a string compatible with the API
|
|
* before attempting to change it.
|
|
*/
|
|
vm.changeSyncStartDate = function(data, callback) {
|
|
let newSyncStartDate = vm.timestampToISO(data.values.sync_start_date);
|
|
data.values.sync_start_date = newSyncStartDate;
|
|
return vm.changeConfig(data, callback);
|
|
}
|
|
|
|
/**
|
|
* Enable `Verify TLS`.
|
|
*/
|
|
vm.enableVerifyTLS = function() {
|
|
let data = {
|
|
'fieldName': 'TLS verification',
|
|
'values': {
|
|
'external_registry_config': {
|
|
'verify_tls': true
|
|
}
|
|
}
|
|
}
|
|
|
|
return vm.changeConfig(data, null);
|
|
}
|
|
|
|
/**
|
|
* Disable `Verify TLS`
|
|
*/
|
|
vm.disableVerifyTLS = function() {
|
|
let data = {
|
|
'fieldName': 'TLS verification',
|
|
'values': {
|
|
'external_registry_config': {
|
|
'verify_tls': false
|
|
}
|
|
}
|
|
}
|
|
|
|
return vm.changeConfig(data, null);
|
|
}
|
|
|
|
/**
|
|
* Toggle `Verify TLS`.
|
|
*/
|
|
vm.toggleVerifyTLS = function() {
|
|
if (vm.verifyTLS) return vm.disableVerifyTLS();
|
|
else return vm.enableVerifyTLS();
|
|
}
|
|
|
|
/**
|
|
* Change Robot user.
|
|
*/
|
|
vm.changeRobot = function(robot) {
|
|
if (!vm.robot) return;
|
|
if (!robot || robot.name == vm.robot.name) return;
|
|
|
|
let data = {
|
|
'fieldName': 'robot',
|
|
'values': {
|
|
'robot_username': robot.name
|
|
}
|
|
}
|
|
|
|
return vm.changeConfig(data, null)
|
|
}
|
|
|
|
/**
|
|
* Delete Credentials
|
|
*/
|
|
vm.deleteCredentials = function() {
|
|
let data = {
|
|
'fieldName': 'credentials',
|
|
'values': {
|
|
'external_registry_username': null,
|
|
'external_registry_password': null
|
|
}
|
|
}
|
|
|
|
return vm.changeConfig(data, null);
|
|
}
|
|
|
|
/**
|
|
* Enable mirroring configuration.
|
|
*/
|
|
vm.enableMirroring = function() {
|
|
let data = {
|
|
'fieldName': 'enabled state',
|
|
'values': {
|
|
'is_enabled': true
|
|
}
|
|
}
|
|
|
|
return vm.changeConfig(data, null)
|
|
}
|
|
|
|
/**
|
|
* Disable mirroring configuration.
|
|
*/
|
|
vm.disableMirroring = function() {
|
|
let data = {
|
|
'fieldName': 'enabled state',
|
|
'values': {
|
|
'is_enabled': false
|
|
}
|
|
}
|
|
|
|
return vm.changeConfig(data, null)
|
|
}
|
|
|
|
/**
|
|
* Toggle mirroring on/off.
|
|
*/
|
|
vm.toggleMirroring = function() {
|
|
if (vm.isEnabled) return vm.disableMirroring();
|
|
else return vm.enableMirroring();
|
|
}
|
|
|
|
/**
|
|
* Update Tag-Rules
|
|
*/
|
|
vm.changeTagRules = function(data, callback) {
|
|
let csv = data.values.rule_value;
|
|
let patterns = csv.split(',');
|
|
|
|
patterns.map(s => s.trim()); // Trim excess whitespace
|
|
patterns = Array.from(new Set(patterns)); // De-duplicate
|
|
|
|
if (patterns.length < 1) {
|
|
bootbox.alert('Rule value required');
|
|
callback(false);
|
|
return false;
|
|
}
|
|
|
|
data = {
|
|
'root_rule': {
|
|
'rule_type': 'TAG_GLOB_CSV',
|
|
'rule_value': patterns
|
|
}
|
|
}
|
|
|
|
let displayError = ApiService.errorDisplay('Could not change Tag Rules', callback);
|
|
|
|
ApiService
|
|
.changeRepoMirrorRule(data, params)
|
|
.then(function(resp) {
|
|
vm.getMirror();
|
|
callback(true);
|
|
}, displayError);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Trigger Immediate Synchronization
|
|
*/
|
|
vm.syncNow = function () {
|
|
let displayError = ApiService.errorDisplay('Unable to sync now', null);
|
|
|
|
ApiService
|
|
.syncNow(null, params)
|
|
.then(function(resp) {
|
|
vm.getMirror(); // Reload latest changes
|
|
return true;
|
|
}, displayError);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Cancel In-Progress Synchronization
|
|
*/
|
|
vm.syncCancel = function() {
|
|
let displayError = ApiService.errorDisplay('Unable to cancel sync', null);
|
|
|
|
ApiService
|
|
.syncCancel(null, params)
|
|
.then(function(resp) {
|
|
vm.getMirror(); // Reload latest changes
|
|
return true;
|
|
}, displayError);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Load the current mirror configuration on initialization
|
|
if ($scope.repository.state == 'MIRROR') {
|
|
vm.getMirror();
|
|
}
|
|
|
|
/**
|
|
* Configure mirroing.
|
|
* TODO: Move this, and the associated template/view, to its own component and use the
|
|
* wizard-flow instead of a single form.
|
|
*/
|
|
vm.setupMirror = function() {
|
|
|
|
// Apply transformations
|
|
let now = vm.timestampToISO(moment().unix());
|
|
let syncStartDate = vm.timestampToISO(vm.syncStartDate) || now;
|
|
let patterns = Array.from(new Set(vm.tags.split(',').map(s => s.trim()))); // trim + de-dupe
|
|
|
|
let requestBody = {
|
|
'external_reference': vm.externalReference,
|
|
'external_registry_username': vm.username,
|
|
'external_registry_password': vm.password,
|
|
'sync_interval': vm.syncInterval,
|
|
'sync_start_date': syncStartDate,
|
|
'robot_username': vm.robot.name,
|
|
'external_registry_config': {
|
|
'verify_tls': vm.verifyTLS || false, // `null` not allowed
|
|
'proxy': {
|
|
'http_proxy': vm.httpProxy,
|
|
'https_proxy': vm.httpsProxy,
|
|
'no_proxy': vm.noProxy
|
|
}
|
|
},
|
|
'root_rule': {
|
|
'rule_type': 'TAG_GLOB_CSV',
|
|
'rule_value': patterns
|
|
}
|
|
}
|
|
|
|
let successHandler = function(resp) { vm.getMirror(); return true; }
|
|
let errorHandler = ApiService.errorDisplay('Unable to setup mirror.', null);
|
|
ApiService.createRepoMirrorConfig(requestBody, params).then(successHandler, errorHandler);
|
|
|
|
}
|
|
}
|
|
};
|
|
return directiveDefinitionObject;
|
|
});
|