This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/static/js/directives/repo-view/repo-panel-mirroring.js
2019-11-12 11:09:47 -05:00

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;
});