blob: 68ef3234e103b255acf74ac02ffc7e958c8986ad [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
dwallecke62b9f02012-10-10 23:34:42 -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
Tiago Melloeda03b52012-08-22 23:47:29 -030016import urllib
17
18from lxml import etree
19
vponomaryov960eeb42014-02-22 18:25:25 +020020from tempest.common import rest_client
Matthew Treinish28f164c2014-03-04 18:55:06 +000021from tempest.common import xml_utils
Matthew Treinish684d8992014-01-30 16:27:40 +000022from tempest import config
Tiago Melloeda03b52012-08-22 23:47:29 -030023
Matthew Treinish684d8992014-01-30 16:27:40 +000024CONF = config.CONF
Tiago Melloeda03b52012-08-22 23:47:29 -030025
26XMLNS_OS_FLV_EXT_DATA = \
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +053027 "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1"
28XMLNS_OS_FLV_ACCESS = \
ivan-zhuae7c7c52013-10-21 22:13:22 +080029 "http://docs.openstack.org/compute/ext/flavor_access/api/v2"
Tiago Melloeda03b52012-08-22 23:47:29 -030030
31
vponomaryov960eeb42014-02-22 18:25:25 +020032class FlavorsClientXML(rest_client.RestClient):
33 TYPE = "xml"
Tiago Melloeda03b52012-08-22 23:47:29 -030034
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000035 def __init__(self, auth_provider):
36 super(FlavorsClientXML, self).__init__(auth_provider)
Matthew Treinish684d8992014-01-30 16:27:40 +000037 self.service = CONF.compute.catalog_type
Tiago Melloeda03b52012-08-22 23:47:29 -030038
39 def _format_flavor(self, f):
40 flavor = {'links': []}
41 for k, v in f.items():
Ken'ichi Ohmichi35772602013-11-14 15:03:27 +090042 if k == 'id':
43 flavor['id'] = v
44 continue
45
Tiago Melloeda03b52012-08-22 23:47:29 -030046 if k == 'link':
47 flavor['links'].append(v)
48 continue
49
50 if k == '{%s}ephemeral' % XMLNS_OS_FLV_EXT_DATA:
51 k = 'OS-FLV-EXT-DATA:ephemeral'
52
ivan-zhuae7c7c52013-10-21 22:13:22 +080053 if k == '{%s}is_public' % XMLNS_OS_FLV_ACCESS:
54 k = 'os-flavor-access:is_public'
55 v = True if v == 'True' else False
56
Aditi Raveeshccfa6532013-08-19 17:11:05 +053057 if k == 'extra_specs':
Aarti Kriplanic04a0fc2013-08-06 05:10:49 -050058 k = 'OS-FLV-WITH-EXT-SPECS:extra_specs'
59 flavor[k] = dict(v)
60 continue
61
Tiago Melloeda03b52012-08-22 23:47:29 -030062 try:
63 v = int(v)
64 except ValueError:
65 try:
66 v = float(v)
67 except ValueError:
68 pass
69
70 flavor[k] = v
71
72 return flavor
73
74 def _parse_array(self, node):
Matthew Treinish28f164c2014-03-04 18:55:06 +000075 return [self._format_flavor(xml_utils.xml_to_json(x)) for x in node]
Tiago Melloeda03b52012-08-22 23:47:29 -030076
77 def _list_flavors(self, url, params):
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050078 if params:
Tiago Melloeda03b52012-08-22 23:47:29 -030079 url += "?%s" % urllib.urlencode(params)
80
vponomaryovf4c27f92014-02-18 10:56:42 +020081 resp, body = self.get(url)
Tiago Melloeda03b52012-08-22 23:47:29 -030082 flavors = self._parse_array(etree.fromstring(body))
83 return resp, flavors
84
85 def list_flavors(self, params=None):
86 url = 'flavors'
87 return self._list_flavors(url, params)
88
89 def list_flavors_with_detail(self, params=None):
90 url = 'flavors/detail'
91 return self._list_flavors(url, params)
92
93 def get_flavor_details(self, flavor_id):
vponomaryovf4c27f92014-02-18 10:56:42 +020094 resp, body = self.get("flavors/%s" % str(flavor_id))
Matthew Treinish28f164c2014-03-04 18:55:06 +000095 body = xml_utils.xml_to_json(etree.fromstring(body))
Tiago Melloeda03b52012-08-22 23:47:29 -030096 flavor = self._format_flavor(body)
97 return resp, flavor
98
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +053099 def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs):
Sean Daguef237ccb2013-01-04 15:19:14 -0500100 """Creates a new flavor or instance type."""
Matthew Treinish28f164c2014-03-04 18:55:06 +0000101 flavor = xml_utils.Element("flavor",
102 xmlns=xml_utils.XMLNS_11,
103 ram=ram,
104 vcpus=vcpus,
105 disk=disk,
106 id=flavor_id,
107 name=name)
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530108 if kwargs.get('rxtx'):
109 flavor.add_attr('rxtx_factor', kwargs.get('rxtx'))
110 if kwargs.get('swap'):
111 flavor.add_attr('swap', kwargs.get('swap'))
112 if kwargs.get('ephemeral'):
113 flavor.add_attr('OS-FLV-EXT-DATA:ephemeral',
114 kwargs.get('ephemeral'))
115 if kwargs.get('is_public'):
116 flavor.add_attr('os-flavor-access:is_public',
117 kwargs.get('is_public'))
Tiago Melloeda03b52012-08-22 23:47:29 -0300118 flavor.add_attr('xmlns:OS-FLV-EXT-DATA', XMLNS_OS_FLV_EXT_DATA)
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530119 flavor.add_attr('xmlns:os-flavor-access', XMLNS_OS_FLV_ACCESS)
Matthew Treinish28f164c2014-03-04 18:55:06 +0000120 resp, body = self.post('flavors', str(xml_utils.Document(flavor)))
121 body = xml_utils.xml_to_json(etree.fromstring(body))
Tiago Melloeda03b52012-08-22 23:47:29 -0300122 flavor = self._format_flavor(body)
123 return resp, flavor
124
125 def delete_flavor(self, flavor_id):
Sean Daguef237ccb2013-01-04 15:19:14 -0500126 """Deletes the given flavor."""
vponomaryovf4c27f92014-02-18 10:56:42 +0200127 return self.delete("flavors/%s" % str(flavor_id))
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530128
129 def is_resource_deleted(self, id):
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200130 # Did not use get_flavor_details(id) for verification as it gives
131 # 200 ok even for deleted id. LP #981263
132 # we can remove the loop here and use get by ID when bug gets sortedout
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530133 resp, flavors = self.list_flavors_with_detail()
134 for flavor in flavors:
135 if flavor['id'] == id:
136 return False
137 return True
rajalakshmi-ganesan6d0e7a22012-12-18 20:52:38 +0530138
139 def set_flavor_extra_spec(self, flavor_id, specs):
140 """Sets extra Specs to the mentioned flavor."""
Matthew Treinish28f164c2014-03-04 18:55:06 +0000141 extra_specs = xml_utils.Element("extra_specs")
rajalakshmi-ganesan6d0e7a22012-12-18 20:52:38 +0530142 for key in specs.keys():
143 extra_specs.add_attr(key, specs[key])
144 resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
Matthew Treinish28f164c2014-03-04 18:55:06 +0000145 str(xml_utils.Document(extra_specs)))
146 body = xml_utils.xml_to_json(etree.fromstring(body))
rajalakshmi-ganesan6d0e7a22012-12-18 20:52:38 +0530147 return resp, body
148
149 def get_flavor_extra_spec(self, flavor_id):
150 """Gets extra Specs of the mentioned flavor."""
vponomaryovf4c27f92014-02-18 10:56:42 +0200151 resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
Matthew Treinish28f164c2014-03-04 18:55:06 +0000152 body = xml_utils.xml_to_json(etree.fromstring(body))
rajalakshmi-ganesan6d0e7a22012-12-18 20:52:38 +0530153 return resp, body
154
lijunjbj9feaa212013-10-14 02:11:49 -0500155 def get_flavor_extra_spec_with_key(self, flavor_id, key):
Zhu Zhu2e1872d2013-10-08 21:23:29 -0500156 """Gets extra Specs key-value of the mentioned flavor and key."""
157 resp, xml_body = self.get('flavors/%s/os-extra_specs/%s' %
vponomaryovf4c27f92014-02-18 10:56:42 +0200158 (str(flavor_id), key))
Zhu Zhu2e1872d2013-10-08 21:23:29 -0500159 body = {}
160 element = etree.fromstring(xml_body)
161 key = element.get('key')
Matthew Treinish28f164c2014-03-04 18:55:06 +0000162 body[key] = xml_utils.xml_to_json(element)
lijunjbj9feaa212013-10-14 02:11:49 -0500163 return resp, body
164
ivan-zhuae7c7c52013-10-21 22:13:22 +0800165 def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
Zhu Zhu2e1872d2013-10-08 21:23:29 -0500166 """Update extra Specs details of the mentioned flavor and key."""
Matthew Treinish28f164c2014-03-04 18:55:06 +0000167 doc = xml_utils.Document()
ivan-zhuae7c7c52013-10-21 22:13:22 +0800168 for (k, v) in kwargs.items():
Matthew Treinish28f164c2014-03-04 18:55:06 +0000169 element = xml_utils.Element(k)
ivan-zhuae7c7c52013-10-21 22:13:22 +0800170 doc.append(element)
Matthew Treinish28f164c2014-03-04 18:55:06 +0000171 value = xml_utils.Text(v)
ivan-zhuae7c7c52013-10-21 22:13:22 +0800172 element.append(value)
173
174 resp, body = self.put('flavors/%s/os-extra_specs/%s' %
vponomaryovf4c27f92014-02-18 10:56:42 +0200175 (flavor_id, key), str(doc))
Matthew Treinish28f164c2014-03-04 18:55:06 +0000176 body = xml_utils.xml_to_json(etree.fromstring(body))
ivan-zhuae7c7c52013-10-21 22:13:22 +0800177 return resp, {key: body}
178
rajalakshmi-ganesan6d0e7a22012-12-18 20:52:38 +0530179 def unset_flavor_extra_spec(self, flavor_id, key):
180 """Unsets an extra spec based on the mentioned flavor and key."""
181 return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
182 key))
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900183
184 def _parse_array_access(self, node):
Matthew Treinish28f164c2014-03-04 18:55:06 +0000185 return [xml_utils.xml_to_json(x) for x in node]
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900186
Zhu Zhu705f24a2013-10-11 05:52:54 -0500187 def list_flavor_access(self, flavor_id):
188 """Gets flavor access information given the flavor id."""
vponomaryovf4c27f92014-02-18 10:56:42 +0200189 resp, body = self.get('flavors/%s/os-flavor-access' % str(flavor_id))
Zhu Zhu705f24a2013-10-11 05:52:54 -0500190 body = self._parse_array(etree.fromstring(body))
191 return resp, body
192
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900193 def add_flavor_access(self, flavor_id, tenant_id):
194 """Add flavor access for the specified tenant."""
Matthew Treinish28f164c2014-03-04 18:55:06 +0000195 doc = xml_utils.Document()
196 server = xml_utils.Element("addTenantAccess")
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900197 doc.append(server)
198 server.add_attr("tenant", tenant_id)
vponomaryovf4c27f92014-02-18 10:56:42 +0200199 resp, body = self.post('flavors/%s/action' % str(flavor_id), str(doc))
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900200 body = self._parse_array_access(etree.fromstring(body))
201 return resp, body
202
203 def remove_flavor_access(self, flavor_id, tenant_id):
204 """Remove flavor access from the specified tenant."""
Matthew Treinish28f164c2014-03-04 18:55:06 +0000205 doc = xml_utils.Document()
206 server = xml_utils.Element("removeTenantAccess")
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900207 doc.append(server)
208 server.add_attr("tenant", tenant_id)
vponomaryovf4c27f92014-02-18 10:56:42 +0200209 resp, body = self.post('flavors/%s/action' % str(flavor_id), str(doc))
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900210 body = self._parse_array_access(etree.fromstring(body))
211 return resp, body