7be00d00b7f1ef536633c55176790806af8dfe79
[raven.git] / apps / gacks / bridgeconfig.py
1 class NetworkBuilder:
2     def __init__(self, plc):
3         self.plc = plc
4
5     def set_tag(self, tagname, slice_id, node_id, value):
6         if node_id is not None:
7             tags = self.plc.GetSliceTags({"tagname": tagname, "slice_id": slice_id, "node_id": node_id})
8         else:
9             tags = self.plc.GetSliceTags({"tagname": tagname, "slice_id": slice_id})
10         if tags:
11             if tags[0]["value"] != value:
12                 self.plc.UpdateSliceTag(tags[0]['slice_tag_id'], value)\r
13         else:\r
14             self.plc.AddSliceTag(slice_id, tagname, value, node_id)
15
16 class NetworkBuilder_gre(NetworkBuilder):
17     """ This sets up nodes using private bridges and GRE tunnels.
18
19         There can be up to 65535 node_ids.
20
21         Each bridge gets the address 10.1.<node_id_hi>.<node_id_lo>
22         Each sliver gets the address 10.2.<node_id_hi>.<node_id_lo>
23
24         GRE tunnels are setup between nodes. Nodes can talk to each other across
25         sites. The current topology that is used is a star, with all nodes talking
26         to a head node. This represents a single point of failure, as well as a
27         bottleneck.
28     """
29
30     def __init__(self, plc):
31         NetworkBuilder.__init__(self, plc)
32
33     def configure_slice(self, slice_name_or_id):
34         slices = self.plc.GetSlices(slice_name_or_id, ["slice_id", "node_ids", "slice_tag_ids"])
35         if not slices:
36             # we couldn't find it
37             return
38
39         slice = slices[0]
40         slice_id = slice["slice_id"]
41
42         nodes = self.plc.GetNodes(slice["node_ids"], ["node_id", "hostname"])
43         interfaces = self.plc.GetInterfaces({"node_id": slice["node_ids"]}, ["node_id", "ip", "is_primary"])
44         topology = self.generate_star_topology(nodes)
45
46         node_ips = {}
47         for interface in interfaces:
48             if interface["is_primary"]:
49                 node_ips[interface["node_id"]] = interface["ip"]
50
51         # filter out any nodes where we do not know the ip address
52         nodes = [x for x in nodes if node_ips.get(x["node_id"], None)]
53
54         bridge_name = "br-slice-" + str(slice_id)
55         self.set_tag("slice_bridge_name", slice_id, None, bridge_name)
56
57         hostmap = []
58         for (node_id,neighbor_list) in topology.items():
59             sliver_ip_addr = "10.2.%d.%d" % (node_id/254, node_id%254+1)
60             bridge_ip_addr = "10.1.%d.%d" % (node_id/254, node_id%254+1)
61
62             neighbors = []
63             for neighbor_id in neighbor_list:
64                 neighbors.append("%d/%s" % (neighbor_id, node_ips[neighbor_id]))
65
66             self.set_tag("slice_bridge_addr", slice_id, node_id, bridge_ip_addr)
67             self.set_tag("slice_bridge_neighbors", slice_id, node_id, ",".join(neighbors))
68             self.set_tag("interface", slice_id, node_id, "{'bridge':'%s', 'DEVICE':'eth0', 'BOOTPROTO':'static', 'ONBOOT':'yes', 'PRIMARY':'yes', 'IPADDR': '%s', 'NETMASK': '255.0.0.0'}" % (bridge_name, sliver_ip_addr))
69
70             hostmap.append("%s node%d" % (sliver_ip_addr, node_id))
71
72         self.set_tag("slice_hostmap", slice_id, None, "\n".join(hostmap))
73
74     def generate_star_topology(self, nodes):
75         if not nodes:
76             # if there are no nodes, then there is no topology
77             return {}
78
79         topology = {}
80
81         headnode = nodes[0]
82         headnode_id = headnode["node_id"]
83         for node in nodes[1:]:
84             node_id = node["node_id"]
85             topology[headnode_id] = topology.get(headnode_id, []) + [node_id]
86             topology[node_id] = [headnode_id]
87
88         return topology
89
90 class NetworkBuilder_10(NetworkBuilder):
91     """ This sets up each slice as a class A private network.
92
93         10.<slice_id_hi>.<slice_id_lo>.<node_id>
94
95         There can be at most 65535 slice_ids. There can be at most 255 nodes
96         per site.
97
98         Nodes in one site cannot talk to nodes in another site
99     """
100
101     def __init__(self, plc):
102         NetworkBuilder.__init__(self, plc)
103
104     def configure_slice(self, slice_name_or_id):
105         slices = self.plc.GetSlices(slice_name_or_id, ["slice_id", "node_ids", "slice_tag_ids"])
106         if not slices:
107             # we couldn't find it
108             return
109
110         slice = slices[0]
111         slice_id = slice["slice_id"]
112
113         nodes = self.plc.GetNodes(slice["node_ids"], ["node_id", "hostname", "site_id"])
114
115         site_ids = []
116         for node in nodes:
117            if not (node["site_id"] in site_ids):
118                site_ids.append(node["site_id"])
119
120         node_indices = {}
121         sites = self.plc.GetSites(site_ids)
122         for site in sites:
123             for (i, node_id) in enumerate(site["node_ids"]):
124                 node_indices[node_id] = i
125
126         for node in nodes:
127             node_id = node["node_id"]
128             node_index = node_indices.get(node_id, 0)
129             ip_addr = "10.%d.%d.%d" % (slice_id>>8, slice_id&0xFF, node_index + 1)
130             self.set_tag("interface", slice_id, node_id, "{'bridge':'public0', 'DEVICE':'eth0', 'BOOTPROTO':'static', 'ONBOOT':'yes', 'PRIMARY':'yes', 'IPADDR': '%s', 'NETMASK': '255.255.255.0'}" % ip_addr)
131
132