Changes for robustness when deleting a sliver
[nodemanager-topo.git] / topo.py
1 # $Id$
2 # $URL$
3
4 """ 
5 VINI/Trellis NodeManager plugin.
6 Create virtual links from the topo_rspec slice attribute. 
7 """
8
9 import logger
10 import subprocess
11 import sioc
12 import re
13 import vserver
14 import os
15
16 dryrun=0
17 setup_link_cmd="/usr/share/vini/setup-egre-link"
18 teardown_link_cmd="/usr/share/vini/teardown-egre-link"
19 ifaces = {}
20 old_ifaces = {}
21
22 def run(cmd):
23     if dryrun:
24         logger.log(cmd)
25         return -1
26     else:
27         return subprocess.call(cmd, shell=True);
28
29
30 """
31 Check for existence of interface d<key>x<nodeid>
32 """
33 def virtual_link(key, nodeid):
34     name = "d%sx%s" % (key, nodeid)
35     if name in ifaces:
36         return True
37     else:
38         return False
39
40
41 """
42 Create a "virtual link" for slice between here and nodeid.
43 The key is used to create the EGRE tunnel.
44 """
45 def setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr):
46     logger.log("%s: Set up virtual link to node %d" % (slice, nodeid))
47     if myid < nodeid:
48         virtip = "10.%d.%d.2" % (myid, nodeid)
49     else:
50         virtip = "10.%d.%d.3" % (nodeid, myid)
51         
52     run(setup_link_cmd + " %s %s %s %s %s %s" % (slice, nodeid, ipaddr, 
53                                                  key, rate, virtip))
54     return
55
56
57 """
58 Tear down the "virtual link" for slice between here and nodeid.
59 """
60 def teardown_virtual_link(key, nodeid):
61     logger.log("topo: Tear down virtual link %sx%s" % (key, nodeid))
62     run(teardown_link_cmd + " %s %s" % (nodeid, key))
63     return
64
65
66 """
67 Called for all active virtual link interfaces, so they won't be cleaned up.
68 """
69 def refresh_virtual_link(nodeid, key):
70     try:
71         name = "d%sx%s" % (key, nodeid)
72         del old_ifaces[name]
73     except:
74         pass
75
76
77 """
78 Clean up old virtual links (e.g., to nodes that have been deleted 
79 from the slice).
80 """
81 def clean_up_old_virtual_links():
82     pattern = "d(.*)x(.*)"
83     for iface in old_ifaces:
84         m = re.match(pattern, iface)
85         if m:
86             key = int(m.group(1))
87             node = int(m.group(2))
88             teardown_virtual_link(key, node)
89
90
91 """
92 Not the safest thing to do, probably should use pickle() or something.
93 """
94 def convert_topospec_to_list(rspec):
95     return eval(rspec)
96
97
98 """
99 Update virtual links for the slice
100 """
101 def update(slice, myid, topospec, key, netns):
102     topolist = convert_topospec_to_list(topospec)
103     for (nodeid,ipaddr,rate) in topolist:
104         if not virtual_link(key, nodeid):
105             if netns:
106                 setup_virtual_link(slice, key, rate, myid, nodeid, ipaddr)
107         else:
108             logger.log("%s: virtual link to node %s exists" % (slice, nodeid))
109             refresh_virtual_link(nodeid, key)
110
111 """
112 Write /etc/vservers/<slicename>/spaces/net
113 """
114 def writeConf(slicename, value):
115     SLICEDIR="/etc/vservers/%s/" % slicename
116     SPACESDIR="%s/spaces/" % SLICEDIR
117     if os.path.exists(SLICEDIR):
118         if not os.path.exists(SPACESDIR):
119             try:
120                 os.mkdir(SPACESDIR)
121             except os.error:
122                 logger.log("netns: could not create %s\n" % SPACESDIR)
123                 return
124         f = open("%s/net" % SPACESDIR, "w")
125         f.write("%s\n" % value)
126         f.close()
127         STATUS="OFF"
128         if int(value) >= 1:
129             STATUS="ON"
130         logger.log("%s: network namespace %s\n" % (slicename, STATUS))
131
132
133 def start(options, config):
134     pass
135
136
137 """
138 Update the virtual links for a sliver if it has a 'netns' attribute,
139 an 'egre_key' attribute, and a 'topo_rspec' attribute.
140
141 Creating the virtual link depends on the contents of 
142 /etc/vservers/<slice>/spaces/net.  Update this first.
143 """
144 def GetSlivers(data):
145     global ifaces, old_ifaces
146     ifaces = old_ifaces = sioc.gifconf()
147
148     for sliver in data['slivers']:
149         attrs = {}
150         for attribute in sliver['attributes']:
151             attrs[attribute['name']] = attribute['value']
152         if 'netns' in attrs:
153             writeConf(sliver['name'], attrs['netns'])
154             netns = attrs['netns']
155         else:
156             netns = 0
157
158         try:
159             if vserver.VServer(sliver['name']).is_running():
160                 if 'egre_key' in attrs and 'topo_rspec' in attrs:
161                     logger.log("topo: Update topology for slice %s" % \
162                                    sliver['name'])
163                     update(sliver['name'], data['node_id'], 
164                            attrs['topo_rspec'], attrs['egre_key'], netns)
165         except:
166             logger.log("topo: sliver %s not running yet. Deferring." % \
167                            sliver['name'])
168
169     clean_up_old_virtual_links()
170
171