(*) the various modules have a priority; lower gets invoked first
[nodemanager.git] / plugins / vsys.py
1 # $Id$
2 # $URL$
3
4 """vsys configurator.  Maintains ACLs and script pipes inside vservers based on slice attributes."""
5
6 import logger
7 import os
8 from sets import Set
9
10 VSYSCONF="/etc/vsys.conf"
11 VSYSBKEND="/vsys"
12
13 def start(options, conf):
14     logger.log("vsys: plugin starting up...")
15
16 def GetSlivers(data, config=None, plc=None):
17     """For each sliver with the vsys attribute, set the script ACL, create the vsys directory in the slice, and restart vsys."""
18
19     if 'slivers' not in data:
20         logger.log_missing_data("vsys.GetSlivers",'slivers')
21         return
22
23     # Touch ACLs and create dict of available
24     scripts = {}
25     for script in touchAcls(): scripts[script] = []
26     # slices that need to be written to the conf
27     slices = []
28     _restart = False
29     # Parse attributes and update dict of scripts
30     if 'slivers' not in data:
31         logger.log_missing_data("vsys.GetSlivers",'slivers')
32         return
33     for sliver in data['slivers']:
34         for attribute in sliver['attributes']:
35             if attribute['tagname'] == 'vsys':
36                 if sliver['name'] not in slices:
37                     # add to conf
38                     slices.append(sliver['name'])
39                     _restart = createVsysDir(sliver['name']) or _restart
40                 if attribute['value'] in scripts.keys():
41                     scripts[attribute['value']].append(sliver['name'])
42  
43     # Write the conf
44     _restart = writeConf(slices, parseConf()) or _restart
45     # Write out the ACLs
46     if writeAcls(scripts, parseAcls()) or _restart:
47         logger.log("vsys: restarting vsys service")
48         logger.log_call(["/etc/init.d/vsys", "restart", ])
49
50
51 def createVsysDir(sliver):
52     '''Create /vsys directory in slice.  Update vsys conf file.'''
53     try: 
54         os.mkdir("/vservers/%s/vsys" % sliver)
55         return True
56     except OSError: 
57         return False
58
59
60 def touchAcls():
61     '''Creates empty acl files for scripts.  
62     To be ran in case of new scripts that appear in the backend.
63     Returns list of available scripts.'''
64     acls = []
65     scripts = []
66     for (root, dirs, files) in os.walk(VSYSBKEND):
67         for file in files:
68             # ingore scripts that start with local_
69             if file.startswith("local_"): continue
70             if file.endswith(".acl"):
71                 acls.append(file.replace(".acl", ""))
72             else:
73                 scripts.append(file)
74     for new in (Set(scripts) - Set(acls)):
75         logger.log("vsys: Found new script %s.  Writing empty acl." % new)
76         f = open("%s/%s.acl" %(VSYSBKEND, new), "w")
77         f.write("\n")
78         f.close()
79     
80     return scripts
81
82
83 def writeAcls(currentscripts, oldscripts):
84     '''Creates .acl files for script in the script repo.'''
85     # Check each oldscript entry to see if we need to modify
86     _restartvsys = False
87     # for iteritems along dict(oldscripts), if length of values
88     # not the same as length of values of new scripts,
89     # and length of non intersection along new scripts is not 0,
90     # then dicts are different.
91     for (acl, oldslivers) in oldscripts.iteritems():
92         if (len(oldslivers) != len(currentscripts[acl])) or \
93         (len(Set(oldslivers) - Set(currentscripts[acl])) != 0):
94             _restartvsys = True
95             logger.log("vsys: Updating %s.acl w/ slices %s" % (acl, currentscripts[acl]))
96             f = open("%s/%s.acl" % (VSYSBKEND, acl), "w")
97             for slice in currentscripts[acl]: f.write("%s\n" % slice)
98             f.close()
99     # Trigger a restart
100     return _restartvsys
101
102
103 def parseAcls():
104     '''Parse the frontend script acls.  Return {script: [slices]} in conf.'''
105     # make a dict of what slices are in what acls.
106     scriptacls = {}
107     for (root, dirs, files) in os.walk(VSYSBKEND):
108         for file in files:
109             if file.endswith(".acl") and not file.startswith("local_"):
110                 f = open(root+"/"+file,"r+")
111                 scriptname = file.replace(".acl", "")
112                 scriptacls[scriptname] = []
113                 for slice in f.readlines():  
114                     scriptacls[scriptname].append(slice.rstrip())
115                 f.close()
116     # return what scripts are configured for which slices.
117     return scriptacls
118
119
120 def writeConf(slivers, oldslivers):
121     # Check if this is needed
122     # The assumption here is if lengths are the same,
123     # and the non intersection of both arrays has length 0,
124     # then the arrays are identical.
125     if (len(slivers) != len(oldslivers)) or \
126     (len(Set(oldslivers) - Set(slivers)) != 0):
127         logger.log("vsys:  Updating %s" % VSYSCONF)
128         f = open(VSYSCONF,"w")
129         for sliver in slivers:
130             f.write("/vservers/%(name)s/vsys %(name)s\n" % {"name": sliver})
131         f.truncate()
132         f.close()
133         return True
134     else:
135         return False
136
137
138 def parseConf():
139     '''Parse the vsys conf and return list of slices in conf.'''
140     scriptacls = {}
141     slicesinconf = []
142     try: 
143         f = open(VSYSCONF)
144         for line in f.readlines():
145             (path, slice) = line.split()
146             slicesinconf.append(slice)
147         f.close()
148     except: logger.log_exc("vsys: failed parseConf")
149     return slicesinconf