Make sdnvpn a package
[sdnvpn.git] / sdnvpn / lib / utils.py
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2015 All rights reserved
4 # This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 import sys
11 import time
12
13 import functest.utils.functest_logger as ft_logger
14 import functest.utils.openstack_utils as os_utils
15 import re
16
17 from sdnvpn.lib import config as sdnvpn_config
18
19 logger = ft_logger.Logger("sndvpn_test_utils").getLogger()
20
21 common_config = sdnvpn_config.CommonConfig()
22
23
24 def create_net(neutron_client, name):
25     logger.debug("Creating network %s", name)
26     net_id = os_utils.create_neutron_net(neutron_client, name)
27     if not net_id:
28         logger.error(
29             "There has been a problem when creating the neutron network")
30         sys.exit(-1)
31     return net_id
32
33
34 def create_subnet(neutron_client, name, cidr, net_id):
35     logger.debug("Creating subnet %s in network %s with cidr %s",
36                  name, net_id, cidr)
37     subnet_id = os_utils.create_neutron_subnet(neutron_client,
38                                                name,
39                                                cidr,
40                                                net_id)
41     if not subnet_id:
42         logger.error(
43             "There has been a problem when creating the neutron subnet")
44         sys.exit(-1)
45     return subnet_id
46
47
48 def create_network(neutron_client, net, subnet1, cidr1,
49                    router, subnet2=None, cidr2=None):
50     """Network assoc will not work for networks/subnets created by this function.
51
52     It is an ODL limitation due to it handling routers as vpns.
53     See https://bugs.opendaylight.org/show_bug.cgi?id=6962"""
54     network_dic = os_utils.create_network_full(neutron_client,
55                                                net,
56                                                subnet1,
57                                                router,
58                                                cidr1)
59     if not network_dic:
60         logger.error(
61             "There has been a problem when creating the neutron network")
62         sys.exit(-1)
63     net_id = network_dic["net_id"]
64     subnet_id = network_dic["subnet_id"]
65     router_id = network_dic["router_id"]
66
67     if subnet2 is not None:
68         logger.debug("Creating and attaching a second subnet...")
69         subnet_id = os_utils.create_neutron_subnet(
70             neutron_client, subnet2, cidr2, net_id)
71         if not subnet_id:
72             logger.error(
73                 "There has been a problem when creating the second subnet")
74             sys.exit(-1)
75         logger.debug("Subnet '%s' created successfully" % subnet_id)
76     return net_id, subnet_id, router_id
77
78
79 def create_instance(nova_client,
80                     name,
81                     image_id,
82                     network_id,
83                     sg_id,
84                     secgroup_name=None,
85                     fixed_ip=None,
86                     compute_node='',
87                     userdata=None,
88                     files=None,
89                     **kwargs
90                     ):
91     if 'flavor' not in kwargs:
92         kwargs['flavor'] = common_config.default_flavor
93
94     logger.info("Creating instance '%s'..." % name)
95     logger.debug(
96         "Configuration:\n name=%s \n flavor=%s \n image=%s \n"
97         " network=%s\n secgroup=%s \n hypervisor=%s \n"
98         " fixed_ip=%s\n files=%s\n userdata=\n%s\n"
99         % (name, kwargs['flavor'], image_id, network_id, sg_id,
100            compute_node, fixed_ip, files, userdata))
101     instance = os_utils.create_instance_and_wait_for_active(
102         kwargs['flavor'],
103         image_id,
104         network_id,
105         name,
106         config_drive=True,
107         userdata=userdata,
108         av_zone=compute_node,
109         fixed_ip=fixed_ip,
110         files=files)
111
112     if instance is None:
113         logger.error("Error while booting instance.")
114         sys.exit(-1)
115     else:
116         logger.debug("Instance '%s' booted successfully. IP='%s'." %
117                      (name, instance.networks.itervalues().next()[0]))
118     # Retrieve IP of INSTANCE
119     # instance_ip = instance.networks.get(network_id)[0]
120
121     if secgroup_name:
122         logger.debug("Adding '%s' to security group '%s'..."
123                      % (name, secgroup_name))
124     else:
125         logger.debug("Adding '%s' to security group '%s'..."
126                      % (name, sg_id))
127     os_utils.add_secgroup_to_instance(nova_client, instance.id, sg_id)
128
129     return instance
130
131
132 def generate_ping_userdata(ips_array):
133     ips = ""
134     for ip in ips_array:
135         ips = ("%s %s" % (ips, ip))
136
137     ips = ips.replace('  ', ' ')
138     return ("#!/bin/sh\n"
139             "set%s\n"
140             "while true; do\n"
141             " for i do\n"
142             "  ip=$i\n"
143             "  ping -c 1 $ip 2>&1 >/dev/null\n"
144             "  RES=$?\n"
145             "  if [ \"Z$RES\" = \"Z0\" ] ; then\n"
146             "   echo ping $ip OK\n"
147             "  else echo ping $ip KO\n"
148             "  fi\n"
149             " done\n"
150             " sleep 1\n"
151             "done\n"
152             % ips)
153
154
155 def generate_userdata_common():
156     return ("#!/bin/sh\n"
157             "sudo mkdir -p /home/cirros/.ssh/\n"
158             "sudo chown cirros:cirros /home/cirros/.ssh/\n"
159             "sudo chown cirros:cirros /home/cirros/id_rsa\n"
160             "mv /home/cirros/id_rsa /home/cirros/.ssh/\n"
161             "sudo echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgnWtSS98Am516e"
162             "stBsq0jbyOB4eLMUYDdgzsUHsnxFQCtACwwAg9/2uq3FoGUBUWeHZNsT6jcK9"
163             "sCMEYiS479CUCzbrxcd8XaIlK38HECcDVglgBNwNzX/WDfMejXpKzZG61s98rU"
164             "ElNvZ0YDqhaqZGqxIV4ejalqLjYrQkoly3R+2k= "
165             "cirros@test1>/home/cirros/.ssh/authorized_keys\n"
166             "sudo chown cirros:cirros /home/cirros/.ssh/authorized_keys\n"
167             "chmod 700 /home/cirros/.ssh\n"
168             "chmod 644 /home/cirros/.ssh/authorized_keys\n"
169             "chmod 600 /home/cirros/.ssh/id_rsa\n"
170             )
171
172
173 def generate_userdata_with_ssh(ips_array):
174     u1 = generate_userdata_common()
175
176     ips = ""
177     for ip in ips_array:
178         ips = ("%s %s" % (ips, ip))
179
180     ips = ips.replace('  ', ' ')
181     u2 = ("#!/bin/sh\n"
182           "set%s\n"
183           "while true; do\n"
184           " for i do\n"
185           "  ip=$i\n"
186           "  hostname=$(ssh -y -i /home/cirros/.ssh/id_rsa "
187           "cirros@$ip 'hostname' </dev/zero 2>/dev/null)\n"
188           "  RES=$?\n"
189           "  if [ \"Z$RES\" = \"Z0\" ]; then echo $ip $hostname;\n"
190           "  else echo $ip 'not reachable';fi;\n"
191           " done\n"
192           " sleep 1\n"
193           "done\n"
194           % ips)
195     return (u1 + u2)
196
197
198 def wait_for_instance(instance):
199     logger.info("Waiting for instance %s to get a DHCP lease..." % instance.id)
200     # The sleep this function replaced waited for 80s
201     tries = 40
202     sleep_time = 2
203     pattern = "Lease of .* obtained, lease time"
204     expected_regex = re.compile(pattern)
205     console_log = ""
206     while tries > 0 and not expected_regex.search(console_log):
207         console_log = instance.get_console_output()
208         time.sleep(sleep_time)
209         tries -= 1
210
211     if not expected_regex.search(console_log):
212         logger.error("Instance %s seems to have failed leasing an IP."
213                      % instance.id)
214         return False
215     return True
216
217
218 def wait_for_instances_up(*args):
219     check = [wait_for_instance(instance) for instance in args]
220     return all(check)
221
222
223 def wait_for_bgp_net_assoc(neutron_client, bgpvpn_id, net_id):
224     tries = 30
225     sleep_time = 1
226     nets = []
227     logger.debug("Waiting for network %s to associate with BGPVPN %s "
228                  % (bgpvpn_id, net_id))
229
230     while tries > 0 and net_id not in nets:
231         nets = os_utils.get_bgpvpn_networks(neutron_client, bgpvpn_id)
232         time.sleep(sleep_time)
233         tries -= 1
234     if net_id not in nets:
235         logger.error("Association of network %s with BGPVPN %s failed" %
236                      (net_id, bgpvpn_id))
237         return False
238     return True
239
240
241 def wait_for_bgp_net_assocs(neutron_client, bgpvpn_id, *args):
242     check = [wait_for_bgp_net_assoc(neutron_client, bgpvpn_id, id)
243              for id in args]
244     # Return True if all associations succeeded
245     return all(check)
246
247
248 def wait_for_bgp_router_assoc(neutron_client, bgpvpn_id, router_id):
249     tries = 30
250     sleep_time = 1
251     routers = []
252     logger.debug("Waiting for router %s to associate with BGPVPN %s "
253                  % (bgpvpn_id, router_id))
254     while tries > 0 and router_id not in routers:
255         routers = os_utils.get_bgpvpn_routers(neutron_client, bgpvpn_id)
256         time.sleep(sleep_time)
257         tries -= 1
258     if router_id not in routers:
259         logger.error("Association of router %s with BGPVPN %s failed" %
260                      (router_id, bgpvpn_id))
261         return False
262     return True
263
264
265 def wait_for_bgp_router_assocs(neutron_client, bgpvpn_id, *args):
266     check = [wait_for_bgp_router_assoc(neutron_client, bgpvpn_id, id)
267              for id in args]
268     # Return True if all associations succeeded
269     return all(check)
270
271
272 def wait_before_subtest(*args, **kwargs):
273     ''' This is a placeholder.
274         TODO: Replace delay with polling logic. '''
275     time.sleep(30)
276
277
278 def assert_and_get_compute_nodes(nova_client, required_node_number=2):
279     """Get the compute nodes in the deployment
280
281     Exit if the deployment doesn't have enough compute nodes"""
282     compute_nodes = os_utils.get_hypervisors(nova_client)
283
284     num_compute_nodes = len(compute_nodes)
285     if num_compute_nodes < 2:
286         logger.error("There are %s compute nodes in the deployment. "
287                      "Minimum number of nodes to complete the test is 2."
288                      % num_compute_nodes)
289         sys.exit(-1)
290
291     logger.debug("Compute nodes: %s" % compute_nodes)
292     return compute_nodes
293
294
295 def open_icmp_ssh(neutron_client, security_group_id):
296     os_utils.create_secgroup_rule(neutron_client,
297                                   security_group_id,
298                                   'ingress',
299                                   'icmp')
300     os_utils.create_secgroup_rule(neutron_client,
301                                   security_group_id,
302                                   'tcp',
303                                   80, 80)