blob: 349d1b0ad94ef7943d645ca78a40be4ed5c3912e [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
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010017from tempest import exceptions
Matthew Treinishf4a9b0f2013-07-26 16:58:26 -040018from tempest.openstack.common import log as logging
Ken'ichi Ohmichia39d0be2014-12-17 08:46:11 +000019from tempest.services.volume.json import base
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010020
Matthew Treinish684d8992014-01-30 16:27:40 +000021
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010022LOG = logging.getLogger(__name__)
23
24
Ken'ichi Ohmichia39d0be2014-12-17 08:46:11 +000025class BaseSnapshotsClientJSON(base.VolumeClient):
Zhi Kun Liu38641c62014-07-10 20:12:48 +080026 """Base Client class to send CRUD Volume API requests."""
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010027
Ken'ichi Ohmichia39d0be2014-12-17 08:46:11 +000028 create_resp = 200
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010029
30 def list_snapshots(self, params=None):
31 """List all the snapshot."""
32 url = 'snapshots'
33 if params:
34 url += '?%s' % urllib.urlencode(params)
35
36 resp, body = self.get(url)
37 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000038 self.expected_success(200, resp.status)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010039 return resp, body['snapshots']
40
Abhijeet Malawade5945ffe2013-09-17 05:54:44 -070041 def list_snapshots_with_detail(self, params=None):
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010042 """List the details of all snapshots."""
43 url = 'snapshots/detail'
44 if params:
45 url += '?%s' % urllib.urlencode(params)
46
47 resp, body = self.get(url)
48 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000049 self.expected_success(200, resp.status)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010050 return resp, body['snapshots']
51
52 def get_snapshot(self, snapshot_id):
53 """Returns the details of a single snapshot."""
54 url = "snapshots/%s" % str(snapshot_id)
55 resp, body = self.get(url)
56 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000057 self.expected_success(200, resp.status)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010058 return resp, body['snapshot']
59
60 def create_snapshot(self, volume_id, **kwargs):
61 """
62 Creates a new snapshot.
63 volume_id(Required): id of the volume.
64 force: Create a snapshot even if the volume attached (Default=False)
65 display_name: Optional snapshot Name.
66 display_description: User friendly snapshot description.
67 """
68 post_body = {'volume_id': volume_id}
69 post_body.update(kwargs)
70 post_body = json.dumps({'snapshot': post_body})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +020071 resp, body = self.post('snapshots', post_body)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010072 body = json.loads(body)
Zhi Kun Liu38641c62014-07-10 20:12:48 +080073 self.expected_success(self.create_resp, resp.status)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010074 return resp, body['snapshot']
75
QingXin Mengdc95f5e2013-09-16 19:06:44 -070076 def update_snapshot(self, snapshot_id, **kwargs):
77 """Updates a snapshot."""
78 put_body = json.dumps({'snapshot': kwargs})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +020079 resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
QingXin Mengdc95f5e2013-09-16 19:06:44 -070080 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +000081 self.expected_success(200, resp.status)
QingXin Mengdc95f5e2013-09-16 19:06:44 -070082 return resp, body['snapshot']
83
Attila Fazekasa8b5fe72013-08-01 16:59:06 +020084 # NOTE(afazekas): just for the wait function
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010085 def _get_snapshot_status(self, snapshot_id):
86 resp, body = self.get_snapshot(snapshot_id)
87 status = body['status']
Attila Fazekasa8b5fe72013-08-01 16:59:06 +020088 # NOTE(afazekas): snapshot can reach an "error"
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010089 # state in a "normal" lifecycle
90 if (status == 'error'):
91 raise exceptions.SnapshotBuildErrorException(
Sean Dague14c68182013-04-14 15:34:30 -040092 snapshot_id=snapshot_id)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010093
94 return status
95
Attila Fazekasa8b5fe72013-08-01 16:59:06 +020096 # NOTE(afazkas): Wait reinvented again. It is not in the correct layer
Attila Fazekas36b1fcf2013-01-31 16:41:04 +010097 def wait_for_snapshot_status(self, snapshot_id, status):
98 """Waits for a Snapshot to reach a given status."""
99 start_time = time.time()
100 old_value = value = self._get_snapshot_status(snapshot_id)
101 while True:
102 dtime = time.time() - start_time
103 time.sleep(self.build_interval)
104 if value != old_value:
105 LOG.info('Value transition from "%s" to "%s"'
106 'in %d second(s).', old_value,
107 value, dtime)
108 if (value == status):
109 return value
110
111 if dtime > self.build_timeout:
112 message = ('Time Limit Exceeded! (%ds)'
113 'while waiting for %s, '
114 'but we got %s.' %
115 (self.build_timeout, status, value))
116 raise exceptions.TimeoutException(message)
117 time.sleep(self.build_interval)
118 old_value = value
119 value = self._get_snapshot_status(snapshot_id)
120
121 def delete_snapshot(self, snapshot_id):
122 """Delete Snapshot."""
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000123 resp, body = self.delete("snapshots/%s" % str(snapshot_id))
124 self.expected_success(202, resp.status)
Attila Fazekas36b1fcf2013-01-31 16:41:04 +0100125
126 def is_resource_deleted(self, id):
127 try:
128 self.get_snapshot(id)
129 except exceptions.NotFound:
130 return True
131 return False
zhangyanzid4d3c6d2013-11-06 09:27:13 +0800132
Matt Riedemannd2b96512014-10-13 10:18:16 -0700133 @property
134 def resource_type(self):
135 """Returns the primary type of resource this client works with."""
136 return 'volume-snapshot'
137
zhangyanzid4d3c6d2013-11-06 09:27:13 +0800138 def reset_snapshot_status(self, snapshot_id, status):
139 """Reset the specified snapshot's status."""
140 post_body = json.dumps({'os-reset_status': {"status": status}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200141 resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000142 self.expected_success(202, resp.status)
zhangyanzid4d3c6d2013-11-06 09:27:13 +0800143 return resp, body
144
145 def update_snapshot_status(self, snapshot_id, status, progress):
146 """Update the specified snapshot's status."""
147 post_body = {
148 'status': status,
149 'progress': progress
150 }
151 post_body = json.dumps({'os-update_snapshot_status': post_body})
152 url = 'snapshots/%s/action' % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200153 resp, body = self.post(url, post_body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000154 self.expected_success(202, resp.status)
zhangyanzid4d3c6d2013-11-06 09:27:13 +0800155 return resp, body
huangtianhua1346d702013-12-09 18:42:35 +0800156
157 def create_snapshot_metadata(self, snapshot_id, metadata):
158 """Create metadata for the snapshot."""
159 put_body = json.dumps({'metadata': metadata})
160 url = "snapshots/%s/metadata" % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200161 resp, body = self.post(url, put_body)
huangtianhua1346d702013-12-09 18:42:35 +0800162 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000163 self.expected_success(200, resp.status)
huangtianhua1346d702013-12-09 18:42:35 +0800164 return resp, body['metadata']
165
166 def get_snapshot_metadata(self, snapshot_id):
167 """Get metadata of the snapshot."""
168 url = "snapshots/%s/metadata" % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200169 resp, body = self.get(url)
huangtianhua1346d702013-12-09 18:42:35 +0800170 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000171 self.expected_success(200, resp.status)
huangtianhua1346d702013-12-09 18:42:35 +0800172 return resp, body['metadata']
173
174 def update_snapshot_metadata(self, snapshot_id, metadata):
175 """Update metadata for the snapshot."""
176 put_body = json.dumps({'metadata': metadata})
177 url = "snapshots/%s/metadata" % str(snapshot_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200178 resp, body = self.put(url, put_body)
huangtianhua1346d702013-12-09 18:42:35 +0800179 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000180 self.expected_success(200, resp.status)
huangtianhua1346d702013-12-09 18:42:35 +0800181 return resp, body['metadata']
182
183 def update_snapshot_metadata_item(self, snapshot_id, id, meta_item):
184 """Update metadata item for the snapshot."""
185 put_body = json.dumps({'meta': meta_item})
186 url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200187 resp, body = self.put(url, put_body)
huangtianhua1346d702013-12-09 18:42:35 +0800188 body = json.loads(body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000189 self.expected_success(200, resp.status)
huangtianhua1346d702013-12-09 18:42:35 +0800190 return resp, body['meta']
191
192 def delete_snapshot_metadata_item(self, snapshot_id, id):
193 """Delete metadata item for the snapshot."""
194 url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200195 resp, body = self.delete(url)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000196 self.expected_success(200, resp.status)
wanghaofa3908c2014-01-15 19:34:03 +0800197
198 def force_delete_snapshot(self, snapshot_id):
199 """Force Delete Snapshot."""
200 post_body = json.dumps({'os-force_delete': {}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200201 resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
Swapnil Kulkarnid9df38c2014-08-16 18:06:52 +0000202 self.expected_success(202, resp.status)
wanghaofa3908c2014-01-15 19:34:03 +0800203 return resp, body
Zhi Kun Liu38641c62014-07-10 20:12:48 +0800204
205
206class SnapshotsClientJSON(BaseSnapshotsClientJSON):
207 """Client class to send CRUD Volume V1 API requests."""