blob: 9737be36294a95d49fd5fd00897c1aebcc786f51 [file] [log] [blame]
Kurt Taylor6a6f5be2013-04-02 18:53:47 -04001# Copyright 2013 IBM Corp.
Matthew Treinish72ea4422013-02-07 14:42:49 -05002# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Jordan Pittier9a573d92016-04-29 17:04:39 +020016import functools
Matthew Treinish72ea4422013-02-07 14:42:49 -050017
Matthew Treinish21905512015-07-13 10:33:35 -040018from oslo_serialization import jsonutils as json
Matthew Treinish89128142015-04-23 10:44:30 -040019from six.moves.urllib import parse as urllib
Masayuki Igawabfa07602015-01-20 18:47:17 +090020
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -080021from tempest.lib.common import rest_client
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050022from tempest.lib import exceptions as lib_exc
Matthew Treinish72ea4422013-02-07 14:42:49 -050023
Jordan Pittier9a573d92016-04-29 17:04:39 +020024CHUNKSIZE = 1024 * 64 # 64kB
Attila Fazekase72b7cd2013-03-26 18:34:21 +010025
Matthew Treinish72ea4422013-02-07 14:42:49 -050026
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -080027class ImagesClient(rest_client.RestClient):
Andrea Frittolicf40a862016-06-07 14:45:32 +090028 api_version = "v1"
Matthew Treinish72ea4422013-02-07 14:42:49 -050029
Matthew Treinish72ea4422013-02-07 14:42:49 -050030 def _create_with_data(self, headers, data):
Jordan Pittier9a573d92016-04-29 17:04:39 +020031 # We are going to do chunked transfert, so split the input data
32 # info fixed-sized chunks.
33 headers['Content-Type'] = 'application/octet-stream'
34 data = iter(functools.partial(data.read, CHUNKSIZE), b'')
Andrea Frittolicf40a862016-06-07 14:45:32 +090035 resp, body = self.request('POST', 'images',
Jordan Pittier9a573d92016-04-29 17:04:39 +020036 headers=headers, body=data, chunked=True)
Andrea Frittolicf40a862016-06-07 14:45:32 +090037 self._error_checker('POST', 'images', headers, data, resp,
Jordan Pittier9a573d92016-04-29 17:04:39 +020038 body)
39 body = json.loads(body)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -080040 return rest_client.ResponseBody(resp, body)
Matthew Treinish72ea4422013-02-07 14:42:49 -050041
42 def _update_with_data(self, image_id, headers, data):
Jordan Pittier9a573d92016-04-29 17:04:39 +020043 # We are going to do chunked transfert, so split the input data
44 # info fixed-sized chunks.
45 headers['Content-Type'] = 'application/octet-stream'
46 data = iter(functools.partial(data.read, CHUNKSIZE), b'')
Andrea Frittolicf40a862016-06-07 14:45:32 +090047 url = 'images/%s' % image_id
Jordan Pittier9a573d92016-04-29 17:04:39 +020048 resp, body = self.request('PUT', url, headers=headers,
49 body=data, chunked=True)
Matthew Treinish72ea4422013-02-07 14:42:49 -050050 self._error_checker('PUT', url, headers, data,
Jordan Pittier9a573d92016-04-29 17:04:39 +020051 resp, body)
52 body = json.loads(body)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -080053 return rest_client.ResponseBody(resp, body)
Matthew Treinish72ea4422013-02-07 14:42:49 -050054
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000055 @property
56 def http(self):
57 if self._http is None:
Masayuki Igawabc7e1892015-03-03 11:46:48 +090058 self._http = self._get_http()
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000059 return self._http
60
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -070061 def create_image(self, data=None, headers=None):
Ken'ichi Ohmichid9016382016-06-13 15:57:42 -070062 """Create an image.
63
zhufl3a36f052016-09-07 11:08:19 +080064 For a full list of available parameters, please refer to the official
65 API reference:
66 http://developer.openstack.org/api-ref-image-v1.html#createImage-v1
Ken'ichi Ohmichid9016382016-06-13 15:57:42 -070067 """
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -070068 if headers is None:
69 headers = {}
Matthew Treinish72ea4422013-02-07 14:42:49 -050070
Ghanshyam86a31e12015-12-16 15:42:47 +090071 if data is not None:
72 return self._create_with_data(headers, data)
Matthew Treinish72ea4422013-02-07 14:42:49 -050073
Andrea Frittolicf40a862016-06-07 14:45:32 +090074 resp, body = self.post('images', None, headers)
David Kranz9c3b3b62014-06-19 16:05:53 -040075 self.expected_success(201, resp.status)
Matthew Treinish72ea4422013-02-07 14:42:49 -050076 body = json.loads(body)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -080077 return rest_client.ResponseBody(resp, body)
Matthew Treinish72ea4422013-02-07 14:42:49 -050078
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -070079 def update_image(self, image_id, data=None, headers=None):
Ken'ichi Ohmichid9016382016-06-13 15:57:42 -070080 """Update an image.
81
zhufl3a36f052016-09-07 11:08:19 +080082 For a full list of available parameters, please refer to the official
83 API reference:
84 http://developer.openstack.org/api-ref-image-v1.html#updateImage-v1
Ken'ichi Ohmichid9016382016-06-13 15:57:42 -070085 """
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -070086 if headers is None:
87 headers = {}
Matthew Treinish72ea4422013-02-07 14:42:49 -050088
89 if data is not None:
90 return self._update_with_data(image_id, headers, data)
91
Andrea Frittolicf40a862016-06-07 14:45:32 +090092 url = 'images/%s' % image_id
Ghanshyam86a31e12015-12-16 15:42:47 +090093 resp, body = self.put(url, None, headers)
David Kranz9c3b3b62014-06-19 16:05:53 -040094 self.expected_success(200, resp.status)
Matthew Treinish72ea4422013-02-07 14:42:49 -050095 body = json.loads(body)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -080096 return rest_client.ResponseBody(resp, body)
Matthew Treinish72ea4422013-02-07 14:42:49 -050097
98 def delete_image(self, image_id):
Andrea Frittolicf40a862016-06-07 14:45:32 +090099 url = 'images/%s' % image_id
David Kranz9c3b3b62014-06-19 16:05:53 -0400100 resp, body = self.delete(url)
101 self.expected_success(200, resp.status)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -0800102 return rest_client.ResponseBody(resp, body)
Matthew Treinish72ea4422013-02-07 14:42:49 -0500103
Ghanshyame60db482016-01-13 09:50:12 +0900104 def list_images(self, detail=False, **kwargs):
105 """Return a list of all images filtered by input parameters.
106
zhufl3a36f052016-09-07 11:08:19 +0800107 For a full list of available parameters, please refer to the official
108 API reference:
109 http://developer.openstack.org/api-ref/image/v1/#list-images
Ghanshyame60db482016-01-13 09:50:12 +0900110
111 Most parameters except the following are passed to the API without
112 any changes.
113 :param changes_since: The name is changed to changes-since
114 """
Andrea Frittolicf40a862016-06-07 14:45:32 +0900115 url = 'images'
Matthew Treinish72ea4422013-02-07 14:42:49 -0500116
Ken'ichi Ohmichibcad2a22015-05-22 09:37:06 +0000117 if detail:
118 url += '/detail'
Attila Fazekas11795b52013-02-24 15:49:08 +0100119
Ghanshyame60db482016-01-13 09:50:12 +0900120 if kwargs.get('changes_since'):
121 kwargs['changes-since'] = kwargs.pop('changes_since')
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800122
Attila Fazekas11795b52013-02-24 15:49:08 +0100123 if len(kwargs) > 0:
124 url += '?%s' % urllib.urlencode(kwargs)
Matthew Treinish72ea4422013-02-07 14:42:49 -0500125
126 resp, body = self.get(url)
David Kranz9c3b3b62014-06-19 16:05:53 -0400127 self.expected_success(200, resp.status)
Matthew Treinish72ea4422013-02-07 14:42:49 -0500128 body = json.loads(body)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -0800129 return rest_client.ResponseBody(resp, body)
Matthew Treinish72ea4422013-02-07 14:42:49 -0500130
Yaroslav Lobankov9d28a0f2016-04-19 15:05:57 +0300131 def check_image(self, image_id):
132 """Check image metadata."""
Andrea Frittolicf40a862016-06-07 14:45:32 +0900133 url = 'images/%s' % image_id
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700134 resp, body = self.head(url)
David Kranz9c3b3b62014-06-19 16:05:53 -0400135 self.expected_success(200, resp.status)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -0800136 return rest_client.ResponseBody(resp, body)
Attila Fazekase72b7cd2013-03-26 18:34:21 +0100137
Ken'ichi Ohmichi5d410762015-05-22 01:10:03 +0000138 def show_image(self, image_id):
Yaroslav Lobankov9d28a0f2016-04-19 15:05:57 +0300139 """Get image details plus the image itself."""
Andrea Frittolicf40a862016-06-07 14:45:32 +0900140 url = 'images/%s' % image_id
Attila Fazekase72b7cd2013-03-26 18:34:21 +0100141 resp, body = self.get(url)
David Kranz9c3b3b62014-06-19 16:05:53 -0400142 self.expected_success(200, resp.status)
Ken'ichi Ohmichie76510d2016-03-02 10:33:48 -0800143 return rest_client.ResponseBodyData(resp, body)
Matthew Treinish72ea4422013-02-07 14:42:49 -0500144
145 def is_resource_deleted(self, id):
146 try:
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700147 resp = self.check_image(id)
148 if resp.response["x-image-meta-status"] == 'deleted':
Joshua White95dcef22016-04-11 06:17:42 -0700149 return True
Masayuki Igawabfa07602015-01-20 18:47:17 +0900150 except lib_exc.NotFound:
Matthew Treinish72ea4422013-02-07 14:42:49 -0500151 return True
152 return False
Matthew Treinishfa23cf82013-03-06 14:23:02 -0500153
Matt Riedemannd2b96512014-10-13 10:18:16 -0700154 @property
155 def resource_type(self):
156 """Returns the primary type of resource this client works with."""
157 return 'image_meta'