Auto-generated patch by python-black
[integration/test.git] / csit / suites / groupbasedpolicy / common_scripts / infrastructure_launch.py
1 #!/usr/bin/python
2
3 """
4 Spin-up script for Opendaylight GBP and GBPSFC sample concept demonstrations.
5
6 This script has to be run from the environment on which OVS switches and Docker
7 containers are located. This script works together with infrastructure_config.py
8 configuration script where the entire topology for specific scenario is configured. This
9 file defines to which already existing switch docker containers have to be connected.
10 OVS switch have to be created on the same hosting environment as this script is executed
11 from. Local switch name should match one of the names specified in configuration file so that
12 docker containers are created and connected to it.
13
14 Updated: 22.10.2015
15
16 """
17
18 import socket
19 import os
20 import sys
21 import ipaddr
22 from subprocess import call
23 from subprocess import check_output
24 from infrastructure_config import switches
25 from infrastructure_config import hosts
26 from infrastructure_config import defaultContainerImage
27
28
29 def add_controller(sw, ip):
30     """Connects OVS switch to a controller. The switch is specified
31         by it's name and the controller by it's IP address.
32
33     Args:
34         :param sw: name of a switch on which controller is set
35
36         :param ip: IP address of controller
37
38     NOTE:
39         :Required controller should listen on TCP port 6653.
40     """
41
42     try:
43         socket.inet_aton(ip)
44     except socket.error:
45         print("Error: %s is not a valid IPv4 address of controller!" % (ip))
46         os.exit(2)
47
48     call(["sudo", "ovs-vsctl", "set-controller", sw, "tcp:%s:6653" % ip])
49
50
51 def add_manager(ip):
52     """Sets OVSDB manager for OVS instance.
53
54     Args:
55         :param ip: IP address of specified manager
56
57     NOTE:
58         :Required manager should listen on TCP port 6640.
59     """
60
61     try:
62         socket.inet_aton(ip)
63     except socket.error:
64         print("Error: %s is not a valid IPv4 address of manager!" % (ip))
65         os.exit(2)
66
67     cmd = ["sudo", "ovs-vsctl", "set-manager", "tcp:%s:6640" % ip]
68     call(cmd)
69
70
71 def add_switch(name, dpid=None):
72     """Adds switch to OVS instance and sets it's DataPath ID
73         if specified.
74
75     Args:
76         :param ip: name of new switch
77
78         :param dpid: DataPath ID of new switch
79     """
80
81     call(["sudo", "ovs-vsctl", "add-br", name])  # Add bridge
82     if dpid:
83         if len(dpid) < 16:  # DPID must be 16-bytes in later versions of OVS
84             filler = "0000000000000000"
85             # prepending zeros to match 16-byt length, e.g. 123 -> 0000000000000123
86             dpid = filler[: len(filler) - len(dpid)] + dpid
87         elif len(dpid) > 16:
88             print("DPID: %s is too long" % dpid)
89             sys.exit(3)
90         call(
91             [
92                 "sudo",
93                 "ovs-vsctl",
94                 "set",
95                 "bridge",
96                 name,
97                 "other-config:datapath-id=%s" % dpid,
98             ]
99         )
100
101
102 def set_of_version(sw, version="OpenFlow13,OpenFlow12,OpenFlow10"):
103     """Sets OpenFlow protocol versions on OVS switch
104
105     Args:
106         :param sw: name of switch
107
108         :param sw: OpenFlow versions to support on switch
109     """
110
111     call(["sudo", "ovs-vsctl", "set", "bridge", sw, "protocols={}".format(version)])
112
113
114 def add_vxlan_tunnel(sw):
115     """Adds VXLAN tunnel to OVS switch.
116
117     Args:
118         :param sw: name of switch
119
120     NOTE:
121         :Remote IP is read from flows.
122     """
123     ifaceName = "{}-vxlan-0".format(sw)
124     cmd = [
125         "sudo",
126         "ovs-vsctl",
127         "add-port",
128         sw,
129         ifaceName,
130         "--",
131         "set",
132         "Interface",
133         ifaceName,
134         "type=vxlan",
135         "options:remote_ip=flow",
136         "options:key=flow",
137     ]
138     call(cmd)
139
140
141 def add_gpe_tunnel(sw):
142     """Adds GPE tunnel to OVS switch.
143
144     Args:
145         :param sw: name of switch
146
147         :param dpid: DataPath ID of new switches
148
149     NOTE:
150         :Remote IP is read from flows.
151     """
152
153     ifaceName = "{}-vxlangpe-0".format(sw)
154     cmd = [
155         "sudo",
156         "ovs-vsctl",
157         "add-port",
158         sw,
159         ifaceName,
160         "--",
161         "set",
162         "Interface",
163         ifaceName,
164         "type=vxlan",
165         "options:remote_ip=flow",
166         "options:dst_port=6633",
167         "options:nshc1=flow",
168         "options:nshc2=flow",
169         "options:nshc3=flow",
170         "options:nshc4=flow",
171         "options:nsp=flow",
172         "options:nsi=flow",
173         "options:key=flow",
174     ]
175     call(cmd)
176
177
178 def launch_container(host, containerImage):
179     # TODO use Docker.py
180     """Runs docker container in background.
181
182     Args:
183         :param host: container host name
184
185         :param dpid: DataPath ID of new switch
186
187     Returns:
188         :returns string: container ID
189
190     NOTE:
191         :No networking set.
192
193     """
194
195     containerID = check_output(
196         [
197             "docker",
198             "run",
199             "-d",
200             "--net=none",
201             "--name=%s" % host["name"],
202             "-h",
203             host["name"],
204             "-t",
205             "-i",
206             "--privileged=True",
207             containerImage,
208             "/bin/bash",
209         ]
210     )
211     return containerID[:-1]  # Remove extraneous \n from output of above
212
213
214 def connect_container_to_switch(sw, host, containerID):
215     """Connects docker to OVS switch.
216
217     Args:
218         :param sw: name of switch
219
220         :param host: host object to process.
221             Here is an example of such as object
222             {'name': 'h35_2',
223              'mac': '00:00:00:00:35:02',
224              'ip': '10.0.35.2/24',
225              'switch': 'sw1'}
226              Note: 'switch' - name of OVS switch to
227                  which the host will be connected
228
229         :param containerID: ID of docker container
230     """
231
232     hostIP = host["ip"]
233     mac = host["mac"]
234     nw = ipaddr.IPv4Network(hostIP)
235     broadcast = "{}".format(nw.broadcast)
236     router = "{}".format(nw.network + 1)
237     ovswork_path = os.path.dirname(os.path.realpath(__file__)) + "/ovswork.sh"
238     cmd = [ovswork_path, sw, containerID, hostIP, broadcast, router, mac, host["name"]]
239     if ("vlan") in host:
240         cmd.append(host["vlan"])
241     call(cmd)
242
243
244 def launch(switches, hosts, odl_ip="127.0.0.1"):
245     """Connects hosts to switches. Arguments are
246        tied to underlying configuration file. Processing runs
247        for switch, that is present on local environment and
248        for hosts configured to be connected to the switch.
249
250     Args:
251         :param switches: switches to connect to
252             Example of switch object
253             {'name': 'sw1',
254              'dpid': '1'}
255
256         :param hosts: hosts to connect
257             Example of host object
258             {'name': 'h35_2',
259              'mac': '00:00:00:00:35:02',
260              'ip': '10.0.35.2/24',
261              'switch': 'sw1'}
262              Note: 'switch' - name of OVS switch to
263                  which the host will be connected
264
265         :param odl_ip: IP address of ODL, acting as
266             both - manager and controller.
267             Default value is '127.0.0.1'
268     """
269
270     for sw in switches:
271         add_manager(odl_ip)
272         ports = 0
273         first_host = True
274         for host in hosts:
275             if host["switch"] == sw["name"]:
276                 if first_host:
277                     add_switch(sw["name"], sw["dpid"])
278                     set_of_version(sw["name"])
279                     add_controller(sw["name"], odl_ip)
280                     add_gpe_tunnel(sw["name"])
281                     add_vxlan_tunnel(sw["name"])
282                 first_host = False
283                 containerImage = defaultContainerImage  # from Config
284                 if ("container_image") in host:  # from Config
285                     containerImage = host["container_image"]
286                 containerID = launch_container(host, containerImage)
287                 ports += 1
288                 connect_container_to_switch(sw["name"], host, containerID)
289                 host["port-name"] = "vethl-" + host["name"]
290                 print(
291                     "Created container: %s with IP: %s. Connect using docker attach %s,"
292                     "disconnect with 'ctrl-p-q'."
293                     % (host["name"], host["ip"], host["name"])
294                 )
295
296
297 if __name__ == "__main__":
298     if len(sys.argv) < 2 or len(sys.argv) > 3:
299         print("Please, specify IP of ODL and switch index in arguments.")
300         print("usage: ./infrastructure_launch.py ODL_IP SWITCH_INDEX")
301         sys.exit(2)
302
303     controller = sys.argv[1]
304     try:
305         socket.inet_aton(controller)
306     except socket.error:
307         print("Error: %s is not a valid IPv4 address!" % (controller))
308         sys.exit(2)
309
310     sw_index = int(sys.argv[2])
311     print(sw_index)
312     print(switches[sw_index])
313     if sw_index not in range(0, len(switches) + 1):
314         print(len(switches) + 1)
315         print("Error: %s is not a valid switch index!" % (sw_index))
316         sys.exit(2)
317
318     sw_type = switches[sw_index]["type"]
319     sw_name = switches[sw_index]["name"]
320     if sw_type == "gbp":
321         print("*****************************")
322         print("Configuring %s as a GBP node." % (sw_name))
323         print("*****************************")
324         print
325         launch([switches[sw_index]], hosts, controller)
326         print("*****************************")
327         print("OVS status:")
328         print("-----------")
329         print
330         call(["sudo", "ovs-vsctl", "show"])
331         print
332         print("Docker containers:")
333         print("------------------")
334         call(["docker", "ps"])
335         print("*****************************")
336     elif sw_type == "sff":
337         print("*****************************")
338         print("Configuring %s as an SFF." % (sw_name))
339         print("*****************************")
340         call(["sudo", "ovs-vsctl", "set-manager", "tcp:%s:6640" % controller])
341         print
342     elif sw_type == "sf":
343         print("*****************************")
344         print("Configuring %s as an SF." % (sw_name))
345         print("*****************************")
346         call(
347             [
348                 "%s/sf-config.sh" % os.path.dirname(os.path.realpath(__file__)),
349                 "%s" % sw_name,
350             ]
351         )