diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py index fa46a2a025..42790d4ce6 100644 --- a/openstack_dashboard/api/nova.py +++ b/openstack_dashboard/api/nova.py @@ -485,11 +485,13 @@ def server_serial_console(request, instance_id, console_type='serial'): def flavor_create(request, name, memory, vcpu, disk, flavorid='auto', - ephemeral=0, swap=0, metadata=None, is_public=True): + ephemeral=0, swap=0, metadata=None, is_public=True, + rxtx_factor=1): flavor = novaclient(request).flavors.create(name, memory, vcpu, disk, flavorid=flavorid, ephemeral=ephemeral, - swap=swap, is_public=is_public) + swap=swap, is_public=is_public, + rxtx_factor=rxtx_factor) if (metadata): flavor_extra_set(request, flavor.id, metadata) return flavor diff --git a/openstack_dashboard/dashboards/admin/flavors/tables.py b/openstack_dashboard/dashboards/admin/flavors/tables.py index 4b68d2e172..18517290d9 100644 --- a/openstack_dashboard/dashboards/admin/flavors/tables.py +++ b/openstack_dashboard/dashboards/admin/flavors/tables.py @@ -151,6 +151,7 @@ class FlavorsTable(tables.DataTable): swap = tables.Column(get_swap_size, verbose_name=_('Swap Disk'), attrs={'data-type': 'size'}) + rxtx_factor = tables.Column('rxtx_factor', verbose_name=_("RX/TX factor")) flavor_id = tables.Column('id', verbose_name=_('ID')) public = tables.Column("is_public", verbose_name=_("Public"), diff --git a/openstack_dashboard/dashboards/admin/flavors/tests.py b/openstack_dashboard/dashboards/admin/flavors/tests.py index c0cd4aaa22..b3fe0d18f1 100644 --- a/openstack_dashboard/dashboards/admin/flavors/tests.py +++ b/openstack_dashboard/dashboards/admin/flavors/tests.py @@ -45,6 +45,7 @@ class BaseFlavorWorkflowTests(test.BaseAdminViewTests): "memory": flavor.ram, "disk": flavor.disk, "swap": flavor.swap, + "rxtx_factor": flavor.rxtx_factor, "ephemeral": eph, "is_public": flavor.is_public} if id: @@ -58,6 +59,7 @@ class BaseFlavorWorkflowTests(test.BaseAdminViewTests): "memory_mb": flavor.ram, "disk_gb": flavor.disk, "swap_mb": flavor.swap, + "rxtx_factor": flavor.rxtx_factor, "eph_gb": eph} if access: access_field_name = 'update_flavor_access_role_member' @@ -325,6 +327,8 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): self.assertEqual(step.action.initial['memory_mb'], flavor.ram) self.assertEqual(step.action.initial['disk_gb'], flavor.disk) self.assertEqual(step.action.initial['swap_mb'], flavor.swap) + self.assertEqual(step.action.initial['rxtx_factor'], + flavor.rxtx_factor) self.assertEqual(step.action.initial['eph_gb'], eph) step = workflow.get_step("update_flavor_access") @@ -365,6 +369,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'vcpus': flavor.vcpus + 1, 'disk': flavor.disk, 'ram': flavor.ram, + 'rxtx_factor': flavor.rxtx_factor, 'swap': 0, 'OS-FLV-EXT-DATA:ephemeral': eph, 'extra_specs': extra_specs}) @@ -388,6 +393,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): new_flavor.vcpus, new_flavor.disk, swap=new_flavor.swap, + rxtx_factor=new_flavor.rxtx_factor, ephemeral=eph, is_public=True).AndReturn(new_flavor) @@ -407,6 +413,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'memory_mb': new_flavor.ram, 'disk_gb': new_flavor.disk, 'swap_mb': new_flavor.swap, + 'rxtx_factor': flavor.rxtx_factor, 'eph_gb': eph, 'is_public': True} resp = self.client.post(url, workflow_data) @@ -436,6 +443,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'disk': flavor.disk, 'ram': flavor.ram, 'swap': flavor.swap, + 'rxtx_factor': flavor.rxtx_factor, 'OS-FLV-EXT-DATA:ephemeral': eph, 'extra_specs': extra_specs}) @@ -458,6 +466,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): new_flavor.vcpus, new_flavor.disk, swap=new_flavor.swap, + rxtx_factor=new_flavor.rxtx_factor, ephemeral=eph, is_public=True).AndReturn(new_flavor) api.nova.flavor_extra_set(IsA(http.HttpRequest), @@ -478,6 +487,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'memory_mb': new_flavor.ram, 'disk_gb': new_flavor.disk, 'swap_mb': new_flavor.swap, + 'rxtx_factor': flavor.rxtx_factor, 'eph_gb': eph, 'is_public': True} resp = self.client.post(url, workflow_data) @@ -505,6 +515,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'vcpus': flavor.vcpus + 1, 'disk': flavor.disk, 'ram': flavor.ram, + 'rxtx_factor': flavor.rxtx_factor, 'swap': 0, 'OS-FLV-EXT-DATA:ephemeral': eph, 'extra_specs': extra_specs}) @@ -530,6 +541,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): new_flavor.vcpus, new_flavor.disk, swap=new_flavor.swap, + rxtx_factor=new_flavor.rxtx_factor, ephemeral=eph, is_public=True)\ .AndRaise(self.exceptions.nova) @@ -550,6 +562,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'memory_mb': new_flavor.ram, 'disk_gb': new_flavor.disk, 'swap_mb': new_flavor.swap, + 'rxtx_factor': flavor.rxtx_factor, 'eph_gb': eph, 'is_public': True} resp = self.client.post(url, workflow_data) @@ -582,6 +595,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'disk': flavor.disk, 'ram': flavor.ram, 'swap': 0, + 'rxtx_factor': flavor.rxtx_factor, 'OS-FLV-EXT-DATA:ephemeral': eph, 'os-flavor-access:is_public': False, 'extra_specs': extra_specs}) @@ -606,6 +620,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): new_flavor.vcpus, new_flavor.disk, swap=new_flavor.swap, + rxtx_factor=new_flavor.rxtx_factor, ephemeral=eph, is_public=new_flavor.is_public) \ .AndReturn(new_flavor) @@ -667,6 +682,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'memory_mb': flavor.ram, 'disk_gb': flavor.disk, 'swap_mb': flavor.swap, + 'rxtx_factor': flavor.rxtx_factor, 'eph_gb': eph, 'is_public': True} resp = self.client.post(url, workflow_data) @@ -689,6 +705,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'disk': flavor_a.disk, 'ram': flavor_a.ram, 'swap': flavor_a.swap, + 'rxtx_factor': flavor_a.rxtx_factor, 'OS-FLV-EXT-DATA:ephemeral': eph, 'extra_specs': extra_specs}) @@ -716,6 +733,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'memory_mb': new_flavor.ram, 'disk_gb': new_flavor.disk, 'swap_mb': new_flavor.swap, + 'rxtx_factor': new_flavor.rxtx_factor, 'eph_gb': eph, 'is_public': True} resp = self.client.post(url, data) @@ -753,6 +771,7 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): 'memory_mb': flavor.ram, 'disk_gb': flavor.disk, 'swap_mb': flavor.swap, + 'rxtx_factor': flavor.rxtx_factor, 'eph_gb': eph, 'is_public': True} workflow_data.update(override_data) @@ -788,3 +807,9 @@ class UpdateFlavorWorkflowTests(BaseFlavorWorkflowTests): data = {'eph_gb': -1} self.generic_update_flavor_invalid_data_form_fails(override_data=data, error_msg=error) + + def test_update_flavor_invalid_rxtx_factor_fails(self): + error = 'Ensure this value is greater than or equal to 1.' + data = {'rxtx_factor': 0} + self.generic_update_flavor_invalid_data_form_fails(override_data=data, + error_msg=error) diff --git a/openstack_dashboard/dashboards/admin/flavors/views.py b/openstack_dashboard/dashboards/admin/flavors/views.py index 70b8ac4083..571332c212 100644 --- a/openstack_dashboard/dashboards/admin/flavors/views.py +++ b/openstack_dashboard/dashboards/admin/flavors/views.py @@ -80,4 +80,5 @@ class UpdateView(workflows.WorkflowView): 'memory_mb': flavor.ram, 'disk_gb': flavor.disk, 'swap_mb': flavor.swap or 0, + 'rxtx_factor': flavor.rxtx_factor or 1, 'eph_gb': getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral', None)} diff --git a/openstack_dashboard/dashboards/admin/flavors/workflows.py b/openstack_dashboard/dashboards/admin/flavors/workflows.py index ca62b64371..e1a63fdefa 100644 --- a/openstack_dashboard/dashboards/admin/flavors/workflows.py +++ b/openstack_dashboard/dashboards/admin/flavors/workflows.py @@ -57,6 +57,10 @@ class CreateFlavorInfoAction(workflows.Action): required=False, initial=0, min_value=0) + rxtx_factor = forms.FloatField(label=_("RX/TX Factor"), + required=False, + initial=1, + min_value=1) class Meta(object): name = _("Flavor Information") @@ -99,7 +103,8 @@ class CreateFlavorInfo(workflows.Step): "memory_mb", "disk_gb", "eph_gb", - "swap_mb") + "swap_mb", + "rxtx_factor") class UpdateFlavorAccessAction(workflows.MembershipAction): @@ -196,6 +201,7 @@ class CreateFlavor(workflows.Workflow): ephemeral = data.get('eph_gb') or 0 flavor_access = data['flavor_access'] is_public = not flavor_access + rxtx_factor = data.get('rxtx_factor') or 1 # Create the flavor try: @@ -207,7 +213,8 @@ class CreateFlavor(workflows.Workflow): ephemeral=ephemeral, swap=swap, flavorid=flavor_id, - is_public=is_public) + is_public=is_public, + rxtx_factor=rxtx_factor) except Exception: exceptions.handle(request, _('Unable to create flavor.')) return False @@ -264,7 +271,8 @@ class UpdateFlavorInfo(workflows.Step): "memory_mb", "disk_gb", "eph_gb", - "swap_mb") + "swap_mb", + "rxtx_factor") class UpdateFlavor(workflows.Workflow): @@ -305,7 +313,8 @@ class UpdateFlavor(workflows.Workflow): data['disk_gb'], ephemeral=data['eph_gb'], swap=data['swap_mb'], - is_public=is_public) + is_public=is_public, + rxtx_factor=data['rxtx_factor']) if (extras_dict): api.nova.flavor_extra_set(request, flavor.id, extras_dict) except Exception: diff --git a/openstack_dashboard/test/test_data/nova_data.py b/openstack_dashboard/test/test_data/nova_data.py index 8c4279473e..86968f6c16 100644 --- a/openstack_dashboard/test/test_data/nova_data.py +++ b/openstack_dashboard/test/test_data/nova_data.py @@ -263,6 +263,7 @@ def data(TEST): 'disk': 0, 'ram': 512, 'swap': 0, + 'rxtx_factor': 1, 'extra_specs': {}, 'os-flavor-access:is_public': True, 'OS-FLV-EXT-DATA:ephemeral': 0}) @@ -273,6 +274,7 @@ def data(TEST): 'disk': 1024, 'ram': 10000, 'swap': 0, + 'rxtx_factor': 1, 'extra_specs': {'Trusted': True, 'foo': 'bar'}, 'os-flavor-access:is_public': True, 'OS-FLV-EXT-DATA:ephemeral': 2048}) @@ -283,6 +285,7 @@ def data(TEST): 'disk': 1024, 'ram': 10000, 'swap': 0, + 'rxtx_factor': 1, 'extra_specs': {}, 'os-flavor-access:is_public': False, 'OS-FLV-EXT-DATA:ephemeral': 2048}) @@ -293,6 +296,7 @@ def data(TEST): 'disk': 1024, 'ram': 10000, 'swap': 0, + 'rxtx_factor': 1, 'extra_specs': FlavorExtraSpecs( {'key': 'key_mock', 'value': 'value_mock'}),