blob: a1c74d964dd1d53059feb3c1f4dbf68b0f80f834 [file] [log] [blame]
dwallecke62b9f02012-10-10 23:34:42 -05001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
ZhiQiang Fan39f97222013-09-20 04:49:44 +08003# Copyright 2012 OpenStack Foundation
dwallecke62b9f02012-10-10 23:34:42 -05004# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
Tiago Melloeda03b52012-08-22 23:47:29 -030018import urllib
19
20from lxml import etree
21
22from tempest.common.rest_client import RestClientXML
dwallecke62b9f02012-10-10 23:34:42 -050023from tempest.services.compute.xml.common import Document
24from tempest.services.compute.xml.common import Element
ivan-zhuae7c7c52013-10-21 22:13:22 +080025from tempest.services.compute.xml.common import Text
dwallecke62b9f02012-10-10 23:34:42 -050026from tempest.services.compute.xml.common import xml_to_json
27from tempest.services.compute.xml.common import XMLNS_11
Tiago Melloeda03b52012-08-22 23:47:29 -030028
29
30XMLNS_OS_FLV_EXT_DATA = \
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +053031 "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1"
32XMLNS_OS_FLV_ACCESS = \
ivan-zhuae7c7c52013-10-21 22:13:22 +080033 "http://docs.openstack.org/compute/ext/flavor_access/api/v2"
Tiago Melloeda03b52012-08-22 23:47:29 -030034
35
36class FlavorsClientXML(RestClientXML):
37
38 def __init__(self, config, username, password, auth_url, tenant_name=None):
39 super(FlavorsClientXML, self).__init__(config, username, password,
40 auth_url, tenant_name)
41 self.service = self.config.compute.catalog_type
42
43 def _format_flavor(self, f):
44 flavor = {'links': []}
45 for k, v in f.items():
Ken'ichi Ohmichi35772602013-11-14 15:03:27 +090046 if k == 'id':
47 flavor['id'] = v
48 continue
49
Tiago Melloeda03b52012-08-22 23:47:29 -030050 if k == 'link':
51 flavor['links'].append(v)
52 continue
53
54 if k == '{%s}ephemeral' % XMLNS_OS_FLV_EXT_DATA:
55 k = 'OS-FLV-EXT-DATA:ephemeral'
56
ivan-zhuae7c7c52013-10-21 22:13:22 +080057 if k == '{%s}is_public' % XMLNS_OS_FLV_ACCESS:
58 k = 'os-flavor-access:is_public'
59 v = True if v == 'True' else False
60
Aditi Raveeshccfa6532013-08-19 17:11:05 +053061 if k == 'extra_specs':
Aarti Kriplanic04a0fc2013-08-06 05:10:49 -050062 k = 'OS-FLV-WITH-EXT-SPECS:extra_specs'
63 flavor[k] = dict(v)
64 continue
65
Tiago Melloeda03b52012-08-22 23:47:29 -030066 try:
67 v = int(v)
68 except ValueError:
69 try:
70 v = float(v)
71 except ValueError:
72 pass
73
74 flavor[k] = v
75
76 return flavor
77
78 def _parse_array(self, node):
79 return [self._format_flavor(xml_to_json(x)) for x in node]
80
81 def _list_flavors(self, url, params):
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050082 if params:
Tiago Melloeda03b52012-08-22 23:47:29 -030083 url += "?%s" % urllib.urlencode(params)
84
85 resp, body = self.get(url, self.headers)
86 flavors = self._parse_array(etree.fromstring(body))
87 return resp, flavors
88
89 def list_flavors(self, params=None):
90 url = 'flavors'
91 return self._list_flavors(url, params)
92
93 def list_flavors_with_detail(self, params=None):
94 url = 'flavors/detail'
95 return self._list_flavors(url, params)
96
97 def get_flavor_details(self, flavor_id):
98 resp, body = self.get("flavors/%s" % str(flavor_id), self.headers)
99 body = xml_to_json(etree.fromstring(body))
100 flavor = self._format_flavor(body)
101 return resp, flavor
102
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530103 def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs):
Sean Daguef237ccb2013-01-04 15:19:14 -0500104 """Creates a new flavor or instance type."""
Tiago Melloeda03b52012-08-22 23:47:29 -0300105 flavor = Element("flavor",
106 xmlns=XMLNS_11,
107 ram=ram,
108 vcpus=vcpus,
109 disk=disk,
110 id=flavor_id,
Tiago Melloeda03b52012-08-22 23:47:29 -0300111 name=name)
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530112 if kwargs.get('rxtx'):
113 flavor.add_attr('rxtx_factor', kwargs.get('rxtx'))
114 if kwargs.get('swap'):
115 flavor.add_attr('swap', kwargs.get('swap'))
116 if kwargs.get('ephemeral'):
117 flavor.add_attr('OS-FLV-EXT-DATA:ephemeral',
118 kwargs.get('ephemeral'))
119 if kwargs.get('is_public'):
120 flavor.add_attr('os-flavor-access:is_public',
121 kwargs.get('is_public'))
Tiago Melloeda03b52012-08-22 23:47:29 -0300122 flavor.add_attr('xmlns:OS-FLV-EXT-DATA', XMLNS_OS_FLV_EXT_DATA)
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530123 flavor.add_attr('xmlns:os-flavor-access', XMLNS_OS_FLV_ACCESS)
Tiago Melloeda03b52012-08-22 23:47:29 -0300124 resp, body = self.post('flavors', str(Document(flavor)), self.headers)
125 body = xml_to_json(etree.fromstring(body))
126 flavor = self._format_flavor(body)
127 return resp, flavor
128
129 def delete_flavor(self, flavor_id):
Sean Daguef237ccb2013-01-04 15:19:14 -0500130 """Deletes the given flavor."""
Tiago Melloeda03b52012-08-22 23:47:29 -0300131 return self.delete("flavors/%s" % str(flavor_id), self.headers)
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530132
133 def is_resource_deleted(self, id):
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200134 # Did not use get_flavor_details(id) for verification as it gives
135 # 200 ok even for deleted id. LP #981263
136 # we can remove the loop here and use get by ID when bug gets sortedout
rajalakshmi-ganesanf344cc32012-12-31 20:02:27 +0530137 resp, flavors = self.list_flavors_with_detail()
138 for flavor in flavors:
139 if flavor['id'] == id:
140 return False
141 return True
rajalakshmi-ganesan6d0e7a22012-12-18 20:52:38 +0530142
143 def set_flavor_extra_spec(self, flavor_id, specs):
144 """Sets extra Specs to the mentioned flavor."""
145 extra_specs = Element("extra_specs")
146 for key in specs.keys():
147 extra_specs.add_attr(key, specs[key])
148 resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
149 str(Document(extra_specs)), self.headers)
150 body = xml_to_json(etree.fromstring(body))
151 return resp, body
152
153 def get_flavor_extra_spec(self, flavor_id):
154 """Gets extra Specs of the mentioned flavor."""
155 resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id,
156 self.headers)
157 body = xml_to_json(etree.fromstring(body))
158 return resp, body
159
lijunjbj9feaa212013-10-14 02:11:49 -0500160 def get_flavor_extra_spec_with_key(self, flavor_id, key):
Zhu Zhu2e1872d2013-10-08 21:23:29 -0500161 """Gets extra Specs key-value of the mentioned flavor and key."""
162 resp, xml_body = self.get('flavors/%s/os-extra_specs/%s' %
163 (str(flavor_id), key), self.headers)
164 body = {}
165 element = etree.fromstring(xml_body)
166 key = element.get('key')
167 body[key] = xml_to_json(element)
lijunjbj9feaa212013-10-14 02:11:49 -0500168 return resp, body
169
ivan-zhuae7c7c52013-10-21 22:13:22 +0800170 def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
Zhu Zhu2e1872d2013-10-08 21:23:29 -0500171 """Update extra Specs details of the mentioned flavor and key."""
ivan-zhuae7c7c52013-10-21 22:13:22 +0800172 doc = Document()
173 for (k, v) in kwargs.items():
174 element = Element(k)
175 doc.append(element)
176 value = Text(v)
177 element.append(value)
178
179 resp, body = self.put('flavors/%s/os-extra_specs/%s' %
180 (flavor_id, key),
181 str(doc), self.headers)
182 body = xml_to_json(etree.fromstring(body))
183 return resp, {key: body}
184
rajalakshmi-ganesan6d0e7a22012-12-18 20:52:38 +0530185 def unset_flavor_extra_spec(self, flavor_id, key):
186 """Unsets an extra spec based on the mentioned flavor and key."""
187 return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
188 key))
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900189
190 def _parse_array_access(self, node):
191 return [xml_to_json(x) for x in node]
192
Zhu Zhu705f24a2013-10-11 05:52:54 -0500193 def list_flavor_access(self, flavor_id):
194 """Gets flavor access information given the flavor id."""
195 resp, body = self.get('flavors/%s/os-flavor-access' % str(flavor_id),
196 self.headers)
197 body = self._parse_array(etree.fromstring(body))
198 return resp, body
199
Mitsuhiko Yamazakif5f4da62013-03-29 17:40:03 +0900200 def add_flavor_access(self, flavor_id, tenant_id):
201 """Add flavor access for the specified tenant."""
202 doc = Document()
203 server = Element("addTenantAccess")
204 doc.append(server)
205 server.add_attr("tenant", tenant_id)
206 resp, body = self.post('flavors/%s/action' % str(flavor_id),
207 str(doc), self.headers)
208 body = self._parse_array_access(etree.fromstring(body))
209 return resp, body
210
211 def remove_flavor_access(self, flavor_id, tenant_id):
212 """Remove flavor access from the specified tenant."""
213 doc = Document()
214 server = Element("removeTenantAccess")
215 doc.append(server)
216 server.add_attr("tenant", tenant_id)
217 resp, body = self.post('flavors/%s/action' % str(flavor_id),
218 str(doc), self.headers)
219 body = self._parse_array_access(etree.fromstring(body))
220 return resp, body