blob: e0a26dee6bcf0f887f8146933918636f68212273 [file] [log] [blame]
Daryl Wallecked8bef32011-12-05 23:02:08 -06001from tempest import exceptions
2from tempest.common import rest_client
Daryl Wallecke5b83d42011-11-10 14:39:02 -06003import json
Daryl Wallecke5b83d42011-11-10 14:39:02 -06004import time
5
6
7class ServersClient(object):
8
Jay Pipes7f757632011-12-02 15:53:32 -05009 def __init__(self, config, username, key, auth_url, tenant_name=None):
10 self.config = config
Daryl Walleckb90a1a62012-02-27 11:23:10 -060011 catalog_type = self.config.nova.catalog_type
Jay Pipes7f757632011-12-02 15:53:32 -050012 self.client = rest_client.RestClient(config, username, key,
Daryl Walleckb90a1a62012-02-27 11:23:10 -060013 auth_url, catalog_type,
Daryl Walleck4aa82a92012-02-14 15:45:46 -060014 tenant_name)
Daryl Wallecked8bef32011-12-05 23:02:08 -060015
Daryl Wallecke5b83d42011-11-10 14:39:02 -060016 self.build_interval = self.config.nova.build_interval
17 self.build_timeout = self.config.nova.build_timeout
18 self.headers = {'Content-Type': 'application/json',
19 'Accept': 'application/json'}
20
Rohit Karajgi95446a22011-12-12 06:21:43 -080021 def create_server(self, name, image_ref, flavor_ref, **kwargs):
Daryl Wallecke5b83d42011-11-10 14:39:02 -060022 """
23 Creates an instance of a server.
Rohit Karajgi95446a22011-12-12 06:21:43 -080024 name (Required): The name of the server.
25 image_ref (Required): Reference to the image used to build the server.
26 flavor_ref (Required): The flavor used to build the server.
27 Following optional keyword arguments are accepted:
Daryl Wallecke5b83d42011-11-10 14:39:02 -060028 adminPass: Sets the initial root password.
Rohit Karajgi95446a22011-12-12 06:21:43 -080029 metadata: A dictionary of values to be used as metadata.
Daryl Wallecke5b83d42011-11-10 14:39:02 -060030 personality: A list of dictionaries for files to be injected into
31 the server.
Rohit Karajgi95446a22011-12-12 06:21:43 -080032 security_groups: A list of security group dicts.
33 networks: A list of network dicts with UUID and fixed_ip.
34 user_data: User data for instance.
35 availability_zone: Availability zone in which to launch instance.
Daryl Wallecke5b83d42011-11-10 14:39:02 -060036 accessIPv4: The IPv4 access address for the server.
37 accessIPv6: The IPv6 access address for the server.
Rohit Karajgi95446a22011-12-12 06:21:43 -080038 min_count: Count of minimum number of instances to launch.
39 max_count: Count of maximum number of instances to launch.
Daryl Wallecke5b83d42011-11-10 14:39:02 -060040 """
Daryl Wallecke5b83d42011-11-10 14:39:02 -060041 post_body = {
42 'name': name,
43 'imageRef': image_ref,
44 'flavorRef': flavor_ref,
Rohit Karajgi95446a22011-12-12 06:21:43 -080045 'metadata': kwargs.get('meta'),
46 'personality': kwargs.get('personality'),
47 'adminPass': kwargs.get('adminPass'),
48 'security_groups': kwargs.get('security_groups'),
49 'networks': kwargs.get('networks'),
50 'user_data': kwargs.get('user_data'),
51 'availability_zone': kwargs.get('availability_zone'),
52 'accessIPv4': kwargs.get('accessIPv4'),
53 'accessIPv6': kwargs.get('accessIPv6'),
54 'min_count': kwargs.get('min_count'),
55 'max_count': kwargs.get('max_count'),
Daryl Wallecke5b83d42011-11-10 14:39:02 -060056 }
57
Daryl Wallecke5b83d42011-11-10 14:39:02 -060058 post_body = json.dumps({'server': post_body})
59 resp, body = self.client.post('servers', post_body, self.headers)
Jay Pipes5135bfc2012-01-05 15:46:49 -050060
Daryl Wallecke5b83d42011-11-10 14:39:02 -060061 body = json.loads(body)
62 return resp, body['server']
63
64 def update_server(self, server_id, name=None, meta=None, accessIPv4=None,
65 accessIPv6=None):
66 """
67 Updates the properties of an existing server.
68 server_id: The id of an existing server.
69 name: The name of the server.
70 personality: A list of files to be injected into the server.
71 accessIPv4: The IPv4 access address for the server.
72 accessIPv6: The IPv6 access address for the server.
73 """
74
75 post_body = {}
76
77 if meta != None:
78 post_body['metadata'] = meta
79
80 if name != None:
81 post_body['name'] = name
82
83 if accessIPv4 != None:
84 post_body['accessIPv4'] = accessIPv4
85
86 if accessIPv6 != None:
87 post_body['accessIPv6'] = accessIPv6
88
89 post_body = json.dumps({'server': post_body})
90 resp, body = self.client.put("servers/%s" % str(server_id),
91 post_body, self.headers)
92 body = json.loads(body)
93 return resp, body['server']
94
95 def get_server(self, server_id):
96 """Returns the details of an existing server"""
97 resp, body = self.client.get("servers/%s" % str(server_id))
98 body = json.loads(body)
99 return resp, body['server']
100
101 def delete_server(self, server_id):
102 """Deletes the given server"""
103 return self.client.delete("servers/%s" % str(server_id))
104
105 def list_servers(self, params=None):
106 """Lists all servers for a user"""
107
108 url = 'servers'
109 if params != None:
110 param_list = []
111 for param, value in params.iteritems():
112 param_list.append("%s=%s&" % (param, value))
113
114 url = "servers?" + "".join(param_list)
115
116 resp, body = self.client.get(url)
117 body = json.loads(body)
118 return resp, body
119
120 def list_servers_with_detail(self, params=None):
121 """Lists all servers in detail for a user"""
122
123 url = 'servers/detail'
124 if params != None:
125 param_list = []
126 for param, value in params.iteritems():
127 param_list.append("%s=%s&" % (param, value))
128
129 url = "servers/detail?" + "".join(param_list)
130
131 resp, body = self.client.get(url)
132 body = json.loads(body)
133 return resp, body
134
135 def wait_for_server_status(self, server_id, status):
136 """Waits for a server to reach a given status"""
137 resp, body = self.get_server(server_id)
138 server_status = body['status']
139 start = int(time.time())
140
141 while(server_status != status):
142 time.sleep(self.build_interval)
143 resp, body = self.get_server(server_id)
144 server_status = body['status']
145
Jay Pipes5135bfc2012-01-05 15:46:49 -0500146 if server_status == 'ERROR':
147 raise exceptions.BuildErrorException(server_id=server_id)
Daryl Wallecke5b83d42011-11-10 14:39:02 -0600148
Eoghan Glynnf72969c2012-03-05 12:33:10 +0000149 timed_out = int(time.time()) - start >= self.build_timeout
150
151 if server_status != status and timed_out:
David Kranzbcc91952012-02-24 16:08:52 -0500152 message = 'Server %s failed to reach %s status within the \
153 required time (%s s).' % (server_id, status,
154 self.build_timeout)
Eoghan Glynnf72969c2012-03-05 12:33:10 +0000155 message += ' Current status: %s.' % server_status
Daryl Walleckf0087032011-12-18 13:37:05 -0600156 raise exceptions.TimeoutException(message)
Daryl Wallecke5b83d42011-11-10 14:39:02 -0600157
158 def list_addresses(self, server_id):
159 """Lists all addresses for a server"""
160 resp, body = self.client.get("servers/%s/ips" % str(server_id))
161 body = json.loads(body)
162 return resp, body['addresses']
163
164 def list_addresses_by_network(self, server_id, network_id):
165 """Lists all addresses of a specific network type for a server"""
166 resp, body = self.client.get("servers/%s/ips/%s" %
167 (str(server_id), network_id))
168 body = json.loads(body)
169 return resp, body
170
171 def change_password(self, server_id, password):
172 """Changes the root password for the server"""
173 post_body = {
174 'changePassword': {
175 'adminPass': password,
176 }
177 }
178
179 post_body = json.dumps(post_body)
180 return self.client.post('servers/%s/action' % str(server_id),
181 post_body, self.headers)
182
183 def reboot(self, server_id, reboot_type):
184 """Reboots a server"""
185 post_body = {
186 'reboot': {
187 'type': reboot_type,
188 }
189 }
190
191 post_body = json.dumps(post_body)
192 return self.client.post('servers/%s/action' % str(server_id),
193 post_body, self.headers)
194
195 def rebuild(self, server_id, image_ref, name=None, meta=None,
196 personality=None, adminPass=None):
197 """Rebuilds a server with a new image"""
198 post_body = {
199 'imageRef': image_ref,
200 }
201
202 if name != None:
203 post_body['name'] = name
204
205 if adminPass != None:
206 post_body['adminPass'] = adminPass
207
208 if meta != None:
209 post_body['metadata'] = meta
210
211 if personality != None:
212 post_body['personality'] = personality
213
214 post_body = json.dumps({'rebuild': post_body})
215 resp, body = self.client.post('servers/%s/action' %
216 str(server_id), post_body,
217 self.headers)
218 body = json.loads(body)
Brian Waldon738cd632011-12-12 18:45:09 -0500219 return resp, body['server']
Daryl Wallecke5b83d42011-11-10 14:39:02 -0600220
221 def resize(self, server_id, flavor_ref):
222 """Changes the flavor of a server."""
223 post_body = {
224 'resize': {
225 'flavorRef': flavor_ref,
226 }
227 }
228
229 post_body = json.dumps(post_body)
230 resp, body = self.client.post('servers/%s/action' %
231 str(server_id), post_body, self.headers)
232 return resp, body
233
234 def confirm_resize(self, server_id):
235 """Confirms the flavor change for a server"""
236 post_body = {
Brian Waldon3bde07f2011-12-13 15:11:22 -0500237 'confirmResize': None,
Daryl Wallecke5b83d42011-11-10 14:39:02 -0600238 }
239
240 post_body = json.dumps(post_body)
241 resp, body = self.client.post('servers/%s/action' %
242 str(server_id), post_body, self.headers)
243 return resp, body
244
245 def revert_resize(self, server_id):
246 """Reverts a server back to its original flavor"""
247 post_body = {
Brian Waldon3bde07f2011-12-13 15:11:22 -0500248 'revertResize': None,
Daryl Wallecke5b83d42011-11-10 14:39:02 -0600249 }
250
251 post_body = json.dumps(post_body)
252 resp, body = self.client.post('servers/%s/action' %
253 str(server_id), post_body, self.headers)
254 return resp, body
255
256 def create_image(self, server_id, image_name):
257 """Creates an image of the given server"""
258 post_body = {
259 'createImage': {
260 'name': image_name,
261 }
262 }
263
264 post_body = json.dumps(post_body)
265 resp, body = self.client.post('servers/%s/action' %
266 str(server_id), post_body, self.headers)
Daryl Wallecke5b83d42011-11-10 14:39:02 -0600267 return resp, body
Daryl Walleck73a9e7a2011-11-15 17:43:31 -0600268
269 def list_server_metadata(self, server_id):
270 resp, body = self.client.get("servers/%s/metadata" % str(server_id))
271 body = json.loads(body)
272 return resp, body['metadata']
273
274 def set_server_metadata(self, server_id, meta):
275 post_body = json.dumps({'metadata': meta})
276 resp, body = self.client.put('servers/%s/metadata' %
277 str(server_id), post_body, self.headers)
278 body = json.loads(body)
279 return resp, body['metadata']
280
281 def update_server_metadata(self, server_id, meta):
282 post_body = json.dumps({'metadata': meta})
283 resp, body = self.client.post('servers/%s/metadata' %
284 str(server_id), post_body, self.headers)
285 body = json.loads(body)
286 return resp, body['metadata']
287
288 def get_server_metadata_item(self, server_id, key):
289 resp, body = self.client.get("servers/%s/metadata/%s" %
290 (str(server_id), key))
291 body = json.loads(body)
292 return resp, body['meta']
293
294 def set_server_metadata_item(self, server_id, key, meta):
295 post_body = json.dumps({'meta': meta})
Daryl Walleck416af922011-11-22 22:28:33 -0600296 resp, body = self.client.put('servers/%s/metadata/%s' %
Daryl Walleck73a9e7a2011-11-15 17:43:31 -0600297 (str(server_id), key),
298 post_body, self.headers)
299 body = json.loads(body)
300 return resp, body['meta']
301
302 def delete_server_metadata_item(self, server_id, key):
303 resp, body = self.client.delete("servers/%s/metadata/%s" %
304 (str(server_id), key))
305 return resp, body