5 VINI/Trellis NodeManager plugin.
6 Create virtual links from the topo_rspec slice attribute.
15 from time import strftime
18 vinidir = "/usr/share/vini/"
19 setup_link_cmd = vinidir + "setup-egre-link"
20 teardown_link_cmd = vinidir + "teardown-egre-link"
21 setup_nat_cmd = vinidir + "setup-nat"
22 teardown_nat_cmd = vinidir + "teardown-nat"
31 return subprocess.call(cmd, shell=True);
35 Check for existence of interface d<key>x<nodeid>
37 def virtual_link(key, nodeid):
38 name = "d%sx%s" % (key, nodeid)
45 Create a "virtual link" for slice between here and nodeid.
46 The key is used to create the EGRE tunnel.
48 def setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr, virtip, vnet):
49 logger.log("%s: Set up virtual link to node %d" % (slice, nodeid))
50 run(setup_link_cmd + " %s %s %s %s %s %s %s" % (slice, nodeid, ipaddr,
51 key, rate, virtip, vnet))
56 Tear down the "virtual link" for slice between here and nodeid.
58 def teardown_virtual_link(key, nodeid):
59 logger.log("topo: Tear down virtual link %sx%s" % (key, nodeid))
60 run(teardown_link_cmd + " %s %s" % (nodeid, key))
65 Called for all active virtual link interfaces, so they won't be cleaned up.
67 def refresh_virtual_link(nodeid, key):
68 name = "d%sx%s" % (key, nodeid)
69 if name in old_ifaces:
75 Check for existence of interface natx<key>
86 Create a NAT interface inside the sliver.
88 def setup_nat(slice, myid, key):
89 logger.log("%s: Set up NAT" % slice)
90 run(setup_nat_cmd + " %s %s %s" % (slice, myid, key))
95 Tear down the NAT interface identified by key
97 def teardown_nat(key):
98 logger.log("topo: Tear down NAT %s" % key)
99 run(teardown_nat_cmd + " %s" % key)
104 Called for all active NAT interfaces, so they won't be cleaned up.
106 def refresh_nat(key):
107 name = "natx%s" % (key)
108 if name in old_ifaces:
114 Clean up old virtual links (e.g., to nodes that have been deleted
117 def clean_up_old_virtual_links():
118 pattern1 = "d(.*)x(.*)"
119 pattern2 = "natx(.*)"
120 for iface in old_ifaces:
121 m = re.match(pattern1, iface)
123 key = int(m.group(1))
124 node = int(m.group(2))
125 teardown_virtual_link(key, node)
127 m = re.match(pattern2, iface)
129 key = int(m.group(1))
135 Not the safest thing to do, probably should use pickle() or something.
137 def convert_topospec_to_list(rspec):
142 Update virtual links for the slice
144 def update_links(slice, myid, topospec, key, netns):
145 topolist = convert_topospec_to_list(topospec)
146 for (nodeid, ipaddr, rate, myvirtip, remvirtip, virtnet) in topolist:
147 if not virtual_link(key, nodeid):
149 setup_virtual_link(slice, key, rate, myid, nodeid,
150 ipaddr, myvirtip, virtnet)
152 logger.log("%s: virtual link to node %s exists" % (slice, nodeid))
153 refresh_virtual_link(nodeid, key)
155 if not nat_exists(key):
157 setup_nat(slice, myid, key)
159 logger.log("%s: NAT exists" % slice)
164 Write /etc/vservers/<slicename>/spaces/net
166 def writeConf(slicename, value):
167 SLICEDIR="/etc/vservers/%s/" % slicename
168 SPACESDIR="%s/spaces/" % SLICEDIR
169 if os.path.exists(SLICEDIR):
170 if not os.path.exists(SPACESDIR):
174 logger.log("topo: could not create %s\n" % SPACESDIR)
176 f = open("%s/net" % SPACESDIR, "w")
177 f.write("%s\n" % value)
182 logger.log("%s: network namespace %s\n" % (slicename, STATUS))
186 Generate information for each interface in the sliver, in order to configure
189 def get_ifaces(hostname, myid, topospec, key):
191 topolist = convert_topospec_to_list(topospec)
192 for (nodeid, ipaddr, rate, myvirtip, remvirtip, virtnet) in topolist:
193 name = "a%sx%s" % (key, nodeid)
195 ifaces[name]['remote-ip'] = remvirtip
196 ifaces[name]['local-ip'] = myvirtip
197 ifaces[name]['network'] = virtnet
198 ifaces[name]['short-name'] = hostname.replace('.vini-veritas.net', '')
202 def write_header(f, myname, password):
203 f.write ("""! Configuration for %s
209 """ % (myname, strftime("%Y-%m-%d %H:%M:%S"), myname, password))
214 Network used by OpenVPN on this node
216 def openvpn_net(myid):
217 return "10.%s.0.0/16" % myid
221 IP address of NAT gateway to outside world
223 def nat_gw(key, myid):
224 return "10.%s.%s.1" % (key, myid)
228 Write zebra.conf file for Quagga
230 def write_zebra(filename, myname, ifaces, myid, key):
231 f = open(filename, 'w')
233 write_header(f, myname, password)
235 f.write ("enable password %s\n" % password)
246 access-list vty permit 127.0.0.1/32
250 """ % (openvpn_net(myid), nat_gw(key, myid)))
256 Write ospfd.conf file for Quagga.
258 def write_ospf(filename, myname, ifaces):
259 f = open(filename, 'w')
261 write_header(f, myname, password)
267 ip ospf hello-interval 5
268 ip ospf dead-interval 10
269 ip ospf network non-broadcast
275 """ % ifaces[name]['local-ip'])
278 f.write (" neighbor %s\n" % ifaces[name]['remote-ip'])
281 net = ifaces[name]['network']
282 f.write (" network %s area 0\n" % net)
284 f.write(""" redistribute static
286 access-list vty permit 127.0.0.1/32
294 Write config files directly into the slice's file system.
296 def update_quagga_configs(slicename, hostname, myid, topo, key, netns):
297 ifaces = get_ifaces(hostname, myid, topo, key)
299 quagga_dir = "/vservers/%s/etc/quagga/" % slicename
300 if not os.path.exists(quagga_dir):
302 # Quagga not installed. Install it here? Chkconfig, sym links.
305 logger.log("topo: could not create %s\n" % quagga_dir)
308 write_zebra(quagga_dir + "zebra.conf.generated", hostname, ifaces,
310 write_ospf(quagga_dir + "ospfd.conf.generated", hostname, ifaces)
312 # Start up Quagga if we installed it earlier and netns = 1.
318 Write /etc/hosts in the sliver
320 def update_hosts(slicename, hosts):
321 hosts_file = "/vservers/%s/etc/hosts" % slicename
322 f = open(hosts_file, 'w')
328 def start(options, config):
333 Update the virtual links for a sliver if it has a 'netns' attribute,
334 an 'egre_key' attribute, and a 'topo_rspec' attribute.
336 Creating the virtual link depends on the contents of
337 /etc/vservers/<slice>/spaces/net. Update this first.
339 def GetSlivers(data):
340 global ifaces, old_ifaces
341 ifaces = old_ifaces = sioc.gifconf()
343 for sliver in data['slivers']:
345 for attribute in sliver['attributes']:
346 attrs[attribute['name']] = attribute['value']
348 netns = int(attrs['netns'])
349 writeConf(sliver['name'], netns)
353 if vserver.VServer(sliver['name']).is_running():
354 if 'egre_key' in attrs and 'topo_rspec' in attrs:
355 logger.log("topo: Update topology for slice %s" % \
357 update_links(sliver['name'], data['node_id'],
358 attrs['topo_rspec'], attrs['egre_key'], netns)
359 update_quagga_configs(sliver['name'], data['hostname'],
360 data['node_id'], attrs['topo_rspec'],
361 attrs['egre_key'], netns)
363 update_hosts(sliver['name'], attrs['hosts'])
365 logger.log("topo: sliver %s not running yet. Deferring." % \
368 clean_up_old_virtual_links()