Merge "Add os-assisted-volume-snapshots extension"
This commit is contained in:
19 changed files with 315 additions and 13 deletions
@@ -128,6 +128,14 @@
"namespace": "http://docs.openstack.org/compute/ext/aggregates/api/v1.1",
"updated": "2012年01月12日T00:00:00+00:00"
},
{
"alias": "os-assisted-volume-snapshots",
"description": "Assisted volume snapshots.",
"links": [],
"name": "AssistedVolumeSnapshots",
"namespace": "http://docs.openstack.org/compute/ext/assisted-volume-snapshots/api/v2",
"updated": "2013年08月15日T00:00:00-00:00"
},
{
"alias": "os-attach-interfaces",
"description": "Attach interface support.",
@@ -472,14 +480,6 @@
"namespace": "http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1",
"updated": "2011年08月08日T00:00:00+00:00"
},
{
"alias": "os-user-quotas",
"description": "Project user quota support.",
"links": [],
"name": "UserQuotas",
"namespace": "http://docs.openstack.org/compute/ext/user_quotas/api/v1.1",
"updated": "2013年07月18日T00:00:00+00:00"
},
{
"alias": "os-rescue",
"description": "Instance rescue mode.",
@@ -584,6 +584,14 @@
"namespace": "http://docs.openstack.org/compute/ext/userdata/api/v1.1",
"updated": "2012年08月07日T00:00:00+00:00"
},
{
"alias": "os-user-quotas",
"description": "Project user quota support.",
"links": [],
"name": "UserQuotas",
"namespace": "http://docs.openstack.org/compute/ext/user_quotas/api/v1.1",
"updated": "2013年07月18日T00:00:00+00:00"
},
{
"alias": "os-virtual-interfaces",
"description": "Virtual interface support.",
@@ -609,4 +617,4 @@
"updated": "2011年03月25日T00:00:00+00:00"
}
]
}
}
@@ -52,6 +52,9 @@
<extension alias="os-aggregates" updated="2012年01月12日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/aggregates/api/v1.1" name="Aggregates">
<description>Admin-only aggregate administration.</description>
</extension>
<extension alias="os-assisted-volume-snapshots" updated="2013年08月15日T00:00:00-00:00" namespace="http://docs.openstack.org/compute/ext/assisted-volume-snapshots/api/v2" name="AssistedVolumeSnapshots">
<description>Assisted volume snapshots.</description>
</extension>
<extension alias="os-attach-interfaces" updated="2012年07月22日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/interfaces/api/v1.1" name="AttachInterfaces">
<description>Attach interface support.</description>
</extension>
@@ -197,9 +200,6 @@
<extension alias="os-quota-sets" updated="2011年08月08日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1" name="Quotas">
<description>Quotas management support.</description>
</extension>
<extension alias="os-user-quotas" updated="2013年07月18日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/user_quotas/api/v1.1" name="UserQuotas">
<description>Project user quota support.</description>
</extension>
<extension alias="os-rescue" updated="2011年08月18日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
<description>Instance rescue mode.</description>
</extension>
@@ -239,6 +239,9 @@
<extension alias="os-user-data" updated="2012年08月07日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/userdata/api/v1.1" name="UserData">
<description>Add user_data to the Create Server v1.1 API.</description>
</extension>
<extension alias="os-user-quotas" updated="2013年07月18日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/user_quotas/api/v1.1" name="UserQuotas">
<description>Project user quota support.</description>
</extension>
<extension alias="os-virtual-interfaces" updated="2011年08月17日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1" name="VirtualInterfaces">
<description>Virtual interface support.</description>
</extension>
@@ -248,4 +251,4 @@
<extension alias="os-volumes" updated="2011年03月25日T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/volumes/api/v1.1" name="Volumes">
<description>Volumes support.</description>
</extension>
</extensions>
</extensions>
@@ -0,0 +1,10 @@
{
"snapshot": {
"display_name": "snap-001",
"display_description": "Daily backup",
"volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
"force": false,
"assisted": true,
"create_info": {}
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<snapshot>
<display_name>snap-001</display_name>
<display_description>Daily backup</display_description>
<volume_id>521752a6-acf6-4b2d-bc7a-119f9148cd8c</volume_id>
<force>false</force>
<assisted>true</assisted>
<create_info/>
</snapshot>
@@ -0,0 +1,6 @@
{
"snapshot": {
"id": 100,
"volumeId": "521752a6-acf6-4b2d-bc7a-119f9148cd8c"
}
}
@@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<snapshot volumeId="521752a6-acf6-4b2d-bc7a-119f9148cd8c" id="100"/>
@@ -243,6 +243,8 @@
"compute_extension:migrations:index": "rule:admin_api",
"compute_extension:v3:os-migrations:index": "rule:admin_api",
"compute_extension:v3:os-migrations:discoverable": "",
"compute_extension:os-assisted-volume-snapshots:create": "rule:admin_api",
"compute_extension:os-assisted-volume-snapshots:delete": "rule:admin_api",
"volume:create": "",
110
nova/api/openstack/compute/contrib/assisted_volume_snapshots.py
Normal file
110
nova/api/openstack/compute/contrib/assisted_volume_snapshots.py
Normal file
@@ -0,0 +1,110 @@
# Copyright 2013 Red Hat, Inc.
#
# 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 webob
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova import exception
from nova.openstack.common.gettextutils import _
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('compute',
'os-assisted-volume-snapshots')
def make_snapshot(elem):
elem.set('id')
elem.set('volumeId')
class SnapshotTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('snapshot', selector='snapshot')
make_snapshot(root)
return xmlutil.MasterTemplate(root, 1)
class AssistedVolumeSnapshotsController(wsgi.Controller):
def __init__(self):
self.compute_api = compute.API()
super(AssistedVolumeSnapshotsController, self).__init__()
@wsgi.serializers(xml=SnapshotTemplate)
def create(self, req, body):
"""Creates a new snapshot."""
context = req.environ['nova.context']
authorize(context, action='create')
if not self.is_valid_body(body, 'snapshot'):
raise webob.exc.HTTPBadRequest()
try:
snapshot = body['snapshot']
create_info = snapshot['create_info']
volume_id = snapshot['volume_id']
except KeyError:
raise webob.exc.HTTPBadRequest()
LOG.audit(_("Create assisted snapshot from volume %s"), volume_id,
context=context)
return self.compute_api.volume_snapshot_create(context, volume_id,
create_info)
def delete(self, req, id):
"""Delete a snapshot."""
context = req.environ['nova.context']
authorize(context, action='delete')
LOG.audit(_("Delete snapshot with id: %s"), id, context=context)
delete_metadata = {}
delete_metadata.update(req.GET)
try:
delete_info = jsonutils.loads(delete_metadata['delete_info'])
volume_id = delete_info['volume_id']
except (KeyError, ValueError) as e:
raise webob.exc.HTTPBadRequest(explanation=str(e))
try:
self.compute_api.volume_snapshot_delete(context, volume_id,
id, delete_info)
except exception.NotFound:
return webob.exc.HTTPNotFound()
return webob.Response(status_int=204)
class Assisted_volume_snapshots(extensions.ExtensionDescriptor):
"""Assisted volume snapshots."""
name = "AssistedVolumeSnapshots"
alias = "os-assisted-volume-snapshots"
namespace = ("http://docs.openstack.org/compute/ext/"
"assisted-volume-snapshots/api/v2")
updated = "2013年08月29日T00:00:00-00:00"
def get_resources(self):
resource = extensions.ResourceExtension('os-assisted-volume-snapshots',
AssistedVolumeSnapshotsController())
return [resource]
@@ -1,4 +1,5 @@
# Copyright 2013 Josh Durgin
# Copyright 2013 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -20,6 +21,8 @@ from oslo.config import cfg
import webob
from webob import exc
from nova.api.openstack.compute.contrib import assisted_volume_snapshots as \
assisted_snaps
from nova.api.openstack.compute.contrib import volumes
from nova.api.openstack import extensions
from nova.compute import api as compute_api
@@ -79,6 +82,16 @@ def fake_delete_snapshot(self, context, snapshot_id):
pass
def fake_compute_volume_snapshot_delete(self, context, volume_id, snapshot_id,
delete_info):
pass
def fake_compute_volume_snapshot_create(self, context, volume_id,
create_info):
pass
def fake_get_instance_bdms(self, context, instance):
return [{'id': 1,
'instance_uuid': instance['uuid'],
@@ -793,3 +806,51 @@ class DeleteSnapshotTestCase(test.TestCase):
self.req.method = 'DELETE'
result = self.controller.delete(self.req, result['snapshot']['id'])
self.assertEqual(result.status_int, 202)
class AssistedSnapshotCreateTestCase(test.TestCase):
def setUp(self):
super(AssistedSnapshotCreateTestCase, self).setUp()
self.controller = assisted_snaps.AssistedVolumeSnapshotsController()
self.stubs.Set(compute_api.API, 'volume_snapshot_create',
fake_compute_volume_snapshot_create)
def test_assisted_create(self):
req = fakes.HTTPRequest.blank('/v2/fake/os-assisted-volume-snapshots')
body = {'snapshot': {'volume_id': 1, 'create_info': {}}}
req.method = 'POST'
self.controller.create(req, body=body)
def test_assisted_create_missing_create_info(self):
req = fakes.HTTPRequest.blank('/v2/fake/os-assisted-volume-snapshots')
body = {'snapshot': {'volume_id': 1}}
req.method = 'POST'
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
req, body=body)
class AssistedSnapshotDeleteTestCase(test.TestCase):
def setUp(self):
super(AssistedSnapshotDeleteTestCase, self).setUp()
self.controller = assisted_snaps.AssistedVolumeSnapshotsController()
self.stubs.Set(compute_api.API, 'volume_snapshot_delete',
fake_compute_volume_snapshot_delete)
def test_assisted_delete(self):
params = {
'delete_info': jsonutils.dumps({'volume_id': 1}),
}
req = fakes.HTTPRequest.blank(
'/v2/fake/os-assisted-volume-snapshots?%s' %
'&'.join(['%s=%s' % (k, v) for k, v in params.iteritems()]))
req.method = 'DELETE'
result = self.controller.delete(req, '5')
self.assertEqual(result.status_int, 204)
def test_assisted_delete_missing_delete_info(self):
req = fakes.HTTPRequest.blank('/v2/fake/os-assisted-volume-snapshots')
req.method = 'DELETE'
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete,
req, '5')
@@ -176,6 +176,7 @@ class ExtensionControllerTest(ExtensionTestCase):
self.ext_list = [
"AdminActions",
"Aggregates",
"AssistedVolumeSnapshots",
"AvailabilityZone",
"Agents",
"Certificates",
@@ -679,11 +679,20 @@ def stub_snapshot_create(self, context, volume_id, name, description):
display_description=description)
def stub_compute_volume_snapshot_create(self, context, volume_id, create_info):
return {'snapshot': {'id': 100, 'volumeId': volume_id}}
def stub_snapshot_delete(self, context, snapshot_id):
if snapshot_id == '-1':
raise exc.NotFound
def stub_compute_volume_snapshot_delete(self, context, volume_id, snapshot_id,
delete_info):
pass
def stub_snapshot_get(self, context, snapshot_id):
if snapshot_id == '-1':
raise exc.NotFound
@@ -279,6 +279,8 @@ policy_data = """
"compute_extension:v3:os-used-limits:tenant": "is_admin:True",
"compute_extension:migrations:index": "is_admin:True",
"compute_extension:v3:os-migrations:index": "is_admin:True",
"compute_extension:os-assisted-volume-snapshots:create": "",
"compute_extension:os-assisted-volume-snapshots:delete": "",
"volume:create": "",
"volume:get": "",
@@ -136,6 +136,14 @@
"namespace": "http://docs.openstack.org/compute/ext/agents/api/v2",
"updated": "%(timestamp)s"
},
{
"alias": "os-assisted-volume-snapshots",
"description": "%(text)s",
"links": [],
"name": "AssistedVolumeSnapshots",
"namespace": "http://docs.openstack.org/compute/ext/assisted-volume-snapshots/api/v2",
"updated": "%(timestamp)s"
},
{
"alias": "os-attach-interfaces",
"description": "Attach interface support.",
@@ -228,4 +228,7 @@
<extension alias="os-migrations" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/migrations/api/v2.0" name="Migrations">
<description>%(text)s</description>
</extension>
<extension alias="os-assisted-volume-snapshots" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/assisted-volume-snapshots/api/v2" name="AssistedVolumeSnapshots">
<description>%(text)s</description>
</extension>
</extensions>
@@ -0,0 +1,10 @@
{
"snapshot": {
"display_name": "%(snapshot_name)s",
"display_description": "%(description)s",
"volume_id": "%(volume_id)s",
"force": false,
"assisted": true,
"create_info": {}
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<snapshot>
<display_name>%(snapshot_name)s</display_name>
<display_description>%(description)s</display_description>
<volume_id>%(volume_id)s</volume_id>
<force>false</force>
<assisted>true</assisted>
<create_info/>
</snapshot>
@@ -0,0 +1,6 @@
{
"snapshot": {
"id": 100,
"volumeId": "%(uuid)s"
}
}
@@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<snapshot volumeId="521752a6-acf6-4b2d-bc7a-119f9148cd8c" id="100"/>
@@ -3700,6 +3700,47 @@ class SnapshotsSampleXmlTests(SnapshotsSampleJsonTests):
ctype = "xml"
class AssistedVolumeSnapshotsJsonTest(ApiSampleTestBaseV2):
"""Assisted volume snapshots."""
extension_name = ("nova.api.openstack.compute.contrib."
"assisted_volume_snapshots.Assisted_volume_snapshots")
def _create_assisted_snapshot(self, subs):
self.stubs.Set(compute_api.API, 'volume_snapshot_create',
fakes.stub_compute_volume_snapshot_create)
response = self._do_post("os-assisted-volume-snapshots",
"snapshot-create-assisted-req",
subs)
return response
def test_snapshots_create_assisted(self):
subs = {
'snapshot_name': 'snap-001',
'description': 'Daily backup',
'volume_id': '521752a6-acf6-4b2d-bc7a-119f9148cd8c'
}
subs.update(self._get_regexes())
response = self._create_assisted_snapshot(subs)
self._verify_response("snapshot-create-assisted-resp",
subs, response, 200)
def test_snapshots_delete_assisted(self):
self.stubs.Set(compute_api.API, 'volume_snapshot_delete',
fakes.stub_compute_volume_snapshot_delete)
snapshot_id = '100'
response = self._do_delete(
'os-assisted-volume-snapshots/%s?delete_info='
'{"volume_id":"521752a6-acf6-4b2d-bc7a-119f9148cd8c"}'
% snapshot_id)
self.assertEqual(response.status, 204)
self.assertEqual(response.read(), '')
class AssistedVolumeSnapshotsXmlTest(AssistedVolumeSnapshotsJsonTest):
ctype = "xml"
class VolumeAttachmentsSampleBase(ServersSampleBase):
def _stub_compute_api_get_instance_bdms(self, server_id):
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.