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)
44 def get_virt_ip(myid, nodeid):
46 virtip = "10.%d.%d.2" % (myid, nodeid)
48 virtip = "10.%d.%d.3" % (nodeid, myid)
52 Create a "virtual link" for slice between here and nodeid.
53 The key is used to create the EGRE tunnel.
55 def setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr):
56 logger.log("%s: Set up virtual link to node %d" % (slice, nodeid))
57 virtip = get_virt_ip(myid, nodeid)
58 run(setup_link_cmd + " %s %s %s %s %s %s" % (slice, nodeid, ipaddr,
64 Tear down the "virtual link" for slice between here and nodeid.
66 def teardown_virtual_link(key, nodeid):
67 logger.log("topo: Tear down virtual link %sx%s" % (key, nodeid))
68 run(teardown_link_cmd + " %s %s" % (nodeid, key))
73 Called for all active virtual link interfaces, so they won't be cleaned up.
75 def refresh_virtual_link(nodeid, key):
76 name = "d%sx%s" % (key, nodeid)
77 if name in old_ifaces:
83 Check for existence of interface natx<key>
94 Create a NAT interface inside the sliver.
96 def setup_nat(slice, myid, key):
97 logger.log("%s: Set up NAT" % slice)
98 run(setup_nat_cmd + " %s %s %s" % (slice, myid, key))
103 Tear down the NAT interface identified by key
105 def teardown_nat(key):
106 logger.log("topo: Tear down NAT %s" % key)
107 run(teardown_nat_cmd + " %s" % key)
112 Called for all active NAT interfaces, so they won't be cleaned up.
114 def refresh_nat(key):
115 name = "natx%s" % (key)
116 if name in old_ifaces:
122 Clean up old virtual links (e.g., to nodes that have been deleted
125 def clean_up_old_virtual_links():
126 pattern1 = "d(.*)x(.*)"
127 pattern2 = "natx(.*)"
128 for iface in old_ifaces:
129 m = re.match(pattern1, iface)
131 key = int(m.group(1))
132 node = int(m.group(2))
133 teardown_virtual_link(key, node)
135 m = re.match(pattern2, iface)
137 key = int(m.group(1))
143 Not the safest thing to do, probably should use pickle() or something.
145 def convert_topospec_to_list(rspec):
150 Update virtual links for the slice
152 def update_links(slice, myid, topospec, key, netns):
153 topolist = convert_topospec_to_list(topospec)
154 for (nodeid,ipaddr,rate) in topolist:
155 if not virtual_link(key, nodeid):
157 setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr)
159 logger.log("%s: virtual link to node %s exists" % (slice, nodeid))
160 refresh_virtual_link(nodeid, key)
162 if not nat_exists(key):
163 setup_nat(slice, myid, key)
165 logger.log("%s: NAT exists" % slice)
170 Write /etc/vservers/<slicename>/spaces/net
172 def writeConf(slicename, value):
173 SLICEDIR="/etc/vservers/%s/" % slicename
174 SPACESDIR="%s/spaces/" % SLICEDIR
175 if os.path.exists(SLICEDIR):
176 if not os.path.exists(SPACESDIR):
180 logger.log("topo: could not create %s\n" % SPACESDIR)
182 f = open("%s/net" % SPACESDIR, "w")
183 f.write("%s\n" % value)
188 logger.log("%s: network namespace %s\n" % (slicename, STATUS))
192 Generate information for each interface in the sliver, in order to configure
195 def get_ifaces(hostname, myid, topospec, key):
197 topolist = convert_topospec_to_list(topospec)
198 for (nodeid, ipaddr, rate) in topolist:
199 name = "a%sx%s" % (key, nodeid)
201 ifaces[name]['remote-ip'] = get_virt_ip(nodeid, myid)
202 ifaces[name]['local-ip'] = get_virt_ip(myid, nodeid)
203 ifaces[name]['short-name'] = hostname.replace('.vini-veritas.net', '')
207 def write_header(f, myname, password):
208 f.write ("""! Configuration for %s
214 """ % (myname, strftime("%Y-%m-%d %H:%M:%S"), myname, password))
219 Write zebra.conf file for Quagga
221 def write_zebra(filename, myname, ifaces):
222 f = open(filename, 'w')
224 write_header(f, myname, password)
226 f.write ("""enable password %s
238 access-list vty permit 127.0.0.1/32
248 Write ospfd.conf file for Quagga.
250 def write_ospf(filename, myname, ifaces):
251 f = open(filename, 'w')
253 write_header(f, myname, password)
259 ip ospf hello-interval 5
260 ip ospf dead-interval 10
261 ip ospf network non-broadcast
267 """ % ifaces[name]['local-ip'])
270 f.write (" neighbor %s\n" % ifaces[name]['remote-ip'])
273 net = ifaces[name]['local-ip'].rstrip('23')+'0'
274 f.write (" network %s/24 area 0\n" % net)
277 access-list vty permit 127.0.0.1/32
285 Write config files directly into the slice's file system.
287 def update_quagga_configs(slicename, hostname, myid, topo, key, netns):
288 ifaces = get_ifaces(hostname, myid, topo, key)
290 quagga_dir = "/vservers/%s/etc/quagga/" % slicename
291 if not os.path.exists(quagga_dir):
293 # Quagga not installed. Install it here? Chkconfig, sym links.
296 logger.log("topo: could not create %s\n" % quagga_dir)
299 write_zebra(quagga_dir + "zebra.conf.generated", hostname, ifaces)
300 write_ospf(quagga_dir + "ospfd.conf.generated", hostname, ifaces)
302 # Start up Quagga if we installed it earlier and netns = 1.
308 Write /etc/hosts in the sliver
310 def update_hosts(slicename, hosts):
311 hosts_file = "/vservers/%s/etc/hosts" % slicename
312 f = open(hosts_file, 'w')
318 def start(options, config):
323 Update the virtual links for a sliver if it has a 'netns' attribute,
324 an 'egre_key' attribute, and a 'topo_rspec' attribute.
326 Creating the virtual link depends on the contents of
327 /etc/vservers/<slice>/spaces/net. Update this first.
329 def GetSlivers(data):
330 global ifaces, old_ifaces
331 ifaces = old_ifaces = sioc.gifconf()
333 for sliver in data['slivers']:
335 for attribute in sliver['attributes']:
336 attrs[attribute['name']] = attribute['value']
338 netns = int(attrs['netns'])
339 writeConf(sliver['name'], netns)
343 if vserver.VServer(sliver['name']).is_running():
344 if 'egre_key' in attrs and 'topo_rspec' in attrs:
345 logger.log("topo: Update topology for slice %s" % \
347 update_links(sliver['name'], data['node_id'],
348 attrs['topo_rspec'], attrs['egre_key'], netns)
349 update_quagga_configs(sliver['name'], data['hostname'],
350 data['node_id'], attrs['topo_rspec'],
351 attrs['egre_key'], netns)
353 update_hosts(sliver['name'], attrs['hosts'])
355 logger.log("topo: sliver %s not running yet. Deferring." % \
358 clean_up_old_virtual_links()