Skip to content

Commit

Permalink
Fixes bug 1086290
Browse files Browse the repository at this point in the history
https://bugs.launchpad.net/horizon/+bug/1086290,
edit-flavor broken when flavor has extra specs.
Includes unittest for the same, and modified mock data to
to include extra-specs
Change-Id: I286d97568daff26bbd03418b2ea0b808caceadba
  • Loading branch information
Malini Bhandaru committed Dec 11, 2012
1 parent e0c43a4 commit 95a034a
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 30 deletions.
13 changes: 10 additions & 3 deletions openstack_dashboard/api/nova.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,14 @@ def server_vnc_console(request, instance_id, console_type='novnc'):
console_type)['console'])


def flavor_create(request, name, memory, vcpu, disk, ephemeral=0, swap=0):
return novaclient(request).flavors.create(name, memory, vcpu, disk,
ephemeral=ephemeral, swap=swap)
def flavor_create(request, name, memory, vcpu, disk, ephemeral=0, swap=0,
metadata=None):
flavor = novaclient(request).flavors.create(name, memory, vcpu, disk,
ephemeral=ephemeral,
swap=swap)
if (metadata):
flavor_extra_set(request, flavor.id, metadata)
return flavor


def flavor_delete(request, flavor_id):
Expand Down Expand Up @@ -233,6 +238,8 @@ def flavor_extra_delete(request, flavor_id, keys):
def flavor_extra_set(request, flavor_id, metadata):
"""Set the flavor extra spec keys."""
flavor = novaclient(request).flavors.get(flavor_id)
if (not metadata): # not a way to delete keys
return None
return flavor.set_keys(metadata)


Expand Down
11 changes: 4 additions & 7 deletions openstack_dashboard/dashboards/admin/flavors/extras/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@

class FlavorExtrasTests(test.BaseAdminViewTests):

@test.create_stubs({api.nova: ('flavor_get_extras',
'flavor_get'), })
def test_list_extras_when_none_exists(self):
flavor = self.flavors.first()
extras = [api.FlavorExtraSpec(flavor.id, 'k1', 'v1')]

self.mox.StubOutWithMock(api.nova, 'flavor_get')
self.mox.StubOutWithMock(api.nova, 'flavor_get_extras')

