Convert v3 cells API to v2.1

This patch changes v3 cells API to v2.1 and makes v2
unit tests share between v2 and v2.1.

This patch also delete the V3 cells API tests.

The differences between v2 and v3 are described on the wiki page
https://wiki.openstack.org/wiki/NovaAPIv2tov3.

Partially implements blueprint v2-on-v3-api

Change-Id: Iacfd1881ff24eb3bfc73006244044fc139897eda
This commit is contained in:
Ghanshyam 2014-08-14 16:02:23 +09:00
parent 921e01cd21
commit 4657850097
3 changed files with 94 additions and 615 deletions

View File

@ -24,7 +24,6 @@ from webob import exc
from nova.api.openstack import common
from nova.api.openstack.compute.schemas.v3 import cells
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api import validation
from nova.cells import rpcapi as cells_rpcapi
from nova.compute import api as compute
@ -170,9 +169,11 @@ class CellsController(object):
raise exc.HTTPNotFound(explanation=e.format_message())
return dict(cell=_scrub_cell(cell))
# NOTE(gmann): Returns 200 for backwards compatibility but should be 204
# as this operation complete the deletion of aggregate resource and return
# no response body.
@extensions.expected_errors((403, 404, 501))
@common.check_cells_enabled
@wsgi.response(204)
def delete(self, req, id):
"""Delete a child or parent cell entry. 'id' is a cell name."""
context = req.environ['nova.context']
@ -231,9 +232,11 @@ class CellsController(object):
# Now set the transport URL
cell['transport_url'] = str(transport_url)
# NOTE(gmann): Returns 200 for backwards compatibility but should be 201
# as this operation complete the creation of aggregates resource when
# returning a response.
@extensions.expected_errors((400, 403, 501))
@common.check_cells_enabled
@wsgi.response(201)
@validation.schema(cells.create)
def create(self, req, body):
"""Create a child cell entry."""
@ -282,9 +285,11 @@ class CellsController(object):
raise exc.HTTPForbidden(explanation=e.format_message())
return dict(cell=_scrub_cell(cell))
# NOTE(gmann): Returns 200 for backwards compatibility but should be 204
# as this operation complete the sync instance info and return
# no response body.
@extensions.expected_errors((400, 501))
@common.check_cells_enabled
@wsgi.response(204)
@validation.schema(cells.sync_instances)
def sync_instances(self, req, body):
"""Tell all cells to sync instance info."""

View File

