From aa83752f20225c9817196263915ad02b9d823cb7 Mon Sep 17 00:00:00 2001 From: zitptan Date: Tue, 17 Aug 2021 14:37:00 +0530 Subject: [PATCH] Add Rules operation to Network QoS Policy Added create, edit, and delete rules operation to the network qos policy. Rules: Minimum-Bandwidth, DSCP-Marking, and Bandwidth-Limit, Minimum-Packet-Rate Partially-Implements: https://blueprints.launchpad.net/horizon/+spec/create-network-qos-policy Change-Id: I49058036f1d78ef022d966f6b375cdc984755813 --- openstack_dashboard/api/neutron.py | 183 +++++++++ openstack_dashboard/api/rest/neutron.py | 154 ++++++++ .../network_qos/actions/actions.module.js | 34 ++ .../actions/actions.module.spec.js | 15 + .../actions/add-rule.action.service.js | 182 +++++++++ .../actions/add-rule.action.service.spec.js | 154 ++++++++ .../actions/add-rule.controller.js | 74 ++++ .../actions/add-rule.controller.spec.js | 130 +++++++ .../core/network_qos/actions/add-rule.html | 98 +++++ .../actions/delete-rule.action.service.js | 117 ++++++ .../delete-rule.action.service.spec.js | 224 +++++++++++ .../actions/edit-rule.action.service.js | 173 +++++++++ .../actions/edit-rule.action.service.spec.js | 244 ++++++++++++ .../actions/edit-rule.controller.js | 104 +++++ .../actions/edit-rule.controller.spec.js | 161 ++++++++ .../core/network_qos/actions/edit-rule.html | 106 +++++ .../network_qos/actions/rule.description.html | 18 + .../workflow/delete-rule.workflow.service.js | 118 ++++++ .../delete-rule.workflow.service.spec.js | 97 +++++ .../details/overview.controller.js | 58 ++- .../core/network_qos/details/overview.html | 37 +- .../openstack-service-api/neutron.service.js | 366 +++++++++++++++++- .../neutron.service.spec.js | 108 ++++++ .../test/test_data/neutron_data.py | 51 +++ .../test/unit/api/test_neutron.py | 259 +++++++++++++ .../network_qos_rules-cd103f9383b6cdf9.yaml | 8 + 26 files changed, 3259 insertions(+), 14 deletions(-) create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.spec.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.spec.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/add-rule.html create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.spec.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.spec.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.spec.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/edit-rule.html create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/rule.description.html create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.js create mode 100644 openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.spec.js create mode 100644 releasenotes/notes/network_qos_rules-cd103f9383b6cdf9.yaml diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py index 0f06a1b22b..ccf0d67827 100644 --- a/openstack_dashboard/api/neutron.py +++ b/openstack_dashboard/api/neutron.py @@ -2012,6 +2012,189 @@ def policy_delete(request, policy_id): neutronclient(request).delete_qos_policy(policy_id) +class DSCPMarkingRule(NeutronAPIDictWrapper): + """Wrapper for neutron DSCPMarkingRule.""" + + +@profiler.trace +def dscp_marking_rule_create(request, policy_id, **kwargs): + """Create a DSCP Marking rule. + + :param request: request context + :param policy_id: Id of the policy + :param dscp_mark: integer + :return: A dscp_mark_rule object. + """ + if 'tenant_id' not in kwargs: + kwargs['tenant_id'] = request.user.project_id + body = {'dscp_marking_rule': kwargs} + rule = 'dscp_marking_rule' + dscp_marking_rule = neutronclient(request)\ + .create_dscp_marking_rule(policy_id, body).get(rule) + return DSCPMarkingRule(dscp_marking_rule) + + +@profiler.trace +def dscp_marking_rule_update(request, policy_id, rule_id, **kwargs): + """Update a DSCP Marking Limit Rule.""" + + body = {'dscp_marking_rule': kwargs} + ruleType = 'dscp_marking_rule' + dscpmarking_update = neutronclient(request)\ + .update_dscp_marking_rule(rule_id, policy_id, body).get(ruleType) + return DSCPMarkingRule(dscpmarking_update) + + +def dscp_marking_rule_delete(request, policy_id, rule_id): + """Deletes a DSCP Marking Rule.""" + + neutronclient(request).delete_dscp_marking_rule(rule_id, policy_id) + + +class MinimumBandwidthRule(NeutronAPIDictWrapper): + """Wrapper for neutron MinimumBandwidthRule.""" + + +@profiler.trace +def minimum_bandwidth_rule_create(request, policy_id, **kwargs): + """Create a Minimum Bandwidth rule. + + :param request: request context + :param policy_id: Id of the policy + :param min_kbps: integer + :param direction: string (egress or ingress) + :return: A minimum_bandwidth_rule object. + """ + if 'tenant_id' not in kwargs: + kwargs['tenant_id'] = request.user.project_id + body = {'minimum_bandwidth_rule': kwargs} + rule = 'minimum_bandwidth_rule' + minimum_bandwidth_rule = neutronclient(request)\ + .create_minimum_bandwidth_rule(policy_id, body).get(rule) + return MinimumBandwidthRule(minimum_bandwidth_rule) + + +@profiler.trace +def minimum_bandwidth_rule_update(request, policy_id, rule_id, **kwargs): + """Update a Minimum Bandwidth rule. + + :param request: request context + :param policy_id: Id of the policy + :param min_kbps: integer + :param direction: string (egress or ingress) + :return: A minimum_bandwidth_rule object. + """ + body = {'minimum_bandwidth_rule': kwargs} + ruleType = 'minimum_bandwidth_rule' + minbandwidth_update = neutronclient(request)\ + .update_minimum_bandwidth_rule(rule_id, policy_id, body)\ + .get(ruleType) + return MinimumBandwidthRule(minbandwidth_update) + + +def minimum_bandwidth_rule_delete(request, policy_id, rule_id): + """Deletes a Minimum Bandwidth Rule.""" + + neutronclient(request).delete_minimum_bandwidth_rule(rule_id, policy_id) + + +class BandwidthLimitRule(NeutronAPIDictWrapper): + """Wrapper for neutron BandwidthLimitRule.""" + + +@profiler.trace +def bandwidth_limit_rule_create(request, policy_id, **kwargs): + """Create a Bandwidth Limit rule. + + :param request: request context + :param policy_id: Id of the policy + :param max_kbps: integer + :param max_burst_kbps: integer + :param direction: string (egress or ingress) + :return: A bandwidth_limit_rule object. + """ + body = {'bandwidth_limit_rule': kwargs} + if 'tenant_id' not in kwargs: + kwargs['tenant_id'] = request.user.project_id + body = {'bandwidth_limit_rule': kwargs} + rule = 'bandwidth_limit_rule' + bandwidth_limit_rule = neutronclient(request)\ + .create_bandwidth_limit_rule(policy_id, body).get(rule) + return BandwidthLimitRule(bandwidth_limit_rule) + + +@profiler.trace +def bandwidth_limit_rule_update(request, policy_id, rule_id, **kwargs): + """Update a Bandwidth Limit rule. + + :param request: request context + :param policy_id: Id of the policy + :param max_kbps: integer + :param max_burst_kbps: integer + :param direction: string (egress or ingress) + :return: A bandwidth_limit_rule object. + """ + body = {'bandwidth_limit_rule': kwargs} + ruleType = 'bandwidth_limit_rule' + bandwidthlimit_update = neutronclient(request)\ + .update_bandwidth_limit_rule(rule_id, policy_id, body)\ + .get(ruleType) + return BandwidthLimitRule(bandwidthlimit_update) + + +@profiler.trace +def bandwidth_limit_rule_delete(request, policy_id, rule_id): + """Deletes a Bandwidth Limit Rule.""" + neutronclient(request).delete_bandwidth_limit_rule(rule_id, policy_id) + + +class MinimumPacketRateRule(NeutronAPIDictWrapper): + """Wrapper for neutron MinimumPacketRateRule.""" + + +@profiler.trace +def minimum_packet_rate_rule_create(request, policy_id, **kwargs): + """Create a Minimum Packet Rate rule. + + :param request: request context + :param policy_id: Id of the policy + :param min_kpps: integer + :param direction: string (egress or ingress) + :return: A minimum_packet_rate_rule object. + """ + body = {'minimum_packet_rate_rule': kwargs} + if 'tenant_id' not in kwargs: + kwargs['tenant_id'] = request.user.project_id + body = {'minimum_packet_rate_rule': kwargs} + rule = 'minimum_packet_rate_rule' + minimum_packet_rate_rule = neutronclient(request)\ + .create_minimum_packet_rate_rule(policy_id, body).get(rule) + return MinimumPacketRateRule(minimum_packet_rate_rule) + + +@profiler.trace +def minimum_packet_rate_rule_update(request, policy_id, rule_id, **kwargs): + """Update a Minimum Packet Rate rule. + + :param request: request context + :param policy_id: Id of the policy + :param min_kpps: integer + :param direction: string (egress or ingress) + :return: A minimum_packet_rate_rule object. + """ + body = {'minimum_packet_rate_rule': kwargs} + ruleType = 'minimum_packet_rate_rule' + minpacketrate_update = neutronclient(request)\ + .update_minimum_packet_rate_rule(rule_id, policy_id, body)\ + .get(ruleType) + return MinimumPacketRateRule(minpacketrate_update) + + +def minimum_packet_rate_rule_delete(request, policy_id, rule_id): + """Deletes a Minimum Packet Rate Rule.""" + neutronclient(request).delete_minimum_packet_rate_rule(rule_id, policy_id) + + @profiler.trace def list_availability_zones(request, resource=None, state=None): az_list = neutronclient(request).list_availability_zones().get( diff --git a/openstack_dashboard/api/rest/neutron.py b/openstack_dashboard/api/rest/neutron.py index ae1e7944d1..df5df49fd4 100644 --- a/openstack_dashboard/api/rest/neutron.py +++ b/openstack_dashboard/api/rest/neutron.py @@ -330,3 +330,157 @@ class QoSPolicy(generic.View): """Get a specific policy""" policy = api.neutron.policy_get(request, policy_id) return policy.to_dict() + + +@urls.register +class MinimumBandwidthRules(generic.View): + """API for Minimum Bandwidth Rule create.""" + url_regex = ( + r'neutron/qos/policies/' + + r'(?P[^/]+)/minimum_bandwidth_rules/$') + + @rest_utils.ajax(data_required=True) + def post(self, req, policy_id): + minimum_bandwidth_rule = api.neutron.minimum_bandwidth_rule_create( + req, policy_id, **req.DATA) + return rest_utils.CreatedResponse( + '/api/neutron/qospolicies/minimumbandwidthrules/%s' + % minimum_bandwidth_rule.id, + minimum_bandwidth_rule.to_dict() + ) + + +@urls.register +class MinimumBandwidthRule(generic.View): + """API for Minimum Bandwidth Rule update and delete.""" + url_regex = ( + r'neutron/qos/policies/' + + r'(?P[^/]+)/minimum_bandwidth_rules/(?P[^/]+)$' + ) + + @rest_utils.ajax(data_required=True) + def patch(self, req, policy_id, rule_id): + """Update a QoS Minimum Bandwidth rule.""" + return api.neutron.minimum_bandwidth_rule_update( + req, policy_id, rule_id, **req.DATA) + + @rest_utils.ajax() + def delete(self, req, policy_id, rule_id): + """Delete a QoS Minimum Badwidth rule""" + api.neutron.minimum_bandwidth_rule_delete(req, policy_id, rule_id) + + +@urls.register +class DSCPMarkingRules(generic.View): + """API for DSCP Marking Rule create""" + url_regex = ( + r'neutron/qos/policies/(?P[^/]+)' + + r'/dscp_marking_rules/$') + + @rest_utils.ajax(data_required=True) + def post(self, req, policy_id): + """Create QoS DSCP Marking rules.""" + dscp_marking_rule = api.neutron.dscp_marking_rule_create( + req, policy_id, **req.DATA) + return rest_utils.CreatedResponse( + '/api/neutron/qospolicies/dscpmarkingrules/%s' + % dscp_marking_rule.id, + dscp_marking_rule.to_dict() + ) + + +@urls.register +class DSCPMarkingRule(generic.View): + """API for DSCP Marking Rule Delete and Update""" + url_regex = ( + r'neutron/qos/policies/(?P[^/]+)' + + r'/dscp_marking_rules/(?P[^/]+)$') + + @rest_utils.ajax(data_required=True) + def patch(self, req, policy_id, rule_id): + """Update a qos DSCP Marking rule.""" + return api.neutron.dscp_marking_rule_update( + req, policy_id, rule_id, **req.DATA) + + @rest_utils.ajax() + def delete(self, req, policy_id, rule_id): + """Delete a qos DSCP Marking rule.""" + api.neutron.dscp_marking_rule_delete(req, policy_id, rule_id) + + +@urls.register +class BandwidthLimitRules(generic.View): + """API for Bandwidth Limit Rule Create""" + url_regex = ( + r'neutron/qos/policies/(?P[^/]+)' + + r'/bandwidth_limit_rules/$' + ) + + @rest_utils.ajax(data_required=True) + def post(self, req, policy_id): + """Create QoS Bandwidth Limit rules.""" + bandwidth_limit_rule = api.neutron.bandwidth_limit_rule_create( + req, policy_id, **req.DATA) + return rest_utils.CreatedResponse( + '/api/neutron/qospolicies/bandwidthlimitrules/%s' + % bandwidth_limit_rule.id, + bandwidth_limit_rule.to_dict() + ) + + +@urls.register +class BandwidthLimitRule(generic.View): + """API for Bandwidth Limit Rule Update and Delete""" + url_regex = ( + r'neutron/qos/policies/(?P[^/]+)' + + r'/bandwidth_limit_rules/(?P[^/]+)$') + + @rest_utils.ajax(data_required=True) + def patch(self, req, policy_id, rule_id): + """Update a QoS Bandwidth Limit rule.""" + return api.neutron.bandwidth_limit_rule_update( + req, policy_id, rule_id, **req.DATA) + + @rest_utils.ajax() + def delete(self, req, policy_id, rule_id): + """Delete a QoS Bandwidth Limit rule.""" + api.neutron.bandwidth_limit_rule_delete(req, policy_id, rule_id) + + +@urls.register +class MinimumPacketRateRules(generic.View): + """API for Minimum Packet Rate Rule Create.""" + url_regex = ( + r'neutron/qos/policies/' + + r'(?P[^/]+)/minimum_packet_rate_rules/$') + + @rest_utils.ajax(data_required=True) + def post(self, req, policy_id): + """Create QoS Minimum Packet Rate rules.""" + minimum_packet_rate_rule = api.neutron.minimum_packet_rate_rule_create( + req, policy_id, **req.DATA) + return rest_utils.CreatedResponse( + '/api/neutron/qospolicies/minimumpacketraterules/%s' + % minimum_packet_rate_rule.id, + minimum_packet_rate_rule.to_dict() + ) + + +@urls.register +class MinimumPacketRateRule(generic.View): + """API for Updating and Deleting Minimum Packet Rate Rule""" + url_regex = ( + r'neutron/qos/policies/' + + r'(?P[^/]+)/minimum_packet_rate_rules/(?P[^/]+)$' + ) + + @rest_utils.ajax(data_required=True) + def patch(self, req, policy_id, rule_id): + """Update a QoS Minimum Packet Rate rule.""" + return api.neutron.minimum_packet_rate_rule_update( + req, policy_id, rule_id, **req.DATA) + + @rest_utils.ajax() + def delete(self, req, policy_id, rule_id): + """Delete a QoS Minimum Packet Rate rule.""" + api.neutron.minimum_packet_rate_rule_delete(req, policy_id, rule_id) diff --git a/openstack_dashboard/static/app/core/network_qos/actions/actions.module.js b/openstack_dashboard/static/app/core/network_qos/actions/actions.module.js index 31239d943b..2611c256f6 100644 --- a/openstack_dashboard/static/app/core/network_qos/actions/actions.module.js +++ b/openstack_dashboard/static/app/core/network_qos/actions/actions.module.js @@ -33,6 +33,9 @@ 'horizon.framework.conf.resource-type-registry.service', 'horizon.app.core.network_qos.actions.create.service', 'horizon.app.core.network_qos.actions.delete.service', + 'horizon.app.core.network_qos.actions.add-rule.service', + 'horizon.app.core.network_qos.actions.edit-rule.service', + 'horizon.app.core.network_qos.actions.delete-rule.service', 'horizon.app.core.network_qos.resourceType' ]; @@ -40,6 +43,9 @@ registry, createService, deleteService, + addRuleService, + editRuleService, + deleteRuleService, qosResourceTypeCode ) { var qosResourceType = registry.getResourceType(qosResourceTypeCode); @@ -55,6 +61,34 @@ } ); + qosResourceType.itemActions + .append({ + id: 'addRulePolicyAction', + service: addRuleService, + template: { + text: gettext('Add Rule') + } + }); + + qosResourceType.itemActions + .append({ + id: 'editRuleAction', + service: editRuleService, + template: { + text: gettext('Edit Rule') + } + }); + + qosResourceType.itemActions + .append({ + id: 'deleteRuleAction', + service: deleteRuleService, + template: { + text: gettext('Delete Rule'), + type: 'delete' + } + }); + qosResourceType.itemActions .append({ id: 'deletePolicyAction', diff --git a/openstack_dashboard/static/app/core/network_qos/actions/actions.module.spec.js b/openstack_dashboard/static/app/core/network_qos/actions/actions.module.spec.js index 34cb8c5183..72df2f1289 100644 --- a/openstack_dashboard/static/app/core/network_qos/actions/actions.module.spec.js +++ b/openstack_dashboard/static/app/core/network_qos/actions/actions.module.spec.js @@ -28,6 +28,21 @@ expect(actionHasId(actions, 'createPolicyAction')).toBe(true); }); + it('registers Create Rule as a global action', function() { + var actions = registry.getResourceType('OS::Neutron::QoSPolicy').itemActions; + expect(actionHasId(actions, 'addRulePolicyAction')).toBe(true); + }); + + it('registers Edit Rule as a global action', function() { + var actions = registry.getResourceType('OS::Neutron::QoSPolicy').itemActions; + expect(actionHasId(actions, 'editRuleAction')).toBe(true); + }); + + it('registers Delete Rule as a global action', function() { + var actions = registry.getResourceType('OS::Neutron::QoSPolicy').itemActions; + expect(actionHasId(actions, 'deleteRuleAction')).toBe(true); + }); + it('registers Delete Policy as an item action', function() { var actions = registry.getResourceType('OS::Neutron::QoSPolicy').itemActions; expect(actionHasId(actions, 'deletePolicyAction')).toBe(true); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.js b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.js new file mode 100644 index 0000000000..50f4f6da74 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.js @@ -0,0 +1,182 @@ +/* Liscensed 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 + * @ngname horizon.app.core.network_qos.actions.add-rule.service + * + * @description + * Provides all of the actions for creating rule to a network qos policy. + */ + + angular + .module('horizon.app.core.network_qos') + .factory('horizon.app.core.network_qos.actions.add-rule.service', addRuleService); + + addRuleService.$inject = [ + 'horizon.app.core.openstack-service-api.neutron', + 'horizon.app.core.openstack-service-api.policy', + 'horizon.app.core.network_qos.resourceType', + 'horizon.framework.widgets.form.ModalFormService', + 'horizon.framework.widgets.toast.service', + 'horizon.framework.util.actions.action-result.service', + 'horizon.app.core.network_qos.basePath' + ]; + + function addRuleService( + neutronAPI, + policy, + resourceType, + modal, + toast, + actionResultService, + basePath + ) { + + var caption = gettext("Add Rule"); + + // schema + var schema = { + type: "object", + properties: { + qospolicy: { + title: gettext('QoS Policy Id'), + type: 'string', + readOnly: true + }, + qospolicyname: { + title: gettext('QoS Policy Name'), + type: 'string', + readOnly: true + }, + type: { + title: gettext('Type'), + type: 'string', + enum: ['bandwidth_limit', 'dscp_marking', 'minimum_bandwidth', 'minimum_packet_rate'] + } + }, + required: ['type'] + }; + + // form + var form = [ + { + type: "section", + htmlClass: "row", + items: [ + { + type: "section", + htmlClass: "col-sm-12", + items: [ + { + key: ["qospolicy", "qospolicyname", "type"], + type: "template", + templateUrl: basePath + "actions/add-rule.html" + } + ] + } + ] + } + ]; + + // model + var model = {}; + + var service = { + allowed: allowed, + perform: perform, + submit: submit + }; + + return service; + + ////////////// + + function allowed() { + return policy.ifAllowed( + {rules: [['network', 'create_policy_dscp_marking_rule'], + ['network', 'create_policy_minimum_bandwidth_rule'], + ['network', 'create_policy_bandwidth_limit_rule']]}); + } + + function perform(qospolicy) { + model = {"qospolicy": qospolicy.id, "qospolicyname": qospolicy.name}; + var config = { + "title": caption, + "submitText": caption, + "schema": schema, + "form": form, + "model": model, + "submitIcon": "plus", + "helpUrl": basePath + "actions/rule.description.html" + }; + return modal.open(config).then(submit); + } + + function submit(context) { + var id = context.model.qospolicy; + var data = {}; + if (context.model.rule_type === 'dscp_marking') { + data = { + dscp_mark: context.model.dscpmarking + }; + return neutronAPI.createDSCPMarkingRule(id, data).then(onAddRule); + } + else if (context.model.rule_type === 'minimum_bandwidth') { + data = { + direction: context.model.direction, + min_kbps: context.model.minkbps + }; + return neutronAPI.createMinimumBandwidthRule(id, data).then(onAddRule); + } + else if (context.model.rule_type === 'bandwidth_limit') { + var direction = context.model.direction !== undefined + ? context.model.direction : 'egress'; + data = { + direction: direction, + max_burst_kbps: context.model.maxburstkbps, + max_kbps: context.model.maxkbps + }; + return neutronAPI.createBandwidthLimitRule(id, data).then(onAddRule); + } + else if (context.model.rule_type === 'minimum_packet_rate') { + data = { + direction: context.model.direction, + min_kpps: context.model.minkpps + }; + return neutronAPI.createMinimumPacketRateRule(id, data).then(onAddRule); + } + } + + /** + * @ngdoc function + * @name onAddRule + * @description + * Informs the user about the added rule. + */ + + function onAddRule(response) { + var ruleRes = response.data; + toast.add('success', interpolate('QoS Policy Rule successfully created')); + + return actionResultService.getActionResult() + .created(resourceType, ruleRes.id) + .result; + } + + } +})(); + diff --git a/openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.spec.js b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.spec.js new file mode 100644 index 0000000000..ca8c4eec7c --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.action.service.spec.js @@ -0,0 +1,154 @@ +/* Liscensed 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.app.core.network_qos.actions.add-rule.service', function() { + + var $q, $scope, neutronAPI, service, modalFormService, toast, nbwdLmtRule, + qosPolicy, dscpRule, minBwdRule, bwdLmtRule, policyAPI, minpckRtRule; + + /////////////////////// + + beforeEach(module('horizon.framework')); + beforeEach(module('horizon.app.core')); + beforeEach(module('horizon.app.core.network_qos')); + + beforeEach(inject(function($injector, _$rootScope_, _$q_) { + $scope = _$rootScope_.$new(); + $q = _$q_; + service = $injector.get('horizon.app.core.network_qos.actions.add-rule.service'); + toast = $injector.get('horizon.framework.widgets.toast.service'); + policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); + modalFormService = $injector.get('horizon.framework.widgets.form.ModalFormService'); + neutronAPI = $injector.get('horizon.app.core.openstack-service-api.neutron'); + qosPolicy = {model: {id: '1', name: 'qos', description: "qos rules", shared: 'yes'}}; + dscpRule = {model: {qospolicy: '1', rule_type: "dscp_marking", dscpmarking: 0}}; + minBwdRule = { + model: { + qospolicy: '1', rule_type: "minimum_bandwidth", + minkbps: 128, direction: "egress" + }}; + minpckRtRule = { + model: { + qospolicy: '1', rule_type: "minimum_packet_rate", + minkpps: 1000, direction: "egress" + }}; + bwdLmtRule = { + model: { + qospolicy: '1', rule_type: "bandwidth_limit", + maxkbps: 1000, direction: "egress", maxburstkbps: 1100 + }}; + nbwdLmtRule = { + model: { + qospolicy: '1', rule_type: "bandwidth_limit", + maxkbps: 1000, direction: undefined, maxburstkbps: 1100 + }}; + })); + + it('should check policy is allowed or not', function() { + spyOn(policyAPI, 'ifAllowed').and.callThrough(); + var allowed = service.allowed(); + expect(allowed).toBeTruthy(); + expect(policyAPI.ifAllowed).toHaveBeenCalledWith( + { rules: [['network', 'create_policy_dscp_marking_rule'], + ['network', 'create_policy_minimum_bandwidth_rule'], + ['network', 'create_policy_bandwidth_limit_rule']] }); + }); + + it('should open the modal for selecting rule', function() { + spyOn(modalFormService, 'open').and.returnValue($q.defer().promise); + service.perform(qosPolicy); + expect(modalFormService.open).toHaveBeenCalled(); + }); + + it('should submit DSCP Marking add rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"dscp_mark": 0}; + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'createDSCPMarkingRule').and.returnValue(deferred.promise); + deferred.resolve({data: {dscp_mark: 0, id: '1'}}); + service.submit(dscpRule).then(service.onAddRule); + $scope.$apply(); + expect(neutronAPI.createDSCPMarkingRule).toHaveBeenCalledWith( + '1', data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'QoS Policy Rule successfully created' + ); + }); + + it('should submit Minimum Bandwidth add rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"min_kbps": 128, "direction": "egress"}; + spyOn(neutronAPI, 'createMinimumBandwidthRule').and.returnValue(deferred.promise); + spyOn(toast, 'add').and.callFake(angular.noop); + deferred.resolve({data: {mainbps: 128, direction: "egress", id:'1'}}); + service.submit(minBwdRule).then(service.onAddRule); + $scope.$apply(); + expect(neutronAPI.createMinimumBandwidthRule).toHaveBeenCalledWith( + '1', data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'QoS Policy Rule successfully created' + ); + }); + + it('should submit Bandwidth Limit add rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"max_kbps": 1000, "direction": "egress", "max_burst_kbps": 1100}; + spyOn(neutronAPI, 'createBandwidthLimitRule').and.returnValue(deferred.promise); + spyOn(toast, 'add').and.callFake(angular.noop); + deferred.resolve({data: {"max_kbps": 1000, "direction": "egress", + "max_burst_kbps": 1100, id: '1'}}); + service.submit(bwdLmtRule).then(service.onAddRule); + $scope.$apply(); + expect(neutronAPI.createBandwidthLimitRule).toHaveBeenCalledWith( + '1', data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'QoS Policy Rule successfully created' + ); + }); + + it('should submit Bandwidth Limit with undefined add rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"max_kbps": 1000, "direction": "egress", "max_burst_kbps": 1100}; + spyOn(neutronAPI, 'createBandwidthLimitRule').and.returnValue(deferred.promise); + spyOn(toast, 'add').and.callFake(angular.noop); + deferred.resolve({data: {"max_kbps": 1000, "direction": "egress", + "max_burst_kbps": 1100, id: '1'}}); + service.submit(nbwdLmtRule).then(service.onAddRule); + $scope.$apply(); + expect(neutronAPI.createBandwidthLimitRule).toHaveBeenCalledWith( + '1', data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'QoS Policy Rule successfully created' + ); + }); + + it('should submit add Minimum Packet Rate rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"min_kpps": 1000, "direction": "egress"}; + spyOn(neutronAPI, 'createMinimumPacketRateRule').and.returnValue(deferred.promise); + spyOn(toast, 'add').and.callFake(angular.noop); + deferred.resolve({data: {minkpps: 1000, direction: "egress", id:'1'}}); + service.submit(minpckRtRule).then(service.onAddRule); + $scope.$apply(); + expect(neutronAPI.createMinimumPacketRateRule).toHaveBeenCalledWith( + '1', data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'QoS Policy Rule successfully created' + ); + }); + + }); +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.js b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.js new file mode 100644 index 0000000000..a000257088 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.js @@ -0,0 +1,74 @@ +/** + * 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 controller + * @name horizon.app.core.network_qos.actions.AddQoSRuleController + * @ngController + * + * @description + * Controller for the adding rules for qos policy + */ + angular + .module('horizon.app.core.network_qos.actions') + .controller('horizon.app.core.network_qos.actions.AddQoSRuleController', + addQoSRuleController); + + addQoSRuleController.$inject = [ + '$scope' + ]; + + function addQoSRuleController($scope) { + var ctrl = this; + ctrl.qospolicy = $scope.model.qospolicy; + ctrl.qospolicyname = $scope.model.qospolicyname; + ctrl.rule_types = { + 'bandwidth_limit': gettext("Bandwidth Limit"), + 'dscp_marking': gettext("DSCP Marking"), + 'minimum_bandwidth': gettext("Minimum Bandwidth"), + 'minimum_packet_rate': gettext("Minimum Packet Rate") + }; + ctrl.directions = { + "egress": gettext("egress"), + "ingress": gettext("ingress") + }; + ctrl.ppsDirections = { + "egress": gettext("egress"), + "ingress": gettext("ingress"), + "any": gettext("any") + }; + ctrl.onRuleTypeChange = function(ruleType) { + $scope.model.rule_type = ruleType; + }; + ctrl.bwdLimit = function(bwd) { + $scope.model.maxkbps = bwd.maxkbps; + $scope.model.maxburstkbps = bwd.maxburstkbps; + $scope.model.direction = bwd.direction || 'egress'; + }; + ctrl.onDSCPChange = function(dscpmark) { + $scope.model.dscpmarking = dscpmark; + }; + ctrl.minBandwidth = function(mb) { + $scope.model.minkbps = mb.minkbps; + $scope.model.direction = mb.direction || 'egress'; + }; + ctrl.minPacketRate = function(mpr) { + $scope.model.minkpps = mpr.minkpps; + $scope.model.direction = mpr.direction || 'egress'; + }; + } +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.spec.js b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.spec.js new file mode 100644 index 0000000000..911afbe974 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.controller.spec.js @@ -0,0 +1,130 @@ +/* + * 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('qos rules datails', function() { + + var ctrl, rules, directions, ppsDirections, $controller, $scope, + $rootScope, dscp, minBwd, nminBwd, bwdLmt, nbwdLmt, minPckRt, + nminPckRt; + + beforeEach(module('horizon.app.core.network_qos')); + + beforeEach(inject(function(_$controller_, _$rootScope_) { + $controller = _$controller_; + $rootScope = _$rootScope_; + $scope = $rootScope.$new(); + + $scope = { + model: { + qospolicy: "1", + qospolicyname: "test-qos" + } + }; + + ctrl = $controller('horizon.app.core.network_qos.actions.AddQoSRuleController', + { + $scope: $scope + } + ); + + rules = { + 'bandwidth_limit': "Bandwidth Limit", + 'dscp_marking': "DSCP Marking", + 'minimum_bandwidth': "Minimum Bandwidth", + 'minimum_packet_rate': "Minimum Packet Rate" + }; + directions = { + "egress": "egress", + "ingress": "ingress" + }; + ppsDirections = { + "egress": "egress", + "ingress": "ingress", + "any": "any" + }; + dscp = { + model: { + dscpmarking: 0 + } + }; + minBwd = { + model: { + minkbps: 1000, + direction: 'egress' + } + }; + nminBwd = { + model: { + minkbps: 1000, + direction: '' + } + }; + bwdLmt = { + model: { + maxkbps: 2000, + maxburstkbps: 3000, + direction: 'egress' + } + }; + nbwdLmt = { + model: { + maxkbps: 2000, + maxburstkbps: 3000, + direction: '' + } + }; + minPckRt = { + model: { + minkpps: 1000, + direction: 'egress' + } + }; + nminPckRt = { + model: { + minkpps: 1000, + direction: '' + } + }; + })); + + it('sets ctrl', inject(function() { + expect(ctrl.qospolicy).toEqual($scope.model.qospolicy); + expect(ctrl.qospolicy).not.toEqual('2'); + expect(ctrl.qospolicyname).toEqual($scope.model.qospolicyname); + expect(ctrl.rule_types).toEqual(rules); + ctrl.onRuleTypeChange('dscp_mark'); + expect(ctrl.onRuleTypeChange).toBeDefined(); + expect(ctrl.directions).toEqual(directions); + expect(ctrl.ppsDirections).toEqual(ppsDirections); + ctrl.onDSCPChange(dscp.model); + expect(ctrl.onDSCPChange).toBeDefined(); + ctrl.minBandwidth(minBwd.model); + expect(ctrl.minBandwidth).toBeDefined(); + ctrl.minBandwidth(nminBwd.model); + expect(ctrl.minBandwidth).toBeDefined(); + ctrl.bwdLimit(bwdLmt.model); + expect(ctrl.bwdLimit).toBeDefined(); + ctrl.bwdLimit(nbwdLmt.model); + expect(ctrl.nbwdLimit).not.toBeDefined(); + ctrl.minPacketRate(minPckRt.model); + expect(ctrl.minPacketRate).toBeDefined(); + ctrl.minPacketRate(nminPckRt.model); + expect(ctrl.minPacketRate).toBeDefined(); + })); + + }); +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/add-rule.html b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.html new file mode 100644 index 0000000000..71a4949eb1 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/add-rule.html @@ -0,0 +1,98 @@ +
+ + + + + + +
+ + + + + + +
+
+ + +
+
+ + + + +
+
+ + + + +
+
\ No newline at end of file diff --git a/openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.js b/openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.js new file mode 100644 index 0000000000..f23689671e --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.js @@ -0,0 +1,117 @@ +/* Liscensed 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 + * @ngname horizon.app.core.network_qos.actions.delete-rule.service + * + * @description + * Provides all of the actions for deleting rule to a network qos policy. + */ + + angular + .module('horizon.app.core.network_qos') + .factory('horizon.app.core.network_qos.actions.delete-rule.service', deleteRuleService); + + deleteRuleService.$inject = [ + 'horizon.app.core.openstack-service-api.neutron', + 'horizon.app.core.openstack-service-api.policy', + 'horizon.app.core.network_qos.actions.deleteRuleWorkflow', + 'horizon.app.core.network_qos.resourceType', + 'horizon.framework.widgets.form.ModalFormService', + 'horizon.framework.widgets.toast.service', + 'horizon.framework.util.actions.action-result.service', + 'horizon.framework.widgets.modal.deleteModalService' + ]; + + function deleteRuleService( + neutronAPI, + policy, + workflow, + resourceType, + modalFormService, + toast, + actionResultService + ) { + + var service = { + allowed: allowed, + perform: perform, + submit: submit + }; + + return service; + + ////////////// + + function allowed() { + return policy.ifAllowed( + {rules: [['network', 'delete_policy_bandwidth_limit_rule'], + ['network', 'delete_policy_dscp_marking_rule'], + ['network', 'delete_policy_minimum_bandwidth_rule']]}); + } + + function perform(qospolicy) { + if (qospolicy.rules.length !== 0) { + var config = workflow.init(qospolicy); + config.title = gettext("Delete Rule"); + config.model.qospolicy = qospolicy.id; + config.model.qospolicyname = qospolicy.name; + config.model.rules = qospolicy.rules; + config.submitText = 'Delete'; + config.submitIcon = 'delete'; + return modalFormService.open(config).then(submit); + } + else { + toast.add('info', interpolate( + gettext('There are no rules to delete.'))); + return actionResultService.getActionResult().result; + } + } + + function submit(context) { + var id = context.model.qospolicy; + var ruleid = [context.model.ruleid]; + var ruleType = ''; + angular.forEach(context.model.rules, function(k) { + if ((k.id).toString() === (ruleid).toString()) { + ruleType = (k.type).toString(); + } + }, this); + if (ruleType === 'bandwidth_limit') { + return neutronAPI.deleteBandwidthLimitRule(id, ruleid).then(onDeleteRule); + } + else if (ruleType === 'dscp_marking') { + return neutronAPI.deleteDSCPMarkingRule(id, ruleid).then(onDeleteRule); + } + else if (ruleType === 'minimum_bandwidth') { + return neutronAPI.deleteMinimumBandwidthRule(id, ruleid).then(onDeleteRule); + } + else if (ruleType === 'minimum_packet_rate') { + return neutronAPI.deleteMinimumPacketRateRule(id, ruleid).then(onDeleteRule); + } + } + + function onDeleteRule() { + toast.add('success', interpolate( + gettext('Qos Policy Rule was successfully deleted.'))); + + return actionResultService.getActionResult() + .result; + } + } + +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.spec.js b/openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.spec.js new file mode 100644 index 0000000000..e69fbc5116 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/delete-rule.action.service.spec.js @@ -0,0 +1,224 @@ +/* Liscensed 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.app.core.network_qos.actions.delete-rule.service', function() { + + var $q, $scope, neutronAPI, service, modalFormService, toast, nqosPolicy, edscpRule, + qosPolicy, dscpRule, bwdLmtRule, minBwdRule, policyAPI; + + /////////////////////// + + beforeEach(module('horizon.framework')); + beforeEach(module('horizon.app.core')); + beforeEach(module('horizon.app.core.network_qos')); + + beforeEach(inject(function($injector, _$rootScope_, _$q_) { + $scope = _$rootScope_.$new(); + $q = _$q_; + service = $injector.get('horizon.app.core.network_qos.actions.delete-rule.service'); + toast = $injector.get('horizon.framework.widgets.toast.service'); + policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); + modalFormService = $injector.get('horizon.framework.widgets.form.ModalFormService'); + neutronAPI = $injector.get('horizon.app.core.openstack-service-api.neutron'); + qosPolicy = { + "id": "6", + "name": "qos", + "description": "qos rules", + "shared": "yes", + "rules": [ + { + "direction": "egress", + "id": "8", + "max_burst_kbps": 22000, + "max_kbps": 20000, + "qos_policy_id": "6", + "type": "bandwidth_limit" + }, + { + "dscp_mark": 26, + "id": "5", + "qos_policy_id": "6", + "type": "dscp_marking" + }, + { + "direction": "egress", + "id": "2", + "min_kbps": 1000, + "qos_policy_id": "6", + "type": "minimum_bandwidth" + } + ] + }; + nqosPolicy = { + "id": "6", + "name": "qos", + "description": "qos rules", + "shared": "yes", + "rules": [] + }; + dscpRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "2", + "rules": [ + { + "dscp_mark": 0, + "id": "2", + "qos_policy_id": "6", + "type": "dscp_marking" + } + ] + } + }; + edscpRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "3", + "rules": [ + { + "dscp_mark": 0, + "id": "2", + "qos_policy_id": "6", + "type": "dscp_marking" + } + ] + } + }; + minBwdRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "2", + "rules": [ + { + "min_kbps": 0, + "direction": "egress", + "id": 2, + "qos_policy_id": "6", + "type": "minimum_bandwidth" + } + ] + } + }; + bwdLmtRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "2", + "rules": [ + { + "max_kbps": 0, + "direction": "egress", + "id": 2, + "qos_policy_id": "6", + "type": "bandwidth_limit" + } + ] + } + }; + })); + + it('should check policy is allowed or not', function() { + spyOn(policyAPI, 'ifAllowed').and.callThrough(); + var allowed = service.allowed(); + expect(allowed).toBeTruthy(); + expect(policyAPI.ifAllowed).toHaveBeenCalledWith( + { rules: [['network', 'delete_policy_bandwidth_limit_rule'], + ['network', 'delete_policy_dscp_marking_rule'], + ['network', 'delete_policy_minimum_bandwidth_rule']] }); + }); + + it('should open the modal with existing rule', function() { + spyOn(modalFormService, 'open').and.returnValue($q.defer().promise); + + service.perform(qosPolicy); + + expect(modalFormService.open).toHaveBeenCalled(); + }); + + it('should not open the modal', function() { + spyOn(modalFormService, 'open').and.returnValue($q.defer().promise); + spyOn(toast, 'add').and.callFake(angular.noop); + + service.perform(nqosPolicy); + + expect(modalFormService.open).not.toHaveBeenCalled(); + expect(toast.add).toHaveBeenCalledWith( + 'info', 'There are no rules to delete.' + ); + }); + + it('should submit DSCP Marking delete rule request to neutron', function() { + var deferred = $q.defer(); + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'deleteDSCPMarkingRule').and.returnValue(deferred.promise); + deferred.resolve({data: {"id": "2", "dscp_mark": 12}}); + service.submit(dscpRule).then(service.success); + $scope.$apply(); + expect(neutronAPI.deleteDSCPMarkingRule).toHaveBeenCalledWith( + qosPolicy.id, [dscpRule.model.ruleid]); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'Qos Policy Rule was successfully deleted.' + ); + }); + + it('should submit DSCP Marking check delete rule request to neutron', function() { + var deferred = $q.defer(); + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'deleteDSCPMarkingRule').and.returnValue(deferred.promise); + deferred.resolve({data: {"id": "3", "dscp_mark": 0}}); + service.submit(edscpRule); + $scope.$apply(); + expect(neutronAPI.deleteDSCPMarkingRule).not.toHaveBeenCalledWith( + qosPolicy.id, [dscpRule.model.ruleid]); + expect(toast.add).not.toHaveBeenCalledWith( + 'success', 'Qos Policy Rule was successfully deleted.' + ); + }); + + it('should submit Bandwidth Limit delete rule request to neutron', function() { + var deferred = $q.defer(); + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'deleteBandwidthLimitRule').and.returnValue(deferred.promise); + deferred.resolve({data: {"id": "2", "max_kbps": 1000, "direction": "ingress", + "max_burst_kbps": 1200}}); + service.submit(bwdLmtRule).then(service.onDeleteRule); + $scope.$apply(); + expect(neutronAPI.deleteBandwidthLimitRule).toHaveBeenCalledWith( + qosPolicy.id, [bwdLmtRule.model.ruleid]); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'Qos Policy Rule was successfully deleted.' + ); + }); + + it('should submit Minimum Bandwidth Limit edit rule request to neutron', function() { + var deferred = $q.defer(); + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'deleteMinimumBandwidthRule').and.returnValue(deferred.promise); + deferred.resolve({data: {"id": "2", "min_kbps": 100, "direction": "ingress"}}); + service.submit(minBwdRule).then(service.success); + $scope.$apply(); + expect(neutronAPI.deleteMinimumBandwidthRule).toHaveBeenCalledWith( + qosPolicy.id, [minBwdRule.model.ruleid]); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'Qos Policy Rule was successfully deleted.' + ); + }); + + }); +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.js b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.js new file mode 100644 index 0000000000..cf3337be60 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.js @@ -0,0 +1,173 @@ +/* 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 + * @ngname horizon.app.core.network_qos.actions.edit-rule.service + * + * @description + * Provides all of the actions for editing rule to a network qos policy. + */ + + angular + .module('horizon.app.core.network_qos') + .factory('horizon.app.core.network_qos.actions.edit-rule.service', editRuleService); + + editRuleService.$inject = [ + 'horizon.app.core.openstack-service-api.neutron', + 'horizon.app.core.openstack-service-api.policy', + 'horizon.app.core.network_qos.resourceType', + 'horizon.framework.widgets.form.ModalFormService', + 'horizon.framework.widgets.toast.service', + 'horizon.framework.util.actions.action-result.service', + 'horizon.app.core.network_qos.basePath' + ]; + + function editRuleService( + neutronAPI, + policy, + resourceType, + modalFormService, + toast, + actionResultService, + basePath + ) { + + var caption = gettext("Edit Rule"); + + var schema = { + type: 'object', + properties: { + qospolicy: { + title: gettext('QoSPolicyId'), + type: 'string', + readOnly: true + }, + qospolicyname: { + title: gettext('QoSPolicyName'), + type: 'string', + readOnly: true + }, + ruleid: { + title: gettext('RuleId'), + type: 'string' + } + }, + required: ['ruleid'] + }; + + var form = [ + { + type: "section", + htmlClass: "row", + items: [ + { + type: "section", + htmlClass: "col-sm-12", + items: [ + { + key: ["qospolicy", "qospolicyname", "type"], + type: "template", + templateUrl: basePath + "actions/edit-rule.html" + } + ] + } + ] + } + ]; + + var model = {}; + + var service = { + allowed: allowed, + perform: perform, + submit: submit + }; + + return service; + + ////////////// + + function allowed() { + return policy.ifAllowed( + {rules: [['network', 'update_policy_bandwidth_limit_rule'], + ['network', 'update_policy_dscp_marking_rule'], + ['network', 'update_policy_minimum_bandwidth_rule']]}); + } + + function perform(qospolicy) { + if (qospolicy.rules.length !== 0) { + model = {"qospolicy": qospolicy.id, "qospolicyname": qospolicy.name, + "rules": qospolicy.rules}; + var config = { + "title": caption, + "submitText": caption, + "schema": schema, + "form": form, + "model": model, + "submitIcon": "pen", + "helpUrl": basePath + "actions/rule.description.html" + }; + return modalFormService.open(config).then(submit); + } + else { + toast.add('info', interpolate( + gettext('There are no rules to modify.'))); + return actionResultService.getActionResult() + .result; + + } + } + + function submit(context) { + var id = context.model.qospolicy; + var ruleid = [context.model.ruleid]; + var rule = context.model.rule_type; + var data = ''; + + if (rule === 'bandwidth_limit') { + data = {direction: context.model.direction, + max_burst_kbps: context.model.maxburstkbps, + max_kbps: context.model.maxkbps}; + return neutronAPI.updateBandwidthRule(id, ruleid, data).then(onEditRule); + } + else if (rule === 'dscp_marking') { + data = { dscp_mark: context.model.dscpmarking }; + return neutronAPI.updateDSCPMarkingRule(id, ruleid, data).then(onEditRule); + } + else if (rule === 'minimum_bandwidth') { + data = {direction: context.model.direction, + min_kbps: context.model.minkbps}; + return neutronAPI.updateMinimumBandwidthRule(id, ruleid, data).then(onEditRule); + } + else if (rule === 'minimum_packet_rate') { + data = {direction: context.model.direction, + min_kpps: context.model.minkpps}; + return neutronAPI.updateMinimumPacketRateRule(id, ruleid, data).then(onEditRule); + } + } + + function onEditRule(response) { + var qosrule = response.data; + toast.add('success', interpolate( + gettext('Qos Policy Rule %s was successfully updated.'),[qosrule.id])); + + return actionResultService.getActionResult() + .result; + } + + } +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.spec.js b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.spec.js new file mode 100644 index 0000000000..7e6a6b44c7 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.action.service.spec.js @@ -0,0 +1,244 @@ +/* Liscensed 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.app.core.network_qos.actions.edit-rule.service', function() { + + var $q, $scope, neutronAPI, service, modalFormService, toast, nqosPolicy, + qosPolicy, dscpRule, bwdLmtRule, minBwdRule, policyAPI, minPckRtRule; + + /////////////////////// + + beforeEach(module('horizon.framework')); + beforeEach(module('horizon.app.core')); + beforeEach(module('horizon.app.core.network_qos')); + + beforeEach(inject(function($injector, _$rootScope_, _$q_) { + $scope = _$rootScope_.$new(); + $q = _$q_; + service = $injector.get('horizon.app.core.network_qos.actions.edit-rule.service'); + toast = $injector.get('horizon.framework.widgets.toast.service'); + policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); + modalFormService = $injector.get('horizon.framework.widgets.form.ModalFormService'); + neutronAPI = $injector.get('horizon.app.core.openstack-service-api.neutron'); + qosPolicy = { + "id": "6", + "name": "qos", + "description": "qos rules", + "shared": "yes", + "rules": [ + { + "direction": "egress", + "id": "8", + "max_burst_kbps": 22000, + "max_kbps": 20000, + "qos_policy_id": "6", + "type": "bandwidth_limit" + }, + { + "dscp_mark": 26, + "id": "5", + "qos_policy_id": "6", + "type": "dscp_marking" + }, + { + "direction": "egress", + "id": "2", + "min_kbps": 1000, + "qos_policy_id": "6", + "type": "minimum_bandwidth" + }, + { + "direction": "egress", + "id": "2", + "min_kbps": 10000, + "qos_policy_id": "6", + "type": "minimum_packet_rate" + } + ] + }; + nqosPolicy = { + "id": "6", + "name": "qos", + "description": "qos rules", + "shared": "yes", + "rules": [] + }; + dscpRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "2", + "rule_type": "dscp_marking", + "dscpmarking": 26, + "rules": [ + { + "dscp_mark": 0, + "id": 2, + "qos_policy_id": "6", + "type": "dscp_marking" + } + ] + } + }; + minBwdRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "2", + "rule_type": "minimum_bandwidth", + "minkbps": 128, + "direction": "egress", + "rules": [ + { + "min_kbps": 0, + "direction": "egress", + "id": 2, + "qos_policy_id": "6", + "type": "minimum_bandwidth" + } + ] + } + }; + bwdLmtRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "2", + "rule_type": "bandwidth_limit", + "maxkbps": 1000, + "maxburstkbps": 1100, + "direction": "egress", + "rules": [ + { + "max_kbps": 0, + "direction": "egress", + "id": 2, + "qos_policy_id": "6", + "type": "bandwidth_limit" + } + ] + } + }; + minPckRtRule = { + "model": { + "qospolicy": "6", + "qospolicyname": "test", + "ruleid": "2", + "rule_type": "minimum_packet_rate", + "minkpps": 20000, + "direction": "ingress", + "rules": [ + { + "min_kpps": 10000, + "direction": "egress", + "id": 2, + "qos_policy_id": "6", + "type": "minimum_packet_rate" + } + ] + } + }; + })); + + it('should check policy is allowed or not', function() { + spyOn(policyAPI, 'ifAllowed').and.callThrough(); + var allowed = service.allowed(); + expect(allowed).toBeTruthy(); + expect(policyAPI.ifAllowed).toHaveBeenCalledWith( + { rules: [['network', 'update_policy_bandwidth_limit_rule'], + ['network', 'update_policy_dscp_marking_rule'], + ['network', 'update_policy_minimum_bandwidth_rule']] }); + }); + + it('should open the modal with existing rule', function() { + spyOn(modalFormService, 'open').and.returnValue($q.defer().promise); + service.perform(qosPolicy); + expect(modalFormService.open).toHaveBeenCalled(); + }); + + it('should not open the modal', function() { + spyOn(modalFormService, 'open').and.returnValue($q.defer().promise); + spyOn(toast, 'add').and.callFake(angular.noop); + service.perform(nqosPolicy); + expect(modalFormService.open).not.toHaveBeenCalled(); + expect(toast.add).toHaveBeenCalledWith( + 'info', 'There are no rules to modify.' + ); + }); + + it('should submit DSCP Marking edit rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"dscp_mark": 26}; + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'updateDSCPMarkingRule').and.returnValue(deferred.promise); + deferred.resolve({data: {dscp_mark: 26, id: '2'}}); + service.submit(dscpRule).then(service.success); + $scope.$apply(); + expect(neutronAPI.updateDSCPMarkingRule).toHaveBeenCalledWith( + qosPolicy.id, [dscpRule.model.ruleid], data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'Qos Policy Rule 2 was successfully updated.' + ); + }); + + it('should submit Bandwidth Limit edit rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"max_kbps": 1000, "direction": "egress", "max_burst_kbps": 1100}; + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'updateBandwidthRule').and.returnValue(deferred.promise); + deferred.resolve({data: {"id": "2", "max_kbps": 1000, "direction": "egress", + "max_burst_kbps": 1100}}); + service.submit(bwdLmtRule).then(service.success); + $scope.$apply(); + expect(neutronAPI.updateBandwidthRule).toHaveBeenCalledWith( + qosPolicy.id, [bwdLmtRule.model.ruleid], data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'Qos Policy Rule 2 was successfully updated.' + ); + }); + + it('should submit Minimum BandwidthLimit edit rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"min_kbps": 128, "direction": "egress"}; + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'updateMinimumBandwidthRule').and.returnValue(deferred.promise); + deferred.resolve({data: {"id": "2", "min_kbps": 128, "direction": "egress"}}); + service.submit(minBwdRule).then(service.success); + $scope.$apply(); + expect(neutronAPI.updateMinimumBandwidthRule).toHaveBeenCalledWith( + qosPolicy.id, [minBwdRule.model.ruleid], data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'Qos Policy Rule 2 was successfully updated.' + ); + }); + + it('should submit Minimum Packet Rate edit rule request to neutron', function() { + var deferred = $q.defer(); + var data = {"min_kpps": 20000, "direction": "ingress"}; + spyOn(toast, 'add').and.callFake(angular.noop); + spyOn(neutronAPI, 'updateMinimumPacketRateRule').and.returnValue(deferred.promise); + deferred.resolve({data: {"id": "2", "min_kpps": 20000, "direction": "ingress"}}); + service.submit(minPckRtRule).then(service.success); + $scope.$apply(); + expect(neutronAPI.updateMinimumPacketRateRule).toHaveBeenCalledWith( + qosPolicy.id, [minPckRtRule.model.ruleid], data); + expect(toast.add).toHaveBeenCalledWith( + 'success', 'Qos Policy Rule 2 was successfully updated.' + ); + }); + + }); +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.js b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.js new file mode 100644 index 0000000000..49840d3d69 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.js @@ -0,0 +1,104 @@ +/** + * 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 controller + * @name horizon.app.core.network_qos.actions.EditQoSRuleController + * @ngController + * + * @description + * Controller for the editing rules for qos policy + */ + angular + .module('horizon.app.core.network_qos.actions') + .controller('horizon.app.core.network_qos.actions.EditQoSRuleController', + editQoSRuleController); + + editQoSRuleController.$inject = [ + '$scope' + ]; + + function editQoSRuleController($scope) { + var ctrl = this; + ctrl.qospolicy = $scope.model.qospolicy; + ctrl.qospolicyname = $scope.model.qospolicyname; + ctrl.rule_types = []; + angular.forEach($scope.model.rules, function(k) { + if (k.type === 'bandwidth_limit') { + ctrl.rule_types.push({name: 'bandwidth_limit', val: gettext('Bandwidth Limit - ' + + k.id + ', ' + k.max_kbps + ', ' + k.max_burst_kbps + ', ' + k.direction)}); + ctrl.bwdid = k.id; + ctrl.maxkbps = k.max_kbps; + ctrl.maxburstkbps = k.max_burst_kbps || 0; + ctrl.bwddirection = k.direction; + } + else if (k.type === 'dscp_marking') { + ctrl.rule_types.push({name: 'dscp_marking', + val: gettext("DSCP Mark - " + k.id + ', ' + k.dscp_mark)}); + ctrl.dscpid = k.id; + ctrl.dscpmark = k.dscp_mark; + } + else if (k.type === 'minimum_bandwidth') { + ctrl.rule_types.push({name: 'minimum_bandwidth', + val: gettext('Minimum Bandwidth - ' + k.id + ', ' + k.min_kbps + ', ' + k.direction)}); + ctrl.minbwdid = k.id; + ctrl.minkbps = k.min_kbps; + ctrl.minbwddirection = k.direction; + } + else if (k.type === 'minimum_packet_rate') { + ctrl.rule_types.push({name: 'minimum_packet_rate', + val: gettext('Minimum Packet Rate - ' + k.id + ', ' + k.min_kpps + ', ' + + k.direction)}); + ctrl.minpckrtid = k.id; + ctrl.minkpps = k.min_kpps; + ctrl.minpckrtdirection = k.direction; + } + }, this); + ctrl.directions = { + "egress": gettext("egress"), + "ingress": gettext("ingress") + }; + ctrl.ppsDirections = { + "egress": gettext("egress"), + "ingress": gettext("ingress"), + "any": gettext("any") + }; + ctrl.onRuleTypeChange = function(ruleType) { + $scope.model.rule_type = ruleType.name; + }; + ctrl.bwdLimit = function(bwd) { + $scope.model.ruleid = ctrl.bwdid; + $scope.model.maxkbps = bwd.maxkbps || ctrl.maxkbps; + $scope.model.maxburstkbps = bwd.maxburstkbps || ctrl.maxburstkbps; + $scope.model.direction = bwd.direction || ctrl.bwddirection; + }; + ctrl.onDSCPChange = function(dscpmark) { + $scope.model.ruleid = ctrl.dscpid; + $scope.model.dscpmarking = dscpmark || ctrl.dscpmark; + }; + ctrl.minBandwidth = function(mb) { + $scope.model.ruleid = ctrl.minbwdid; + $scope.model.minkbps = mb.minkbps || ctrl.minkbps; + $scope.model.direction = mb.direction || ctrl.minbwddirection; + }; + ctrl.minPacketRate = function(mpr) { + $scope.model.ruleid = ctrl.minpckrtid; + $scope.model.minkpps = mpr.minkpps || ctrl.minkpps; + $scope.model.direction = mpr.direction || ctrl.minpckrtdirection; + }; + } +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.spec.js b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.spec.js new file mode 100644 index 0000000000..3ba4dc6d7d --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.controller.spec.js @@ -0,0 +1,161 @@ +/* + * 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('qos rules datails', function() { + + var ctrl, rules, directions, ppsDirections, $controller, $scope, + $rootScope, dscp, ndscp, minBwd, nminBwd, bwdLmt, nbwdLmt, + minPckRt, nminPckRt; + + beforeEach(module('horizon.app.core.network_qos')); + + beforeEach(inject(function(_$controller_, _$rootScope_) { + $controller = _$controller_; + $rootScope = _$rootScope_; + $scope = $rootScope.$new(); + + $scope = { + model: { + qospolicy: "1", + qospolicyname: "test_qos", + rules: [ + { + type: "bandwidth_limit", + id: 1, max_kbps: 1000, + max_burst_kbps: 100, direction: "egress" + }, + { + type: "dscp_marking", + id: 1, dscp_mark: 12 + }, + { + type: "minimum_bandwidth", + id: 1, min_kbps: 100, + direction: "egress" + }, + { + type: "minimum_packet_rate", + id: 1, min_kpps: 10000, + direction: "egress" + } + ] + } + }; + + ctrl = $controller('horizon.app.core.network_qos.actions.EditQoSRuleController', + { + $scope: $scope + } + ); + + rules = [ + {name: "bandwidth_limit", val: "Bandwidth Limit - 1, 1000, 100, egress"}, + {name: "dscp_marking", val: "DSCP Mark - 1, 12"}, + {name: "minimum_bandwidth", val: "Minimum Bandwidth - 1, 100, egress"}, + {name: "minimum_packet_rate", val: "Minimum Packet Rate - 1, 10000, egress"} + ]; + directions = { + "egress": "egress", + "ingress": "ingress" + }; + ppsDirections = { + "egress": "egress", + "ingress": "ingress", + "any": "any" + }; + dscp = { + model: { + dscpmarking: 0 + } + }; + ndscp = { + model: { + dscpmarking: undefined + } + }; + minBwd = { + model: { + minkbps: 1000, + direction: 'egress' + } + }; + nminBwd = { + model: { + minkbps: '', + direction: '' + } + }; + bwdLmt = { + model: { + maxkbps: 2000, + maxburstkbps: 3000, + direction: 'egress' + } + }; + nbwdLmt = { + model: { + maxkbps: '', + maxburstkbps: '', + direction: '' + } + }; + minPckRt = { + model: { + minkpps: 10000, + direction: 'egress' + } + }; + nminPckRt = { + model: { + minkpps: '', + direction: '' + } + }; + })); + + it('sets edit ctrl', inject(function() { + expect(ctrl.qospolicy).toEqual($scope.model.qospolicy); + expect(ctrl.qospolicy).not.toEqual('2'); + expect(ctrl.rule_types).toEqual(rules); + ctrl.onRuleTypeChange('dscp_mark'); + expect(ctrl.onRuleTypeChange).toBeDefined(); + expect(ctrl.directions).toEqual(directions); + expect(ctrl.ppsDirections).toEqual(ppsDirections); + // DSCP Mark + ctrl.onDSCPChange(dscp.model); + expect(ctrl.onDSCPChange).toBeDefined(); + ctrl.onDSCPChange(ndscp.model); + expect(ctrl.onDSCPChange).toBeDefined(); + // Minimum Bandwidth + ctrl.minBandwidth(minBwd.model); + expect(ctrl.minBandwidth).toBeDefined(); + ctrl.minBandwidth(nminBwd.model); + expect(ctrl.minBandwidth).toBeDefined(); + // Bandwidth Limit + ctrl.bwdLimit(bwdLmt.model); + expect(ctrl.bwdLimit).toBeDefined(); + ctrl.bwdLimit(nbwdLmt.model); + expect(ctrl.nbwdLimit).not.toBeDefined(); + // Minimum Packet Rate + ctrl.minPacketRate(minPckRt.model); + expect(ctrl.minPacketRate).toBeDefined(); + ctrl.minPacketRate(nminPckRt.model); + expect(ctrl.minPacketRate).toBeDefined(); + })); + + }); +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.html b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.html new file mode 100644 index 0000000000..ce54412be0 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/edit-rule.html @@ -0,0 +1,106 @@ +
+ + + + + + +
+ + + + + + +
+
+ + +
+
+ + + + +
+
+ + + + +
+
\ No newline at end of file diff --git a/openstack_dashboard/static/app/core/network_qos/actions/rule.description.html b/openstack_dashboard/static/app/core/network_qos/actions/rule.description.html new file mode 100644 index 0000000000..bc839e15c1 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/rule.description.html @@ -0,0 +1,18 @@ +

+ Valid DSCP mark values are even numbers between 0 and 56, + except 2-6, 42, 44, and 50-54. The full list of valid DSCP marks is: + 0, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 46, 48, 56. +

+

+ The maximum KBPS (kilobits per second) value. + If you specify this value, must be greater than 0 otherwise max_kbps will have no value. +

+ The maximum burst size (in kilobits). Default is 0. +

+

+

+ The minimum KBPS (kilobits per second) value which should be available for port. +

+

+ The minimum kpps (kilo(1000) packets per second) value which should be available for port. +

\ No newline at end of file diff --git a/openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.js b/openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.js new file mode 100644 index 0000000000..73726ed654 --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.js @@ -0,0 +1,118 @@ +/* Liscensed 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 factory + * @name horizon.app.core.network_qos.actions.delete-rule.workflow.service + * @ngController + * + * @description + * Workflow for deleting rule to a network qos policy. + */ + + angular + .module('horizon.app.core.network_qos.actions') + .factory('horizon.app.core.network_qos.actions.deleteRuleWorkflow', deleteRuleWorkflow); + + deleteRuleWorkflow.$inject = [ + 'horizon.app.core.openstack-service-api.neutron' + ]; + + function deleteRuleWorkflow(neutronAPI) { + + var workflow = { + init: init + }; + + function init(qospolicy) { + var schema = { + type: 'object', + properties: { + qospolicyname: { + title: gettext('QoS Policy Name'), + type: 'string', + readOnly: true + }, + ruleid: { + title: gettext('Rule'), + type: 'string' + }, + qospolicy: { + title: gettext('QoS Policy ID'), + type: 'string', + readOnly: true + } + }, + required: ['ruleid'] + }; + + var form = [ + "qospolicy", + "qospolicyname", + { + key: "ruleid", + type: "select", + titleMap: [] + } + ]; + + var model = {}; + + var config = { + schema: schema, + form: form, + model: model + }; + + neutronAPI.getQosPolicy(qospolicy.id).then(modifyPolicies); + + function modifyPolicies(policies) { + var policyField = config.form[2]; + angular.forEach(policies.data.rules, function(k) { + if (k.type === 'dscp_marking') { + this.push({ + name: String(k.id + ' - ' + k.type + ' - dscpmark: ' + k.dscp_mark), + value: String(k.id) + }); + } + else if (k.type === 'bandwidth_limit') { + this.push({ + name: String(k.id + ' - ' + k.type + ' - maxkbps: ' + k.max_kbps + + ', maxburstkbps: ' + k.max_burst_kbps + ', ' + k.direction), + value: String(k.id) + }); + } + else if (k.type === 'minimum_bandwidth') { + this.push({ + name: String(k.id + ' - ' + k.type + ' - minkbps: ' + + k.min_kbps + ', ' + k.direction), + value: String(k.id) + }); + } + else if (k.type === 'minimum_packet_rate') { + this.push({ + name: String(k.id + ' - ' + k.type + ' - minkpps: ' + + k.min_kpps + ', ' + k.direction), + value: String(k.id) + }); + } + }, policyField.titleMap); + } + return config; + } + return workflow; + } +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.spec.js b/openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.spec.js new file mode 100644 index 0000000000..0792512d0a --- /dev/null +++ b/openstack_dashboard/static/app/core/network_qos/actions/workflow/delete-rule.workflow.service.spec.js @@ -0,0 +1,97 @@ +/* + * 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.app.core.network_qos.actions.deleteRuleWorkflow.service', function() { + + var $q, $scope, workflow, policies, neutronAPI; + + beforeEach(module('horizon.framework')); + beforeEach(module('horizon.app.core')); + beforeEach(module('horizon.app.core.network_qos')); + + beforeEach(inject(function($injector, _$rootScope_, _$q_) { + $q = _$q_; + $scope = _$rootScope_.$new(); + neutronAPI = $injector.get('horizon.app.core.openstack-service-api.neutron'); + workflow = $injector.get('horizon.app.core.network_qos.actions.deleteRuleWorkflow'); + policies = { + "data": { + "created_at": "Z", + "description": "", + "id": "1", + "is_default": false, + "name": "qos_test", + "project_id": "5", + "revision_number": 1, + "rules": [ + { + "direction": "egress", + "id": "1", + "max_burst_kbps": 1100, + "max_kbps": 1000, + "qos_policy_id": "2", + "type": "bandwidth_limit" + }, + { + "dscp_mark": 0, + "id": "3", + "qos_policy_id": "2", + "type": "dscp_marking" + }, + { + "direction": "egress", + "id": "6", + "min_kbps": 128, + "qos_policy_id": "2", + "type": "minimum_bandwidth" + }, + { + "direction": "egress", + "id": "6", + "min_kbps": 1000, + "qos_policy_id": "2", + "type": "minimum_packet_rate" + } + ], + "shared": false, + "tags": [], + "tenant_id": "54", + "updated_at": "2021-09-15T07:38:49.000Z" + } + }; + })); + + function testInitWorkflow() { + var deferred = $q.defer(); + spyOn(neutronAPI, 'getQosPolicy').and.returnValue(deferred.promise); + var config = workflow.init(policies.data); + deferred.resolve(policies); + neutronAPI.getQosPolicy(policies.data.id).then(workflow.modifyPolicies); + $scope.$apply(); + expect(neutronAPI.getQosPolicy).toHaveBeenCalled(); + expect(config.schema).toBeDefined(); + expect(config.form).toBeDefined(); + expect(config.model).toBeDefined(); + return config; + } + + it('should create workflow config for select rule for deleting', function() { + testInitWorkflow(); + }); + + }); +})(); diff --git a/openstack_dashboard/static/app/core/network_qos/details/overview.controller.js b/openstack_dashboard/static/app/core/network_qos/details/overview.controller.js index 542cf74de4..30177d11f5 100644 --- a/openstack_dashboard/static/app/core/network_qos/details/overview.controller.js +++ b/openstack_dashboard/static/app/core/network_qos/details/overview.controller.js @@ -34,7 +34,7 @@ var ctrl = this; ctrl.resourceType = registry.getResourceType(qosResourceTypeCode); - ctrl.tableConfig = { + ctrl.tableConfigBwd = { selectAll: false, expand: false, trackId: 'id', @@ -47,14 +47,66 @@ columns: [ {id: 'id', title: gettext('Rule ID'), priority: 1, sortDefault: true}, {id: 'type', title: gettext('Type'), priority: 1}, - {id: 'direction', title: gettext('Direction'), priority: 1}, {id: 'max_kbps', title: gettext('Max Kbps'), priority: 1}, {id: 'max_burst_kbps', title: gettext('Max Burst Kbits'), priority: 1}, - {id: 'min_kbps', title: gettext('Min Kbps'), priority: 1}, + {id: 'direction', title: gettext('Direction'), priority: 1} + ] + }; + + ctrl.tableConfigDSCP = { + selectAll: false, + expand: false, + trackId: 'id', + /* + * getTableColumns here won't work as that will give back the + * columns for the policy, but here we need columns only for the + * policy rules, which is a (list of) dictionary(ies) in the + * policy dictionary. + */ + columns: [ + {id: 'id', title: gettext('Rule ID'), priority: 1, sortDefault: true}, + {id: 'type', title: gettext('Type'), priority: 1}, {id: 'dscp_mark', title: gettext('DSCP Mark'), priority: 1} ] }; + ctrl.tableConfigMinBwd = { + selectAll: false, + expand: false, + trackId: 'id', + /* + * getTableColumns here won't work as that will give back the + * columns for the policy, but here we need columns only for the + * policy rules, which is a (list of) dictionary(ies) in the + * policy dictionary. + */ + columns: [ + {id: 'id', title: gettext('Rule ID'), priority: 1, sortDefault: true}, + {id: 'type', title: gettext('Type'), priority: 1}, + {id: 'min_kbps', title: gettext('Min Kbps'), priority: 1}, + {id: 'direction', title: gettext('Direction'), priority: 1} + + ] + }; + + ctrl.tableConfigMinPckRt = { + selectAll: false, + expand: false, + trackId: 'id', + /* + * getTableColumns here won't work as that will give back the + * columns for the policy, but here we need columns only for the + * policy rules, which is a (list of) dictionary(ies) in the + * policy dictionary. + */ + columns: [ + {id: 'id', title: gettext('Rule ID'), priority: 1, sortDefault: true}, + {id: 'type', title: gettext('Type'), priority: 1}, + {id: 'min_kpps', title: gettext('Min Kpps'), priority: 1}, + {id: 'direction', title: gettext('Direction'), priority: 1}, + ] + }; + $scope.context.loadPromise.then(onGetPolicy); function onGetPolicy(response) { diff --git a/openstack_dashboard/static/app/core/network_qos/details/overview.html b/openstack_dashboard/static/app/core/network_qos/details/overview.html index 55a1112133..5733b7e0e9 100644 --- a/openstack_dashboard/static/app/core/network_qos/details/overview.html +++ b/openstack_dashboard/static/app/core/network_qos/details/overview.html @@ -25,12 +25,43 @@

Rules


-
+
+
+

DSCP Rules

+
+
+
+

Bandwidth Rules

+
+ + +
+
+

Minimum Bandwidth Rules

+
+ + +
+
+

Minimum Packet Rules

+
+ + +
diff --git a/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.js b/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.js index 504eaece12..e474324895 100644 --- a/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.js +++ b/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.js @@ -39,6 +39,10 @@ createSubnet: createSubnet, createTrunk: createTrunk, createNetworkQoSPolicy: createNetworkQoSPolicy, + createBandwidthLimitRule: createBandwidthLimitRule, + createDSCPMarkingRule: createDSCPMarkingRule, + createMinimumBandwidthRule: createMinimumBandwidthRule, + createMinimumPacketRateRule: createMinimumPacketRateRule, deletePolicy: deletePolicy, deleteTrunk: deleteTrunk, getAgents: getAgents, @@ -52,7 +56,15 @@ getTrunk: getTrunk, getTrunks: getTrunks, updateProjectQuota: updateProjectQuota, - updateTrunk: updateTrunk + updateTrunk: updateTrunk, + deleteDSCPMarkingRule: deleteDSCPMarkingRule, + deleteBandwidthLimitRule: deleteBandwidthLimitRule, + deleteMinimumBandwidthRule: deleteMinimumBandwidthRule, + deleteMinimumPacketRateRule: deleteMinimumPacketRateRule, + updateMinimumBandwidthRule: updateMinimumBandwidthRule, + updateDSCPMarkingRule: updateDSCPMarkingRule, + updateBandwidthRule: updateBandwidthRule, + updateMinimumPacketRateRule: updateMinimumPacketRateRule }; return service; @@ -428,13 +440,13 @@ }); } - /** - * @name deletePolicy - * @description - * Delete a single neutron qos policy. - * @param {string} policyId - * Specifies the id of the policy to be deleted. - */ + /** + * @name deletePolicy + * @description + * Delete a single neutron qos policy. + * @param {string} policyId + * Specifies the id of the policy to be deleted. + */ function deletePolicy(policyId, suppressError) { var promise = apiService.delete('/api/neutron/qos_policies/' + policyId + '/'); promise = suppressError ? promise : promise.error(function() { @@ -443,6 +455,344 @@ }); return promise; } + + /** + * @name createBandwidthLimitRule + * @description + * Creates a bandwidth limit rule for a QoS policy + * @returns {Object} A bandwidth_limit_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * The bandwidth limit rule to create. Required. + * + * Example new bandwidth limit rule response object + * { + * "bandwidth_limit_rule": { + * "id": "5f126d84-551a-4dcf-bb01-0e9c0df0c793", + * "max_kbps": 10000, + * "max_burst_kbps": 0, + * "direction": "egress" + * } + * } + * + * Description of properties on the bandwidth limit rule object + * + * @property {integer} ruleId.max_kbps + * The maximum KBPS (kilobits per second) value. + * If you specify this value, must be greater than '0' + * otherwise max_kbps will have no value. Required. + * + * @property {integer} ruleId.max_burst_kbps + * The maximum burst size (in kilobits). Default is '0'. Optional. + * + * @property {string} ruleId.direction + * The direction of the traffic to which the QoS rule is applied, + * as seen from the point of view of the port. + * Valid values are egress and ingress. Default value is egress. + * Optional. + * + */ + function createBandwidthLimitRule(policyId, ruleId) { + return apiService.post('/api/neutron/qos/policies/' + policyId + + '/bandwidth_limit_rules/', ruleId) + .error(function () { + toastService.add('error', gettext('Unable to add the bandwidthrule .')); + }); + } + + /** + * @name createDSCPMarkingRule + * @description + * Creates a DSCP marking rule for a QoS policy. + * @returns {Object} A dscp_marking_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * The dscp marking rule to create. Required. + * + * Example new dscp mark rule response object + * { + * "dscp_marking_rule": { + * "id": "5f126d84-551a-4dcf-bb01-0e9c0df0c794", + * "dscp_mark": 26 + * } + * } + * + * Description of properties on the dscp marking rule object + * + * @property {integer} ruleId.dscp_mark + * The DSCP mark value. Required. + * Valid DSCP mark values are even numbers between 0 and 56, + * except 2-6, 42, 44, and 50-54. The full list of valid DSCP marks is: + * 0, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 46, 48, 56 + * + */ + function createDSCPMarkingRule(policyId, ruleId) { + return apiService.post('/api/neutron/qos/policies/' + policyId + + '/dscp_marking_rules/', ruleId) + .error(function () { + toastService.add('error', gettext('Unable to add the dscp_marking_rule .')); + }); + } + + /** + * @name createMinimumBandwidthRule + * @description + * Creates a minimum bandwidth rule for a QoS policy + * @returns {Object} A minimum_bandwidth_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * The minimum bandwidth rule to create. Required. + * + * Example new minimum bandwidth rule response object + * { + * "minimum_bandwidth_rule": { + * "id": "1eddf7af-0b4c-42c5-8ae1-390b32f1de08", + * "min_kbps": 10000, + * "direction": "egress" + * } + * } + * + * Description of properties on the minimum bandwidth rule object + * + * @property {integer} ruleId.min_kbps + * The minimum KBPS (kilobits per second) value which should be available for port. + * Required. + * + * @property {string} ruleId.direction + * The direction of the traffic to which the QoS rule is applied, + * as seen from the point of view of the port. + * Valid values are egress and ingress. Default value is egress. + * Optional. + * + */ + function createMinimumBandwidthRule(policyId, ruleId) { + return apiService.post('/api/neutron/qos/policies/' + policyId + + '/minimum_bandwidth_rules/', ruleId) + .error(function () { + toastService.add('error', gettext('Unable to add the minimum_bandwidth_rule .')); + }); + } + + /** + * @name createMinimumPacketRateRule + * @description + * Creates a minimum packet rate rule for a QoS policy + * @returns {Object} A minimum_bandwidth_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * The minimum packet rate rule to create. Required. + * + * Example new minimum packet rate rule response object + * { + * "minimum_packet_rate_rule": { + * "id": "1eddf7af-0b4c-42c5-8ae1-390b32f1de08", + * "min_kpps": 10000, + * "direction": "egress" + * } + * } + * + * Description of properties on the minimum packet rate rule object + * + * @property {integer} ruleId.min_kbps + * The minimum kpps (kilo(1000) packets per second) value which should be available for port. + * Required. + * + * @property {string} ruleId.direction + * The direction of the traffic to which the QoS rule is applied, + * as seen from the point of view of the port. + * Valid values are egress and ingress. Default value is egress. + * Optional. + * + */ + function createMinimumPacketRateRule(policyId, ruleId) { + return apiService.post('/api/neutron/qos/policies/' + policyId + + '/minimum_packet_rate_rules/', ruleId) + .error(function () { + toastService.add('error', gettext('Unable to add the minimum_packet_rate_rule.')); + }); + } + + /** + * @name updateBandwidthRule + * @description + * Update an existing bandwidth limit rule for a QoS policy. + * @returns {Object} A bandwidth_limit_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * This param is for rule. + * + * @param {Object} updateRuleId + * The bandwidth limit rule to update. Required. + * + */ + function updateBandwidthRule(policyId, ruleId, updateRuleId) { + return apiService.patch('/api/neutron/qos/policies/' + policyId + + '/bandwidth_limit_rules/' + ruleId , updateRuleId) + .error(function () { + toastService.add('error', gettext('Unable to update the bandwidthrule.')); + }); + } + + /** + * @name updateDSCPMarkingRule + * @description + * Update an existing bandwidth limit rule for a QoS policy. + * @returns {Object} A bandwidth_limit_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * This param is for rule. + * + * @param {Object} updateRuleId + * The bandwidth limit rule to update. Required. + * + */ + function updateDSCPMarkingRule(policyId, ruleId, updateRuleId) { + return apiService.patch('/api/neutron/qos/policies/' + policyId + + '/dscp_marking_rules/' + ruleId , updateRuleId) + .error(function () { + toastService.add('error', gettext('Unable to update the dscp marking rule.')); + }); + } + + /** + * @name updateMinimumBandwidthRule + * @description + * Update an existing minimum bandwidth rule for a QoS policy. + * @returns {Object} A minimum_bandwidth_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * This param is for rule. + * + * @param {Object} updateRuleId + * The minimum bandwidth limit rule to update. Required. + * + */ + function updateMinimumBandwidthRule(policyId, ruleId, updateRuleId) { + return apiService.patch('/api/neutron/qos/policies/' + policyId + + '/minimum_bandwidth_rules/' + ruleId , updateRuleId) + .error(function () { + toastService.add('error', gettext('Unable to update the minimum bandwidth rule.')); + }); + } + + /** + * @name updateMinimumPacketRateRule + * @description + * Update an existing minimum packet rate limit rule for a QoS policy. + * @returns {Object} A minimum_packet_rate_rule object on success. + * + * @param {Object} policyId + * This param is for qos policy. + * + * @param {Object} ruleId + * This param is for rule. + * + * @param {Object} updateRuleId + * The minimum packet rate limit rule to update. Required. + * + */ + function updateMinimumPacketRateRule(policyId, ruleId, updateRuleId) { + return apiService.patch('/api/neutron/qos/policies/' + policyId + + '/minimum_packet_rate_rules/' + ruleId , updateRuleId) + .error(function () { + toastService.add('error', gettext('Unable to update the minimum packet rate rule.')); + }); + } + + /** + * @name deleteBandwidthLimitRule + * @description + * Delete a single bandwidth limit rule. + * + * @param {string} policyId + * The ID of the QoS policy. + * + * @param {string} deleteruleId + * The ID of the QoS rule. + * + */ + function deleteBandwidthLimitRule(policyId, deleteRuleId) { + return apiService.delete('/api/neutron/qos/policies/' + policyId + + '/bandwidth_limit_rules/' + deleteRuleId).error(function() { + toastService.add('error', gettext('Unable to delete the bandwidth_limit_rule.')); + }); + } + + /** + * @name deleteDSCPMarkingRule + * @description + * Delete a single dscp mark rule. + * + * @param {string} policyId + * The ID of the QoS policy. + * + * @param {string} deleteruleId + * The ID of the QoS rule. + */ + function deleteDSCPMarkingRule(policyId, deleteRuleId) { + return apiService.delete('/api/neutron/qos/policies/' + policyId + + '/dscp_marking_rules/' + deleteRuleId).error(function() { + toastService.add('error', gettext('Unable to delete the dscp_marking_rule.')); + }); + } + + /** + * @name deleteMinimumBandwidthRule + * @description + * Delete a single minimum bandwidth rule. + * + * @param {string} policyId + * The ID of the QoS policy. + * + * @param {string} deleteruleId + * The ID of the QoS rule. + */ + function deleteMinimumBandwidthRule(policyId, deleteRuleId) { + return apiService.delete('/api/neutron/qos/policies/' + policyId + + '/minimum_bandwidth_rules/' + deleteRuleId).error(function() { + toastService.add('error', gettext('Unable to delete the minimum_bandwidth_rule .')); + }); + } + + /** + * @name deleteMinimumPacketRateRule + * @description + * Delete a single minimum packet rate rule. + * + * @param {string} policyId + * The ID of the QoS policy. + * + * @param {string} deleteruleId + * The ID of the QoS rule. + */ + function deleteMinimumPacketRateRule(policyId, deleteRuleId) { + return apiService.delete('/api/neutron/qos/policies/' + policyId + + '/minimum_packet_rate_rules/' + deleteRuleId).error(function() { + toastService.add('error', gettext('Unable to delete the minimum_packet_rate_rule .')); + }); + } + // Trunks /** diff --git a/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.spec.js b/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.spec.js index 918db157a3..93fdd1f223 100644 --- a/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.spec.js +++ b/openstack_dashboard/static/app/core/openstack-service-api/neutron.service.spec.js @@ -329,6 +329,114 @@ "testInput": [ 63 ] + }, + { + "func": "createDSCPMarkingRule", + "method": "post", + "path": "/api/neutron/qos/policies/63/dscp_marking_rules/", + "data": {"dscp_marking_rule":{"dscp_mark":16}}, + "error": "Unable to add the dscp_marking_rule .", + "testInput": [63, + {"dscp_marking_rule":{"dscp_mark": 16}} + ] + }, + { + "func": "createBandwidthLimitRule", + "method": "post", + "path": "/api/neutron/qos/policies/63/bandwidth_limit_rules/", + "data": {"bandwidth_limit_rule": {"max_kbps": 10000}}, + "error": "Unable to add the bandwidthrule .", + "testInput": [63, + {"bandwidth_limit_rule": {"max_kbps": 10000}} + ] + }, + { + "func": "createMinimumBandwidthRule", + "method": "post", + "path": "/api/neutron/qos/policies/63/minimum_bandwidth_rules/", + "data": {"minimum_banwdiwth_rule": {"min_kbps": 1000, "direction": "egress"}}, + "error": "Unable to add the minimum_bandwidth_rule .", + "testInput": [63, + {"minimum_banwdiwth_rule": {"min_kbps": 1000, "direction": "egress"}} + ] + }, + { + "func": "createMinimumPacketRateRule", + "method": "post", + "path": "/api/neutron/qos/policies/63/minimum_packet_rate_rules/", + "data": {"minimum_packet_rate_rule": {"min_kpps": 1000, "direction": "ingress"}}, + "error": "Unable to add the minimum_packet_rate_rule.", + "testInput": [63, + {"minimum_packet_rate_rule": {"min_kpps": 1000, "direction": "ingress"}} + ] + }, + { + "func": "updateDSCPMarkingRule", + "method": "patch", + "path": "/api/neutron/qos/policies/63/dscp_marking_rules/1", + "data": {"dscp_marking_rule":{"dscp_mark":16}}, + "error": "Unable to update the dscp marking rule.", + "testInput": [63, 1, + {"dscp_marking_rule":{"dscp_mark": 16}} + ] + }, + { + "func": "updateBandwidthRule", + "method": "patch", + "path": "/api/neutron/qos/policies/63/bandwidth_limit_rules/1", + "data": {"bandwidth_limit_rule": {"max_kbps": "11000"}}, + "error": "Unable to update the bandwidthrule.", + "testInput": [63, 1, + {"bandwidth_limit_rule": {"max_kbps": "11000"}} + ] + }, + { + "func": "updateMinimumBandwidthRule", + "method": "patch", + "path": "/api/neutron/qos/policies/63/minimum_bandwidth_rules/1", + "data": {"minimum_bandwidth_rule": {"min_kbps": 1000, "direction": "ingress"}}, + "error": "Unable to update the minimum bandwidth rule.", + "testInput": [63, 1, + {"minimum_bandwidth_rule": {"min_kbps": 1000, "direction": "ingress"}} + ] + }, + { + "func": "updateMinimumPacketRateRule", + "method": "patch", + "path": "/api/neutron/qos/policies/63/minimum_packet_rate_rules/1", + "data": {"minimum_packet_rate_rule": {"min_kpps": 1000, "direction": "ingress"}}, + "error": "Unable to update the minimum packet rate rule.", + "testInput": [63, 1, + {"minimum_packet_rate_rule": {"min_kpps": 1000, "direction": "ingress"}} + ] + }, + { + "func": "deleteDSCPMarkingRule", + "method": "delete", + "path": "/api/neutron/qos/policies/63/dscp_marking_rules/1", + "error": "Unable to delete the dscp_marking_rule.", + "testInput": [63, 1] + }, + { + "func": "deleteBandwidthLimitRule", + "method": "delete", + "path": "/api/neutron/qos/policies/63/bandwidth_limit_rules/1", + "error": "Unable to delete the bandwidth_limit_rule.", + "testInput": [63, 1] + }, + { + "func": "deleteMinimumBandwidthRule", + "method": "delete", + "path": "/api/neutron/qos/policies/63/minimum_bandwidth_rules/1", + "error": "Unable to delete the minimum_bandwidth_rule .", + "testInput": [63, 1] + }, + { + "func": "deleteMinimumPacketRateRule", + "method": "delete", + "path": "/api/neutron/qos/policies/63/minimum_packet_rate_rules/1", + "error": "Unable to delete the minimum_packet_rate_rule .", + "testInput": [63, 1] } ]; diff --git a/openstack_dashboard/test/test_data/neutron_data.py b/openstack_dashboard/test/test_data/neutron_data.py index ef2ec07e00..e902f74c7a 100644 --- a/openstack_dashboard/test/test_data/neutron_data.py +++ b/openstack_dashboard/test/test_data/neutron_data.py @@ -45,6 +45,10 @@ def data(TEST): TEST.neutron_quota_usages = utils.TestDataContainer() TEST.ip_availability = utils.TestDataContainer() TEST.qos_policies = utils.TestDataContainer() + TEST.dscp_mark_rule = utils.TestDataContainer() + TEST.bandwidth_limit_rule = utils.TestDataContainer() + TEST.minimum_bandwidth_rule = utils.TestDataContainer() + TEST.minimum_packet_rate_rule = utils.TestDataContainer() TEST.rbac_policies = utils.TestDataContainer() TEST.tp_ports = utils.TestDataContainer() TEST.neutron_availability_zones = utils.TestDataContainer() @@ -69,6 +73,10 @@ def data(TEST): TEST.api_ip_availability = utils.TestDataContainer() TEST.api_rbac_policies = utils.TestDataContainer() TEST.api_qos_policies = utils.TestDataContainer() + TEST.api_dscp_mark_rule = utils.TestDataContainer() + TEST.api_bandwidth_limit_rule = utils.TestDataContainer() + TEST.api_minimum_bandwidth_rule = utils.TestDataContainer() + TEST.api_minimum_packet_rate_rule = utils.TestDataContainer() TEST.api_tp_trunks = utils.TestDataContainer() TEST.api_tp_ports = utils.TestDataContainer() @@ -807,6 +815,49 @@ def data(TEST): TEST.api_qos_policies.add(policy_dict1) TEST.qos_policies.add(neutron.QoSPolicy(policy_dict1)) + # qos rule - dscp mark + dscp_mark_rule_dict = { + "id": "5f126d84-551a-4dcf-bb01-0e9c0df0c794", + "dscp_mark": 26, + "tenant_id": "1" + } + TEST.api_dscp_mark_rule.add(dscp_mark_rule_dict) + TEST.dscp_mark_rule.add(neutron.DSCPMarkingRule(dscp_mark_rule_dict)) + + # qos rule - bandwidth limit + bandwidth_limit_rule = { + "id": "5f126d84-551a-4dcf-bb01-0e9c0df0c793", + "max_kbps": 10000, + "max_burst_kbps": 0, + "direction": "egress", + "tenant_id": "1" + } + TEST.api_bandwidth_limit_rule.add(bandwidth_limit_rule) + TEST.bandwidth_limit_rule.add(neutron.BandwidthLimitRule( + bandwidth_limit_rule)) + + # qos rule - minimum bandwidth + minimum_bandwidth_rule = { + "id": "1eddf7af-0b4c-42c5-8ae1-390b32f1de08", + "min_kbps": 10000, + "direction": "egress", + "tenant_id": "1" + } + TEST.api_minimum_bandwidth_rule.add(minimum_bandwidth_rule) + TEST.minimum_bandwidth_rule.add(neutron.MinimumBandwidthRule( + minimum_bandwidth_rule)) + + # qos rule - minimum packet rate + minimum_packet_rate_rule = { + "id": "1eddf7af-0b4c-42c5-8ae1-390b32f1de08", + "min_kpps": 10000, + "direction": "egress", + "tenant_id": "1" + } + TEST.api_minimum_packet_rate_rule.add(minimum_packet_rate_rule) + TEST.minimum_packet_rate_rule.add(neutron.MinimumPacketRateRule( + minimum_packet_rate_rule)) + # rbac policies rbac_policy_dict = {"project_id": "1", "object_type": "network", diff --git a/openstack_dashboard/test/unit/api/test_neutron.py b/openstack_dashboard/test/unit/api/test_neutron.py index 9affe7f8b8..fe22121a9b 100644 --- a/openstack_dashboard/test/unit/api/test_neutron.py +++ b/openstack_dashboard/test/unit/api/test_neutron.py @@ -1120,6 +1120,265 @@ class NeutronApiTests(test.APIMockTestCase): self.assertEqual(qos_policy['name'], ret_val.name) neutronclient.create_qos_policy.assert_called_once_with(body=post_data) + @mock.patch.object(api.neutron, 'neutronclient') + def test_dscp_mark_rule_create(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + dscp_mark_rule = self.api_dscp_mark_rule.first() + post_data = {'dscp_marking_rule': { + "dscp_mark": dscp_mark_rule["dscp_mark"], + "tenant_id": dscp_mark_rule["tenant_id"]} + } + + neutronclient = mock_neutronclient.return_value + + neutronclient.create_dscp_marking_rule.return_value = { + 'dscp_marking_rule': dscp_mark_rule + } + + ret_val = api.neutron.dscp_marking_rule_create( + self.request, + policy_id=qos_policy['id'], + dscp_mark=dscp_mark_rule['dscp_mark']) + + self.assertIsInstance(ret_val, api.neutron.DSCPMarkingRule) + self.assertEqual(dscp_mark_rule['dscp_mark'], ret_val.dscp_mark) + neutronclient.create_dscp_marking_rule.assert_called_once_with( + qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_dscp_mark_rule_update(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + dscp_mark_rule = self.api_dscp_mark_rule.first() + dscp_mark_rule["dscp_mark"] = 28 + post_data = {'dscp_marking_rule': { + "dscp_mark": 28} + } + + neutronclient = mock_neutronclient.return_value + + neutronclient.update_dscp_marking_rule.return_value = { + 'dscp_marking_rule': dscp_mark_rule + } + + ret_val = api.neutron.dscp_marking_rule_update( + self.request, + policy_id=qos_policy['id'], + rule_id=dscp_mark_rule['id'], + dscp_mark=dscp_mark_rule['dscp_mark']) + + self.assertIsInstance(ret_val, api.neutron.DSCPMarkingRule) + self.assertEqual( + dscp_mark_rule['dscp_mark'], ret_val.dscp_mark) + neutronclient.update_dscp_marking_rule.assert_called_once_with( + dscp_mark_rule['id'], qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_dscp_mark_rule_delete(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + dscp_mark_rule = self.api_dscp_mark_rule.first() + + neutronclient = mock_neutronclient.return_value + + neutronclient.delete_dscp_marking_rule.return_value = None + + api.neutron.dscp_marking_rule_delete( + self.request, qos_policy['id'], dscp_mark_rule['id']) + + neutronclient.delete_dscp_marking_rule.assert_called_once_with( + dscp_mark_rule['id'], qos_policy['id']) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_bandwidth_limit_rule_create(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + bwd_limit_rule = self.api_bandwidth_limit_rule.first() + post_data = { + 'bandwidth_limit_rule': { + "max_kbps": bwd_limit_rule["max_kbps"], + "tenant_id": bwd_limit_rule["tenant_id"] + } + } + + neutronclient = mock_neutronclient.return_value + + neutronclient.create_bandwidth_limit_rule.return_value = { + 'bandwidth_limit_rule': bwd_limit_rule} + + ret_val = api.neutron.bandwidth_limit_rule_create( + self.request, + policy_id=qos_policy['id'], + max_kbps=bwd_limit_rule["max_kbps"]) + + self.assertIsInstance(ret_val, api.neutron.BandwidthLimitRule) + self.assertEqual(bwd_limit_rule["max_kbps"], ret_val.max_kbps) + neutronclient.create_bandwidth_limit_rule.assert_called_once_with( + qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_bandwidth_limit_rule_update(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + bwd_limit_rule = self.api_bandwidth_limit_rule.first() + bwd_limit_rule["max_kbps"] = 20000 + post_data = { + "bandwidth_limit_rule": { + "max_kbps": 20000 + } + } + + neutronclient = mock_neutronclient.return_value + + neutronclient.update_bandwidth_limit_rule.return_value = { + 'bandwidth_limit_rule': bwd_limit_rule} + + ret_val = api.neutron.bandwidth_limit_rule_update( + self.request, + policy_id=qos_policy['id'], + rule_id=bwd_limit_rule['id'], + max_kbps=bwd_limit_rule["max_kbps"]) + + self.assertIsInstance(ret_val, api.neutron.BandwidthLimitRule) + self.assertEqual(bwd_limit_rule["max_kbps"], ret_val.max_kbps) + neutronclient.update_bandwidth_limit_rule.assert_called_once_with( + bwd_limit_rule['id'], qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_bandwidth_limit_rule_delete(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + bandwidth_limit_rule = self.api_bandwidth_limit_rule.first() + + neutronclient = mock_neutronclient.return_value + + neutronclient.delete_bandwidth_limit_rule.return_value = None + + api.neutron.bandwidth_limit_rule_delete( + self.request, qos_policy['id'], bandwidth_limit_rule['id']) + + neutronclient.delete_bandwidth_limit_rule.assert_called_once_with( + bandwidth_limit_rule['id'], qos_policy['id']) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_minimum_bandwidth_rule_create(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + min_bwd_rule = self.api_minimum_bandwidth_rule.first() + post_data = {'minimum_bandwidth_rule': { + "min_kbps": min_bwd_rule["min_kbps"], + "tenant_id": min_bwd_rule["tenant_id"]}} + + neutronclient = mock_neutronclient.return_value + + neutronclient.create_minimum_bandwidth_rule.return_value = { + 'minimum_bandwidth_rule': min_bwd_rule} + + ret_val = api.neutron.minimum_bandwidth_rule_create( + self.request, + policy_id=qos_policy['id'], + min_kbps=min_bwd_rule["min_kbps"]) + + self.assertIsInstance(ret_val, api.neutron.MinimumBandwidthRule) + self.assertEqual(min_bwd_rule["min_kbps"], ret_val.min_kbps) + neutronclient.create_minimum_bandwidth_rule.assert_called_once_with( + qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_minimum_bandwidth_rule_update(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + min_bwd_rule = self.api_minimum_bandwidth_rule.first() + min_bwd_rule['min_kbps'] = 20000 + post_data = {'minimum_bandwidth_rule': { + "min_kbps": 20000}} + + neutronclient = mock_neutronclient.return_value + + neutronclient.update_minimum_bandwidth_rule.return_value = { + 'minimum_bandwidth_rule': min_bwd_rule} + + ret_val = api.neutron.minimum_bandwidth_rule_update( + self.request, + policy_id=qos_policy['id'], + rule_id=min_bwd_rule['id'], + min_kbps=min_bwd_rule["min_kbps"]) + + self.assertIsInstance(ret_val, api.neutron.MinimumBandwidthRule) + self.assertEqual(min_bwd_rule["min_kbps"], ret_val.min_kbps) + neutronclient.update_minimum_bandwidth_rule.assert_called_once_with( + min_bwd_rule['id'], qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_minimum_bandwidth_rule_delete(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + min_bwd_rule = self.api_minimum_bandwidth_rule.first() + + neutronclient = mock_neutronclient.return_value + + neutronclient.delete_minimum_bandwidth_rule.return_value = None + + api.neutron.minimum_bandwidth_rule_delete( + self.request, qos_policy['id'], min_bwd_rule['id']) + + neutronclient.delete_minimum_bandwidth_rule.assert_called_once_with( + min_bwd_rule['id'], qos_policy['id']) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_minimum_packer_rate_rule_create(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + min_pckt_rt_rule = self.api_minimum_packet_rate_rule.first() + post_data = {'minimum_packet_rate_rule': { + "min_kpps": min_pckt_rt_rule["min_kpps"], + "tenant_id": min_pckt_rt_rule["tenant_id"]}} + + neutronclient = mock_neutronclient.return_value + + neutronclient.create_minimum_packet_rate_rule.return_value = { + 'minimum_packet_rate_rule': min_pckt_rt_rule} + + ret_val = api.neutron.minimum_packet_rate_rule_create( + self.request, + policy_id=qos_policy['id'], + min_kpps=min_pckt_rt_rule["min_kpps"]) + + self.assertIsInstance(ret_val, api.neutron.MinimumPacketRateRule) + self.assertEqual(min_pckt_rt_rule['min_kpps'], ret_val.min_kpps) + neutronclient.create_minimum_packet_rate_rule.assert_called_once_with( + qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_minimum_packer_rate_rule_update(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + min_pckt_rt_rule = self.api_minimum_packet_rate_rule.first() + min_pckt_rt_rule['min_kpps'] = 11000 + post_data = {'minimum_packet_rate_rule': { + "min_kpps": 11000}} + + neutronclient = mock_neutronclient.return_value + + neutronclient.update_minimum_packet_rate_rule.return_value = { + 'minimum_packet_rate_rule': min_pckt_rt_rule} + + ret_val = api.neutron.minimum_packet_rate_rule_update( + self.request, + policy_id=qos_policy['id'], + rule_id=min_pckt_rt_rule['id'], + min_kpps=min_pckt_rt_rule["min_kpps"]) + + self.assertIsInstance(ret_val, api.neutron.MinimumPacketRateRule) + self.assertEqual(min_pckt_rt_rule["min_kpps"], ret_val.min_kpps) + neutronclient.update_minimum_packet_rate_rule.assert_called_once_with( + min_pckt_rt_rule['id'], qos_policy['id'], post_data) + + @mock.patch.object(api.neutron, 'neutronclient') + def test_minimum_packet_rate_rule_delete(self, mock_neutronclient): + qos_policy = self.api_qos_policies.first() + min_pckt_rt_rule = self.api_minimum_packet_rate_rule.first() + + neutronclient = mock_neutronclient.return_value + + neutronclient.delete_minimum_packet_rate_rule.return_value = None + + api.neutron.minimum_packet_rate_rule_delete( + self.request, qos_policy['id'], min_pckt_rt_rule['id']) + + neutronclient.delete_minimum_packet_rate_rule.assert_called_once_with( + min_pckt_rt_rule['id'], qos_policy['id']) + class NeutronApiSecurityGroupTests(test.APIMockTestCase): diff --git a/releasenotes/notes/network_qos_rules-cd103f9383b6cdf9.yaml b/releasenotes/notes/network_qos_rules-cd103f9383b6cdf9.yaml new file mode 100644 index 0000000000..ed8f350dec --- /dev/null +++ b/releasenotes/notes/network_qos_rules-cd103f9383b6cdf9.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Add Rules CRUD operations to the Network QoS Policy. + + Added create, edit, and delete rules operation to the network qos policy. + Rules supported - Bandwidth-Limit, Minimum-Bandwidth, DSCP-Marking, and + Minimum-Packet-Rate.