1
# Copyright 2012 OpenStack LLC.
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
18
from lxml import etree
21
from nova.api.openstack.compute.contrib import flavor_access
22
from nova.api.openstack.compute import flavors
23
from nova.compute import instance_types
24
from nova import context
25
from nova import exception
27
from nova.tests.api.openstack import fakes
30
def generate_instance_type(flavorid, ispublic):
33
'flavorid': str(flavorid),
38
'created_at': datetime.datetime(2012, 1, 1, 1, 1, 1, 1),
47
'is_public': bool(ispublic)
52
'0': generate_instance_type(0, True),
53
'1': generate_instance_type(1, True),
54
'2': generate_instance_type(2, False),
55
'3': generate_instance_type(3, False)}
58
ACCESS_LIST = [{'flavor_id': '2', 'project_id': 'proj2'},
59
{'flavor_id': '2', 'project_id': 'proj3'},
60
{'flavor_id': '3', 'project_id': 'proj3'}]
63
def fake_get_instance_type_access_by_flavor_id(flavorid):
65
for access in ACCESS_LIST:
66
if access['flavor_id'] == flavorid:
71
def fake_get_instance_type_by_flavor_id(flavorid):
72
return INSTANCE_TYPES[flavorid]
75
def _has_flavor_access(flavorid, projectid):
76
for access in ACCESS_LIST:
77
if access['flavor_id'] == flavorid and \
78
access['project_id'] == projectid:
83
def fake_get_all_types(context, inactive=0, filters=None):
84
if filters == None or filters['is_public'] == None:
88
for k, v in INSTANCE_TYPES.iteritems():
89
if filters['is_public'] and _has_flavor_access(k, context.project_id):
92
if v['is_public'] == filters['is_public']:
98
class FakeRequest(object):
99
environ = {"nova.context": context.get_admin_context()}
102
class FlavorAccessTest(test.TestCase):
104
super(FlavorAccessTest, self).setUp()
105
self.flavor_controller = flavors.Controller()
106
self.flavor_access_controller = flavor_access.FlavorAccessController()
107
self.flavor_action_controller = flavor_access.FlavorActionController()
108
self.req = FakeRequest()
109
self.context = self.req.environ['nova.context']
110
self.stubs.Set(instance_types, 'get_instance_type_by_flavor_id',
111
fake_get_instance_type_by_flavor_id)
112
self.stubs.Set(instance_types, 'get_all_types', fake_get_all_types)
113
self.stubs.Set(instance_types, 'get_instance_type_access_by_flavor_id',
114
fake_get_instance_type_access_by_flavor_id)
116
def _verify_flavor_list(self, result, expected):
117
# result already sorted by flavor_id
118
self.assertEqual(len(result), len(expected))
120
for d1, d2 in zip(result, expected):
121
self.assertEqual(d1['id'], d2['id'])
123
def test_list_flavor_access_public(self):
124
# query os-flavor-access on public flavor should return 404
125
req = fakes.HTTPRequest.blank('/v2/fake/flavors/os-flavor-access',
126
use_admin_context=True)
127
self.assertRaises(exc.HTTPNotFound,
128
self.flavor_access_controller.index,
131
def test_list_flavor_access_private(self):
132
expected = {'flavor_access': [
133
{'flavor_id': '2', 'tenant_id': 'proj2'},
134
{'flavor_id': '2', 'tenant_id': 'proj3'}]}
135
result = self.flavor_access_controller.index(self.req, '2')
136
self.assertEqual(result, expected)
138
def test_list_flavor_with_admin_default_proj1(self):
139
expected = {'flavors': [{'id': '0'}, {'id': '1'}]}
140
req = fakes.HTTPRequest.blank('/v2/fake/flavors',
141
use_admin_context=True)
142
req.environ['nova.context'].project_id = 'proj1'
143
result = self.flavor_controller.index(req)
144
self._verify_flavor_list(result['flavors'], expected['flavors'])
146
def test_list_flavor_with_admin_default_proj2(self):
147
expected = {'flavors': [{'id': '0'}, {'id': '1'}, {'id': '2'}]}
148
req = fakes.HTTPRequest.blank('/v2/fake/flavors',
149
use_admin_context=True)
150
req.environ['nova.context'].project_id = 'proj2'
151
result = self.flavor_controller.index(req)
152
self._verify_flavor_list(result['flavors'], expected['flavors'])
154
def test_list_flavor_with_admin_ispublic_true(self):
155
expected = {'flavors': [{'id': '0'}, {'id': '1'}]}
156
req = fakes.HTTPRequest.blank('/v2/fake/flavors?is_public=true',
157
use_admin_context=True)
158
result = self.flavor_controller.index(req)
159
self._verify_flavor_list(result['flavors'], expected['flavors'])
161
def test_list_flavor_with_admin_ispublic_false(self):
162
expected = {'flavors': [{'id': '2'}, {'id': '3'}]}
163
req = fakes.HTTPRequest.blank('/v2/fake/flavors?is_public=false',
164
use_admin_context=True)
165
result = self.flavor_controller.index(req)
166
self._verify_flavor_list(result['flavors'], expected['flavors'])
168
def test_list_flavor_with_admin_ispublic_false_proj2(self):
169
expected = {'flavors': [{'id': '2'}, {'id': '3'}]}
170
req = fakes.HTTPRequest.blank('/v2/fake/flavors?is_public=false',
171
use_admin_context=True)
172
req.environ['nova.context'].project_id = 'proj2'
173
result = self.flavor_controller.index(req)
174
self._verify_flavor_list(result['flavors'], expected['flavors'])
176
def test_list_flavor_with_admin_ispublic_none(self):
177
expected = {'flavors': [{'id': '0'}, {'id': '1'}, {'id': '2'},
179
req = fakes.HTTPRequest.blank('/v2/fake/flavors?is_public=none',
180
use_admin_context=True)
181
result = self.flavor_controller.index(req)
182
self._verify_flavor_list(result['flavors'], expected['flavors'])
184
def test_list_flavor_with_no_admin_default(self):
185
expected = {'flavors': [{'id': '0'}, {'id': '1'}]}
186
req = fakes.HTTPRequest.blank('/v2/fake/flavors',
187
use_admin_context=False)
188
result = self.flavor_controller.index(req)
189
self._verify_flavor_list(result['flavors'], expected['flavors'])
191
def test_list_flavor_with_no_admin_ispublic_true(self):
192
expected = {'flavors': [{'id': '0'}, {'id': '1'}]}
193
req = fakes.HTTPRequest.blank('/v2/fake/flavors?is_public=true',
194
use_admin_context=False)
195
result = self.flavor_controller.index(req)
196
self._verify_flavor_list(result['flavors'], expected['flavors'])
198
def test_list_flavor_with_no_admin_ispublic_false(self):
199
expected = {'flavors': [{'id': '0'}, {'id': '1'}]}
200
req = fakes.HTTPRequest.blank('/v2/fake/flavors?is_public=false',
201
use_admin_context=False)
202
result = self.flavor_controller.index(req)
203
self._verify_flavor_list(result['flavors'], expected['flavors'])
205
def test_list_flavor_with_no_admin_ispublic_none(self):
206
expected = {'flavors': [{'id': '0'}, {'id': '1'}]}
207
req = fakes.HTTPRequest.blank('/v2/fake/flavors?is_public=none',
208
use_admin_context=False)
209
result = self.flavor_controller.index(req)
210
self._verify_flavor_list(result['flavors'], expected['flavors'])
212
def test_add_tenant_access(self):
213
def stub_add_instance_type_access(flavorid, projectid, ctxt=None):
214
self.assertEqual('3', flavorid, "flavorid")
215
self.assertEqual("proj2", projectid, "projectid")
216
self.stubs.Set(instance_types, 'add_instance_type_access',
217
stub_add_instance_type_access)
218
expected = {'flavor_access':
219
[{'flavor_id': '3', 'tenant_id': 'proj3'}]}
220
body = {'addTenantAccess': {'tenant': 'proj2'}}
221
req = fakes.HTTPRequest.blank('/v2/fake/flavors/2/action',
222
use_admin_context=True)
223
result = self.flavor_action_controller.\
224
_addTenantAccess(req, '3', body)
225
self.assertEqual(result, expected)
227
def test_add_tenant_access_with_already_added_access(self):
228
def stub_add_instance_type_access(flavorid, projectid, ctxt=None):
229
raise exception.FlavorAccessExists()
230
self.stubs.Set(instance_types, 'add_instance_type_access',
231
stub_add_instance_type_access)
232
body = {'addTenantAccess': {'tenant': 'proj2'}}
233
req = fakes.HTTPRequest.blank('/v2/fake/flavors/2/action',
234
use_admin_context=True)
235
self.assertRaises(exc.HTTPConflict,
236
self.flavor_action_controller._addTenantAccess,
239
def test_remove_tenant_access_with_bad_access(self):
240
def stub_remove_instance_type_access(flavorid, projectid, ctxt=None):
241
self.assertEqual('3', flavorid, "flavorid")
242
self.assertEqual("proj2", projectid, "projectid")
243
expected = {'flavor_access': [
244
{'flavor_id': '3', 'tenant_id': 'proj3'}]}
245
self.stubs.Set(instance_types, 'remove_instance_type_access',
246
stub_remove_instance_type_access)
247
body = {'removeTenantAccess': {'tenant': 'proj2'}}
248
req = fakes.HTTPRequest.blank('/v2/fake/flavors/2/action',
249
use_admin_context=True)
250
result = self.flavor_action_controller.\
251
_addTenantAccess(req, '3', body)
252
self.assertEqual(result, expected)
254
def test_remove_tenant_access_with_bad_access(self):
255
def stub_remove_instance_type_access(flavorid, projectid, ctxt=None):
256
raise exception.FlavorAccessNotFound()
257
self.stubs.Set(instance_types, 'remove_instance_type_access',
258
stub_remove_instance_type_access)
259
body = {'removeTenantAccess': {'tenant': 'proj2'}}
260
req = fakes.HTTPRequest.blank('/v2/fake/flavors/2/action',
261
use_admin_context=True)
262
self.assertRaises(exc.HTTPNotFound,
263
self.flavor_action_controller._removeTenantAccess,
267
class FlavorAccessSerializerTest(test.TestCase):
268
def test_xml_declaration(self):
269
access_list = [{'flavor_id': '2', 'tenant_id': 'proj2'}]
270
serializer = flavor_access.FlavorAccessTemplate()
271
output = serializer.serialize(access_list)
272
has_dec = output.startswith("<?xml version='1.0' encoding='UTF-8'?>")
273
self.assertTrue(has_dec)
275
def test_serializer_empty(self):
278
serializer = flavor_access.FlavorAccessTemplate()
279
text = serializer.serialize(access_list)
280
tree = etree.fromstring(text)
281
self.assertEqual(len(tree), 0)
283
def test_serializer(self):
284
access_list = [{'flavor_id': '2', 'tenant_id': 'proj2'},
285
{'flavor_id': '2', 'tenant_id': 'proj3'}]
287
serializer = flavor_access.FlavorAccessTemplate()
288
text = serializer.serialize(access_list)
289
tree = etree.fromstring(text)
291
self.assertEqual('flavor_access', tree.tag)
292
self.assertEqual(len(access_list), len(tree))
294
for i in range(len(access_list)):
295
self.assertEqual('access', tree[i].tag)
296
self.assertEqual(access_list[i]['flavor_id'],
297
tree[i].get('flavor_id'))
298
self.assertEqual(access_list[i]['tenant_id'],
299
tree[i].get('tenant_id'))