magnum-ui/magnum_ui/static/dashboard/container-infra/clusters/rolling-upgrade/upgrade.service.js

228 lines
7.3 KiB
JavaScript

/**
* Copyright 2017 NEC Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @name horizon.dashboard.container-infra.clusters.rolling-upgrade.service
* @description Service for the container-infra cluster rolling upgrade modal.
* Allows user to choose a Cluster template with higher version number the
* cluster should upgrade to. Optionally, the number of nodes in a single
* upgrade batch can be chosen.
*/
angular
.module('horizon.dashboard.container-infra.clusters')
.factory('horizon.dashboard.container-infra.clusters.rolling-upgrade.service', upgradeService);
upgradeService.$inject = [
'$q',
'$document',
'horizon.app.core.openstack-service-api.magnum',
'horizon.framework.util.actions.action-result.service',
'horizon.framework.util.i18n.gettext',
'horizon.framework.util.q.extensions',
'horizon.framework.widgets.form.ModalFormService',
'horizon.framework.widgets.toast.service',
'horizon.framework.widgets.modal-wait-spinner.service',
'horizon.dashboard.container-infra.clusters.resourceType',
'horizon.dashboard.container-infra.utils.service'
];
function upgradeService(
$q, $document, magnum, actionResult, gettext, $qExtensions, modal, toast, spinnerModal,
resourceType, utils
) {
var modalConfig, formModel, isLatestTemplate, clusterTemplatesTitleMap;
var service = {
perform: perform,
allowed: allowed
};
return service;
//////////////
function perform(selected, $scope) {
// Simulate a click to dismiss opened action dropdown, otherwise it could interfere with
// correct behaviour of other dropdowns.
$document[0].body.click();
var deferred = $q.defer();
spinnerModal.showModalSpinner(gettext('Loading'));
var activeTemplateVersion, activeTemplateId;
magnum.getCluster(selected.id).then(function(response) {
formModel = getFormModelDefaults();
formModel.id = selected.id;
clusterTemplatesTitleMap = [
// Default <select> placeholder
{
value:'',
name: gettext("Choose a Cluster Template to upgrade to")
}
];
processClusterResponse(response.data);
// Retrieve only cluster templates related to the current one.
return magnum.getClusterTemplates(activeTemplateId);
}).then(function(response) {
processClusterTemplatesResponse(response.data.items);
modalConfig = createModalConfig();
deferred.resolve(modal.open(modalConfig).then(onModalSubmit));
spinnerModal.hideModalSpinner();
$scope.model = formModel;
}).catch(onError);
function processClusterResponse(cluster) {
formModel.master_nodes = cluster.master_count;
formModel.worker_nodes = cluster.node_count;
activeTemplateVersion = cluster.labels.kube_tag;
activeTemplateId = cluster.cluster_template_id;
}
function processClusterTemplatesResponse(clusterTemplates) {
if (!clusterTemplates) { return; }
var startingTemplatesTitleMapLength = clusterTemplatesTitleMap.length;
// Only load templates that are greater than the current template (kube tag comparison)
clusterTemplates.forEach(function(template) {
if (isVersionGreater(activeTemplateVersion, template.labels.kube_tag)) {
clusterTemplatesTitleMap.push({
value: template.id,
name: template.name
});
}
});
// Order templates by name in descending order
clusterTemplatesTitleMap.sort(function(firstTemplate, secondTemplate) {
return firstTemplate.name < secondTemplate.name ? 1 : -1;
});
// If nothing has been added to the map => already on latest template
isLatestTemplate = startingTemplatesTitleMapLength === clusterTemplatesTitleMap.length;
}
function onError(err) {
spinnerModal.hideModalSpinner();
return deferred.reject(err);
}
return deferred.promise;
}
function createModalConfig() {
return {
title: gettext('Rolling Cluster Upgrade'),
schema: {
type: 'object',
properties: {
'cluster_template_id': {
title: gettext('New Cluster Template'),
type: 'string'
},
'max_batch_size': {
title: gettext('Maximum Batch Size'),
type: 'number',
minimum: 1
}
}
},
form: [
{
key: 'cluster_template_id',
type: 'select',
titleMap: clusterTemplatesTitleMap,
required: true,
readonly: isLatestTemplate,
description: isLatestTemplate
? gettext('<em>This cluster is already on the latest compatible template</em>') : null
},
{
key: 'max_batch_size',
placeholder: gettext('The cluster node count.'),
// Disable if there's nothing to upgrade or if the the default value incrementation
// would fail the validation.
readonly: isLatestTemplate ||
!isBatchSizeValid(getFormModelDefaults().max_batch_size + 1),
validationMessage: {
sizeExceeded: gettext('The maximum number of nodes in the batch has been exceeded.'),
101: gettext('A batch cannot have less than one node.')
},
$validators: {
sizeExceeded: isBatchSizeValid
}
}
],
model: formModel
};
}
function getFormModelDefaults() {
return {
cluster_template_id: '',
max_batch_size: 1
};
}
function allowed() {
return $qExtensions.booleanAsPromise(true);
}
function isBatchSizeValid(batchSize) {
return batchSize &&
(batchSize === 1 ||
batchSize <= formModel.master_nodes / 3 && batchSize <= formModel.worker_nodes / 5);
}
function onModalSubmit() {
return magnum.upgradeCluster(formModel.id, {
cluster_template: formModel.cluster_template_id,
max_batch_size: formModel.max_batch_size,
nodegroup: 'default-worker'
}).then(onRequestSuccess);
}
function onRequestSuccess() {
toast.add('success', gettext('Cluster is being upgraded to the new Cluster template'));
return actionResult.getActionResult()
.updated(resourceType, formModel.id)
.result;
}
function isVersionGreater(v1, v2) {
if (!v1 || !v2) { return null; }
// Strip the 'v' if prefixed in the version
if (v1[0] === 'v') { v1 = v1.substr(1); }
if (v2[0] === 'v') { v2 = v2.substr(1); }
return utils.versionCompare(v1, v2) < 0;
}
}
})();