blob: a27370df804c09769ce195e9438bb6855f1f46c1 [file] [log] [blame]
Attila Fazekas36b1fcf2013-01-31 16:41:04 +01001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010014import time
15import urllib
16
Joseph Lanoux6809bab2014-12-18 14:57:18 +000017from tempest.common import service_client
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010018from tempest import exceptions
Matthew Treinishf4a9b0f2013-07-26 16:58:26 -040019from tempest.openstack.common import log as logging
Ken'ichi Ohmichia39d0be2014-12-17 08:46:11 +000020from tempest.services.volume.json import base
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010021
Matthew Treinish684d8992014-01-30 16:27:40 +000022
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010023LOG = logging.getLogger(__name__)
24
25
Ken'ichi Ohmichia39d0be2014-12-17 08:46:11 +000026class BaseSnapshotsClientJSON(base.VolumeClient):
Zhi Kun Liu38641c62014-07-10 20:12:48 +080027 """Base Client class to send CRUD Volume API requests."""
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010028
Ken'ichi Ohmichia39d0be2014-12-17 08:46:11 +000029 create_resp = 200
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010030
31 def list_snapshots(self, params=None):
32 """List all the snapshot."""
33 url = 'snapshots'
34 if params:
35 url += '?%s' % urllib.urlencode(params)
36
37 resp, body = self.get(url)
38 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000039 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +000040 return service_client.ResponseBodyList(resp, body['snapshots'])
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010041
Abhijeet Malawade5945ffe2013-09-17 05:54:44 -070042 def list_snapshots_with_detail(self, params=None):
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010043 """List the details of all snapshots."""
44 url = 'snapshots/detail'
45 if params:
46 url += '?%s' % urllib.urlencode(params)
47
48 resp, body = self.get(url)
49 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000050 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +000051 return service_client.ResponseBodyList(resp, body['snapshots'])
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010052
53 def get_snapshot(self, snapshot_id):
54 """Returns the details of a single snapshot."""
55 url = "snapshots/%s" % str(snapshot_id)
56 resp, body = self.get(url)
57 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000058 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +000059 return service_client.ResponseBody(resp, body['snapshot'])
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010060
61 def create_snapshot(self, volume_id, **kwargs):
62 """
63 Creates a new snapshot.
64 volume_id(Required): id of the volume.
65 force: Create a snapshot even if the volume attached (Default=False)
66 display_name: Optional snapshot Name.
67 display_description: User friendly snapshot description.
68 """
69 post_body = {'volume_id': volume_id}
70 post_body.update(kwargs)
71 post_body = json.dumps({'snapshot': post_body})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +020072 resp, body = self.post('snapshots', post_body)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010073 body = json.loads(body)
Zhi Kun Liu38641c62014-07-10 20:12:48 +080074 self.expected_success(self.create_resp, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +000075 return service_client.ResponseBody(resp, body['snapshot'])
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010076
QingXin Mengdc95f5e2013-09-16 19:06:44 -070077 def update_snapshot(self, snapshot_id, **kwargs):
78 """Updates a snapshot."""
79 put_body = json.dumps({'snapshot': kwargs})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +020080 resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
QingXin Mengdc95f5e2013-09-16 19:06:44 -070081 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000082 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +000083 return service_client.ResponseBody(resp, body['snapshot'])
QingXin Mengdc95f5e2013-09-16 19:06:44 -070084
Attila Fazekasa8b5fe72013-08-01 16:59:06 +020085 # NOTE(afazekas): just for the wait function
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010086 def _get_snapshot_status(self, snapshot_id):
Joseph Lanoux6809bab2014-12-18 14:57:18 +000087 body = self.get_snapshot(snapshot_id)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010088 status = body['status']
Attila Fazekasa8b5fe72013-08-01 16:59:06 +020089 # NOTE(afazekas): snapshot can reach an "error"
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010090 # state in a "normal" lifecycle
91 if (status == 'error'):
92 raise exceptions.SnapshotBuildErrorException(
Sean Dague14c68182013-04-14 15:34:30 -040093 snapshot_id=snapshot_id)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010094
95 return status
96
Attila Fazekasa8b5fe72013-08-01 16:59:06 +020097 # NOTE(afazkas): Wait reinvented again. It is not in the correct layer
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010098 def wait_for_snapshot_status(self, snapshot_id, status):
99 """Waits for a Snapshot to reach a given status."""
100 start_time = time.time()
101 old_value = value = self._get_snapshot_status(snapshot_id)
102 while True:
103 dtime = time.time() - start_time
104 time.sleep(self.build_interval)
105 if value != old_value:
106 LOG.info('Value transition from "%s" to "%s"'
107 'in %d second(s).', old_value,
108 value, dtime)
109 if (value == status):
110 return value
111
112 if dtime > self.build_timeout:
113 message = ('Time Limit Exceeded! (%ds)'
114 'while waiting for %s, '
115 'but we got %s.' %
116 (self.build_timeout, status, value))
117 raise exceptions.TimeoutException(message)
118 time.sleep(self.build_interval)
119 old_value = value
120 value = self._get_snapshot_status(snapshot_id)
121
122 def delete_snapshot(self, snapshot_id):
123 """Delete Snapshot."""
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000124 resp, body = self.delete("snapshots/%s" % str(snapshot_id))
125 self.expected_success(202, resp.status)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +0100126
127 def is_resource_deleted(self, id):
128 try:
129 self.get_snapshot(id)
130 except exceptions.NotFound:
131 return True
132 return False
zhangyanzid4d3c6d2013-11-06 09:27:13 +0800133
Matt Riedemannd2b96512014-10-13 10:18:16 -0700134 @property
135 def resource_type(self):
136 """Returns the primary type of resource this client works with."""
137 return 'volume-snapshot'
138
zhangyanzid4d3c6d2013-11-06 09:27:13 +0800139 def reset_snapshot_status(self, snapshot_id, status):
140 """Reset the specified snapshot's status."""
141 post_body = json.dumps({'os-reset_status': {"status": status}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200142 resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000143 self.expected_success(202, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000144 return service_client.ResponseBody(resp, body)
zhangyanzid4d3c6d2013-11-06 09:27:13 +0800145
146 def update_snapshot_status(self, snapshot_id, status, progress):
147 """Update the specified snapshot's status."""
148 post_body = {
149 'status': status,
150 'progress': progress
151 }
152 post_body = json.dumps({'os-update_snapshot_status': post_body})
153 url = 'snapshots/%s/action' % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200154 resp, body = self.post(url, post_body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000155 self.expected_success(202, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000156 return service_client.ResponseBody(resp, body)
huangtianhua1346d702013-12-09 18:42:35 +0800157
158 def create_snapshot_metadata(self, snapshot_id, metadata):
159 """Create metadata for the snapshot."""
160 put_body = json.dumps({'metadata': metadata})
161 url = "snapshots/%s/metadata" % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200162 resp, body = self.post(url, put_body)
huangtianhua1346d702013-12-09 18:42:35 +0800163 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000164 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000165 return service_client.ResponseBody(resp, body['metadata'])
huangtianhua1346d702013-12-09 18:42:35 +0800166
167 def get_snapshot_metadata(self, snapshot_id):
168 """Get metadata of the snapshot."""
169 url = "snapshots/%s/metadata" % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200170 resp, body = self.get(url)
huangtianhua1346d702013-12-09 18:42:35 +0800171 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000172 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000173 return service_client.ResponseBody(resp, body['metadata'])
huangtianhua1346d702013-12-09 18:42:35 +0800174
175 def update_snapshot_metadata(self, snapshot_id, metadata):
176 """Update metadata for the snapshot."""
177 put_body = json.dumps({'metadata': metadata})
178 url = "snapshots/%s/metadata" % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200179 resp, body = self.put(url, put_body)
huangtianhua1346d702013-12-09 18:42:35 +0800180 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000181 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000182 return service_client.ResponseBody(resp, body['metadata'])
huangtianhua1346d702013-12-09 18:42:35 +0800183
184 def update_snapshot_metadata_item(self, snapshot_id, id, meta_item):
185 """Update metadata item for the snapshot."""
186 put_body = json.dumps({'meta': meta_item})
187 url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200188 resp, body = self.put(url, put_body)
huangtianhua1346d702013-12-09 18:42:35 +0800189 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000190 self.expected_success(200, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000191 return service_client.ResponseBody(resp, body['meta'])
huangtianhua1346d702013-12-09 18:42:35 +0800192
193 def delete_snapshot_metadata_item(self, snapshot_id, id):
194 """Delete metadata item for the snapshot."""
195 url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200196 resp, body = self.delete(url)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000197 self.expected_success(200, resp.status)
wanghaofa3908c2014-01-15 19:34:03 +0800198
199 def force_delete_snapshot(self, snapshot_id):
200 """Force Delete Snapshot."""
201 post_body = json.dumps({'os-force_delete': {}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200202 resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000203 self.expected_success(202, resp.status)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000204 return service_client.ResponseBody(resp, body)
Zhi Kun Liu38641c62014-07-10 20:12:48 +0800205
206
207class SnapshotsClientJSON(BaseSnapshotsClientJSON):
208 """Client class to send CRUD Volume V1 API requests."""