Add update action for cluster
This patch adds update action as item action into cluster table and details view. For now, we can update only node count for cluster. Change-Id: I291c754ad6bfcd36875f1fb929b090f484e3f335 Implements: blueprint bay-update
This commit is contained in:
parent
8ebe759e18
commit
7a66ba0aac
@ -149,17 +149,15 @@ def cluster_template_show(request, id):
|
||||
|
||||
|
||||
def cluster_create(request, **kwargs):
|
||||
args = {}
|
||||
for (key, value) in kwargs.items():
|
||||
if key in CLUSTER_CREATE_ATTRS:
|
||||
args[key] = value
|
||||
else:
|
||||
raise exceptions.BadRequest(
|
||||
"Key must be in %s" % ",".join(CLUSTER_CREATE_ATTRS))
|
||||
args = _cleanup_params(CLUSTER_CREATE_ATTRS, True, **kwargs)
|
||||
return magnumclient(request).clusters.create(**args)
|
||||
|
||||
|
||||
def cluster_update(request, id, patch):
|
||||
def cluster_update(request, id, **kwargs):
|
||||
new = _cleanup_params(CLUSTER_CREATE_ATTRS, True, **kwargs)
|
||||
old = magnumclient(request).clusters.get(id).to_dict()
|
||||
old = _cleanup_params(CLUSTER_CREATE_ATTRS, False, **old)
|
||||
patch = _create_patches(old, new)
|
||||
return magnumclient(request).clusters.update(id, patch)
|
||||
|
||||
|
||||
|
@ -101,6 +101,19 @@ class Cluster(generic.View):
|
||||
"""Get a specific cluster"""
|
||||
return change_to_id(magnum.cluster_show(request, cluster_id).to_dict())
|
||||
|
||||
@rest_utils.ajax(data_required=True)
|
||||
def patch(self, request, cluster_id):
|
||||
"""Update a Cluster.
|
||||
|
||||
Returns the Cluster object on success.
|
||||
"""
|
||||
params = request.DATA
|
||||
updated_cluster = magnum.cluster_update(
|
||||
request, cluster_id, **params)
|
||||
return rest_utils.CreatedResponse(
|
||||
'/api/container_infra/cluster/%s' % cluster_id,
|
||||
updated_cluster.to_dict())
|
||||
|
||||
|
||||
@urls.register
|
||||
class Clusters(generic.View):
|
||||
|
@ -34,6 +34,7 @@
|
||||
'horizon.framework.util.i18n.gettext',
|
||||
'horizon.dashboard.container-infra.clusters.create.service',
|
||||
'horizon.dashboard.container-infra.clusters.delete.service',
|
||||
'horizon.dashboard.container-infra.clusters.update.service',
|
||||
'horizon.dashboard.container-infra.clusters.show-certificate.service',
|
||||
'horizon.dashboard.container-infra.clusters.sign-certificate.service',
|
||||
'horizon.dashboard.container-infra.clusters.resourceType'
|
||||
@ -44,6 +45,7 @@
|
||||
gettext,
|
||||
createClusterService,
|
||||
deleteClusterService,
|
||||
updateClusterService,
|
||||
showCertificateService,
|
||||
signCertificateService,
|
||||
resourceType) {
|
||||
@ -84,6 +86,13 @@
|
||||
text: gettext('Sign Certificate')
|
||||
}
|
||||
})
|
||||
.append({
|
||||
id: 'updateClusterAction',
|
||||
service: updateClusterService,
|
||||
template: {
|
||||
text: gettext('Update Cluster')
|
||||
}
|
||||
})
|
||||
.append({
|
||||
id: 'deleteClusterAction',
|
||||
service: deleteClusterService,
|
||||
|
@ -47,7 +47,8 @@
|
||||
return {data: {items: response.data.items.map(addTrackBy)}};
|
||||
|
||||
function addTrackBy(cluster) {
|
||||
cluster.trackBy = cluster.id;
|
||||
var timestamp = cluster.updated_at ? cluster.updated_at : cluster.created_at;
|
||||
cluster.trackBy = cluster.id + timestamp;
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* 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.update.service
|
||||
* @description Service for the container-infra cluster update modal
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.container-infra.clusters')
|
||||
.factory('horizon.dashboard.container-infra.clusters.update.service', updateService);
|
||||
|
||||
updateService.$inject = [
|
||||
'horizon.app.core.openstack-service-api.magnum',
|
||||
'horizon.app.core.openstack-service-api.policy',
|
||||
'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.dashboard.container-infra.clusters.resourceType',
|
||||
'horizon.dashboard.container-infra.clusters.workflow'
|
||||
];
|
||||
|
||||
function updateService(
|
||||
magnum, policy, actionResult, gettext, $qExtensions, modal, toast, resourceType, workflow
|
||||
) {
|
||||
|
||||
var config;
|
||||
var message = {
|
||||
success: gettext('Cluster %s was successfully updated.')
|
||||
};
|
||||
|
||||
var service = {
|
||||
perform: perform,
|
||||
allowed: allowed
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
//////////////
|
||||
|
||||
function perform(selected, $scope) {
|
||||
config = workflow.init('update', gettext('Update Cluster'), $scope);
|
||||
config.model.id = selected.id;
|
||||
|
||||
// load current data
|
||||
magnum.getCluster(selected.id).then(onLoad);
|
||||
function onLoad(response) {
|
||||
config.model.name = response.data.name
|
||||
? response.data.name : "";
|
||||
config.model.cluster_template_id = response.data.cluster_template_id
|
||||
? response.data.cluster_template_id : "";
|
||||
config.model.master_count = response.data.master_count
|
||||
? response.data.master_count : null;
|
||||
config.model.node_count = response.data.node_count
|
||||
? response.data.node_count : null;
|
||||
config.model.discovery_url = response.data.discovery_url
|
||||
? response.data.discovery_url : "";
|
||||
config.model.create_timeout = response.data.create_timeout
|
||||
? response.data.create_timeout : null;
|
||||
config.model.keypair = response.data.keypair
|
||||
? response.data.keypair : "";
|
||||
}
|
||||
|
||||
return modal.open(config).then(submit);
|
||||
}
|
||||
|
||||
function allowed() {
|
||||
return $qExtensions.booleanAsPromise(true);
|
||||
}
|
||||
|
||||
function submit(context) {
|
||||
var id = context.model.id;
|
||||
context.model = cleanNullProperties(context.model);
|
||||
return magnum.updateCluster(id, context.model, true)
|
||||
.then(success, true);
|
||||
}
|
||||
|
||||
function cleanNullProperties(model) {
|
||||
// Initially clean fields that don't have any value.
|
||||
// Not only "null", blank too.
|
||||
for (var key in model) {
|
||||
if (model.hasOwnProperty(key) && model[key] === null || model[key] === "" ||
|
||||
key === "tabs" || key === "id") {
|
||||
delete model[key];
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
function success(response) {
|
||||
response.data.id = response.data.uuid;
|
||||
toast.add('success', interpolate(message.success, [response.data.id]));
|
||||
return actionResult.getActionResult()
|
||||
.updated(resourceType, response.data.id)
|
||||
.result;
|
||||
}
|
||||
}
|
||||
})();
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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';
|
||||
|
||||
describe('horizon.dashboard.container-infra.clusters.update.service', function() {
|
||||
|
||||
var service, $scope, $q, deferred, magnum;
|
||||
var selected = {
|
||||
id: 1
|
||||
};
|
||||
var model = {
|
||||
id: 1,
|
||||
tabs: "",
|
||||
keypair_id: "",
|
||||
coe: null
|
||||
};
|
||||
var modal = {
|
||||
open: function(config) {
|
||||
config.model = model;
|
||||
deferred = $q.defer();
|
||||
deferred.resolve(config);
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
var workflow = {
|
||||
init: function (action, title) {
|
||||
action = title;
|
||||
return {model: model};
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////
|
||||
|
||||
beforeEach(module('horizon.app.core'));
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(module('horizon.dashboard.container-infra.clusters'));
|
||||
|
||||
beforeEach(module(function($provide) {
|
||||
$provide.value('horizon.dashboard.container-infra.clusters.workflow', workflow);
|
||||
$provide.value('horizon.framework.widgets.form.ModalFormService', modal);
|
||||
}));
|
||||
|
||||
beforeEach(inject(function($injector, _$rootScope_, _$q_) {
|
||||
$q = _$q_;
|
||||
$scope = _$rootScope_.$new();
|
||||
service = $injector.get(
|
||||
'horizon.dashboard.container-infra.clusters.update.service');
|
||||
magnum = $injector.get('horizon.app.core.openstack-service-api.magnum');
|
||||
deferred = $q.defer();
|
||||
deferred.resolve({data: {uuid: 1, labels: "key1:val1,key2:val2"}});
|
||||
spyOn(magnum, 'getCluster').and.returnValue(deferred.promise);
|
||||
spyOn(magnum, 'updateCluster').and.returnValue(deferred.promise);
|
||||
spyOn(workflow, 'init').and.returnValue({model: model});
|
||||
spyOn(modal, 'open').and.callThrough();
|
||||
}));
|
||||
|
||||
it('should check the policy if the user is allowed to update cluster', function() {
|
||||
var allowed = service.allowed();
|
||||
expect(allowed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('open the modal', inject(function($timeout) {
|
||||
service.perform(selected, $scope);
|
||||
|
||||
expect(workflow.init).toHaveBeenCalled();
|
||||
|
||||
expect(modal.open).toHaveBeenCalledWith({model: model});
|
||||
|
||||
$timeout.flush();
|
||||
$scope.$apply();
|
||||
|
||||
expect(magnum.updateCluster).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
})();
|
@ -66,9 +66,7 @@
|
||||
|
||||
function onGetClusterTemplate(response) {
|
||||
ctrl.clusterTemplate = response.data;
|
||||
if (response.data.keypair_id === null) {
|
||||
$scope.model.keypair = "";
|
||||
} else {
|
||||
if ($scope.model.keypair === "") {
|
||||
$scope.model.keypair = response.data.keypair_id;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,8 @@
|
||||
$q = _$q_;
|
||||
$scope = _$rootScope_.$new();
|
||||
$scope.model = {
|
||||
cluster_template_id: '1'
|
||||
cluster_template_id: '1',
|
||||
keypair: ''
|
||||
};
|
||||
magnum = $injector.get('horizon.app.core.openstack-service-api.magnum');
|
||||
controller = $injector.get('$controller');
|
||||
@ -49,11 +50,12 @@
|
||||
});
|
||||
|
||||
it('should keypair is changed by cluster template\'s keypair', function() {
|
||||
$scope.model.cluster_template_id = '1';
|
||||
$scope.$apply();
|
||||
expect($scope.model.keypair).toBe('1');
|
||||
|
||||
$scope.model.cluster_template_id = '';
|
||||
$scope.$digest();
|
||||
$scope.$apply();
|
||||
expect($scope.model.keypair).toBe('');
|
||||
});
|
||||
});
|
||||
|
@ -96,13 +96,15 @@
|
||||
items: [
|
||||
{
|
||||
key: 'name',
|
||||
placeholder: gettext('Name of the cluster.')
|
||||
placeholder: gettext('Name of the cluster.'),
|
||||
readonly: action === 'update'
|
||||
},
|
||||
{
|
||||
key: 'cluster_template_id',
|
||||
type: 'select',
|
||||
titleMap: clusterTemplates,
|
||||
required: true
|
||||
required: true,
|
||||
readonly: action === 'update'
|
||||
},
|
||||
{
|
||||
type: 'template',
|
||||
@ -110,7 +112,8 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
required: true
|
||||
},
|
||||
{
|
||||
title: gettext('Size'),
|
||||
@ -124,7 +127,8 @@
|
||||
items: [
|
||||
{
|
||||
key: 'master_count',
|
||||
placeholder: gettext('The number of master nodes for the cluster.')
|
||||
placeholder: gettext('The number of master nodes for the cluster.'),
|
||||
readonly: action === 'update'
|
||||
},
|
||||
{
|
||||
key: 'node_count',
|
||||
@ -146,23 +150,27 @@
|
||||
items: [
|
||||
{
|
||||
key: 'discovery_url',
|
||||
placeholder: gettext('Specifies custom discovery url for node discovery.')
|
||||
placeholder: gettext('Specifies custom discovery url for node discovery.'),
|
||||
readonly: action === 'update'
|
||||
},
|
||||
{
|
||||
key: 'create_timeout',
|
||||
/* eslint-disable max-len */
|
||||
placeholder: gettext('The timeout for cluster creation in minutes.'),
|
||||
description: gettext('Set to 0 for no timeout. The default is no timeout.')
|
||||
description: gettext('Set to 0 for no timeout. The default is no timeout.'),
|
||||
readonly: action === 'update'
|
||||
},
|
||||
{
|
||||
key: 'keypair',
|
||||
type: 'select',
|
||||
titleMap: keypairs,
|
||||
required: true
|
||||
required: true,
|
||||
readonly: action === 'update'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
function MagnumAPI($timeout, apiService, toastService, gettext) {
|
||||
var service = {
|
||||
createCluster: createCluster,
|
||||
updateCluster: updateCluster,
|
||||
getCluster: getCluster,
|
||||
getClusters: getClusters,
|
||||
deleteCluster: deleteCluster,
|
||||
@ -58,6 +59,13 @@
|
||||
});
|
||||
}
|
||||
|
||||
function updateCluster(id, params) {
|
||||
return apiService.patch('/api/container_infra/clusters/' + id, params)
|
||||
.error(function() {
|
||||
toastService.add('error', gettext('Unable to update cluster.'));
|
||||
});
|
||||
}
|
||||
|
||||
function getCluster(id) {
|
||||
return apiService.get('/api/container_infra/clusters/' + id)
|
||||
.error(function() {
|
||||
|
Loading…
Reference in New Issue
Block a user