Port os-server-groups extension to work in v2.1/v3 framework
Ports v2 os-server-groups extension and adapts it to the v2.1/v3 API framework. API behaviour is identical with the exception that there is no support for XML. Also - unittest code modified to share testing with both v2/v2.1 - Adds expected error decorators for API methods - Adds api sample tests Partially implements blueprint v2-on-v3-api Change-Id: I52e49e6e85a7516e3b184601374e5c987f60a9a0
This commit is contained in:
parent
4e23bff302
commit
89a02bed57
@ -0,0 +1,9 @@
|
||||
{
|
||||
"server_group": {
|
||||
"id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
|
||||
"name": "test",
|
||||
"policies": ["anti-affinity"],
|
||||
"members": [],
|
||||
"metadata": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"server_groups": [
|
||||
{
|
||||
"id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
|
||||
"name": "test",
|
||||
"policies": ["anti-affinity"],
|
||||
"members": [],
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"server_group": {
|
||||
"name": "test",
|
||||
"policies": ["anti-affinity"]
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"server_group": {
|
||||
"id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
|
||||
"name": "test",
|
||||
"policies": ["anti-affinity"],
|
||||
"members": [],
|
||||
"metadata": {}
|
||||
}
|
||||
}
|
@ -228,6 +228,8 @@
|
||||
"compute_extension:server_usage": "",
|
||||
"compute_extension:v3:os-server-usage": "",
|
||||
"compute_extension:v3:os-server-usage:discoverable": "",
|
||||
"compute_extension:v3:os-server-groups": "",
|
||||
"compute_extension:v3:os-server-groups:discoverable": "",
|
||||
"compute_extension:services": "rule:admin_api",
|
||||
"compute_extension:v3:os-services": "rule:admin_api",
|
||||
"compute_extension:v3:os-services:discoverable": "",
|
||||
|
198
nova/api/openstack/compute/plugins/v3/server_groups.py
Normal file
198
nova/api/openstack/compute/plugins/v3/server_groups.py
Normal file
@ -0,0 +1,198 @@
|
||||
# Copyright (c) 2014 Cisco Systems, Inc.
|
||||
# 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.
|
||||
|
||||
"""The Server Group API Extension."""
|
||||
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
import nova.exception
|
||||
from nova.i18n import _
|
||||
from nova import objects
|
||||
from nova import utils
|
||||
|
||||
ALIAS = "os-server-groups"
|
||||
|
||||
# NOTE(russellb) There is one other policy, 'legacy', but we don't allow that
|
||||
# being set via the API. It's only used when a group gets automatically
|
||||
# created to support the legacy behavior of the 'group' scheduler hint.
|
||||
SUPPORTED_POLICIES = ['anti-affinity', 'affinity']
|
||||
|
||||
authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
|
||||
|
||||
|
||||
def _authorize_context(req):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
return context
|
||||
|
||||
|
||||
class ServerGroupController(wsgi.Controller):
|
||||
"""The Server group API controller for the OpenStack API."""
|
||||
|
||||
def _format_server_group(self, context, group):
|
||||
# the id field has its value as the uuid of the server group
|
||||
# There is no 'uuid' key in server_group seen by clients.
|
||||
# In addition, clients see policies as a ["policy-name"] list;
|
||||
# and they see members as a ["server-id"] list.
|
||||
server_group = {}
|
||||
server_group['id'] = group.uuid
|
||||
server_group['name'] = group.name
|
||||
server_group['policies'] = group.policies or []
|
||||
# NOTE(danms): This has been exposed to the user, but never used.
|
||||
# Since we can't remove it, just make sure it's always empty.
|
||||
server_group['metadata'] = {}
|
||||
members = []
|
||||
if group.members:
|
||||
# Display the instances that are not deleted.
|
||||
filters = {'uuid': group.members, 'deleted': False}
|
||||
instances = objects.InstanceList.get_by_filters(
|
||||
context, filters=filters)
|
||||
members = [instance.uuid for instance in instances]
|
||||
server_group['members'] = members
|
||||
return server_group
|
||||
|
||||
def _validate_policies(self, policies):
|
||||
"""Validate the policies.
|
||||
|
||||
Validates that there are no contradicting policies, for example
|
||||
'anti-affinity' and 'affinity' in the same group.
|
||||
Validates that the defined policies are supported.
|
||||
:param policies: the given policies of the server_group
|
||||
"""
|
||||
if ('anti-affinity' in policies and
|
||||
'affinity' in policies):
|
||||
msg = _("Conflicting policies configured!")
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
not_supported = [policy for policy in policies
|
||||
if policy not in SUPPORTED_POLICIES]
|
||||
if not_supported:
|
||||
msg = _("Invalid policies: %s") % ', '.join(not_supported)
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
|
||||
# Note(wingwj): It doesn't make sense to store duplicate policies.
|
||||
if sorted(set(policies)) != sorted(policies):
|
||||
msg = _("Duplicate policies configured!")
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
|
||||
def _validate_input_body(self, body, entity_name):
|
||||
if not self.is_valid_body(body, entity_name):
|
||||
msg = _("the body is invalid.")
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
|
||||
subbody = dict(body[entity_name])
|
||||
|
||||
expected_fields = ['name', 'policies']
|
||||
for field in expected_fields:
|
||||
value = subbody.pop(field, None)
|
||||
if not value:
|
||||
msg = _("'%s' is either missing or empty.") % field
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
if field == 'name':
|
||||
utils.check_string_length(value, field,
|
||||
min_length=1, max_length=255)
|
||||
if not common.VALID_NAME_REGEX.search(value):
|
||||
msg = _("Invalid format for name: '%s'") % value
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
elif field == 'policies':
|
||||
if isinstance(value, list):
|
||||
[utils.check_string_length(v, field,
|
||||
min_length=1, max_length=255) for v in value]
|
||||
self._validate_policies(value)
|
||||
else:
|
||||
msg = _("'%s' is not a list") % value
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
|
||||
if subbody:
|
||||
msg = _("unsupported fields: %s") % subbody.keys()
|
||||
raise nova.exception.InvalidInput(reason=msg)
|
||||
|
||||
@extensions.expected_errors(404)
|
||||
def show(self, req, id):
|
||||
"""Return data about the given server group."""
|
||||
context = _authorize_context(req)
|
||||
try:
|
||||
sg = objects.InstanceGroup.get_by_uuid(context, id)
|
||||
except nova.exception.InstanceGroupNotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.format_message())
|
||||
return {'server_group': self._format_server_group(context, sg)}
|
||||
|
||||
@extensions.expected_errors(404)
|
||||
def delete(self, req, id):
|
||||
"""Delete an server group."""
|
||||
context = _authorize_context(req)
|
||||
try:
|
||||
sg = objects.InstanceGroup.get_by_uuid(context, id)
|
||||
sg.destroy(context)
|
||||
except nova.exception.InstanceGroupNotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.format_message())
|
||||
return webob.Response(status_int=204)
|
||||
|
||||
@extensions.expected_errors(())
|
||||
def index(self, req):
|
||||
"""Returns a list of server groups."""
|
||||
context = _authorize_context(req)
|
||||
project_id = context.project_id
|
||||
if 'all_projects' in req.GET and context.is_admin:
|
||||
sgs = objects.InstanceGroupList.get_all(context)
|
||||
else:
|
||||
sgs = objects.InstanceGroupList.get_by_project_id(
|
||||
context, project_id)
|
||||
limited_list = common.limited(sgs.objects, req)
|
||||
result = [self._format_server_group(context, group)
|
||||
for group in limited_list]
|
||||
return {'server_groups': result}
|
||||
|
||||
@extensions.expected_errors(400)
|
||||
def create(self, req, body):
|
||||
"""Creates a new server group."""
|
||||
context = _authorize_context(req)
|
||||
|
||||
try:
|
||||
self._validate_input_body(body, 'server_group')
|
||||
except nova.exception.InvalidInput as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
vals = body['server_group']
|
||||
sg = objects.InstanceGroup(context)
|
||||
sg.project_id = context.project_id
|
||||
sg.user_id = context.user_id
|
||||
try:
|
||||
sg.name = vals.get('name')
|
||||
sg.policies = vals.get('policies')
|
||||
sg.create()
|
||||
except ValueError as e:
|
||||
raise exc.HTTPBadRequest(explanation=e)
|
||||
|
||||
return {'server_group': self._format_server_group(context, sg)}
|
||||
|
||||
|
||||
class ServerGroups(extensions.V3APIExtensionBase):
|
||||
"""Server group support."""
|
||||
name = "ServerGroups"
|
||||
alias = ALIAS
|
||||
version = 1
|
||||
|
||||
def get_resources(self):
|
||||
res = extensions.ResourceExtension(
|
||||
ALIAS, controller=ServerGroupController(),
|
||||
member_actions={"action": "POST", })
|
||||
return [res]
|
||||
|
||||
def get_controller_extensions(self):
|
||||
return []
|
@ -17,6 +17,7 @@ from lxml import etree
|
||||
import webob
|
||||
|
||||
from nova.api.openstack.compute.contrib import server_groups
|
||||
from nova.api.openstack.compute.plugins.v3 import server_groups as sg_v3
|
||||
from nova.api.openstack import wsgi
|
||||
from nova import context
|
||||
import nova.db
|
||||
@ -78,20 +79,29 @@ def server_group_db(sg):
|
||||
return AttrDict(attrs)
|
||||
|
||||
|
||||
class ServerGroupTest(test.TestCase):
|
||||
class ServerGroupTestV21(test.TestCase):
|
||||
|
||||
sg_controller_cls = sg_v3.ServerGroupController
|
||||
|
||||
def setUp(self):
|
||||
super(ServerGroupTest, self).setUp()
|
||||
self.controller = server_groups.ServerGroupController()
|
||||
self.app = fakes.wsgi_app(init_only=('os-server-groups',))
|
||||
super(ServerGroupTestV21, self).setUp()
|
||||
self.controller = self.sg_controller_cls()
|
||||
self.app = self._get_app()
|
||||
|
||||
def _get_app(self):
|
||||
return fakes.wsgi_app_v3(init_only=('os-server-groups',))
|
||||
|
||||
def _get_url(self):
|
||||
return '/v3'
|
||||
|
||||
def test_create_server_group_with_no_policies(self):
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
sgroup = server_group_template()
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
def test_create_server_group_normal(self):
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
sgroup = server_group_template()
|
||||
policies = ['anti-affinity']
|
||||
sgroup['policies'] = policies
|
||||
@ -123,7 +133,7 @@ class ServerGroupTest(test.TestCase):
|
||||
def test_display_members(self):
|
||||
ctx = context.RequestContext('fake_user', 'fake')
|
||||
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
res_dict = self.controller.show(req, ig_uuid)
|
||||
result_members = res_dict['server_group']['members']
|
||||
self.assertEqual(2, len(result_members))
|
||||
@ -133,7 +143,7 @@ class ServerGroupTest(test.TestCase):
|
||||
def test_display_active_members_only(self):
|
||||
ctx = context.RequestContext('fake_user', 'fake')
|
||||
(ig_uuid, instances, members) = self._create_groups_and_instances(ctx)
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
|
||||
# delete an instance
|
||||
instances[1].destroy(ctx)
|
||||
@ -150,66 +160,66 @@ class ServerGroupTest(test.TestCase):
|
||||
def test_create_server_group_with_illegal_name(self):
|
||||
# blank name
|
||||
sgroup = server_group_template(name='', policies=['test_policy'])
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# name with length 256
|
||||
sgroup = server_group_template(name='1234567890' * 26,
|
||||
policies=['test_policy'])
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# non-string name
|
||||
sgroup = server_group_template(name=12, policies=['test_policy'])
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# name with leading spaces
|
||||
sgroup = server_group_template(name=' leading spaces',
|
||||
policies=['test_policy'])
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# name with trailing spaces
|
||||
sgroup = server_group_template(name='trailing space ',
|
||||
policies=['test_policy'])
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# name with all spaces
|
||||
sgroup = server_group_template(name=' ',
|
||||
policies=['test_policy'])
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
def test_create_server_group_with_illegal_policies(self):
|
||||
# blank policy
|
||||
sgroup = server_group_template(name='fake-name', policies='')
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# policy as integer
|
||||
sgroup = server_group_template(name='fake-name', policies=7)
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# policy as string
|
||||
sgroup = server_group_template(name='fake-name', policies='invalid')
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
# policy as None
|
||||
sgroup = server_group_template(name='fake-name', policies=None)
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
@ -217,7 +227,7 @@ class ServerGroupTest(test.TestCase):
|
||||
sgroup = server_group_template()
|
||||
policies = ['anti-affinity', 'affinity']
|
||||
sgroup['policies'] = policies
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
@ -225,7 +235,7 @@ class ServerGroupTest(test.TestCase):
|
||||
sgroup = server_group_template()
|
||||
policies = ['affinity', 'affinity']
|
||||
sgroup['policies'] = policies
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
@ -233,18 +243,18 @@ class ServerGroupTest(test.TestCase):
|
||||
sgroup = server_group_template()
|
||||
policies = ['storage-affinity', 'anti-affinity', 'rack-affinity']
|
||||
sgroup['policies'] = policies
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, {'server_group': sgroup})
|
||||
|
||||
def test_create_server_group_with_no_body(self):
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, req, None)
|
||||
|
||||
def test_create_server_group_with_no_server_group(self):
|
||||
body = {'no-instanceGroup': None}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, req, body)
|
||||
|
||||
@ -273,7 +283,7 @@ class ServerGroupTest(test.TestCase):
|
||||
self.stubs.Set(nova.db, 'instance_group_get_all_by_project_id',
|
||||
return_server_groups)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() + '/os-server-groups')
|
||||
res_dict = self.controller.index(req)
|
||||
self.assertEqual(res_dict, expected)
|
||||
|
||||
@ -312,7 +322,7 @@ class ServerGroupTest(test.TestCase):
|
||||
self.stubs.Set(nova.db, 'instance_group_get_all_by_project_id',
|
||||
return_tenant_server_groups)
|
||||
|
||||
path = '/v2/fake/os-server-groups?all_projects=True'
|
||||
path = self._get_url() + '/os-server-groups?all_projects=True'
|
||||
|
||||
req = fakes.HTTPRequest.blank(path, use_admin_context=True)
|
||||
res_dict = self.controller.index(req)
|
||||
@ -338,17 +348,29 @@ class ServerGroupTest(test.TestCase):
|
||||
self.stubs.Set(nova.db, 'instance_group_get',
|
||||
return_server_group)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups/123')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() +
|
||||
'/os-server-groups/123')
|
||||
resp = self.controller.delete(req, '123')
|
||||
self.assertTrue(self.called)
|
||||
self.assertEqual(resp.status_int, 204)
|
||||
|
||||
def test_delete_non_existing_server_group(self):
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups/invalid')
|
||||
req = fakes.HTTPRequest.blank(self._get_url() +
|
||||
'/os-server-groups/invalid')
|
||||
self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
|
||||
req, 'invalid')
|
||||
|
||||
|
||||
class ServerGroupTestV2(ServerGroupTestV21):
|
||||
sg_controller_cls = server_groups.ServerGroupController
|
||||
|
||||
def _get_app(self):
|
||||
return fakes.wsgi_app(init_only=('os-server-groups',))
|
||||
|
||||
def _get_url(self):
|
||||
return '/v2/fake'
|
||||
|
||||
|
||||
class TestServerGroupXMLDeserializer(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -273,6 +273,7 @@ policy_data = """
|
||||
"compute_extension:v3:os-server-password": "",
|
||||
"compute_extension:server_usage": "",
|
||||
"compute_extension:v3:os-server-usage": "",
|
||||
"compute_extension:v3:os-server-groups": "",
|
||||
"compute_extension:services": "",
|
||||
"compute_extension:v3:os-services": "",
|
||||
"compute_extension:shelve": "",
|
||||
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"server_group": {
|
||||
"id": "%(id)s",
|
||||
"name": "%(name)s",
|
||||
"policies": ["anti-affinity"],
|
||||
"members": [],
|
||||
"metadata": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"server_groups": [
|
||||
{
|
||||
"id": "%(id)s",
|
||||
"name": "test",
|
||||
"policies": ["anti-affinity"],
|
||||
"members": [],
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"server_group": {
|
||||
"name": "%(name)s",
|
||||
"policies": ["anti-affinity"]
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"server_group": {
|
||||
"id": "%(id)s",
|
||||
"name": "%(name)s",
|
||||
"policies": ["anti-affinity"],
|
||||
"members": [],
|
||||
"metadata": {}
|
||||
}
|
||||
}
|
||||
|
66
nova/tests/integrated/v3/test_server_groups.py
Normal file
66
nova/tests/integrated/v3/test_server_groups.py
Normal file
@ -0,0 +1,66 @@
|
||||
# Copyright 2012 Nebula, Inc.
|
||||
# Copyright 2014 IBM Corp.
|
||||
#
|
||||
# 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 nova.tests.integrated.v3 import test_servers
|
||||
|
||||
|
||||
class ServerGroupsSampleJsonTest(test_servers.ServersSampleBase):
|
||||
extension_name = "os-server-groups"
|
||||
|
||||
def _get_create_subs(self):
|
||||
return {'name': 'test'}
|
||||
|
||||
def _post_server_group(self):
|
||||
"""Verify the response status and returns the UUID of the
|
||||
newly created server group.
|
||||
"""
|
||||
subs = self._get_create_subs()
|
||||
response = self._do_post('os-server-groups',
|
||||
'server-groups-post-req', subs)
|
||||
subs = self._get_regexes()
|
||||
subs['name'] = 'test'
|
||||
return self._verify_response('server-groups-post-resp',
|
||||
subs, response, 200)
|
||||
|
||||
def _create_server_group(self):
|
||||
subs = self._get_create_subs()
|
||||
return self._do_post('os-server-groups',
|
||||
'server-groups-post-req', subs)
|
||||
|
||||
def test_server_groups_post(self):
|
||||
return self._post_server_group()
|
||||
|
||||
def test_server_groups_list(self):
|
||||
subs = self._get_create_subs()
|
||||
uuid = self._post_server_group()
|
||||
response = self._do_get('os-server-groups')
|
||||
subs.update(self._get_regexes())
|
||||
subs['id'] = uuid
|
||||
self._verify_response('server-groups-list-resp',
|
||||
subs, response, 200)
|
||||
|
||||
def test_server_groups_get(self):
|
||||
# Get api sample of server groups get request.
|
||||
subs = {'name': 'test'}
|
||||
uuid = self._post_server_group()
|
||||
subs['id'] = uuid
|
||||
response = self._do_get('os-server-groups/%s' % uuid)
|
||||
|
||||
self._verify_response('server-groups-get-resp', subs, response, 200)
|
||||
|
||||
def test_server_groups_delete(self):
|
||||
uuid = self._post_server_group()
|
||||
response = self._do_delete('os-server-groups/%s' % uuid)
|
||||
self.assertEqual(response.status, 204)
|
@ -106,6 +106,7 @@ nova.api.v3.extensions =
|
||||
server_metadata = nova.api.openstack.compute.plugins.v3.server_metadata:ServerMetadata
|
||||
server_password = nova.api.openstack.compute.plugins.v3.server_password:ServerPassword
|
||||
server_usage = nova.api.openstack.compute.plugins.v3.server_usage:ServerUsage
|
||||
server_groups = nova.api.openstack.compute.plugins.v3.server_groups:ServerGroups
|
||||
servers = nova.api.openstack.compute.plugins.v3.servers:Servers
|
||||
services = nova.api.openstack.compute.plugins.v3.services:Services
|
||||
shelve = nova.api.openstack.compute.plugins.v3.shelve:Shelve
|
||||
|
Loading…
Reference in New Issue
Block a user