Set lock_path correctly.
[openstack-build/neutron-build.git] / neutron / tests / tempest / services / network / json / network_client.py
1 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
2 #    not use this file except in compliance with the License. You may obtain
3 #    a copy of the License at
4 #
5 #         http://www.apache.org/licenses/LICENSE-2.0
6 #
7 #    Unless required by applicable law or agreed to in writing, software
8 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 #    License for the specific language governing permissions and limitations
11 #    under the License.
12
13 import time
14
15 from oslo_serialization import jsonutils as json
16 from six.moves.urllib import parse as urlparse
17 from tempest_lib.common.utils import misc
18 from tempest_lib import exceptions as lib_exc
19
20 from neutron.tests.tempest.common import service_client
21 from neutron.tests.tempest import exceptions
22
23
24 class NetworkClientJSON(service_client.ServiceClient):
25
26     """
27     Tempest REST client for Neutron. Uses v2 of the Neutron API, since the
28     V1 API has been removed from the code base.
29
30     Implements create, delete, update, list and show for the basic Neutron
31     abstractions (networks, sub-networks, routers, ports and floating IP):
32
33     Implements add/remove interface to router using subnet ID / port ID
34
35     It also implements list, show, update and reset for OpenStack Networking
36     quotas
37     """
38
39     version = '2.0'
40     uri_prefix = "v2.0"
41
42     def get_uri(self, plural_name):
43         # get service prefix from resource name
44
45         # The following list represents resource names that do not require
46         # changing underscore to a hyphen
47         hyphen_exceptions = [
48             "firewall_rules", "firewall_policies", "service_profiles"]
49         # the following map is used to construct proper URI
50         # for the given neutron resource
51         service_resource_prefix_map = {
52             'networks': '',
53             'subnets': '',
54             'subnetpools': '',
55             'ports': '',
56             'ipsecpolicies': 'vpn',
57             'vpnservices': 'vpn',
58             'ikepolicies': 'vpn',
59             'ipsec-site-connections': 'vpn',
60             'metering_labels': 'metering',
61             'metering_label_rules': 'metering',
62             'firewall_rules': 'fw',
63             'firewall_policies': 'fw',
64             'firewalls': 'fw',
65             'policies': 'qos',
66             'bandwidth_limit_rules': 'qos',
67             'rule_types': 'qos',
68             'rbac-policies': '',
69         }
70         service_prefix = service_resource_prefix_map.get(
71             plural_name)
72         if plural_name not in hyphen_exceptions:
73             plural_name = plural_name.replace("_", "-")
74         if service_prefix:
75             uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
76                                 plural_name)
77         else:
78             uri = '%s/%s' % (self.uri_prefix, plural_name)
79         return uri
80
81     def pluralize(self, resource_name):
82         # get plural from map or just add 's'
83
84         # map from resource name to a plural name
85         # needed only for those which can't be constructed as name + 's'
86         resource_plural_map = {
87             'security_groups': 'security_groups',
88             'security_group_rules': 'security_group_rules',
89             'ipsecpolicy': 'ipsecpolicies',
90             'ikepolicy': 'ikepolicies',
91             'ipsec_site_connection': 'ipsec-site-connections',
92             'quotas': 'quotas',
93             'firewall_policy': 'firewall_policies',
94             'qos_policy': 'policies',
95             'rbac_policy': 'rbac_policies',
96         }
97         return resource_plural_map.get(resource_name, resource_name + 's')
98
99     def _lister(self, plural_name):
100         def _list(**filters):
101             uri = self.get_uri(plural_name)
102             if filters:
103                 uri += '?' + urlparse.urlencode(filters, doseq=1)
104             resp, body = self.get(uri)
105             result = {plural_name: self.deserialize_list(body)}
106             self.expected_success(200, resp.status)
107             return service_client.ResponseBody(resp, result)
108
109         return _list
110
111     def _deleter(self, resource_name):
112         def _delete(resource_id):
113             plural = self.pluralize(resource_name)
114             uri = '%s/%s' % (self.get_uri(plural), resource_id)
115             resp, body = self.delete(uri)
116             self.expected_success(204, resp.status)
117             return service_client.ResponseBody(resp, body)
118
119         return _delete
120
121     def _shower(self, resource_name):
122         def _show(resource_id, **fields):
123             # fields is a dict which key is 'fields' and value is a
124             # list of field's name. An example:
125             # {'fields': ['id', 'name']}
126             plural = self.pluralize(resource_name)
127             uri = '%s/%s' % (self.get_uri(plural), resource_id)
128             if fields:
129                 uri += '?' + urlparse.urlencode(fields, doseq=1)
130             resp, body = self.get(uri)
131             body = self.deserialize_single(body)
132             self.expected_success(200, resp.status)
133             return service_client.ResponseBody(resp, body)
134
135         return _show
136
137     def _creater(self, resource_name):
138         def _create(**kwargs):
139             plural = self.pluralize(resource_name)
140             uri = self.get_uri(plural)
141             post_data = self.serialize({resource_name: kwargs})
142             resp, body = self.post(uri, post_data)
143             body = self.deserialize_single(body)
144             self.expected_success(201, resp.status)
145             return service_client.ResponseBody(resp, body)
146
147         return _create
148
149     def _updater(self, resource_name):
150         def _update(res_id, **kwargs):
151             plural = self.pluralize(resource_name)
152             uri = '%s/%s' % (self.get_uri(plural), res_id)
153             post_data = self.serialize({resource_name: kwargs})
154             resp, body = self.put(uri, post_data)
155             body = self.deserialize_single(body)
156             self.expected_success(200, resp.status)
157             return service_client.ResponseBody(resp, body)
158
159         return _update
160
161     def __getattr__(self, name):
162         method_prefixes = ["list_", "delete_", "show_", "create_", "update_"]
163         method_functors = [self._lister,
164                            self._deleter,
165                            self._shower,
166                            self._creater,
167                            self._updater]
168         for index, prefix in enumerate(method_prefixes):
169             prefix_len = len(prefix)
170             if name[:prefix_len] == prefix:
171                 return method_functors[index](name[prefix_len:])
172         raise AttributeError(name)
173
174     # Common methods that are hard to automate
175     def create_bulk_network(self, names, shared=False):
176         network_list = [{'name': name, 'shared': shared} for name in names]
177         post_data = {'networks': network_list}
178         body = self.serialize_list(post_data, "networks", "network")
179         uri = self.get_uri("networks")
180         resp, body = self.post(uri, body)
181         body = {'networks': self.deserialize_list(body)}
182         self.expected_success(201, resp.status)
183         return service_client.ResponseBody(resp, body)
184
185     def create_bulk_subnet(self, subnet_list):
186         post_data = {'subnets': subnet_list}
187         body = self.serialize_list(post_data, 'subnets', 'subnet')
188         uri = self.get_uri('subnets')
189         resp, body = self.post(uri, body)
190         body = {'subnets': self.deserialize_list(body)}
191         self.expected_success(201, resp.status)
192         return service_client.ResponseBody(resp, body)
193
194     def create_bulk_port(self, port_list):
195         post_data = {'ports': port_list}
196         body = self.serialize_list(post_data, 'ports', 'port')
197         uri = self.get_uri('ports')
198         resp, body = self.post(uri, body)
199         body = {'ports': self.deserialize_list(body)}
200         self.expected_success(201, resp.status)
201         return service_client.ResponseBody(resp, body)
202
203     def wait_for_resource_deletion(self, resource_type, id):
204         """Waits for a resource to be deleted."""
205         start_time = int(time.time())
206         while True:
207             if self.is_resource_deleted(resource_type, id):
208                 return
209             if int(time.time()) - start_time >= self.build_timeout:
210                 raise exceptions.TimeoutException
211             time.sleep(self.build_interval)
212
213     def is_resource_deleted(self, resource_type, id):
214         method = 'show_' + resource_type
215         try:
216             getattr(self, method)(id)
217         except AttributeError:
218             raise Exception("Unknown resource type %s " % resource_type)
219         except lib_exc.NotFound:
220             return True
221         return False
222
223     def wait_for_resource_status(self, fetch, status, interval=None,
224                                  timeout=None):
225         """
226         @summary: Waits for a network resource to reach a status
227         @param fetch: the callable to be used to query the resource status
228         @type fecth: callable that takes no parameters and returns the resource
229         @param status: the status that the resource has to reach
230         @type status: String
231         @param interval: the number of seconds to wait between each status
232           query
233         @type interval: Integer
234         @param timeout: the maximum number of seconds to wait for the resource
235           to reach the desired status
236         @type timeout: Integer
237         """
238         if not interval:
239             interval = self.build_interval
240         if not timeout:
241             timeout = self.build_timeout
242         start_time = time.time()
243
244         while time.time() - start_time <= timeout:
245             resource = fetch()
246             if resource['status'] == status:
247                 return
248             time.sleep(interval)
249
250         # At this point, the wait has timed out
251         message = 'Resource %s' % (str(resource))
252         message += ' failed to reach status %s' % status
253         message += ' (current: %s)' % resource['status']
254         message += ' within the required time %s' % timeout
255         caller = misc.find_test_caller()
256         if caller:
257             message = '(%s) %s' % (caller, message)
258         raise exceptions.TimeoutException(message)
259
260     def deserialize_single(self, body):
261         return json.loads(body)
262
263     def deserialize_list(self, body):
264         res = json.loads(body)
265         # expecting response in form
266         # {'resources': [ res1, res2] } => when pagination disabled
267         # {'resources': [..], 'resources_links': {}} => if pagination enabled
268         for k in res.keys():
269             if k.endswith("_links"):
270                 continue
271             return res[k]
272
273     def serialize(self, data):
274         return json.dumps(data)
275
276     def serialize_list(self, data, root=None, item=None):
277         return self.serialize(data)
278
279     def update_quotas(self, tenant_id, **kwargs):
280         put_body = {'quota': kwargs}
281         body = json.dumps(put_body)
282         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
283         resp, body = self.put(uri, body)
284         self.expected_success(200, resp.status)
285         body = json.loads(body)
286         return service_client.ResponseBody(resp, body['quota'])
287
288     def reset_quotas(self, tenant_id):
289         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
290         resp, body = self.delete(uri)
291         self.expected_success(204, resp.status)
292         return service_client.ResponseBody(resp, body)
293
294     def create_router(self, name, admin_state_up=True, **kwargs):
295         post_body = {'router': kwargs}
296         post_body['router']['name'] = name
297         post_body['router']['admin_state_up'] = admin_state_up
298         body = json.dumps(post_body)
299         uri = '%s/routers' % (self.uri_prefix)
300         resp, body = self.post(uri, body)
301         self.expected_success(201, resp.status)
302         body = json.loads(body)
303         return service_client.ResponseBody(resp, body)
304
305     def _update_router(self, router_id, set_enable_snat, **kwargs):
306         uri = '%s/routers/%s' % (self.uri_prefix, router_id)
307         resp, body = self.get(uri)
308         self.expected_success(200, resp.status)
309         body = json.loads(body)
310         update_body = {}
311         update_body['name'] = kwargs.get('name', body['router']['name'])
312         update_body['admin_state_up'] = kwargs.get(
313             'admin_state_up', body['router']['admin_state_up'])
314         cur_gw_info = body['router']['external_gateway_info']
315         if cur_gw_info:
316             # TODO(kevinbenton): setting the external gateway info is not
317             # allowed for a regular tenant. If the ability to update is also
318             # merged, a test case for this will need to be added similar to
319             # the SNAT case.
320             cur_gw_info.pop('external_fixed_ips', None)
321             if not set_enable_snat:
322                 cur_gw_info.pop('enable_snat', None)
323         update_body['external_gateway_info'] = kwargs.get(
324             'external_gateway_info', body['router']['external_gateway_info'])
325         if 'distributed' in kwargs:
326             update_body['distributed'] = kwargs['distributed']
327         update_body = dict(router=update_body)
328         update_body = json.dumps(update_body)
329         resp, body = self.put(uri, update_body)
330         self.expected_success(200, resp.status)
331         body = json.loads(body)
332         return service_client.ResponseBody(resp, body)
333
334     def update_router(self, router_id, **kwargs):
335         """Update a router leaving enable_snat to its default value."""
336         # If external_gateway_info contains enable_snat the request will fail
337         # with 404 unless executed with admin client, and therefore we instruct
338         # _update_router to not set this attribute
339         # NOTE(salv-orlando): The above applies as long as Neutron's default
340         # policy is to restrict enable_snat usage to admins only.
341         return self._update_router(router_id, set_enable_snat=False, **kwargs)
342
343     def update_router_with_snat_gw_info(self, router_id, **kwargs):
344         """Update a router passing also the enable_snat attribute.
345
346         This method must be execute with admin credentials, otherwise the API
347         call will return a 404 error.
348         """
349         return self._update_router(router_id, set_enable_snat=True, **kwargs)
350
351     def add_router_interface_with_subnet_id(self, router_id, subnet_id):
352         uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
353                                                       router_id)
354         update_body = {"subnet_id": subnet_id}
355         update_body = json.dumps(update_body)
356         resp, body = self.put(uri, update_body)
357         self.expected_success(200, resp.status)
358         body = json.loads(body)
359         return service_client.ResponseBody(resp, body)
360
361     def add_router_interface_with_port_id(self, router_id, port_id):
362         uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
363                                                       router_id)
364         update_body = {"port_id": port_id}
365         update_body = json.dumps(update_body)
366         resp, body = self.put(uri, update_body)
367         self.expected_success(200, resp.status)
368         body = json.loads(body)
369         return service_client.ResponseBody(resp, body)
370
371     def remove_router_interface_with_subnet_id(self, router_id, subnet_id):
372         uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
373                                                          router_id)
374         update_body = {"subnet_id": subnet_id}
375         update_body = json.dumps(update_body)
376         resp, body = self.put(uri, update_body)
377         self.expected_success(200, resp.status)
378         body = json.loads(body)
379         return service_client.ResponseBody(resp, body)
380
381     def remove_router_interface_with_port_id(self, router_id, port_id):
382         uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
383                                                          router_id)
384         update_body = {"port_id": port_id}
385         update_body = json.dumps(update_body)
386         resp, body = self.put(uri, update_body)
387         self.expected_success(200, resp.status)
388         body = json.loads(body)
389         return service_client.ResponseBody(resp, body)
390
391     def list_router_interfaces(self, uuid):
392         uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
393         resp, body = self.get(uri)
394         self.expected_success(200, resp.status)
395         body = json.loads(body)
396         return service_client.ResponseBody(resp, body)
397
398     def update_agent(self, agent_id, agent_info):
399         """
400         :param agent_info: Agent update information.
401         E.g {"admin_state_up": True}
402         """
403         uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
404         agent = {"agent": agent_info}
405         body = json.dumps(agent)
406         resp, body = self.put(uri, body)
407         self.expected_success(200, resp.status)
408         body = json.loads(body)
409         return service_client.ResponseBody(resp, body)
410
411     def list_routers_on_l3_agent(self, agent_id):
412         uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
413         resp, body = self.get(uri)
414         self.expected_success(200, resp.status)
415         body = json.loads(body)
416         return service_client.ResponseBody(resp, body)
417
418     def list_l3_agents_hosting_router(self, router_id):
419         uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
420         resp, body = self.get(uri)
421         self.expected_success(200, resp.status)
422         body = json.loads(body)
423         return service_client.ResponseBody(resp, body)
424
425     def add_router_to_l3_agent(self, agent_id, router_id):
426         uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
427         post_body = {"router_id": router_id}
428         body = json.dumps(post_body)
429         resp, body = self.post(uri, body)
430         self.expected_success(201, resp.status)
431         body = json.loads(body)
432         return service_client.ResponseBody(resp, body)
433
434     def remove_router_from_l3_agent(self, agent_id, router_id):
435         uri = '%s/agents/%s/l3-routers/%s' % (
436             self.uri_prefix, agent_id, router_id)
437         resp, body = self.delete(uri)
438         self.expected_success(204, resp.status)
439         return service_client.ResponseBody(resp, body)
440
441     def list_dhcp_agent_hosting_network(self, network_id):
442         uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
443         resp, body = self.get(uri)
444         self.expected_success(200, resp.status)
445         body = json.loads(body)
446         return service_client.ResponseBody(resp, body)
447
448     def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
449         uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
450         resp, body = self.get(uri)
451         self.expected_success(200, resp.status)
452         body = json.loads(body)
453         return service_client.ResponseBody(resp, body)
454
455     def remove_network_from_dhcp_agent(self, agent_id, network_id):
456         uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
457                                                  network_id)
458         resp, body = self.delete(uri)
459         self.expected_success(204, resp.status)
460         return service_client.ResponseBody(resp, body)
461
462     def create_ikepolicy(self, name, **kwargs):
463         post_body = {
464             "ikepolicy": {
465                 "name": name,
466             }
467         }
468         for key, val in kwargs.items():
469             post_body['ikepolicy'][key] = val
470         body = json.dumps(post_body)
471         uri = '%s/vpn/ikepolicies' % (self.uri_prefix)
472         resp, body = self.post(uri, body)
473         self.expected_success(201, resp.status)
474         body = json.loads(body)
475         return service_client.ResponseBody(resp, body)
476
477     def update_extra_routes(self, router_id, nexthop, destination):
478         uri = '%s/routers/%s' % (self.uri_prefix, router_id)
479         put_body = {
480             'router': {
481                 'routes': [{'nexthop': nexthop,
482                             "destination": destination}]
483             }
484         }
485         body = json.dumps(put_body)
486         resp, body = self.put(uri, body)
487         self.expected_success(200, resp.status)
488         body = json.loads(body)
489         return service_client.ResponseBody(resp, body)
490
491     def delete_extra_routes(self, router_id):
492         uri = '%s/routers/%s' % (self.uri_prefix, router_id)
493         null_routes = None
494         put_body = {
495             'router': {
496                 'routes': null_routes
497             }
498         }
499         body = json.dumps(put_body)
500         resp, body = self.put(uri, body)
501         self.expected_success(200, resp.status)
502         body = json.loads(body)
503         return service_client.ResponseBody(resp, body)
504
505     def add_dhcp_agent_to_network(self, agent_id, network_id):
506         post_body = {'network_id': network_id}
507         body = json.dumps(post_body)
508         uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
509         resp, body = self.post(uri, body)
510         self.expected_success(201, resp.status)
511         body = json.loads(body)
512         return service_client.ResponseBody(resp, body)
513
514     def insert_firewall_rule_in_policy(self, firewall_policy_id,
515                                        firewall_rule_id, insert_after="",
516                                        insert_before=""):
517         uri = '%s/fw/firewall_policies/%s/insert_rule' % (self.uri_prefix,
518                                                           firewall_policy_id)
519         body = {
520             "firewall_rule_id": firewall_rule_id,
521             "insert_after": insert_after,
522             "insert_before": insert_before
523         }
524         body = json.dumps(body)
525         resp, body = self.put(uri, body)
526         self.expected_success(200, resp.status)
527         body = json.loads(body)
528         return service_client.ResponseBody(resp, body)
529
530     def remove_firewall_rule_from_policy(self, firewall_policy_id,
531                                          firewall_rule_id):
532         uri = '%s/fw/firewall_policies/%s/remove_rule' % (self.uri_prefix,
533                                                           firewall_policy_id)
534         update_body = {"firewall_rule_id": firewall_rule_id}
535         update_body = json.dumps(update_body)
536         resp, body = self.put(uri, update_body)
537         self.expected_success(200, resp.status)
538         body = json.loads(body)
539         return service_client.ResponseBody(resp, body)
540
541     def list_qos_policies(self, **filters):
542         if filters:
543             uri = '%s/qos/policies?%s' % (self.uri_prefix,
544                                           urlparse.urlencode(filters))
545         else:
546             uri = '%s/qos/policies' % self.uri_prefix
547         resp, body = self.get(uri)
548         self.expected_success(200, resp.status)
549         body = json.loads(body)
550         return service_client.ResponseBody(resp, body)
551
552     def create_qos_policy(self, name, description, shared, tenant_id=None):
553         uri = '%s/qos/policies' % self.uri_prefix
554         post_data = {'policy': {
555                 'name': name,
556                 'description': description,
557                 'shared': shared
558             }}
559         if tenant_id is not None:
560             post_data['policy']['tenant_id'] = tenant_id
561         resp, body = self.post(uri, self.serialize(post_data))
562         body = self.deserialize_single(body)
563         self.expected_success(201, resp.status)
564         return service_client.ResponseBody(resp, body)
565
566     def update_qos_policy(self, policy_id, **kwargs):
567         uri = '%s/qos/policies/%s' % (self.uri_prefix, policy_id)
568         post_data = self.serialize({'policy': kwargs})
569         resp, body = self.put(uri, post_data)
570         body = self.deserialize_single(body)
571         self.expected_success(200, resp.status)
572         return service_client.ResponseBody(resp, body)
573
574     def create_bandwidth_limit_rule(self, policy_id, max_kbps, max_burst_kbps):
575         uri = '%s/qos/policies/%s/bandwidth_limit_rules' % (
576             self.uri_prefix, policy_id)
577         post_data = self.serialize(
578             {'bandwidth_limit_rule': {
579                 'max_kbps': max_kbps,
580                 'max_burst_kbps': max_burst_kbps}
581             })
582         resp, body = self.post(uri, post_data)
583         self.expected_success(201, resp.status)
584         body = json.loads(body)
585         return service_client.ResponseBody(resp, body)
586
587     def list_bandwidth_limit_rules(self, policy_id):
588         uri = '%s/qos/policies/%s/bandwidth_limit_rules' % (
589             self.uri_prefix, policy_id)
590         resp, body = self.get(uri)
591         body = self.deserialize_single(body)
592         self.expected_success(200, resp.status)
593         return service_client.ResponseBody(resp, body)
594
595     def show_bandwidth_limit_rule(self, policy_id, rule_id):
596         uri = '%s/qos/policies/%s/bandwidth_limit_rules/%s' % (
597             self.uri_prefix, policy_id, rule_id)
598         resp, body = self.get(uri)
599         body = self.deserialize_single(body)
600         self.expected_success(200, resp.status)
601         return service_client.ResponseBody(resp, body)
602
603     def update_bandwidth_limit_rule(self, policy_id, rule_id, **kwargs):
604         uri = '%s/qos/policies/%s/bandwidth_limit_rules/%s' % (
605             self.uri_prefix, policy_id, rule_id)
606         post_data = {'bandwidth_limit_rule': kwargs}
607         resp, body = self.put(uri, json.dumps(post_data))
608         body = self.deserialize_single(body)
609         self.expected_success(200, resp.status)
610         return service_client.ResponseBody(resp, body)
611
612     def delete_bandwidth_limit_rule(self, policy_id, rule_id):
613         uri = '%s/qos/policies/%s/bandwidth_limit_rules/%s' % (
614             self.uri_prefix, policy_id, rule_id)
615         resp, body = self.delete(uri)
616         self.expected_success(204, resp.status)
617         return service_client.ResponseBody(resp, body)
618
619     def list_qos_rule_types(self):
620         uri = '%s/qos/rule-types' % self.uri_prefix
621         resp, body = self.get(uri)
622         self.expected_success(200, resp.status)
623         body = json.loads(body)
624         return service_client.ResponseBody(resp, body)