blob: 6b15404e07f03276b109ac18e63baf46bb69b8ab [file] [log] [blame]
Kurt Taylor6a6f5be2013-04-02 18:53:47 -04001# Copyright 2012 IBM Corp.
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -04002# 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
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040016import urllib
17
18from lxml import etree
19
vponomaryov960eeb42014-02-22 18:25:25 +020020from tempest.common import rest_client
Matt Riedemannc00f3262013-12-14 12:03:55 -080021from tempest.common import waiters
Matthew Treinish28f164c2014-03-04 18:55:06 +000022from tempest.common import xml_utils
Matthew Treinish684d8992014-01-30 16:27:40 +000023from tempest import config
Matthew Treinisha83a16e2012-12-07 13:44:02 -050024from tempest import exceptions
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040025
Matthew Treinish684d8992014-01-30 16:27:40 +000026CONF = config.CONF
27
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040028
vponomaryov960eeb42014-02-22 18:25:25 +020029class ImagesClientXML(rest_client.RestClient):
30 TYPE = "xml"
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040031
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000032 def __init__(self, auth_provider):
33 super(ImagesClientXML, self).__init__(auth_provider)
Matthew Treinish684d8992014-01-30 16:27:40 +000034 self.service = CONF.compute.catalog_type
35 self.build_interval = CONF.compute.build_interval
36 self.build_timeout = CONF.compute.build_timeout
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040037
38 def _parse_server(self, node):
Matthew Treinish28f164c2014-03-04 18:55:06 +000039 data = xml_utils.xml_to_json(node)
Attila Fazekas7b487be2013-02-12 11:14:41 +010040 return self._parse_links(node, data)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040041
42 def _parse_image(self, node):
Sean Daguef237ccb2013-01-04 15:19:14 -050043 """Parses detailed XML image information into dictionary."""
Matthew Treinish28f164c2014-03-04 18:55:06 +000044 data = xml_utils.xml_to_json(node)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040045
Attila Fazekas7b487be2013-02-12 11:14:41 +010046 self._parse_links(node, data)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040047
48 # parse all metadata
Attila Fazekas7b487be2013-02-12 11:14:41 +010049 if 'metadata' in data:
Matthew Treinish28f164c2014-03-04 18:55:06 +000050 tag = node.find('{%s}metadata' % xml_utils.XMLNS_11)
Attila Fazekas7b487be2013-02-12 11:14:41 +010051 data['metadata'] = dict((x.get('key'), x.text)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040052 for x in tag.getchildren())
53
54 # parse server information
Attila Fazekas7b487be2013-02-12 11:14:41 +010055 if 'server' in data:
Matthew Treinish28f164c2014-03-04 18:55:06 +000056 tag = node.find('{%s}server' % xml_utils.XMLNS_11)
Attila Fazekas7b487be2013-02-12 11:14:41 +010057 data['server'] = self._parse_server(tag)
58 return data
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040059
Attila Fazekas7b487be2013-02-12 11:14:41 +010060 def _parse_links(self, node, data):
Sean Daguef237ccb2013-01-04 15:19:14 -050061 """Append multiple links under a list."""
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040062 # look for links
Attila Fazekas7b487be2013-02-12 11:14:41 +010063 if 'link' in data:
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040064 # remove single link element
Attila Fazekas7b487be2013-02-12 11:14:41 +010065 del data['link']
Matthew Treinish28f164c2014-03-04 18:55:06 +000066 data['links'] = [xml_utils.xml_to_json(x) for x in
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040067 node.findall('{http://www.w3.org/2005/Atom}link')]
Attila Fazekas7b487be2013-02-12 11:14:41 +010068 return data
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040069
Matthew Treinish4e1b3e62013-01-10 11:30:49 -050070 def _parse_images(self, xml):
Attila Fazekas7b487be2013-02-12 11:14:41 +010071 data = {'images': []}
Matthew Treinish4e1b3e62013-01-10 11:30:49 -050072 images = xml.getchildren()
73 for image in images:
Attila Fazekas7b487be2013-02-12 11:14:41 +010074 data['images'].append(self._parse_image(image))
75 return data
Matthew Treinish4e1b3e62013-01-10 11:30:49 -050076
nayna-pateleda1d122013-03-20 14:44:31 +000077 def _parse_key_value(self, node):
78 """Parse <foo key='key'>value</foo> data into {'key': 'value'}."""
79 data = {}
80 for node in node.getchildren():
81 data[node.get('key')] = node.text
82 return data
83
84 def _parse_metadata(self, node):
85 """Parse the response body without children."""
86 data = {}
87 data[node.get('key')] = node.text
88 return data
89
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040090 def create_image(self, server_id, name, meta=None):
Sean Daguef237ccb2013-01-04 15:19:14 -050091 """Creates an image of the original server."""
Matthew Treinish28f164c2014-03-04 18:55:06 +000092 post_body = xml_utils.Element('createImage', name=name)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040093
94 if meta:
Matthew Treinish28f164c2014-03-04 18:55:06 +000095 metadata = xml_utils.Element('metadata')
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -040096 post_body.append(metadata)
97 for k, v in meta.items():
Matthew Treinish28f164c2014-03-04 18:55:06 +000098 data = xml_utils.Element('meta', key=k)
99 data.append(xml_utils.Text(v))
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400100 metadata.append(data)
101 resp, body = self.post('servers/%s/action' % str(server_id),
Matthew Treinish28f164c2014-03-04 18:55:06 +0000102 str(xml_utils.Document(post_body)))
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400103 return resp, body
104
105 def list_images(self, params=None):
Sean Daguef237ccb2013-01-04 15:19:14 -0500106 """Returns a list of all images filtered by any parameters."""
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400107 url = 'images'
108 if params:
Matthew Treinish26dd0fa2012-12-04 17:14:37 -0500109 url += '?%s' % urllib.urlencode(params)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400110
vponomaryovf4c27f92014-02-18 10:56:42 +0200111 resp, body = self.get(url)
Matthew Treinish4e1b3e62013-01-10 11:30:49 -0500112 body = self._parse_images(etree.fromstring(body))
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400113 return resp, body['images']
114
115 def list_images_with_detail(self, params=None):
Sean Daguef237ccb2013-01-04 15:19:14 -0500116 """Returns a detailed list of images filtered by any parameters."""
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400117 url = 'images/detail'
118 if params:
119 param_list = urllib.urlencode(params)
120
121 url = "images/detail?" + param_list
122
vponomaryovf4c27f92014-02-18 10:56:42 +0200123 resp, body = self.get(url)
Matthew Treinish4e1b3e62013-01-10 11:30:49 -0500124 body = self._parse_images(etree.fromstring(body))
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400125 return resp, body['images']
126
127 def get_image(self, image_id):
Sean Daguef237ccb2013-01-04 15:19:14 -0500128 """Returns the details of a single image."""
vponomaryovf4c27f92014-02-18 10:56:42 +0200129 resp, body = self.get("images/%s" % str(image_id))
Attila Fazekas54a42862013-07-28 22:31:06 +0200130 self.expected_success(200, resp)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400131 body = self._parse_image(etree.fromstring(body))
132 return resp, body
133
134 def delete_image(self, image_id):
Sean Daguef237ccb2013-01-04 15:19:14 -0500135 """Deletes the provided image."""
vponomaryovf4c27f92014-02-18 10:56:42 +0200136 return self.delete("images/%s" % str(image_id))
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400137
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400138 def wait_for_image_status(self, image_id, status):
139 """Waits for an image to reach a given status."""
Matt Riedemannc00f3262013-12-14 12:03:55 -0800140 waiters.wait_for_image_status(self, image_id, status)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400141
nayna-pateleda1d122013-03-20 14:44:31 +0000142 def _metadata_body(self, meta):
Matthew Treinish28f164c2014-03-04 18:55:06 +0000143 post_body = xml_utils.Element('metadata')
nayna-pateleda1d122013-03-20 14:44:31 +0000144 for k, v in meta.items():
Matthew Treinish28f164c2014-03-04 18:55:06 +0000145 data = xml_utils.Element('meta', key=k)
146 data.append(xml_utils.Text(v))
nayna-pateleda1d122013-03-20 14:44:31 +0000147 post_body.append(data)
148 return post_body
149
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400150 def list_image_metadata(self, image_id):
Sean Daguef237ccb2013-01-04 15:19:14 -0500151 """Lists all metadata items for an image."""
vponomaryovf4c27f92014-02-18 10:56:42 +0200152 resp, body = self.get("images/%s/metadata" % str(image_id))
nayna-pateleda1d122013-03-20 14:44:31 +0000153 body = self._parse_key_value(etree.fromstring(body))
154 return resp, body
Attila Fazekas7b487be2013-02-12 11:14:41 +0100155
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400156 def set_image_metadata(self, image_id, meta):
Sean Daguef237ccb2013-01-04 15:19:14 -0500157 """Sets the metadata for an image."""
nayna-pateleda1d122013-03-20 14:44:31 +0000158 post_body = self._metadata_body(meta)
159 resp, body = self.put('images/%s/metadata' % image_id,
Matthew Treinish28f164c2014-03-04 18:55:06 +0000160 str(xml_utils.Document(post_body)))
nayna-pateleda1d122013-03-20 14:44:31 +0000161 body = self._parse_key_value(etree.fromstring(body))
162 return resp, body
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400163
164 def update_image_metadata(self, image_id, meta):
Sean Daguef237ccb2013-01-04 15:19:14 -0500165 """Updates the metadata for an image."""
nayna-pateleda1d122013-03-20 14:44:31 +0000166 post_body = self._metadata_body(meta)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400167 resp, body = self.post('images/%s/metadata' % str(image_id),
Matthew Treinish28f164c2014-03-04 18:55:06 +0000168 str(xml_utils.Document(post_body)))
nayna-pateleda1d122013-03-20 14:44:31 +0000169 body = self._parse_key_value(etree.fromstring(body))
170 return resp, body
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400171
172 def get_image_metadata_item(self, image_id, key):
Sean Daguef237ccb2013-01-04 15:19:14 -0500173 """Returns the value for a specific image metadata key."""
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400174 resp, body = self.get("images/%s/metadata/%s.xml" %
vponomaryovf4c27f92014-02-18 10:56:42 +0200175 (str(image_id), key))
nayna-pateleda1d122013-03-20 14:44:31 +0000176 body = self._parse_metadata(etree.fromstring(body))
177 return resp, body
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400178
179 def set_image_metadata_item(self, image_id, key, meta):
Sean Daguef237ccb2013-01-04 15:19:14 -0500180 """Sets the value for a specific image metadata key."""
nayna-pateleda1d122013-03-20 14:44:31 +0000181 for k, v in meta.items():
Matthew Treinish28f164c2014-03-04 18:55:06 +0000182 post_body = xml_utils.Element('meta', key=key)
183 post_body.append(xml_utils.Text(v))
nayna-pateleda1d122013-03-20 14:44:31 +0000184 resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key),
Matthew Treinish28f164c2014-03-04 18:55:06 +0000185 str(xml_utils.Document(post_body)))
186 body = xml_utils.xml_to_json(etree.fromstring(body))
nayna-pateleda1d122013-03-20 14:44:31 +0000187 return resp, body
Attila Fazekas7b487be2013-02-12 11:14:41 +0100188
189 def update_image_metadata_item(self, image_id, key, meta):
190 """Sets the value for a specific image metadata key."""
Matthew Treinish28f164c2014-03-04 18:55:06 +0000191 post_body = xml_utils.Document('meta', xml_utils.Text(meta), key=key)
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400192 resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key),
vponomaryovf4c27f92014-02-18 10:56:42 +0200193 post_body)
Matthew Treinish28f164c2014-03-04 18:55:06 +0000194 body = xml_utils.xml_to_json(etree.fromstring(body))
Mauro S. M. Rodrigues6e373242012-08-27 18:59:19 -0400195 return resp, body['meta']
196
197 def delete_image_metadata_item(self, image_id, key):
Sean Daguef237ccb2013-01-04 15:19:14 -0500198 """Deletes a single image metadata key/value pair."""
vponomaryovf4c27f92014-02-18 10:56:42 +0200199 return self.delete("images/%s/metadata/%s" % (str(image_id), key))
Matthew Treinish0d660492013-06-04 17:26:09 -0400200
201 def is_resource_deleted(self, id):
202 try:
203 self.get_image(id)
204 except exceptions.NotFound:
205 return True
206 return False