# GET -- to determine correctness of output
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id).AndReturn(flavor)
api.nova.flavor_get_extras(IsA(http.HttpRequest),
Expand All @@ -26,15 +25,14 @@ def test_list_extras_when_none_exists(self):
self.assertEqual(resp.status_code, 200)
self.assertTemplateUsed(resp, "admin/flavors/extras/index.html")

@test.create_stubs({api.nova: ('flavor_extra_set', ), })
def test_extra_create_post(self):
flavor = self.flavors.first()
create_url = reverse('horizon:admin:flavors:extras:create',
args=[flavor.id])
index_url = reverse('horizon:admin:flavors:extras:index',
args=[flavor.id])

self.mox.StubOutWithMock(api.nova, 'flavor_extra_set')

# GET to display the flavor_name
api.nova.flavor_extra_set(IsA(http.HttpRequest),
flavor.id,
Expand All @@ -49,13 +47,12 @@ def test_extra_create_post(self):
self.assertMessageCount(success=1)
self.assertRedirectsNoFollow(resp, index_url)

@test.create_stubs({api.nova: ('flavor_get', ), })
def test_extra_create_get(self):
flavor = self.flavors.first()
create_url = reverse('horizon:admin:flavors:extras:create',
args=[flavor.id])

self.mox.StubOutWithMock(api.nova, 'flavor_get')

api.nova.flavor_get(IsA(http.HttpRequest), flavor.id).AndReturn(flavor)
self.mox.ReplayAll()

Expand Down
6 changes: 4 additions & 2 deletions openstack_dashboard/dashboards/admin/flavors/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ def handle(self, request, data):
flavor_id = data['flavor_id']
# grab any existing extra specs, because flavor edit currently
# implemented as a delete followed by a create
extras_dict = api.nova.flavor_get_extras(self.request, flavor_id)
extras_dict = api.nova.flavor_get_extras(self.request,
flavor_id,
raw=True)
# First mark the existing flavor as deleted.
api.nova.flavor_delete(request, data['flavor_id'])
# Then create a new flavor with the same name but a new ID.
Expand All @@ -99,7 +101,7 @@ def handle(self, request, data):
data['disk_gb'],
ephemeral=data['eph_gb'],
swap=data['swap_mb'])
if (len(extras_dict) > 0):
if (extras_dict):
api.nova.flavor_extra_set(request, flavor.id, extras_dict)
msg = _('Updated flavor "%s".') % data['name']
messages.success(request, msg)
Expand Down
109 changes: 91 additions & 18 deletions openstack_dashboard/dashboards/admin/flavors/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@

from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
from novaclient.v1_1 import flavors


class FlavorsTests(test.BaseAdminViewTests):
@test.create_stubs({api.nova: ('flavor_list', 'flavor_create'), })
def test_create_new_flavor_when_none_exist(self):
flavor = self.flavors.first()
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
self.mox.StubOutWithMock(api.nova, 'flavor_list')
self.mox.StubOutWithMock(api.nova, 'flavor_create')

# no pre-existing flavors
api.nova.flavor_create(IsA(http.HttpRequest),
flavor.name,
flavor.ram,
flavor.vcpus,
flavor.disk,
swap=flavor.swap or 0,
swap=flavor.swap,
ephemeral=eph).AndReturn(flavor)
api.nova.flavor_list(IsA(http.HttpRequest))
self.mox.ReplayAll()
Expand All @@ -35,37 +35,108 @@ def test_create_new_flavor_when_none_exist(self):
'vcpus': flavor.vcpus,
'memory_mb': flavor.ram,
'disk_gb': flavor.disk,
'swap_mb': flavor.swap or 0,
'swap_mb': flavor.swap,
'eph_gb': eph}
resp = self.client.post(url, data)
self.assertRedirectsNoFollow(resp,
reverse("horizon:admin:flavors:index"))

# keeping the 2 edit tests separate to aid debug breaks
@test.create_stubs({api.nova: ('flavor_list',
'flavor_create',
'flavor_delete',
'flavor_get_extras',
'flavor_get'), })
def test_edit_flavor(self):
flavor = self.flavors.first()
flavor = self.flavors.first() # has no extra specs
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
extras = {}
self.mox.StubOutWithMock(api.nova, 'flavor_list')
self.mox.StubOutWithMock(api.nova, 'flavor_get_extras')
self.mox.StubOutWithMock(api.nova, 'flavor_get')
self.mox.StubOutWithMock(api.nova, 'flavor_delete')
self.mox.StubOutWithMock(api.nova, 'flavor_create')
extra_specs = getattr(flavor, 'extra_specs')
new_flavor = flavors.Flavor(flavors.FlavorManager(None),
{'id':
"cccccccc-cccc-cccc-cccc-cccccccccccc",
'name': flavor.name,
'vcpus': flavor.vcpus + 1,
'disk': flavor.disk,
'ram': flavor.ram,
'swap': 0,
'OS-FLV-EXT-DATA:ephemeral': eph,
'extra_specs': extra_specs})
# GET
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id).AndReturn(flavor)

# POST
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id).AndReturn(flavor)
api.nova.flavor_get_extras(IsA(http.HttpRequest), flavor.id, raw=True)\
.AndReturn(extra_specs)
api.nova.flavor_delete(IsA(http.HttpRequest), flavor.id)
api.nova.flavor_create(IsA(http.HttpRequest),
new_flavor.name,
new_flavor.ram,
new_flavor.vcpus,
new_flavor.disk,
swap=flavor.swap,
ephemeral=eph).AndReturn(new_flavor)
self.mox.ReplayAll()

