API for shelving
Adds new 'shelve', 'shelveOffload'/'shelve_offload'(V3), and 'unshelve' actions to the API. Exposes the functionality already provided in the compute api. Part of bp shelve-instance Co-author: Dan Smith <danms@us.ibm.com> (Instance objects) Change-Id: Idd485b591730c6ac025ee57a1242afdd02191b2f
This commit is contained in:
parent
b83e3b64a1
commit
e53fb7dcdd
@ -512,6 +512,14 @@
|
|||||||
"namespace": "http://docs.openstack.org/compute/ext/extended_services/api/v2",
|
"namespace": "http://docs.openstack.org/compute/ext/extended_services/api/v2",
|
||||||
"updated": "2013-05-17T00:00:00-00:00"
|
"updated": "2013-05-17T00:00:00-00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"alias": "os-shelve",
|
||||||
|
"description": "Instance shelve mode.",
|
||||||
|
"links": [],
|
||||||
|
"name": "Shelve",
|
||||||
|
"namespace": "http://docs.openstack.org/compute/ext/shelve/api/v1.1",
|
||||||
|
"updated": "2013-04-06T00:00:00+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"alias": "os-simple-tenant-usage",
|
"alias": "os-simple-tenant-usage",
|
||||||
"description": "Simple tenant usage extension.",
|
"description": "Simple tenant usage extension.",
|
||||||
|
@ -210,6 +210,9 @@
|
|||||||
<extension alias="os-extended-services" updated="2013-05-17T00:00:00-00:00" namespace="http://docs.openstack.org/compute/ext/extended_services/api/v2" name="ExtendedServices">
|
<extension alias="os-extended-services" updated="2013-05-17T00:00:00-00:00" namespace="http://docs.openstack.org/compute/ext/extended_services/api/v2" name="ExtendedServices">
|
||||||
<description>Extended services support.</description>
|
<description>Extended services support.</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
<extension alias="os-shelve" updated="2013-04-06T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/shelve/api/v1.1" name="Shelve">
|
||||||
|
<description>Instance shelve mode.</description>
|
||||||
|
</extension>
|
||||||
<extension alias="os-simple-tenant-usage" updated="2011-08-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1" name="SimpleTenantUsage">
|
<extension alias="os-simple-tenant-usage" updated="2011-08-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1" name="SimpleTenantUsage">
|
||||||
<description>Simple tenant usage extension.</description>
|
<description>Simple tenant usage extension.</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
3
doc/api_samples/os-shelve/os-shelve.json
Normal file
3
doc/api_samples/os-shelve/os-shelve.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"shelve": null
|
||||||
|
}
|
2
doc/api_samples/os-shelve/os-shelve.xml
Normal file
2
doc/api_samples/os-shelve/os-shelve.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shelve/>
|
16
doc/api_samples/os-shelve/server-post-req.json
Normal file
16
doc/api_samples/os-shelve/server-post-req.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"server" : {
|
||||||
|
"name" : "new-server-test",
|
||||||
|
"imageRef" : "http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
||||||
|
"flavorRef" : "http://openstack.example.com/openstack/flavors/1",
|
||||||
|
"metadata" : {
|
||||||
|
"My Server Name" : "Apache1"
|
||||||
|
},
|
||||||
|
"personality" : [
|
||||||
|
{
|
||||||
|
"path" : "/etc/banner.txt",
|
||||||
|
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
19
doc/api_samples/os-shelve/server-post-req.xml
Normal file
19
doc/api_samples/os-shelve/server-post-req.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b" flavorRef="http://openstack.example.com/openstack/flavors/1" name="new-server-test">
|
||||||
|
<metadata>
|
||||||
|
<meta key="My Server Name">Apache1</meta>
|
||||||
|
</metadata>
|
||||||
|
<personality>
|
||||||
|
<file path="/etc/banner.txt">
|
||||||
|
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||||
|
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||||
|
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||||
|
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||||
|
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||||
|
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||||
|
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||||
|
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||||
|
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||||
|
</file>
|
||||||
|
</personality>
|
||||||
|
</server>
|
16
doc/api_samples/os-shelve/server-post-resp.json
Normal file
16
doc/api_samples/os-shelve/server-post-resp.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"adminPass": "bGZzzzeaSp9z",
|
||||||
|
"id": "9582b762-0964-4509-8fff-0146c02abe31",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "http://openstack.example.com/v2/openstack/servers/9582b762-0964-4509-8fff-0146c02abe31",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "http://openstack.example.com/openstack/servers/9582b762-0964-4509-8fff-0146c02abe31",
|
||||||
|
"rel": "bookmark"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
6
doc/api_samples/os-shelve/server-post-resp.xml
Normal file
6
doc/api_samples/os-shelve/server-post-resp.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="380d8ce9-bd82-4182-b643-b72232cd11d0" adminPass="LePA926cLP3R">
|
||||||
|
<metadata/>
|
||||||
|
<atom:link href="http://openstack.example.com/v2/openstack/servers/380d8ce9-bd82-4182-b643-b72232cd11d0" rel="self"/>
|
||||||
|
<atom:link href="http://openstack.example.com/openstack/servers/380d8ce9-bd82-4182-b643-b72232cd11d0" rel="bookmark"/>
|
||||||
|
</server>
|
@ -162,10 +162,16 @@
|
|||||||
"compute_extension:services": "rule:admin_api",
|
"compute_extension:services": "rule:admin_api",
|
||||||
"compute_extension:v3:os-services": "rule:admin_api",
|
"compute_extension:v3:os-services": "rule:admin_api",
|
||||||
"compute_extension:v3:servers:discoverable": "",
|
"compute_extension:v3:servers:discoverable": "",
|
||||||
|
"compute_extension:shelve": "",
|
||||||
|
"compute_extension:shelveOffload": "rule:admin_api",
|
||||||
|
"compute_extension:v3:os-shelve:shelve": "",
|
||||||
|
"compute_extension:v3:os-shelve:shelve_offload": "rule:admin_api",
|
||||||
"compute_extension:simple_tenant_usage:show": "rule:admin_or_owner",
|
"compute_extension:simple_tenant_usage:show": "rule:admin_or_owner",
|
||||||
"compute_extension:v3:os-simple-tenant-usage:show": "rule:admin_or_owner",
|
"compute_extension:v3:os-simple-tenant-usage:show": "rule:admin_or_owner",
|
||||||
"compute_extension:simple_tenant_usage:list": "rule:admin_api",
|
"compute_extension:simple_tenant_usage:list": "rule:admin_api",
|
||||||
"compute_extension:v3:os-simple-tenant-usage:list": "rule:admin_api",
|
"compute_extension:v3:os-simple-tenant-usage:list": "rule:admin_api",
|
||||||
|
"compute_extension:unshelve": "",
|
||||||
|
"compute_extension:v3:os-shelve:unshelve": "",
|
||||||
"compute_extension:users": "rule:admin_api",
|
"compute_extension:users": "rule:admin_api",
|
||||||
"compute_extension:virtual_interfaces": "",
|
"compute_extension:virtual_interfaces": "",
|
||||||
"compute_extension:virtual_storage_arrays": "",
|
"compute_extension:virtual_storage_arrays": "",
|
||||||
|
@ -103,6 +103,12 @@ _STATE_MAP = {
|
|||||||
vm_states.SOFT_DELETED: {
|
vm_states.SOFT_DELETED: {
|
||||||
'default': 'DELETED',
|
'default': 'DELETED',
|
||||||
},
|
},
|
||||||
|
vm_states.SHELVED: {
|
||||||
|
'default': 'SHELVED',
|
||||||
|
},
|
||||||
|
vm_states.SHELVED_OFFLOADED: {
|
||||||
|
'default': 'SHELVED_OFFLOADED',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
100
nova/api/openstack/compute/contrib/shelve.py
Normal file
100
nova/api/openstack/compute/contrib/shelve.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
# Copyright 2013 Rackspace Hosting
|
||||||
|
#
|
||||||
|
# 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 shelved mode extension."""
|
||||||
|
|
||||||
|
import webob
|
||||||
|
from webob import exc
|
||||||
|
|
||||||
|
from nova.api.openstack import common
|
||||||
|
from nova.api.openstack import extensions as exts
|
||||||
|
from nova.api.openstack import wsgi
|
||||||
|
from nova import compute
|
||||||
|
from nova import exception
|
||||||
|
|
||||||
|
|
||||||
|
auth_shelve = exts.extension_authorizer('compute', 'shelve')
|
||||||
|
auth_shelve_offload = exts.extension_authorizer('compute', 'shelveOffload')
|
||||||
|
auth_unshelve = exts.extension_authorizer('compute', 'unshelve')
|
||||||
|
|
||||||
|
|
||||||
|
class ShelveController(wsgi.Controller):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ShelveController, self).__init__(*args, **kwargs)
|
||||||
|
self.compute_api = compute.API()
|
||||||
|
|
||||||
|
def _get_instance(self, context, instance_id):
|
||||||
|
try:
|
||||||
|
return self.compute_api.get(context, instance_id,
|
||||||
|
want_objects=True)
|
||||||
|
except exception.InstanceNotFound:
|
||||||
|
msg = _("Server not found")
|
||||||
|
raise exc.HTTPNotFound(msg)
|
||||||
|
|
||||||
|
@wsgi.action('shelve')
|
||||||
|
def _shelve(self, req, id, body):
|
||||||
|
"""Move an instance into shelved mode."""
|
||||||
|
context = req.environ["nova.context"]
|
||||||
|
auth_shelve(context)
|
||||||
|
|
||||||
|
instance = self._get_instance(context, id)
|
||||||
|
try:
|
||||||
|
self.compute_api.shelve(context, instance)
|
||||||
|
except exception.InstanceInvalidState as state_error:
|
||||||
|
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||||
|
'shelve')
|
||||||
|
|
||||||
|
return webob.Response(status_int=202)
|
||||||
|
|
||||||
|
@wsgi.action('shelveOffload')
|
||||||
|
def _shelve_offload(self, req, id, body):
|
||||||
|
"""Force removal of a shelved instance from the compute node."""
|
||||||
|
context = req.environ["nova.context"]
|
||||||
|
auth_shelve_offload(context)
|
||||||
|
|
||||||
|
instance = self._get_instance(context, id)
|
||||||
|
try:
|
||||||
|
self.compute_api.shelve_offload(context, instance)
|
||||||
|
except exception.InstanceInvalidState as state_error:
|
||||||
|
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||||
|
'shelveOffload')
|
||||||
|
|
||||||
|
return webob.Response(status_int=202)
|
||||||
|
|
||||||
|
@wsgi.action('unshelve')
|
||||||
|
def _unshelve(self, req, id, body):
|
||||||
|
"""Restore an instance from shelved mode."""
|
||||||
|
context = req.environ["nova.context"]
|
||||||
|
auth_unshelve(context)
|
||||||
|
instance = self._get_instance(context, id)
|
||||||
|
try:
|
||||||
|
self.compute_api.unshelve(context, instance)
|
||||||
|
except exception.InstanceInvalidState as state_error:
|
||||||
|
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||||
|
'unshelve')
|
||||||
|
return webob.Response(status_int=202)
|
||||||
|
|
||||||
|
|
||||||
|
class Shelve(exts.ExtensionDescriptor):
|
||||||
|
"""Instance shelve mode."""
|
||||||
|
|
||||||
|
name = "Shelve"
|
||||||
|
alias = "os-shelve"
|
||||||
|
namespace = "http://docs.openstack.org/compute/ext/shelve/api/v1.1"
|
||||||
|
updated = "2013-04-06T00:00:00+00:00"
|
||||||
|
|
||||||
|
def get_controller_extensions(self):
|
||||||
|
controller = ShelveController()
|
||||||
|
extension = exts.ControllerExtension(self, 'servers', controller)
|
||||||
|
return [extension]
|
105
nova/api/openstack/compute/plugins/v3/shelve.py
Normal file
105
nova/api/openstack/compute/plugins/v3/shelve.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# Copyright 2013 Rackspace Hosting
|
||||||
|
#
|
||||||
|
# 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 shelved mode extension."""
|
||||||
|
|
||||||
|
import webob
|
||||||
|
from webob import exc
|
||||||
|
|
||||||
|
from nova.api.openstack import common
|
||||||
|
from nova.api.openstack import extensions as exts
|
||||||
|
from nova.api.openstack import wsgi
|
||||||
|
from nova import compute
|
||||||
|
from nova import exception
|
||||||
|
|
||||||
|
|
||||||
|
ALIAS = 'os-shelve'
|
||||||
|
auth_shelve = exts.extension_authorizer('compute', 'v3:%s:shelve' % ALIAS)
|
||||||
|
auth_shelve_offload = exts.extension_authorizer('compute',
|
||||||
|
'v3:%s:shelve_offload' % ALIAS)
|
||||||
|
auth_unshelve = exts.extension_authorizer('compute', 'v3:%s:unshelve' % ALIAS)
|
||||||
|
|
||||||
|
|
||||||
|
class ShelveController(wsgi.Controller):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ShelveController, self).__init__(*args, **kwargs)
|
||||||
|
self.compute_api = compute.API()
|
||||||
|
|
||||||
|
def _get_instance(self, context, instance_id):
|
||||||
|
try:
|
||||||
|
return self.compute_api.get(context, instance_id,
|
||||||
|
want_objects=True)
|
||||||
|
except exception.InstanceNotFound:
|
||||||
|
msg = _("Server not found")
|
||||||
|
raise exc.HTTPNotFound(msg)
|
||||||
|
|
||||||
|
@wsgi.action('shelve')
|
||||||
|
def _shelve(self, req, id, body):
|
||||||
|
"""Move an instance into shelved mode."""
|
||||||
|
context = req.environ["nova.context"]
|
||||||
|
auth_shelve(context)
|
||||||
|
|
||||||
|
instance = self._get_instance(context, id)
|
||||||
|
try:
|
||||||
|
self.compute_api.shelve(context, instance)
|
||||||
|
except exception.InstanceInvalidState as state_error:
|
||||||
|
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||||
|
'shelve')
|
||||||
|
|
||||||
|
return webob.Response(status_int=202)
|
||||||
|
|
||||||
|
@wsgi.action('shelve_offload')
|
||||||
|
def _shelve_offload(self, req, id, body):
|
||||||
|
"""Force removal of a shelved instance from the compute node."""
|
||||||
|
context = req.environ["nova.context"]
|
||||||
|
auth_shelve_offload(context)
|
||||||
|
|
||||||
|
instance = self._get_instance(context, id)
|
||||||
|
try:
|
||||||
|
self.compute_api.shelve_offload(context, instance)
|
||||||
|
except exception.InstanceInvalidState as state_error:
|
||||||
|
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||||
|
'shelve_offload')
|
||||||
|
|
||||||
|
return webob.Response(status_int=202)
|
||||||
|
|
||||||
|
@wsgi.action('unshelve')
|
||||||
|
def _unshelve(self, req, id, body):
|
||||||
|
"""Restore an instance from shelved mode."""
|
||||||
|
context = req.environ["nova.context"]
|
||||||
|
auth_unshelve(context)
|
||||||
|
instance = self._get_instance(context, id)
|
||||||
|
try:
|
||||||
|
self.compute_api.unshelve(context, instance)
|
||||||
|
except exception.InstanceInvalidState as state_error:
|
||||||
|
common.raise_http_conflict_for_instance_invalid_state(state_error,
|
||||||
|
'unshelve')
|
||||||
|
return webob.Response(status_int=202)
|
||||||
|
|
||||||
|
|
||||||
|
class Shelve(exts.V3APIExtensionBase):
|
||||||
|
"""Instance shelve mode."""
|
||||||
|
|
||||||
|
name = "Shelve"
|
||||||
|
alias = ALIAS
|
||||||
|
namespace = "http://docs.openstack.org/compute/ext/shelve/api/v3"
|
||||||
|
version = 1
|
||||||
|
|
||||||
|
def get_controller_extensions(self):
|
||||||
|
controller = ShelveController()
|
||||||
|
extension = exts.ControllerExtension(self, 'servers', controller)
|
||||||
|
return [extension]
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
return []
|
107
nova/tests/api/openstack/compute/contrib/test_shelve.py
Normal file
107
nova/tests/api/openstack/compute/contrib/test_shelve.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# 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 uuid
|
||||||
|
|
||||||
|
from nova.api.openstack.compute.contrib import shelve
|
||||||
|
from nova import db
|
||||||
|
from nova import exception
|
||||||
|
from nova.openstack.common import policy
|
||||||
|
from nova import test
|
||||||
|
from nova.tests.api.openstack import fakes
|
||||||
|
from nova.tests import fake_instance
|
||||||
|
|
||||||
|
|
||||||
|
class ShelvePolicyTest(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(ShelvePolicyTest, self).setUp()
|
||||||
|
self.controller = shelve.ShelveController()
|
||||||
|
|
||||||
|
def test_shelve_restricted_by_role(self):
|
||||||
|
rules = policy.Rules({'compute_extension:shelve':
|
||||||
|
policy.parse_rule('role:admin')})
|
||||||
|
policy.set_rules(rules)
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-shelve')
|
||||||
|
self.assertRaises(exception.NotAuthorized, self.controller._shelve,
|
||||||
|
req, str(uuid.uuid4()), {})
|
||||||
|
|
||||||
|
def test_shelve_allowed(self):
|
||||||
|
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
||||||
|
'compute_extension:shelve':
|
||||||
|
policy.parse_rule('')})
|
||||||
|
policy.set_rules(rules)
|
||||||
|
|
||||||
|
def fake_instance_get_by_uuid(context, instance_id,
|
||||||
|
columns_to_join=None):
|
||||||
|
return fake_instance.fake_db_instance(
|
||||||
|
**{'name': 'fake', 'project_id': '%s_unequal' %
|
||||||
|
context.project_id})
|
||||||
|
|
||||||
|
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
||||||
|
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-shelve')
|
||||||
|
self.assertRaises(exception.NotAuthorized, self.controller._shelve,
|
||||||
|
req, str(uuid.uuid4()), {})
|
||||||
|
|
||||||
|
def test_unshelve_restricted_by_role(self):
|
||||||
|
rules = policy.Rules({'compute_extension:unshelve':
|
||||||
|
policy.parse_rule('role:admin')})
|
||||||
|
policy.set_rules(rules)
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-shelve')
|
||||||
|
self.assertRaises(exception.NotAuthorized, self.controller._unshelve,
|
||||||
|
req, str(uuid.uuid4()), {})
|
||||||
|
|
||||||
|
def test_unshelve_allowed(self):
|
||||||
|
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
||||||
|
'compute_extension:unshelve':
|
||||||
|
policy.parse_rule('')})
|
||||||
|
policy.set_rules(rules)
|
||||||
|
|
||||||
|
def fake_instance_get_by_uuid(context, instance_id,
|
||||||
|
columns_to_join=None):
|
||||||
|
return fake_instance.fake_db_instance(
|
||||||
|
**{'name': 'fake', 'project_id': '%s_unequal' %
|
||||||
|
context.project_id})
|
||||||
|
|
||||||
|
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
||||||
|
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-shelve')
|
||||||
|
self.assertRaises(exception.NotAuthorized, self.controller._unshelve,
|
||||||
|
req, str(uuid.uuid4()), {})
|
||||||
|
|
||||||
|
def test_shelve_offload_restricted_by_role(self):
|
||||||
|
rules = policy.Rules({'compute_extension:shelveOffload':
|
||||||
|
policy.parse_rule('role:admin')})
|
||||||
|
policy.set_rules(rules)
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-shelve')
|
||||||
|
self.assertRaises(exception.NotAuthorized,
|
||||||
|
self.controller._shelve_offload, req, str(uuid.uuid4()), {})
|
||||||
|
|
||||||
|
def test_shelve_offload_allowed(self):
|
||||||
|
rules = policy.Rules({'compute:get': policy.parse_rule(''),
|
||||||
|
'compute_extension:shelveOffload':
|
||||||
|
policy.parse_rule('')})
|
||||||
|
policy.set_rules(rules)
|
||||||
|
|
||||||
|
def fake_instance_get_by_uuid(context, instance_id,
|
||||||
|
columns_to_join=None):
|
||||||
|
return fake_instance.fake_db_instance(
|
||||||
|
**{'name': 'fake', 'project_id': '%s_unequal' %
|
||||||
|
context.project_id})
|
||||||
|
|
||||||
|
self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
|
||||||
|
req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-shelve')
|
||||||
|
self.assertRaises(exception.NotAuthorized,
|
||||||
|
self.controller._shelve_offload, req, str(uuid.uuid4()), {})
|
@ -238,10 +238,16 @@ policy_data = """
|
|||||||
"compute_extension:server_usage": "",
|
"compute_extension:server_usage": "",
|
||||||
"compute_extension:services": "",
|
"compute_extension:services": "",
|
||||||
"compute_extension:v3:os-services": "",
|
"compute_extension:v3:os-services": "",
|
||||||
|
"compute_extension:shelve": "",
|
||||||
|
"compute_extension:shelveOffload": "",
|
||||||
|
"compute_extension:v3:os-shelve:shelve": "",
|
||||||
|
"compute_extension:v3:os-shelve:shelve_offload": "",
|
||||||
"compute_extension:simple_tenant_usage:show": "",
|
"compute_extension:simple_tenant_usage:show": "",
|
||||||
"compute_extension:v3:os-simple-tenant-usage:show": "",
|
"compute_extension:v3:os-simple-tenant-usage:show": "",
|
||||||
"compute_extension:simple_tenant_usage:list": "",
|
"compute_extension:simple_tenant_usage:list": "",
|
||||||
"compute_extension:v3:os-simple-tenant-usage:list": "",
|
"compute_extension:v3:os-simple-tenant-usage:list": "",
|
||||||
|
"compute_extension:unshelve": "",
|
||||||
|
"compute_extension:v3:os-shelve:unshelve": "",
|
||||||
"compute_extension:users": "",
|
"compute_extension:users": "",
|
||||||
"compute_extension:virtual_interfaces": "",
|
"compute_extension:virtual_interfaces": "",
|
||||||
"compute_extension:virtual_storage_arrays": "",
|
"compute_extension:virtual_storage_arrays": "",
|
||||||
|
@ -512,6 +512,14 @@
|
|||||||
"namespace": "http://docs.openstack.org/compute/ext/servers/api/v1.1",
|
"namespace": "http://docs.openstack.org/compute/ext/servers/api/v1.1",
|
||||||
"updated": "%(timestamp)s"
|
"updated": "%(timestamp)s"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"alias": "os-shelve",
|
||||||
|
"description": "%(text)s",
|
||||||
|
"links": [],
|
||||||
|
"name": "Shelve",
|
||||||
|
"namespace": "http://docs.openstack.org/compute/ext/shelve/api/v1.1",
|
||||||
|
"updated": "%(timestamp)s"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"alias": "os-simple-tenant-usage",
|
"alias": "os-simple-tenant-usage",
|
||||||
"description": "%(text)s",
|
"description": "%(text)s",
|
||||||
|
@ -192,6 +192,9 @@
|
|||||||
<extension alias="os-server-start-stop" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/servers/api/v1.1" name="ServerStartStop">
|
<extension alias="os-server-start-stop" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/servers/api/v1.1" name="ServerStartStop">
|
||||||
<description>%(text)s</description>
|
<description>%(text)s</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
<extension alias="os-shelve" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/shelve/api/v1.1" name="Shelve">
|
||||||
|
<description>%(text)s</description>
|
||||||
|
</extension>
|
||||||
<extension alias="os-simple-tenant-usage" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1" name="SimpleTenantUsage">
|
<extension alias="os-simple-tenant-usage" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1" name="SimpleTenantUsage">
|
||||||
<description>%(text)s</description>
|
<description>%(text)s</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"%(action)s": null
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<%(action)s/>
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"server" : {
|
||||||
|
"name" : "new-server-test",
|
||||||
|
"imageRef" : "%(host)s/openstack/images/%(image_id)s",
|
||||||
|
"flavorRef" : "%(host)s/openstack/flavors/1",
|
||||||
|
"metadata" : {
|
||||||
|
"My Server Name" : "Apache1"
|
||||||
|
},
|
||||||
|
"personality" : [
|
||||||
|
{
|
||||||
|
"path" : "/etc/banner.txt",
|
||||||
|
"contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test">
|
||||||
|
<metadata>
|
||||||
|
<meta key="My Server Name">Apache1</meta>
|
||||||
|
</metadata>
|
||||||
|
<personality>
|
||||||
|
<file path="/etc/banner.txt">
|
||||||
|
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
|
||||||
|
dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
|
||||||
|
IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
|
||||||
|
c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
|
||||||
|
QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
|
||||||
|
ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
|
||||||
|
dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
|
||||||
|
c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
|
||||||
|
b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
|
||||||
|
</file>
|
||||||
|
</personality>
|
||||||
|
</server>
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"adminPass": "%(password)s",
|
||||||
|
"id": "%(id)s",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "%(host)s/v2/openstack/servers/%(uuid)s",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "%(host)s/openstack/servers/%(uuid)s",
|
||||||
|
"rel": "bookmark"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s">
|
||||||
|
<metadata/>
|
||||||
|
<atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/>
|
||||||
|
<atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/>
|
||||||
|
</server>
|
@ -1522,6 +1522,40 @@ class RescueXmlTest(RescueJsonTest):
|
|||||||
ctype = 'xml'
|
ctype = 'xml'
|
||||||
|
|
||||||
|
|
||||||
|
class ShelveJsonTest(ServersSampleBase):
|
||||||
|
extension_name = "nova.api.openstack.compute.contrib.shelve.Shelve"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ShelveJsonTest, self).setUp()
|
||||||
|
# Don't offload instance, so we can test the offload call.
|
||||||
|
CONF.shelved_offload_time = -1
|
||||||
|
|
||||||
|
def _test_server_action(self, uuid, action):
|
||||||
|
response = self._do_post('servers/%s/action' % uuid,
|
||||||
|
'os-shelve',
|
||||||
|
{'action': action})
|
||||||
|
self.assertEqual(response.status, 202)
|
||||||
|
self.assertEqual(response.read(), "")
|
||||||
|
|
||||||
|
def test_shelve(self):
|
||||||
|
uuid = self._post_server()
|
||||||
|
self._test_server_action(uuid, 'shelve')
|
||||||
|
|
||||||
|
def test_shelve_offload(self):
|
||||||
|
uuid = self._post_server()
|
||||||
|
self._test_server_action(uuid, 'shelve')
|
||||||
|
self._test_server_action(uuid, 'shelveOffload')
|
||||||
|
|
||||||
|
def test_unshelve(self):
|
||||||
|
uuid = self._post_server()
|
||||||
|
self._test_server_action(uuid, 'shelve')
|
||||||
|
self._test_server_action(uuid, 'unshelve')
|
||||||
|
|
||||||
|
|
||||||
|
class ShelveXmlTest(ShelveJsonTest):
|
||||||
|
ctype = 'xml'
|
||||||
|
|
||||||
|
|
||||||
class VirtualInterfacesJsonTest(ServersSampleBase):
|
class VirtualInterfacesJsonTest(ServersSampleBase):
|
||||||
extension_name = ("nova.api.openstack.compute.contrib"
|
extension_name = ("nova.api.openstack.compute.contrib"
|
||||||
".virtual_interfaces.Virtual_interfaces")
|
".virtual_interfaces.Virtual_interfaces")
|
||||||
|
Loading…
Reference in New Issue
Block a user