diff --git a/magnum_ui/api/magnum.py b/magnum_ui/api/magnum.py index ba5c62fc..befaf45d 100644 --- a/magnum_ui/api/magnum.py +++ b/magnum_ui/api/magnum.py @@ -289,3 +289,8 @@ def quotas_update(request, project_id, resource, **kwargs): def quotas_delete(request, project_id, resource): return magnumclient(request).quotas.delete(project_id, resource) + + +def nodegroup_list(request, cluster_id=None, limit=None, marker=None): + return magnumclient(request).nodegroups.list(cluster_id, limit=limit, + marker=marker) diff --git a/magnum_ui/api/rest/magnum.py b/magnum_ui/api/rest/magnum.py index ba66e0e5..74ea73b3 100644 --- a/magnum_ui/api/rest/magnum.py +++ b/magnum_ui/api/rest/magnum.py @@ -25,6 +25,7 @@ from django.views import generic from magnum_ui.api import heat from magnum_ui.api import magnum +from heatclient import exc as heatexc from openstack_dashboard import api from openstack_dashboard.api import neutron from openstack_dashboard.api.rest import urls @@ -237,18 +238,29 @@ class ClusterResize(generic.View): print(e) return HttpResponseNotFound() - stack = heat.stack_get(request, cluster["stack_id"]) - search_opts = {"name": "%s-" % stack.stack_name} - servers = api.nova.server_list(request, search_opts=search_opts)[0] + try: + ngs = magnum.nodegroup_list(request, cluster_id) + nodegroups = [n.to_dict() for n in ngs] + except AttributeError: + return HttpResponseNotFound() + try: + stack = heat.stack_get(request, cluster["stack_id"]) + except heatexc.HTTPNotFound: + stack = None worker_nodes = [] - for server in servers: - if (server.name.startswith("%s-minion" % stack.stack_name) or - server.name.startswith("%s-node" % stack.stack_name)): - worker_nodes.append({"name": server.name, "id": server.id}) + if stack: + search_opts = {"name": "%s-" % stack.stack_name} + servers = api.nova.server_list(request, search_opts=search_opts)[0] + + for server in servers: + if (server.name.startswith("%s-minion" % stack.stack_name) or + server.name.startswith("%s-node" % stack.stack_name)): + worker_nodes.append({"name": server.name, "id": server.id}) return {"cluster": change_to_id(cluster), - "worker_nodes": worker_nodes} + "worker_nodes": worker_nodes, + "nodegroups": nodegroups} @rest_utils.ajax(data_required=True) def post(self, request, cluster_id): diff --git a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js index ebc6a961..39ecb3f1 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.js @@ -70,7 +70,7 @@ formModel = getFormModelDefaults(); formModel.id = selected.id; - modalConfig = constructModalConfig(response.data.worker_nodes); + modalConfig = constructModalConfig(response.data.nodegroups, response.data.worker_nodes); deferred.resolve(modal.open(modalConfig).then(onModalSubmit)); $scope.model = formModel; @@ -91,9 +91,13 @@ return $qExtensions.booleanAsPromise(true); } - function constructModalConfig(workerNodesList) { - formModel.original_node_count = workerNodesList.length; - formModel.node_count = workerNodesList.length; + function constructModalConfig(nodegroups, workerNodesList) { + var defaultWorker = nodegroups.filter(function(ng) { + return ng.name === 'default-worker'; + })[0]; + formModel.original_node_count = defaultWorker.node_count; + formModel.node_count = defaultWorker.node_count; + formModel.worker_nodes = workerNodesList; return { title: gettext('Resize Cluster'), @@ -116,8 +120,8 @@ form: [ { key: 'node_count', - title: gettext('Node Count'), - placeholder: gettext('The cluster node count.'), + title: gettext('Node Count (default-worker)'), + placeholder: gettext('The default-worker nodegroup node_count.'), required: true, validationMessage: { 101: gettext('You cannot resize to fewer than zero worker nodes.') @@ -129,7 +133,8 @@ type: 'checkboxes', title: gettext('Choose nodes to remove (Optional)'), titleMap: generateNodesTitleMap(workerNodesList), - condition: 'model.node_count < model.original_node_count', + condition: 'model.node_count < model.original_node_count && ' + + 'model.worker_nodes.length > 0', onChange: validateNodeRemovalCount, validationMessage: { nodeRemovalCountExceeded: gettext('You may only select as many nodes ' + diff --git a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js index 842df87d..0f64b938 100644 --- a/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js +++ b/magnum_ui/static/dashboard/container-infra/clusters/resize/resize.service.spec.js @@ -67,10 +67,23 @@ it('should open the modal, hide the loading spinner and check the form model', inject(function($timeout) { - var mockWorkerNodes = [{id: "456", name: "Worker Node 1"}]; + // 2 nodegroups, default-worker and another-nodegroup, with 2 and 3 + // nodes respectively. cluster.node_count will be total nodes in all + // nodegroups + var mockDefaultWorker = {name: 'default-worker', node_count: 2}; + var mockNodegroups = [mockDefaultWorker, + {name: 'default-master', node_count: 1}, + {name: 'another-nodegroup', node_count: 3}]; + var mockCluster = {node_count: 5}; + + // only populated with heat, [] for capi + var mockWorkerNodes = [{id: "456", name: "Worker Node 1"}, + {id: "457", name: "Worker Node 2"}]; deferred = $q.defer(); - deferred.resolve({data: {cluster: {}, worker_nodes: mockWorkerNodes}}); + deferred.resolve({data: {cluster: mockCluster, + worker_nodes: mockWorkerNodes, + nodegroups: mockNodegroups}}); spyOn(magnum, 'getClusterNodes').and.returnValue(deferred.promise); service.perform(selected, $scope); @@ -82,8 +95,8 @@ // Check if the form's model skeleton is correct expect(modalConfig.model.id).toBe(selected.id); - expect(modalConfig.model.original_node_count).toBe(mockWorkerNodes.length); - expect(modalConfig.model.node_count).toBe(mockWorkerNodes.length); + expect(modalConfig.model.original_node_count).toBe(mockDefaultWorker.node_count); + expect(modalConfig.model.node_count).toBe(mockDefaultWorker.node_count); expect(modalConfig.title).toBeDefined(); expect(modalConfig.schema).toBeDefined(); expect(modalConfig.form).toBeDefined();