Add QoS egress minimum bandwidth rule to neutronclient
The following patch implements the QoS egress minimum bandwidth assurance in neutronclient. Change-Id: I025522f73a9a8e3a9f69f097cedaeba330b9914a Depends-On: I6b619a96a2bfde164646c71409b671352bc6ce7d Depends-On: I13c54be22f35ac7eb5835d8424a919d0b61a8e95 Partial-Bug: #1560963
This commit is contained in:
		 Rodolfo Alonso Hernandez
					Rodolfo Alonso Hernandez
				
			
				
					committed by
					
						 Ihar Hrachyshka
						Ihar Hrachyshka
					
				
			
			
				
	
			
			
			 Ihar Hrachyshka
						Ihar Hrachyshka
					
				
			
						parent
						
							25e4314e8b
						
					
				
				
					commit
					a6cdd1dace
				
			
							
								
								
									
										111
									
								
								neutronclient/neutron/v2_0/qos/minimum_bandwidth_rule.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								neutronclient/neutron/v2_0/qos/minimum_bandwidth_rule.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | # Copyright (c) 2016 Intel Corporation. | ||||||
|  | # All Rights Reserved | ||||||
|  | # | ||||||
|  | #    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. | ||||||
|  | # | ||||||
|  |  | ||||||
|  | from neutronclient._i18n import _ | ||||||
|  | from neutronclient.common import utils | ||||||
|  | from neutronclient.neutron import v2_0 as neutronv20 | ||||||
|  | from neutronclient.neutron.v2_0.qos import rule as qos_rule | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MINIMUM_BANDWIDTH_RULE_RESOURCE = 'minimum_bandwidth_rule' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def add_minimum_bandwidth_arguments(parser): | ||||||
|  |     parser.add_argument( | ||||||
|  |         '--min-kbps', | ||||||
|  |         required=True, | ||||||
|  |         type=str, | ||||||
|  |         help=_('QoS minimum bandwidth assurance, expressed in kilobits ' | ||||||
|  |                'per second.')) | ||||||
|  |     # NOTE(ralonsoh): the only direction implemented is "egress". Please, | ||||||
|  |     # refer to the spec (https://review.openstack.org/#/c/316082/). | ||||||
|  |     parser.add_argument( | ||||||
|  |         '--direction', | ||||||
|  |         # NOTE(ihrachys): though server picks the default for us (egress), it's | ||||||
|  |         # better to require the argument to make the UI more explicit and the | ||||||
|  |         # intentions more clear in the future when we add other values for the | ||||||
|  |         # attribute on server side. | ||||||
|  |         required=True, | ||||||
|  |         type=utils.convert_to_lowercase, | ||||||
|  |         choices=['egress'], | ||||||
|  |         help=_('Traffic direction.')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def update_minimum_bandwidth_args2body(parsed_args, body): | ||||||
|  |     neutronv20.update_dict(parsed_args, body, ['min_kbps', 'direction']) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CreateQoSMinimumBandwidthRule(qos_rule.QosRuleMixin, | ||||||
|  |                                     neutronv20.CreateCommand): | ||||||
|  |     """Create a qos minimum bandwidth rule.""" | ||||||
|  |  | ||||||
|  |     resource = MINIMUM_BANDWIDTH_RULE_RESOURCE | ||||||
|  |  | ||||||
|  |     def add_known_arguments(self, parser): | ||||||
|  |         super(CreateQoSMinimumBandwidthRule, self).add_known_arguments( | ||||||
|  |             parser) | ||||||
|  |         add_minimum_bandwidth_arguments(parser) | ||||||
|  |  | ||||||
|  |     def args2body(self, parsed_args): | ||||||
|  |         body = {} | ||||||
|  |         update_minimum_bandwidth_args2body(parsed_args, body) | ||||||
|  |         return {self.resource: body} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ListQoSMinimumBandwidthRules(qos_rule.QosRuleMixin, | ||||||
|  |                                    neutronv20.ListCommand): | ||||||
|  |     """List all qos minimum bandwidth rules belonging to the specified policy. | ||||||
|  |  | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     resource = MINIMUM_BANDWIDTH_RULE_RESOURCE | ||||||
|  |     _formatters = {} | ||||||
|  |     pagination_support = True | ||||||
|  |     sorting_support = True | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ShowQoSMinimumBandwidthRule(qos_rule.QosRuleMixin, | ||||||
|  |                                   neutronv20.ShowCommand): | ||||||
|  |     """Show information about the given qos minimum bandwidth rule.""" | ||||||
|  |  | ||||||
|  |     resource = MINIMUM_BANDWIDTH_RULE_RESOURCE | ||||||
|  |     allow_names = False | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class UpdateQoSMinimumBandwidthRule(qos_rule.QosRuleMixin, | ||||||
|  |                                     neutronv20.UpdateCommand): | ||||||
|  |     """Update the given qos minimum bandwidth rule.""" | ||||||
|  |  | ||||||
|  |     resource = MINIMUM_BANDWIDTH_RULE_RESOURCE | ||||||
|  |     allow_names = False | ||||||
|  |  | ||||||
|  |     def add_known_arguments(self, parser): | ||||||
|  |         super(UpdateQoSMinimumBandwidthRule, self).add_known_arguments( | ||||||
|  |             parser) | ||||||
|  |         add_minimum_bandwidth_arguments(parser) | ||||||
|  |  | ||||||
|  |     def args2body(self, parsed_args): | ||||||
|  |         body = {} | ||||||
|  |         update_minimum_bandwidth_args2body(parsed_args, body) | ||||||
|  |         return {self.resource: body} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DeleteQoSMinimumBandwidthRule(qos_rule.QosRuleMixin, | ||||||
|  |                                     neutronv20.DeleteCommand): | ||||||
|  |     """Delete a given qos minimum bandwidth rule.""" | ||||||
|  |  | ||||||
|  |     resource = MINIMUM_BANDWIDTH_RULE_RESOURCE | ||||||
|  |     allow_names = False | ||||||
| @@ -73,6 +73,7 @@ from neutronclient.neutron.v2_0 import port | |||||||
| from neutronclient.neutron.v2_0 import purge | from neutronclient.neutron.v2_0 import purge | ||||||
| from neutronclient.neutron.v2_0.qos import bandwidth_limit_rule | from neutronclient.neutron.v2_0.qos import bandwidth_limit_rule | ||||||
| from neutronclient.neutron.v2_0.qos import dscp_marking_rule | from neutronclient.neutron.v2_0.qos import dscp_marking_rule | ||||||
|  | from neutronclient.neutron.v2_0.qos import minimum_bandwidth_rule | ||||||
| from neutronclient.neutron.v2_0.qos import policy as qos_policy | from neutronclient.neutron.v2_0.qos import policy as qos_policy | ||||||
| from neutronclient.neutron.v2_0.qos import rule as qos_rule | from neutronclient.neutron.v2_0.qos import rule as qos_rule | ||||||
| from neutronclient.neutron.v2_0 import quota | from neutronclient.neutron.v2_0 import quota | ||||||
| @@ -397,6 +398,21 @@ COMMAND_V2 = { | |||||||
|     'qos-dscp-marking-rule-delete': ( |     'qos-dscp-marking-rule-delete': ( | ||||||
|         dscp_marking_rule.DeleteQoSDscpMarkingRule |         dscp_marking_rule.DeleteQoSDscpMarkingRule | ||||||
|     ), |     ), | ||||||
|  |     'qos-minimum-bandwidth-rule-create': ( | ||||||
|  |         minimum_bandwidth_rule.CreateQoSMinimumBandwidthRule | ||||||
|  |     ), | ||||||
|  |     'qos-minimum-bandwidth-rule-show': ( | ||||||
|  |         minimum_bandwidth_rule.ShowQoSMinimumBandwidthRule | ||||||
|  |     ), | ||||||
|  |     'qos-minimum-bandwidth-rule-list': ( | ||||||
|  |         minimum_bandwidth_rule.ListQoSMinimumBandwidthRules | ||||||
|  |     ), | ||||||
|  |     'qos-minimum-bandwidth-rule-update': ( | ||||||
|  |         minimum_bandwidth_rule.UpdateQoSMinimumBandwidthRule | ||||||
|  |     ), | ||||||
|  |     'qos-minimum-bandwidth-rule-delete': ( | ||||||
|  |         minimum_bandwidth_rule.DeleteQoSMinimumBandwidthRule | ||||||
|  |     ), | ||||||
|     'qos-available-rule-types': qos_rule.ListQoSRuleTypes, |     'qos-available-rule-types': qos_rule.ListQoSRuleTypes, | ||||||
|     'flavor-list': flavor.ListFlavor, |     'flavor-list': flavor.ListFlavor, | ||||||
|     'flavor-show': flavor.ShowFlavor, |     'flavor-show': flavor.ShowFlavor, | ||||||
|   | |||||||
| @@ -0,0 +1,142 @@ | |||||||
|  | # Copyright (c) 2016 Intel Corporation. | ||||||
|  | # All Rights Reserved | ||||||
|  | # | ||||||
|  | #    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. | ||||||
|  | # | ||||||
|  |  | ||||||
|  | import sys | ||||||
|  |  | ||||||
|  | from neutronclient.neutron.v2_0.qos import minimum_bandwidth_rule as bw_rule | ||||||
|  | from neutronclient.tests.unit import test_cli20 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CLITestV20QoSMinimumBandwidthRuleJSON(test_cli20.CLITestV20Base): | ||||||
|  |  | ||||||
|  |     non_admin_status_resources = ['minimum_bandwidth_rule'] | ||||||
|  |  | ||||||
|  |     def setUp(self): | ||||||
|  |         super(CLITestV20QoSMinimumBandwidthRuleJSON, self).setUp() | ||||||
|  |         self.res = 'minimum_bandwidth_rule' | ||||||
|  |         self.cmd_res = 'qos_minimum_bandwidth_rule' | ||||||
|  |         self.ress = self.res + 's' | ||||||
|  |         self.cmd_ress = self.cmd_res + 's' | ||||||
|  |  | ||||||
|  |     def test_create_minimum_bandwidth_rule_min_kbps_only(self): | ||||||
|  |         cmd = bw_rule.CreateQoSMinimumBandwidthRule( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         my_id = 'my-id' | ||||||
|  |         min_kbps = '1500' | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = ['--min-kbps', min_kbps, | ||||||
|  |                 policy_id] | ||||||
|  |         position_names = ['min_kbps'] | ||||||
|  |         position_values = [min_kbps] | ||||||
|  |         self.assertRaises(SystemExit, self._test_create_resource, | ||||||
|  |                           self.res, cmd, '', my_id, args, | ||||||
|  |                           position_names, position_values, | ||||||
|  |                           cmd_resource=self.cmd_res, | ||||||
|  |                           parent_id=policy_id, | ||||||
|  |                           no_api_call=True) | ||||||
|  |  | ||||||
|  |     def test_create_minimum_bandwidth_rule_direction_only(self): | ||||||
|  |         cmd = bw_rule.CreateQoSMinimumBandwidthRule( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         my_id = 'my-id' | ||||||
|  |         direction = 'egress' | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = ['--direction', direction, | ||||||
|  |                 policy_id] | ||||||
|  |         position_names = ['direction'] | ||||||
|  |         position_values = [direction] | ||||||
|  |         self.assertRaises(SystemExit, self._test_create_resource, | ||||||
|  |                           self.res, cmd, '', my_id, args, | ||||||
|  |                           position_names, position_values, | ||||||
|  |                           cmd_resource=self.cmd_res, | ||||||
|  |                           parent_id=policy_id, | ||||||
|  |                           no_api_call=True) | ||||||
|  |  | ||||||
|  |     def test_create_minimum_bandwidth_rule_none(self): | ||||||
|  |         cmd = bw_rule.CreateQoSMinimumBandwidthRule( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         my_id = 'my-id' | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = [policy_id] | ||||||
|  |         position_names = [] | ||||||
|  |         position_values = [] | ||||||
|  |         self.assertRaises(SystemExit, self._test_create_resource, | ||||||
|  |                           self.res, cmd, '', my_id, args, | ||||||
|  |                           position_names, position_values, | ||||||
|  |                           cmd_resource=self.cmd_res, | ||||||
|  |                           parent_id=policy_id, | ||||||
|  |                           no_api_call=True) | ||||||
|  |  | ||||||
|  |     def test_create_minimum_bandwidth_rule_all(self): | ||||||
|  |         cmd = bw_rule.CreateQoSMinimumBandwidthRule( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         my_id = 'my-id' | ||||||
|  |         min_kbps = '1500' | ||||||
|  |         direction = 'egress' | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = ['--min-kbps', min_kbps, | ||||||
|  |                 '--direction', direction, | ||||||
|  |                 policy_id] | ||||||
|  |         position_names = ['direction', 'min_kbps'] | ||||||
|  |         position_values = [direction, min_kbps] | ||||||
|  |         self._test_create_resource(self.res, cmd, '', my_id, args, | ||||||
|  |                                    position_names, position_values, | ||||||
|  |                                    cmd_resource=self.cmd_res, | ||||||
|  |                                    parent_id=policy_id) | ||||||
|  |  | ||||||
|  |     def test_update_minimum_bandwidth_rule(self): | ||||||
|  |         cmd = bw_rule.UpdateQoSMinimumBandwidthRule( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         my_id = 'my-id' | ||||||
|  |         min_kbps = '1200' | ||||||
|  |         direction = 'egress' | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = ['--min-kbps', min_kbps, | ||||||
|  |                 '--direction', direction, | ||||||
|  |                 my_id, policy_id] | ||||||
|  |         self._test_update_resource(self.res, cmd, my_id, args, | ||||||
|  |                                    {'min_kbps': min_kbps, | ||||||
|  |                                     'direction': direction}, | ||||||
|  |                                    cmd_resource=self.cmd_res, | ||||||
|  |                                    parent_id=policy_id) | ||||||
|  |  | ||||||
|  |     def test_delete_minimum_bandwidth_rule(self): | ||||||
|  |         cmd = bw_rule.DeleteQoSMinimumBandwidthRule( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         my_id = 'my-id' | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = [my_id, policy_id] | ||||||
|  |         self._test_delete_resource(self.res, cmd, my_id, args, | ||||||
|  |                                    cmd_resource=self.cmd_res, | ||||||
|  |                                    parent_id=policy_id) | ||||||
|  |  | ||||||
|  |     def test_show_minimum_bandwidth_rule(self): | ||||||
|  |         cmd = bw_rule.ShowQoSMinimumBandwidthRule( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = [self.test_id, policy_id] | ||||||
|  |         self._test_show_resource(self.res, cmd, self.test_id, args, | ||||||
|  |                                  [], cmd_resource=self.cmd_res, | ||||||
|  |                                  parent_id=policy_id) | ||||||
|  |  | ||||||
|  |     def test_list_minimum_bandwidth_rule(self): | ||||||
|  |         cmd = bw_rule.ListQoSMinimumBandwidthRules( | ||||||
|  |             test_cli20.MyApp(sys.stdout), None) | ||||||
|  |         policy_id = 'policy_id' | ||||||
|  |         args = [policy_id] | ||||||
|  |         contents = [{'name': 'rule1', 'min-kbps': 1000, 'direction': 'egress'}] | ||||||
|  |         self._test_list_resources(self.cmd_ress, cmd, parent_id=policy_id, | ||||||
|  |                                   base_args=args, response_contents=contents) | ||||||
| @@ -22,7 +22,9 @@ from neutronclient.tests.unit import test_cli20 | |||||||
|  |  | ||||||
| class CLITestV20QoSRuleJSON(test_cli20.CLITestV20Base): | class CLITestV20QoSRuleJSON(test_cli20.CLITestV20Base): | ||||||
|  |  | ||||||
|     non_admin_status_resources = ['bandwidth_limit_rule', 'dscp_marking_rule'] |     non_admin_status_resources = ['bandwidth_limit_rule', | ||||||
|  |                                   'dscp_marking_rule', | ||||||
|  |                                   'minimum_bandwidth_rule'] | ||||||
|  |  | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|         super(CLITestV20QoSRuleJSON, self).setUp() |         super(CLITestV20QoSRuleJSON, self).setUp() | ||||||
| @@ -32,7 +34,8 @@ class CLITestV20QoSRuleJSON(test_cli20.CLITestV20Base): | |||||||
|         resources = 'rule_types' |         resources = 'rule_types' | ||||||
|         cmd_resources = 'qos_rule_types' |         cmd_resources = 'qos_rule_types' | ||||||
|         response_contents = [{'type': 'bandwidth_limit', |         response_contents = [{'type': 'bandwidth_limit', | ||||||
|                               'type': 'dscp_marking'}] |                               'type': 'dscp_marking', | ||||||
|  |                               'type': 'minimum_bandwidth'}] | ||||||
|  |  | ||||||
|         cmd = qos_rule.ListQoSRuleTypes(test_cli20.MyApp(sys.stdout), |         cmd = qos_rule.ListQoSRuleTypes(test_cli20.MyApp(sys.stdout), | ||||||
|                                         None) |                                         None) | ||||||
|   | |||||||
| @@ -595,6 +595,10 @@ class Client(ClientBase): | |||||||
|     qos_bandwidth_limit_rule_path = "/qos/policies/%s/bandwidth_limit_rules/%s" |     qos_bandwidth_limit_rule_path = "/qos/policies/%s/bandwidth_limit_rules/%s" | ||||||
|     qos_dscp_marking_rules_path = "/qos/policies/%s/dscp_marking_rules" |     qos_dscp_marking_rules_path = "/qos/policies/%s/dscp_marking_rules" | ||||||
|     qos_dscp_marking_rule_path = "/qos/policies/%s/dscp_marking_rules/%s" |     qos_dscp_marking_rule_path = "/qos/policies/%s/dscp_marking_rules/%s" | ||||||
|  |     qos_minimum_bandwidth_rules_path = \ | ||||||
|  |         "/qos/policies/%s/minimum_bandwidth_rules" | ||||||
|  |     qos_minimum_bandwidth_rule_path = \ | ||||||
|  |         "/qos/policies/%s/minimum_bandwidth_rules/%s" | ||||||
|     qos_rule_types_path = "/qos/rule-types" |     qos_rule_types_path = "/qos/rule-types" | ||||||
|     qos_rule_type_path = "/qos/rule-types/%s" |     qos_rule_type_path = "/qos/rule-types/%s" | ||||||
|     flavors_path = "/flavors" |     flavors_path = "/flavors" | ||||||
| @@ -660,6 +664,7 @@ class Client(ClientBase): | |||||||
|                      'qos_policies': 'qos_policy', |                      'qos_policies': 'qos_policy', | ||||||
|                      'policies': 'policy', |                      'policies': 'policy', | ||||||
|                      'bandwidth_limit_rules': 'bandwidth_limit_rule', |                      'bandwidth_limit_rules': 'bandwidth_limit_rule', | ||||||
|  |                      'minimum_bandwidth_rules': 'minimum_bandwidth_rule', | ||||||
|                      'rules': 'rule', |                      'rules': 'rule', | ||||||
|                      'dscp_marking_rules': 'dscp_marking_rule', |                      'dscp_marking_rules': 'dscp_marking_rule', | ||||||
|                      'rule_types': 'rule_type', |                      'rule_types': 'rule_type', | ||||||
| @@ -1740,6 +1745,35 @@ class Client(ClientBase): | |||||||
|         return self.delete(self.qos_dscp_marking_rule_path % |         return self.delete(self.qos_dscp_marking_rule_path % | ||||||
|                            (policy, rule)) |                            (policy, rule)) | ||||||
|  |  | ||||||
|  |     def list_minimum_bandwidth_rules(self, policy_id, retrieve_all=True, | ||||||
|  |                                      **_params): | ||||||
|  |         """Fetches a list of all minimum bandwidth rules for the given policy. | ||||||
|  |  | ||||||
|  |         """ | ||||||
|  |         return self.list('qos_minimum_bandwidth_rules', | ||||||
|  |                          self.qos_minimum_bandwidth_rules_path % | ||||||
|  |                          policy_id, retrieve_all, **_params) | ||||||
|  |  | ||||||
|  |     def show_minimum_bandwidth_rule(self, rule, policy, body=None): | ||||||
|  |         """Fetches information of a certain minimum bandwidth rule.""" | ||||||
|  |         return self.get(self.qos_minimum_bandwidth_rule_path % | ||||||
|  |                         (policy, rule), body=body) | ||||||
|  |  | ||||||
|  |     def create_minimum_bandwidth_rule(self, policy, body=None): | ||||||
|  |         """Creates a new minimum bandwidth rule.""" | ||||||
|  |         return self.post(self.qos_minimum_bandwidth_rules_path % policy, | ||||||
|  |                          body=body) | ||||||
|  |  | ||||||
|  |     def update_minimum_bandwidth_rule(self, rule, policy, body=None): | ||||||
|  |         """Updates a minimum bandwidth rule.""" | ||||||
|  |         return self.put(self.qos_minimum_bandwidth_rule_path % | ||||||
|  |                         (policy, rule), body=body) | ||||||
|  |  | ||||||
|  |     def delete_minimum_bandwidth_rule(self, rule, policy): | ||||||
|  |         """Deletes a minimum bandwidth rule.""" | ||||||
|  |         return self.delete(self.qos_minimum_bandwidth_rule_path % | ||||||
|  |                            (policy, rule)) | ||||||
|  |  | ||||||
|     def create_flavor(self, body=None): |     def create_flavor(self, body=None): | ||||||
|         """Creates a new Neutron service flavor.""" |         """Creates a new Neutron service flavor.""" | ||||||
|         return self.post(self.flavors_path, body=body) |         return self.post(self.flavors_path, body=body) | ||||||
|   | |||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | --- | ||||||
|  | features: | ||||||
|  |   - New create, update, list, show, and delete commands are added for the QoS | ||||||
|  |     minimum bandwidth rule. | ||||||
		Reference in New Issue
	
	Block a user