# get_test
url = reverse('horizon:admin:flavors:edit', args=[flavor.id])
resp = self.client.get(url)
self.assertEqual(resp.status_code, 200)
self.assertTemplateUsed(resp, "admin/flavors/edit.html")

# post test
data = {'flavor_id': flavor.id,
'name': flavor.name,
'vcpus': flavor.vcpus + 1,
'memory_mb': flavor.ram,
'disk_gb': flavor.disk,
'swap_mb': flavor.swap,
'eph_gb': eph}
resp = self.client.post(url, data)
self.assertNoFormErrors(resp)
self.assertMessageCount(success=1)
self.assertRedirectsNoFollow(resp,
reverse("horizon:admin:flavors:index"))

@test.create_stubs({api.nova: ('flavor_list',
'flavor_create',
'flavor_delete',
'flavor_get_extras',
'flavor_extra_set',
'flavor_get'), })
def test_edit_flavor_with_extra_specs(self):
flavor = self.flavors.list()[1] # the second element has extra specs
eph = getattr(flavor, 'OS-FLV-EXT-DATA:ephemeral')
extra_specs = getattr(flavor, 'extra_specs')
new_vcpus = flavor.vcpus + 1
new_flavor = flavors.Flavor(flavors.FlavorManager(None),
{'id':
"cccccccc-cccc-cccc-cccc-cccccccccccc",
'name': flavor.name,
'vcpus': new_vcpus,
'disk': flavor.disk,
'ram': flavor.ram,
'swap': flavor.swap,
'OS-FLV-EXT-DATA:ephemeral': eph,
'extra_specs': extra_specs})
# GET
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id).AndReturn(flavor)

# POST
api.nova.flavor_get(IsA(http.HttpRequest), flavor.id).AndReturn(flavor)
api.nova.flavor_get_extras(IsA(http.HttpRequest), flavor.id)\
.AndReturn(extras)
api.nova.flavor_get_extras(IsA(http.HttpRequest), flavor.id, raw=True)\
.AndReturn(extra_specs)
api.nova.flavor_delete(IsA(http.HttpRequest), flavor.id)
api.nova.flavor_create(IsA(http.HttpRequest),
flavor.name,
flavor.ram,
flavor.vcpus + 1,
new_vcpus,
flavor.disk,
swap=flavor.swap or 0,
ephemeral=eph).AndReturn(flavor)
swap=flavor.swap,
ephemeral=eph).AndReturn(new_flavor)
api.nova.flavor_extra_set(IsA(http.HttpRequest),
new_flavor.id,
extra_specs)
self.mox.ReplayAll()

#get_test
Expand All @@ -77,11 +148,13 @@ def test_edit_flavor(self):
#post test
data = {'flavor_id': flavor.id,
'name': flavor.name,
'vcpus': flavor.vcpus + 1,
'vcpus': new_vcpus,
'memory_mb': flavor.ram,
'disk_gb': flavor.disk,
'swap_mb': flavor.swap or 0,
'swap_mb': flavor.swap,
'eph_gb': eph}
resp = self.client.post(url, data)
self.assertNoFormErrors(resp)
self.assertMessageCount(success=1)
self.assertRedirectsNoFollow(resp,
reverse("horizon:admin:flavors:index"))
2 changes: 2 additions & 0 deletions openstack_dashboard/test/test_data/nova_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ def data(TEST):
'disk': 0,
'ram': 512,
'swap': 0,
'extra_specs': {},
'OS-FLV-EXT-DATA:ephemeral': 0})
flavor_2 = flavors.Flavor(flavors.FlavorManager(None),
{'id': "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
Expand All @@ -212,6 +213,7 @@ def data(TEST):
'disk': 1024,
'ram': 10000,
'swap': 0,
'extra_specs': {'Trusted': True, 'foo': 'bar'},
'OS-FLV-EXT-DATA:ephemeral': 2048})
TEST.flavors.add(flavor_1, flavor_2)

Expand Down

0 comments on commit 95a034a

Please sign in to comment.