@ -18,7 +18,8 @@ import copy
from lxml import etree
from webob import exc
from nova.api.openstack.compute.contrib import cells as cells_ext
from nova.api.openstack.compute.contrib import cells as cells_ext_v2
from nova.api.openstack.compute.plugins.v3 import cells as cells_ext_v21
from nova.api.openstack import extensions
from nova.api.openstack import xmlutil
from nova.cells import rpcapi as cells_rpcapi
@ -89,16 +90,22 @@ class BaseCellsTest(test.NoDBTestCase):
return cells
class CellsTest(BaseCellsTest):
def setUp(self):
super(CellsTest, self).setUp()
self.ext_mgr = self.mox.CreateMock(extensions.ExtensionManager)
self.controller = cells_ext.Controller(self.ext_mgr)
self.context = context.get_admin_context()
self.flags(enable=True, group='cells')
class CellsTestV21(BaseCellsTest):
cell_extension = 'compute_extension:v3:os-cells'
bad_request = exception.ValidationError
def _get_cell_controller(self, ext_mgr):
return cells_ext_v21.CellsController()
def _get_request(self, resource):
return fakes.HTTPRequest.blank('/v2/fake/' + resource)
return fakes.HTTPRequestV3.blank('/' + resource)
def setUp(self):
super(CellsTestV21, self).setUp()
self.ext_mgr = self.mox.CreateMock(extensions.ExtensionManager)
self.controller = self._get_cell_controller(self.ext_mgr)
self.context = context.get_admin_context()
self.flags(enable=True, group='cells')
def test_index(self):
req = self._get_request("cells")
@ -150,7 +157,7 @@ class CellsTest(BaseCellsTest):
def test_cell_delete(self):
# Test cell delete with just cell policy
rules = {"default": "is_admin:true",
"compute_extension:cells": "is_admin:true"}
self.cell_extension: "is_admin:true"}
self.policy.set_rules(rules)
self._cell_delete()
@ -185,13 +192,11 @@ class CellsTest(BaseCellsTest):
'username': 'fred',
'password': 'fubar',
'rpc_host': 'r3.example.org',
'type': 'parent',
# Also test this is ignored/stripped
'is_parent': False}}
'type': 'parent'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
res_dict = self.controller.create(req, body)
res_dict = self.controller.create(req, body=body)
cell = res_dict['cell']
self.assertEqual(cell['name'], 'meow')
@ -204,7 +209,7 @@ class CellsTest(BaseCellsTest):
def test_cell_create_parent(self):
# Test create with just cells policy
rules = {"default": "is_admin:true",
"compute_extension:cells": "is_admin:true"}
self.cell_extension: "is_admin:true"}
self.policy.set_rules(rules)
self._cell_create_parent()
@ -220,7 +225,7 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells")
req.environ['nova.context'] = self.context
res_dict = self.controller.create(req, body)
res_dict = self.controller.create(req, body=body)
cell = res_dict['cell']
self.assertEqual(cell['name'], 'meow')
@ -233,7 +238,7 @@ class CellsTest(BaseCellsTest):
def test_cell_create_child(self):
# Test create with just cells policy
rules = {"default": "is_admin:true",
"compute_extension:cells": "is_admin:true"}
self.cell_extension: "is_admin:true"}
self.policy.set_rules(rules)
self._cell_create_child()
@ -248,8 +253,8 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.create, req, body)
self.assertRaises(self.bad_request,
self.controller.create, req, body=body)
def test_cell_create_name_empty_string_raises(self):
body = {'cell': {'name': '',
@ -260,8 +265,8 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.create, req, body)
self.assertRaises(self.bad_request,
self.controller.create, req, body=body)
def test_cell_create_name_with_bang_raises(self):
body = {'cell': {'name': 'moo!cow',
@ -272,8 +277,8 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.create, req, body)
self.assertRaises(self.bad_request,
self.controller.create, req, body=body)
def test_cell_create_name_with_dot_raises(self):
body = {'cell': {'name': 'moo.cow',
@ -284,8 +289,9 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.create, req, body)
res_dict = self.controller.create(req, body=body)
cell = res_dict['cell']
self.assertEqual(cell['name'], 'moo.cow')
def test_cell_create_name_with_invalid_type_raises(self):
body = {'cell': {'name': 'moocow',
@ -296,8 +302,8 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.create, req, body)
self.assertRaises(self.bad_request,
self.controller.create, req, body=body)
def test_cell_create_fails_for_invalid_policy(self):
body = {'cell': {'name': 'fake'}}
@ -305,7 +311,7 @@ class CellsTest(BaseCellsTest):
req.environ['nova.context'] = self.context
req.environ['nova.context'].is_admin = False
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.create, req, body)
self.controller.create, req, body=body)
def _cell_update(self):
body = {'cell': {'username': 'zeb',
@ -313,7 +319,7 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
res_dict = self.controller.update(req, 'cell1', body)
res_dict = self.controller.update(req, 'cell1', body=body)
cell = res_dict['cell']
self.assertEqual(cell['name'], 'cell1')
@ -324,7 +330,7 @@ class CellsTest(BaseCellsTest):
def test_cell_update(self):
# Test cell update with just cell policy
rules = {"default": "is_admin:true",
"compute_extension:cells": "is_admin:true"}
self.cell_extension: "is_admin:true"}
self.policy.set_rules(rules)
self._cell_update()
@ -337,7 +343,7 @@ class CellsTest(BaseCellsTest):
req.environ['nova.context'] = self.context
req.environ['nova.context'].is_admin = False
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.create, req, body)
self.controller.create, req, body=body)
def test_cell_update_empty_name_raises(self):
body = {'cell': {'name': '',
@ -346,8 +352,8 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.update, req, 'cell1', body)
self.assertRaises(self.bad_request,
self.controller.update, req, 'cell1', body=body)
def test_cell_update_invalid_type_raises(self):
body = {'cell': {'username': 'zeb',
@ -356,15 +362,15 @@ class CellsTest(BaseCellsTest):
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.update, req, 'cell1', body)
self.assertRaises(self.bad_request,
self.controller.update, req, 'cell1', body=body)
def test_cell_update_without_type_specified(self):
body = {'cell': {'username': 'wingwj'}}
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
res_dict = self.controller.update(req, 'cell1', body)
res_dict = self.controller.update(req, 'cell1', body=body)
cell = res_dict['cell']
self.assertEqual(cell['name'], 'cell1')
@ -378,12 +384,12 @@ class CellsTest(BaseCellsTest):
req1 = self._get_request("cells/cell1")
req1.environ['nova.context'] = self.context
res_dict1 = self.controller.update(req1, 'cell1', body1)
res_dict1 = self.controller.update(req1, 'cell1', body=body1)
cell1 = res_dict1['cell']
req2 = self._get_request("cells/cell2")
req2.environ['nova.context'] = self.context
res_dict2 = self.controller.update(req2, 'cell2', body2)
res_dict2 = self.controller.update(req2, 'cell2', body=body2)
cell2 = res_dict2['cell']
self.assertEqual(cell1['name'], 'cell1')
@ -410,7 +416,8 @@ class CellsTest(BaseCellsTest):
self.assertEqual(cell_caps['cap2'], 'c;d')
def test_show_capacities(self):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
if (self.cell_extension == 'compute_extension:cells'):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
self.mox.StubOutWithMock(self.controller.cells_rpcapi,
'get_capacities')
response = {"ram_free":
@ -431,8 +438,9 @@ class CellsTest(BaseCellsTest):
self.assertEqual(response, res_dict['cell']['capacities'])
def test_show_capacity_fails_with_non_admin_context(self):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
rules = {"compute_extension:cells": "is_admin:true"}
if (self.cell_extension == 'compute_extension:cells'):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
rules = {self.cell_extension: "is_admin:true"}
self.policy.set_rules(rules)
self.mox.ReplayAll()
@ -443,7 +451,8 @@ class CellsTest(BaseCellsTest):
self.controller.capacities, req)
def test_show_capacities_for_invalid_cell(self):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
if (self.cell_extension == 'compute_extension:cells'):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
self.mox.StubOutWithMock(self.controller.cells_rpcapi,
'get_capacities')
self.controller.cells_rpcapi. \
@ -456,7 +465,8 @@ class CellsTest(BaseCellsTest):
self.controller.capacities, req, "invalid_cell")
def test_show_capacities_for_cell(self):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
if (self.cell_extension == 'compute_extension:cells'):
self.ext_mgr.is_loaded('os-cell-capacities').AndReturn(True)
self.mox.StubOutWithMock(self.controller.cells_rpcapi,
'get_capacities')
response = {"ram_free":
@ -509,7 +519,7 @@ class CellsTest(BaseCellsTest):
self.assertEqual(call_info['updated_since'], expected)
body = {'updated_since': 'skjdfkjsdkf'}
self.assertRaises(exc.HTTPBadRequest,
self.assertRaises(self.bad_request,
self.controller.sync_instances, req, body=body)
body = {'deleted': False}
@ -531,11 +541,11 @@ class CellsTest(BaseCellsTest):
self.assertEqual(call_info['deleted'], True)
body = {'deleted': 'foo'}
self.assertRaises(exc.HTTPBadRequest,
self.assertRaises(self.bad_request,
self.controller.sync_instances, req, body=body)
body = {'foo': 'meow'}
self.assertRaises(exc.HTTPBadRequest,
self.assertRaises(self.bad_request,
self.controller.sync_instances, req, body=body)
def test_sync_instances_fails_for_invalid_policy(self):
@ -550,7 +560,7 @@ class CellsTest(BaseCellsTest):
body = {}
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.sync_instances, req, body)
self.controller.sync_instances, req, body=body)
def test_cells_disabled(self):
self.flags(enable=False, group='cells')
@ -583,11 +593,34 @@ class CellsTest(BaseCellsTest):
self.controller.sync_instances, req, {})
class CellsTestV2(CellsTestV21):
cell_extension = 'compute_extension:cells'
bad_request = exc.HTTPBadRequest
def _get_cell_controller(self, ext_mgr):
return cells_ext_v2.Controller(ext_mgr)
def _get_request(self, resource):
return fakes.HTTPRequest.blank('/v2/fake/' + resource)
def test_cell_create_name_with_dot_raises(self):
body = {'cell': {'name': 'moo.cow',
'username': 'fred',
'password': 'secret',
'rpc_host': 'r3.example.org',
'type': 'parent'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPBadRequest,
self.controller.create, req, body=body)
class TestCellsXMLSerializer(BaseCellsTest):
def test_multiple_cells(self):
fixture = {'cells': self._get_all_cell_info()}
serializer = cells_ext.CellsTemplate()
serializer = cells_ext_v2.CellsTemplate()
output = serializer.serialize(fixture)
res_tree = etree.XML(output)
@ -604,7 +637,7 @@ class TestCellsXMLSerializer(BaseCellsTest):
'cap2': 'c;d'}}
fixture = {'cell': cell}
serializer = cells_ext.CellTemplate()
serializer = cells_ext_v2.CellTemplate()
output = serializer.serialize(fixture)
res_tree = etree.XML(output)
@ -631,7 +664,7 @@ class TestCellsXMLSerializer(BaseCellsTest):
'name': 'darksecret'}
fixture = {'cell': cell}
serializer = cells_ext.CellTemplate()
serializer = cells_ext_v2.CellTemplate()
output = serializer.serialize(fixture)
res_tree = etree.XML(output)
@ -656,12 +689,12 @@ class TestCellsXMLDeserializer(test.NoDBTestCase):
"<cell><name>testcell1</name><type>child</type>"
"<rpc_host>localhost</rpc_host>"
"%s</cell>") % caps_xml
deserializer = cells_ext.CellDeserializer()
deserializer = cells_ext_v2.CellDeserializer()
result = deserializer.deserialize(intext)
self.assertEqual(dict(body=expected), result)
def test_with_corrupt_xml(self):
deserializer = cells_ext.CellDeserializer()
deserializer = cells_ext_v2.CellDeserializer()
self.assertRaises(
exception.MalformedRequestBody,
deserializer.deserialize,

View File

@ -1,559 +0,0 @@
# Copyright 2011-2012 OpenStack Foundation
# 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 copy
from webob import exc
from nova.api.openstack.compute.plugins.v3 import cells as cells_ext
from nova.cells import rpcapi as cells_rpcapi
from nova import context
from nova import exception
from nova.openstack.common import timeutils
from nova import rpc
from nova import test
from nova.tests.api.openstack import fakes
class BaseCellsTest(test.NoDBTestCase):
def setUp(self):
super(BaseCellsTest, self).setUp()
self.fake_cells = [
dict(id=1, name='cell1', is_parent=True,
weight_scale=1.0, weight_offset=0.0,
transport_url='rabbit://bob:xxxx@r1.example.org/'),
dict(id=2, name='cell2', is_parent=False,
weight_scale=1.0, weight_offset=0.0,
transport_url='rabbit://alice:qwerty@r2.example.org/')]
self.fake_capabilities = [
{'cap1': '0,1', 'cap2': '2,3'},
{'cap3': '4,5', 'cap4': '5,6'}]
def fake_cell_get(_self, context, cell_name):
for cell in self.fake_cells:
if cell_name == cell['name']:
return cell
else:
raise exception.CellNotFound(cell_name=cell_name)
def fake_cell_create(_self, context, values):
cell = dict(id=1)
cell.update(values)
return cell
def fake_cell_update(_self, context, cell_id, values):
cell = fake_cell_get(_self, context, cell_id)
cell.update(values)
return cell
def fake_cells_api_get_all_cell_info(*args):
return self._get_all_cell_info(*args)
self.stubs.Set(cells_rpcapi.CellsAPI, 'cell_get', fake_cell_get)
self.stubs.Set(cells_rpcapi.CellsAPI, 'cell_update', fake_cell_update)
self.stubs.Set(cells_rpcapi.CellsAPI, 'cell_create', fake_cell_create)
self.stubs.Set(cells_rpcapi.CellsAPI, 'get_cell_info_for_neighbors',
fake_cells_api_get_all_cell_info)
def _get_all_cell_info(self, *args):
def insecure_transport_url(url):
transport_url = rpc.get_transport_url(url)
transport_url.hosts[0].password = None
return str(transport_url)
cells = copy.deepcopy(self.fake_cells)
cells[0]['transport_url'] = insecure_transport_url(
cells[0]['transport_url'])
cells[1]['transport_url'] = insecure_transport_url(
cells[1]['transport_url'])
for i, cell in enumerate(cells):
cell['capabilities'] = self.fake_capabilities[i]
return cells
class CellsTest(BaseCellsTest):
def setUp(self):
super(CellsTest, self).setUp()
self.controller = cells_ext.CellsController()
self.context = context.get_admin_context()
self.flags(enable=True, group='cells')
def _get_request(self, resource):
return fakes.HTTPRequestV3.blank('/' + resource)
def test_index(self):
req = self._get_request("cells")
res_dict = self.controller.index(req)
self.assertEqual(len(res_dict['cells']), 2)
for i, cell in enumerate(res_dict['cells']):
self.assertEqual(cell['name'], self.fake_cells[i]['name'])
self.assertNotIn('capabilitiles', cell)
self.assertNotIn('password', cell)
def test_detail(self):
req = self._get_request("cells/detail")
res_dict = self.controller.detail(req)
self.assertEqual(len(res_dict['cells']), 2)
for i, cell in enumerate(res_dict['cells']):
self.assertEqual(cell['name'], self.fake_cells[i]['name'])
self.assertEqual(cell['capabilities'], self.fake_capabilities[i])
self.assertNotIn('password', cell)
def test_show_bogus_cell_raises(self):
req = self._get_request("cells/bogus")
self.assertRaises(exc.HTTPNotFound, self.controller.show, req, 'bogus')
def test_get_cell_by_name(self):
req = self._get_request("cells/cell1")
res_dict = self.controller.show(req, 'cell1')
cell = res_dict['cell']
self.assertEqual(cell['name'], 'cell1')
self.assertEqual(cell['rpc_host'], 'r1.example.org')
self.assertNotIn('password', cell)
def _cell_delete(self):
call_info = {'delete_called': 0}
def fake_cell_delete(inst, context, cell_name):
self.assertEqual(cell_name, 'cell999')
call_info['delete_called'] += 1
self.stubs.Set(cells_rpcapi.CellsAPI, 'cell_delete', fake_cell_delete)
req = self._get_request("cells/cell999")
req.environ['nova.context'] = self.context
self.controller.delete(req, 'cell999')
self.assertEqual(call_info['delete_called'], 1)
def test_cell_delete(self):
# Test delete with just cells policy
rules = {"default": "is_admin:true",
"compute_extension:v3:os-cells": "is_admin:true"}
self.policy.set_rules(rules)
self._cell_delete()
def test_cell_delete_with_delete_policy(self):
self._cell_delete()
def test_delete_bogus_cell_raises(self):
def fake_cell_delete(inst, context, cell_name):
return 0
self.stubs.Set(cells_rpcapi.CellsAPI, 'cell_delete', fake_cell_delete)
req = self._get_request("cells/cell999")
req.environ['nova.context'] = self.context
self.assertRaises(exc.HTTPNotFound, self.controller.delete, req,
'cell999')
def test_cell_delete_fails_for_invalid_policy(self):
def fake_cell_delete(inst, context, cell_name):
pass
self.stubs.Set(cells_rpcapi.CellsAPI, 'cell_delete', fake_cell_delete)
req = self._get_request("cells/cell999")
req.environ['nova.context'] = self.context
req.environ["nova.context"].is_admin = False
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.delete, req, 'cell999')
def _cell_create_parent(self):
body = {'cell': {'name': 'meow',
'username': 'fred',
'password': 'fubar',
'rpc_host': 'r3.example.org',
'type': 'parent'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
res_dict = self.controller.create(req, body=body)
cell = res_dict['cell']
self.assertEqual(self.controller.create.wsgi_code, 201)
self.assertEqual(cell['name'], 'meow')
self.assertEqual(cell['username'], 'fred')
self.assertEqual(cell['rpc_host'], 'r3.example.org')
self.assertEqual(cell['type'], 'parent')
self.assertNotIn('password', cell)
def test_cell_create_parent(self):
# Test create with just cells policy
rules = {"default": "is_admin:true",
"compute_extension:v3:os-cells": "is_admin:true"}
self.policy.set_rules(rules)
self._cell_create_parent()
def test_cell_create_parent_with_create_policy(self):
self._cell_create_parent()
def _cell_create_child(self):
body = {'cell': {'name': 'meow',
'username': 'fred',
'password': 'fubar',
'rpc_host': 'r3.example.org',
'type': 'child'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
res_dict = self.controller.create(req, body=body)
cell = res_dict['cell']
self.assertEqual(self.controller.create.wsgi_code, 201)
self.assertEqual(cell['name'], 'meow')
self.assertEqual(cell['username'], 'fred')
self.assertEqual(cell['rpc_host'], 'r3.example.org')
self.assertEqual(cell['type'], 'child')
self.assertNotIn('password', cell)
self.assertNotIn('is_parent', cell)
def test_cell_create_child(self):
# Test create child with just cells policy
rules = {"default": "is_admin:true",
"compute_extension:v3:os-cells": "is_admin:true"}
self.policy.set_rules(rules)
self._cell_create_child()
def test_cell_create_child_with_create_policy(self):
self._cell_create_child()
def test_cell_create_no_name_raises(self):
body = {'cell': {'username': 'moocow',
'password': 'secret',
'rpc_host': 'r3.example.org',
'type': 'parent'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exception.ValidationError,
self.controller.create, req, body=body)
def test_cell_create_name_empty_string_raises(self):
body = {'cell': {'name': '',
'username': 'fred',
'password': 'secret',
'rpc_host': 'r3.example.org',
'type': 'parent'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exception.ValidationError,
self.controller.create, req, body=body)
def test_cell_create_name_with_bang_raises(self):
body = {'cell': {'name': 'moo!cow',
'username': 'fred',
'password': 'secret',
'rpc_host': 'r3.example.org',
'type': 'parent'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exception.ValidationError,
self.controller.create, req, body=body)
def test_cell_create_name_with_invalid_type_raises(self):
body = {'cell': {'name': 'moocow',
'username': 'fred',
'password': 'secret',
'rpc_host': 'r3.example.org',
'type': 'invalid'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
self.assertRaises(exception.ValidationError,
self.controller.create, req, body=body)
def test_cell_create_fails_for_invalid_policy(self):
body = {'cell': {'name': 'fake'}}
req = self._get_request("cells")
req.environ['nova.context'] = self.context
req.environ['nova.context'].is_admin = False
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.create, req, body=body)
def _cell_update(self):
body = {'cell': {'username': 'zeb',
'password': 'sneaky'}}
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
res_dict = self.controller.update(req, 'cell1', body=body)
cell = res_dict['cell']
self.assertEqual(cell['name'], 'cell1')
self.assertEqual(cell['rpc_host'], 'r1.example.org')
self.assertEqual(cell['username'], 'zeb')
self.assertNotIn('password', cell)
def test_cell_update(self):
# Test update with just cells policy
rules = {"default": "is_admin:true",
"compute_extension:v3:os-cells": "is_admin:true"}
self.policy.set_rules(rules)
self._cell_update()
def test_cell_update_with_update_policy(self):
self._cell_update()
def test_cell_update_fails_for_invalid_policy(self):
body = {'cell': {'name': 'got_changed'}}
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
req.environ['nova.context'].is_admin = False
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.create, req, body=body)
def test_cell_update_empty_name_raises(self):
body = {'cell': {'name': '',
'username': 'zeb',
'password': 'sneaky'}}
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
self.assertRaises(exception.ValidationError,
self.controller.update, req, 'cell1', body=body)
def test_cell_update_invalid_type_raises(self):
body = {'cell': {'username': 'zeb',
'type': 'invalid',
'password': 'sneaky'}}
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
self.assertRaises(exception.ValidationError,
self.controller.update, req, 'cell1', body=body)
def test_cell_update_without_type_specified(self):
body = {'cell': {'username': 'wingwj'}}
req = self._get_request("cells/cell1")
req.environ['nova.context'] = self.context
res_dict = self.controller.update(req, 'cell1', body=body)
cell = res_dict['cell']
self.assertEqual(cell['name'], 'cell1')
self.assertEqual(cell['rpc_host'], 'r1.example.org')
self.assertEqual(cell['username'], 'wingwj')
self.assertEqual(cell['type'], 'parent')
def test_cell_update_with_type_specified(self):
body1 = {'cell': {'username': 'wingwj', 'type': 'child'}}
body2 = {'cell': {'username': 'wingwj', 'type': 'parent'}}
req1 = self._get_request("cells/cell1")
req1.environ['nova.context'] = self.context
res_dict1 = self.controller.update(req1, 'cell1', body=body1)
cell1 = res_dict1['cell']
req2 = self._get_request("cells/cell2")
req2.environ['nova.context'] = self.context
res_dict2 = self.controller.update(req2, 'cell2', body=body2)
cell2 = res_dict2['cell']
self.assertEqual(cell1['name'], 'cell1')
self.assertEqual(cell1['rpc_host'], 'r1.example.org')
self.assertEqual(cell1['username'], 'wingwj')
self.assertEqual(cell1['type'], 'child')
self.assertEqual(cell2['name'], 'cell2')
self.assertEqual(cell2['rpc_host'], 'r2.example.org')
self.assertEqual(cell2['username'], 'wingwj')
self.assertEqual(cell2['type'], 'parent')
def test_cell_info(self):
caps = ['cap1=a;b', 'cap2=c;d']
self.flags(name='darksecret', capabilities=caps, group='cells')
req = self._get_request("cells/info")
res_dict = self.controller.info(req)
cell = res_dict['cell']
cell_caps = cell['capabilities']
self.assertEqual(cell['name'], 'darksecret')
self.assertEqual(cell_caps['cap1'], 'a;b')
self.assertEqual(cell_caps['cap2'], 'c;d')
def test_show_capacities(self):
self.mox.StubOutWithMock(self.controller.cells_rpcapi,
'get_capacities')
response = {"ram_free":
{"units_by_mb": {"8192": 0, "512": 13,
"4096": 1, "2048": 3, "16384": 0},
"total_mb": 7680},
"disk_free":
{"units_by_mb": {"81920": 11, "20480": 46,
"40960": 23, "163840": 5, "0": 0},
"total_mb": 1052672}
}
self.controller.cells_rpcapi.\
get_capacities(self.context, cell_name=None).AndReturn(response)
self.mox.ReplayAll()
req = self._get_request("cells/capacities")
req.environ["nova.context"] = self.context
res_dict = self.controller.capacities(req)
self.assertEqual(response, res_dict['cell']['capacities'])
def test_show_capacity_fails_with_non_admin_context(self):
rules = {"compute_extension:v3:os-cells": "is_admin:true"}
self.policy.set_rules(rules)
self.mox.ReplayAll()
req = self._get_request("cells/capacities")
req.environ["nova.context"] = self.context
req.environ["nova.context"].is_admin = False
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.capacities, req)
def test_show_capacities_for_invalid_cell(self):
self.mox.StubOutWithMock(self.controller.cells_rpcapi,
'get_capacities')
self.controller.cells_rpcapi. \
get_capacities(self.context, cell_name="invalid_cell").AndRaise(
exception.CellNotFound(cell_name="invalid_cell"))
self.mox.ReplayAll()
req = self._get_request("cells/invalid_cell/capacities")
req.environ["nova.context"] = self.context
self.assertRaises(exc.HTTPNotFound,
self.controller.capacities, req, "invalid_cell")
def test_show_capacities_for_cell(self):
self.mox.StubOutWithMock(self.controller.cells_rpcapi,
'get_capacities')
response = {"ram_free":
{"units_by_mb": {"8192": 0, "512": 13,
"4096": 1, "2048": 3, "16384": 0},
"total_mb": 7680},
"disk_free":
{"units_by_mb": {"81920": 11, "20480": 46,
"40960": 23, "163840": 5, "0": 0},
"total_mb": 1052672}
}
self.controller.cells_rpcapi.\
get_capacities(self.context, cell_name='cell_name').\
AndReturn(response)
self.mox.ReplayAll()
req = self._get_request("cells/capacities")
req.environ["nova.context"] = self.context
res_dict = self.controller.capacities(req, 'cell_name')
self.assertEqual(response, res_dict['cell']['capacities'])
def test_sync_instances(self):
call_info = {}
def sync_instances(self, context, **kwargs):
call_info['project_id'] = kwargs.get('project_id')
call_info['updated_since'] = kwargs.get('updated_since')
call_info['deleted'] = kwargs.get('deleted')
self.stubs.Set(cells_rpcapi.CellsAPI, 'sync_instances', sync_instances)
req = self._get_request("cells/sync_instances")
req.environ['nova.context'] = self.context
body = {}
self.controller.sync_instances(req, body=body)
self.assertIsNone(call_info['project_id'])
self.assertIsNone(call_info['updated_since'])
body = {'project_id': 'test-project'}
self.controller.sync_instances(req, body=body)
self.assertEqual(call_info['project_id'], 'test-project')
self.assertIsNone(call_info['updated_since'])
expected = timeutils.utcnow().isoformat()
if not expected.endswith("+00:00"):
expected += "+00:00"
body = {'updated_since': expected}
self.controller.sync_instances(req, body=body)
self.assertIsNone(call_info['project_id'])
self.assertEqual(call_info['updated_since'], expected)
body = {'updated_since': 'skjdfkjsdkf'}
self.assertRaises(exception.ValidationError,
self.controller.sync_instances, req, body=body)
body = {'deleted': False}
self.controller.sync_instances(req, body=body)
self.assertIsNone(call_info['project_id'])
self.assertIsNone(call_info['updated_since'])
self.assertEqual(call_info['deleted'], False)
body = {'deleted': 'False'}
self.controller.sync_instances(req, body=body)
self.assertIsNone(call_info['project_id'])
self.assertIsNone(call_info['updated_since'])
self.assertEqual(call_info['deleted'], False)
body = {'deleted': 'True'}
self.controller.sync_instances(req, body=body)
self.assertIsNone(call_info['project_id'])
self.assertIsNone(call_info['updated_since'])
self.assertEqual(call_info['deleted'], True)
body = {'deleted': 'foo'}
self.assertRaises(exception.ValidationError,
self.controller.sync_instances, req, body=body)
body = {'foo': 'meow'}
self.assertRaises(exception.ValidationError,
self.controller.sync_instances, req, body=body)
def test_sync_instances_fails_for_invalid_policy(self):
def sync_instances(self, context, **kwargs):
pass
self.stubs.Set(cells_rpcapi.CellsAPI, 'sync_instances', sync_instances)
req = self._get_request("cells/sync_instances")
req.environ['nova.context'] = self.context
req.environ['nova.context'].is_admin = False
body = {}
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.sync_instances, req, body=body)
def test_cells_disabled(self):
self.flags(enable=False, group='cells')
req = self._get_request("cells")
self.assertRaises(exc.HTTPNotImplemented,
self.controller.index, req)
req = self._get_request("cells/detail")
self.assertRaises(exc.HTTPNotImplemented,
self.controller.detail, req)
req = self._get_request("cells/cell1")
self.assertRaises(exc.HTTPNotImplemented,
self.controller.show, req)
self.assertRaises(exc.HTTPNotImplemented,
self.controller.delete, req, 'cell999')
req = self._get_request("cells/cells")
self.assertRaises(exc.HTTPNotImplemented,
self.controller.create, req, {})
req = self._get_request("cells/capacities")
self.assertRaises(exc.HTTPNotImplemented,
self.controller.capacities, req)
req = self._get_request("cells/sync_instances")
self.assertRaises(exc.HTTPNotImplemented,
self.controller.sync_instances, req, {})