diff --git a/doc/api_samples/os-volumes/snapshot-create-req.json b/doc/api_samples/os-volumes/snapshot-create-req.json
new file mode 100644
index 000000000000..8ad5b3cb0492
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshot-create-req.json
@@ -0,0 +1,8 @@
+{
+ "snapshot": {
+ "display_name": "snap-001",
+ "display_description": "Daily backup",
+ "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "force": false
+ }
+}
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshot-create-req.xml b/doc/api_samples/os-volumes/snapshot-create-req.xml
new file mode 100644
index 000000000000..e5001cf06f2f
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshot-create-req.xml
@@ -0,0 +1,7 @@
+
+
+ snap-001
+ Daily backup
+ 521752a6-acf6-4b2d-bc7a-119f9148cd8c
+ false
+
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshot-create-resp.json b/doc/api_samples/os-volumes/snapshot-create-resp.json
new file mode 100644
index 000000000000..1a14bea01f57
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshot-create-resp.json
@@ -0,0 +1,32 @@
+{
+ "snapshot": {
+ "createdAt": "2013-02-25T16:27:54.680544",
+ "displayDescription": "Daily backup",
+ "displayName": "snap-001",
+ "id": 100,
+ "size": 100,
+ "status": "available",
+ "volumeId": {
+ "attach_status": "attached",
+ "availability_zone": "fakeaz",
+ "created_at": "1999-01-01T01:01:01.000000",
+ "display_description": "displaydesc",
+ "display_name": "displayname",
+ "host": "fakehost",
+ "id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
+ "instance_uuid": "fakeuuid",
+ "mountpoint": "/",
+ "name": "vol name",
+ "project_id": "fakeproject",
+ "size": 1,
+ "snapshot_id": null,
+ "status": "fakestatus",
+ "user_id": "fakeuser",
+ "volume_metadata": [],
+ "volume_type": {
+ "name": "vol_type_name"
+ },
+ "volume_type_id": "fakevoltype"
+ }
+ }
+}
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshot-create-resp.xml b/doc/api_samples/os-volumes/snapshot-create-resp.xml
new file mode 100644
index 000000000000..ad815f723f9c
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshot-create-resp.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshots-detail-resp.json b/doc/api_samples/os-volumes/snapshots-detail-resp.json
new file mode 100644
index 000000000000..796e522c439f
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshots-detail-resp.json
@@ -0,0 +1,31 @@
+{
+ "snapshots": [
+ {
+ "createdAt": "2013-02-25T16:27:54.671372",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 100,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "2013-02-25T16:27:54.671378",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 101,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "2013-02-25T16:27:54.671381",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 102,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ }
+ ]
+}
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshots-detail-resp.xml b/doc/api_samples/os-volumes/snapshots-detail-resp.xml
new file mode 100644
index 000000000000..5e946939f812
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshots-detail-resp.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshots-list-resp.json b/doc/api_samples/os-volumes/snapshots-list-resp.json
new file mode 100644
index 000000000000..9b7cb412a854
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshots-list-resp.json
@@ -0,0 +1,31 @@
+{
+ "snapshots": [
+ {
+ "createdAt": "2013-02-25T16:27:54.684999",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 100,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "2013-02-25T16:27:54.685005",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 101,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "2013-02-25T16:27:54.685008",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 102,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ }
+ ]
+}
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshots-list-resp.xml b/doc/api_samples/os-volumes/snapshots-list-resp.xml
new file mode 100644
index 000000000000..6714c98bc15e
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshots-list-resp.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshots-show-resp.json b/doc/api_samples/os-volumes/snapshots-show-resp.json
new file mode 100644
index 000000000000..d7b3f26e419f
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshots-show-resp.json
@@ -0,0 +1,11 @@
+{
+ "snapshot": {
+ "createdAt": "2013-02-25T16:27:54.724209",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": "100",
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ }
+}
\ No newline at end of file
diff --git a/doc/api_samples/os-volumes/snapshots-show-resp.xml b/doc/api_samples/os-volumes/snapshots-show-resp.xml
new file mode 100644
index 000000000000..3c70cf033f45
--- /dev/null
+++ b/doc/api_samples/os-volumes/snapshots-show-resp.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/nova/tests/api/openstack/fakes.py b/nova/tests/api/openstack/fakes.py
index c906dae7f166..cced8c787410 100644
--- a/nova/tests/api/openstack/fakes.py
+++ b/nova/tests/api/openstack/fakes.py
@@ -587,7 +587,7 @@ def stub_snapshot(id, **kwargs):
'volume_id': 12,
'status': 'available',
'volume_size': 100,
- 'created_at': None,
+ 'created_at': timeutils.utcnow(),
'display_name': 'Default name',
'display_description': 'Default description',
'project_id': 'fake'
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-req.json.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-req.json.tpl
new file mode 100644
index 000000000000..a8d47ea0312e
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-req.json.tpl
@@ -0,0 +1,8 @@
+{
+ "snapshot": {
+ "display_name": "%(snapshot_name)s",
+ "display_description": "%(description)s",
+ "volume_id": "%(volume_id)s",
+ "force": false
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-req.xml.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-req.xml.tpl
new file mode 100644
index 000000000000..a5b670bc2fb5
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-req.xml.tpl
@@ -0,0 +1,7 @@
+
+
+ %(snapshot_name)s
+ %(description)s
+ %(volume_id)s
+ false
+
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl
new file mode 100644
index 000000000000..73cd02d9d6b1
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.json.tpl
@@ -0,0 +1,32 @@
+{
+ "snapshot": {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "%(description)s",
+ "displayName": "%(snapshot_name)s",
+ "id": 100,
+ "size": 100,
+ "status": "available",
+ "volumeId": {
+ "attach_status": "attached",
+ "availability_zone": "fakeaz",
+ "created_at": "%(timestamp)s",
+ "display_description": "displaydesc",
+ "display_name": "displayname",
+ "host": "fakehost",
+ "id": "%(uuid)s",
+ "instance_uuid": "fakeuuid",
+ "mountpoint": "/",
+ "name": "vol name",
+ "project_id": "fakeproject",
+ "size": 1,
+ "snapshot_id": null,
+ "status": "fakestatus",
+ "user_id": "fakeuser",
+ "volume_metadata": [],
+ "volume_type": {
+ "name": "vol_type_name"
+ },
+ "volume_type_id": "fakevoltype"
+ }
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl
new file mode 100644
index 000000000000..aa713311fc66
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshot-create-resp.xml.tpl
@@ -0,0 +1,2 @@
+
+
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshots-detail-resp.json.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshots-detail-resp.json.tpl
new file mode 100644
index 000000000000..f6b4a3abf3c8
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshots-detail-resp.json.tpl
@@ -0,0 +1,31 @@
+{
+ "snapshots": [
+ {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 100,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 101,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "Default description",
+ "displayName": "Default name",
+ "id": 102,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshots-detail-resp.xml.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshots-detail-resp.xml.tpl
new file mode 100644
index 000000000000..dbfe32526ac5
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshots-detail-resp.xml.tpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshots-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshots-list-resp.json.tpl
new file mode 100644
index 000000000000..5cfbd72830b9
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshots-list-resp.json.tpl
@@ -0,0 +1,31 @@
+{
+ "snapshots": [
+ {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "%(text)s",
+ "displayName": "%(text)s",
+ "id": 100,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "%(text)s",
+ "displayName": "%(text)s",
+ "id": 101,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ },
+ {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "%(text)s",
+ "displayName": "%(text)s",
+ "id": 102,
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshots-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshots-list-resp.xml.tpl
new file mode 100644
index 000000000000..dbfe32526ac5
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshots-list-resp.xml.tpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshots-show-resp.json.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshots-show-resp.json.tpl
new file mode 100644
index 000000000000..0690ed8b66b6
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshots-show-resp.json.tpl
@@ -0,0 +1,11 @@
+{
+ "snapshot": {
+ "createdAt": "%(timestamp)s",
+ "displayDescription": "%(description)s",
+ "displayName": "%(snapshot_name)s",
+ "id": "100",
+ "size": 100,
+ "status": "available",
+ "volumeId": 12
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-volumes/snapshots-show-resp.xml.tpl b/nova/tests/integrated/api_samples/os-volumes/snapshots-show-resp.xml.tpl
new file mode 100644
index 000000000000..3525851cfeaf
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-volumes/snapshots-show-resp.xml.tpl
@@ -0,0 +1,2 @@
+
+
diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py
index aaf22ff9d48b..f6926b50ee90 100644
--- a/nova/tests/integrated/test_api_samples.py
+++ b/nova/tests/integrated/test_api_samples.py
@@ -57,6 +57,7 @@ from nova.tests.image import fake
from nova.tests.integrated import integrated_helpers
from nova.tests import utils as test_utils
from nova import utils
+from nova.volume import cinder
CONF = cfg.CONF
CONF.import_opt('allow_resize_to_same_host', 'nova.compute.api')
@@ -384,7 +385,6 @@ class ApiSamplesTrap(ApiSampleTestBase):
# removed) soon.
do_not_approve_additions = []
do_not_approve_additions.append('os-create-server-ext')
- do_not_approve_additions.append('os-volumes')
tests = self._get_extensions_tested()
extensions = self._get_extensions()
@@ -3589,3 +3589,73 @@ class AttachInterfacesSampleJsonTest(ServersSampleBase):
class AttachInterfacesSampleXmlTest(AttachInterfacesSampleJsonTest):
ctype = 'xml'
+
+
+class SnapshotsSampleJsonTests(ApiSampleTestBase):
+ extension_name = "nova.api.openstack.compute.contrib.volumes.Volumes"
+
+ create_subs = {
+ 'snapshot_name': 'snap-001',
+ 'description': 'Daily backup',
+ 'volume_id': '521752a6-acf6-4b2d-bc7a-119f9148cd8c'
+ }
+
+ def setUp(self):
+ super(SnapshotsSampleJsonTests, self).setUp()
+ self.stubs.Set(cinder.API, "get_all_snapshots",
+ fakes.stub_snapshot_get_all)
+ self.stubs.Set(cinder.API, "get_snapshot", fakes.stub_snapshot_get)
+
+ def _create_snapshot(self):
+ self.stubs.Set(cinder.API, "create_snapshot",
+ fakes.stub_snapshot_create)
+ self.stubs.Set(cinder.API, "get", fakes.stub_volume_get)
+
+ response = self._do_post("os-snapshots",
+ "snapshot-create-req",
+ self.create_subs)
+ return response
+
+ def test_snapshots_create(self):
+ response = self._create_snapshot()
+ self.assertEqual(response.status, 200)
+ self.create_subs.update(self._get_regexes())
+ return self._verify_response("snapshot-create-resp",
+ self.create_subs, response)
+
+ def test_snapshots_delete(self):
+ self.stubs.Set(cinder.API, "delete_snapshot",
+ fakes.stub_snapshot_delete)
+ self._create_snapshot()
+ response = self._do_delete('os-snapshots/100')
+ self.assertEqual(response.status, 202)
+ self.assertEqual(response.read(), '')
+
+ def test_snapshots_detail(self):
+ response = self._do_get('os-snapshots/detail')
+ self.assertEqual(response.status, 200)
+ subs = self._get_regexes()
+ return self._verify_response('snapshots-detail-resp',
+ subs, response)
+
+ def test_snapshots_list(self):
+ response = self._do_get('os-snapshots')
+ self.assertEqual(response.status, 200)
+ subs = self._get_regexes()
+ return self._verify_response('snapshots-list-resp',
+ subs, response)
+
+ def test_snapshots_show(self):
+ response = self._do_get('os-snapshots/100')
+ self.assertEqual(response.status, 200)
+ subs = {
+ 'snapshot_name': 'Default name',
+ 'description': 'Default description'
+ }
+ subs.update(self._get_regexes())
+ return self._verify_response('snapshots-show-resp',
+ subs, response)
+
+
+class SnapshotsSampleXmlTests(SnapshotsSampleJsonTests):
+ ctype = "xml"