source: fedd/fedd_config_file.py @ 11a08b0

axis_examplecompt_changesinfo-opsversion-1.30version-2.00version-3.01version-3.02
Last change on this file since 11a08b0 was 11a08b0, checked in by Ted Faber <faber@…>, 16 years ago

decent logging

  • Property mode set to 100644
File size: 7.1 KB
Line 
1#!/usr/local/bin/python
2
3import os,sys
4
5import re
6import string
7
8from fedd_util import *
9from fedd_access_project import access_project
10
11# Used to report errors parsing the configuration files, not in providing
12# service
13class parse_error(RuntimeError): pass
14
15class config_file:
16    """
17    The implementation of access control based on mapping users to projects.
18
19    Users can be mapped to existing projects or have projects created
20    dynamically.  This implements both direct requests and proxies.
21    """
22    # Attributes that can be parsed from the configuration file
23    bool_attrs = ("dynamic_projects", "project_priority", "create_debug")
24    emulab_attrs = ("boss", "ops", "domain", "fileserver", "eventserver")
25    id_attrs = ("testbed", "cert_file", "cert_pwd", "trusted_certs", "proxy",
26            "proxy_cert_file", "proxy_cert_pwd", "proxy_trusted_certs",
27            "dynamic_projects_url", "dynamic_projects_cert_file", 
28            "dynamic_projects_cert_pwd", "dynamic_projects_trusted_certs",
29            "create_experiment_cert_file", "create_experiment_cert_pwd",
30            "create_experiment_trusted_certs", "federation_script_dir",
31            "ssh_pubkey_file", "experiment_state_file", "experiment_log")
32    id_list_attrs = ("restricted",)
33
34
35    def __init__(self, config=None):
36        """
37        Initializer.  Parses a configuration if one is given.
38        """
39
40        # Create instance attributes from the static lists
41        for a in config_file.bool_attrs:
42            setattr(self, a, False)
43
44        for a in config_file.emulab_attrs + config_file.id_attrs:
45            setattr(self, a, None)
46       
47        for a in config_file.id_list_attrs:
48            setattr(self, a, [])
49
50        self.attrs = { }
51        self.fedid_category = { }
52        self.fedid_default = "user"
53        self.access = { }
54
55        if config:
56            self.read_config(config)
57
58    def read_trust(self, trust):
59        """
60        Read a trust file that splits fedids into testbeds, users or projects
61
62        Format is:
63
64        [type]
65        fedid
66        fedid
67        default: type
68        """
69        lineno = 0;
70        cat = None
71        cat_re = re.compile("\[(user|testbed|project)\]$", re.IGNORECASE)
72        fedid_re = re.compile("[" + string.hexdigits + "]+$")
73        default_re = re.compile("default:\s*(user|testbed|project)$", 
74                re.IGNORECASE)
75
76        f = open(trust, "r")
77        for line in f:
78            lineno += 1
79            line = line.strip()
80            if len(line) == 0 or line.startswith("#"):
81                continue
82            # Category line
83            m = cat_re.match(line)
84            if m != None:
85                cat = m.group(1).lower()
86                continue
87            # Fedid line
88            m = fedid_re.match(line)
89            if m != None:
90                if cat != None:
91                    self.fedid_category[fedid(hexstr=m.string)] = cat
92                else:
93                    raise parse_error(\
94                            "Bad fedid in trust file (%s) line: %d" % \
95                            (trust, lineno))
96                continue
97            # default line
98            m = default_re.match(line)
99            if m != None:
100                self.fedid_default = m.group(1).lower()
101                continue
102            # Nothing matched - bad line, raise exception
103            f.close()
104            raise parse_error(\
105                    "Unparsable line in trustfile %s line %d" % (trust, lineno))
106        f.close()
107
108    def read_config(self, config):
109        """
110        Read a configuration file and set internal parameters.
111
112        The format is more complex than one might hope.  The basic format is
113        attribute value pairs separated by colons(:) on a signle line.  The
114        attributes in bool_attrs, emulab_attrs and id_attrs can all be set
115        directly using the name: value syntax.  E.g.
116        boss: hostname
117        sets self.boss to hostname.  In addition, there are access lines of the
118        form (tb, proj, user) -> (aproj, auser) that map the first tuple of
119        names to the second for access purposes.  Names in the key (left side)
120        can include "<NONE> or <ANY>" to act as wildcards or to require the
121        fields to be empty.  Similarly aproj or auser can be <SAME> or
122        <DYNAMIC> indicating that either the matching key is to be used or a
123        dynamic user or project will be created.  These names can also be
124        federated IDs (fedid's) if prefixed with fedid:.  Finally, the aproj
125        can be followed with a colon-separated list of node types to which that
126        project has access (or will have access if dynamic).
127        Testbed attributes outside the forms above can be given using the
128        format attribute: name value: value.  The name is a single word and the
129        value continues to the end of the line.  Empty lines and lines startin
130        with a # are ignored.
131
132        Parsing errors result in a parse_error exception being raised.
133        """
134        lineno=0
135        name_expr = "["+string.ascii_letters + string.digits + "\.\-_]+"
136        fedid_expr = "fedid:[" + string.hexdigits + "]+"
137        key_name = "(<ANY>|<NONE>|"+fedid_expr + "|"+ name_expr + ")"
138        access_proj = "(<DYNAMIC>(?::" + name_expr +")*|"+ \
139                "<SAME>" + "(?::" + name_expr + ")*|" + \
140                fedid_expr + "(?::" + name_expr + ")*|" + \
141                name_expr + "(?::" + name_expr + ")*)"
142        access_name = "(<DYNAMIC>|<SAME>|" + fedid_expr + "|"+ name_expr + ")"
143
144        bool_re = re.compile('(' + '|'.join(config_file.bool_attrs) + 
145                '):\s+(true|false)', re.IGNORECASE)
146        string_re = re.compile( "(" + \
147                '|'.join(config_file.emulab_attrs + config_file.id_attrs) + \
148                '):\s*(.*)', re.IGNORECASE)
149        list_re = re.compile("(" + '|'.join(config_file.id_list_attrs) + \
150                "):\s*(.*)", re.IGNORECASE)
151        attr_re = re.compile('attribute:\s*([\._\-a-z0-9]+)\s+value:\s*(.*)',
152                re.IGNORECASE)
153        access_re = re.compile('\('+key_name+'\s*,\s*'+key_name+'\s*,\s*'+
154                key_name+'\s*\)\s*->\s*\('+access_proj + '\s*,\s*' + 
155                access_name + '\s*\)', re.IGNORECASE)
156        trustfile_re = re.compile("trustfile:\s*(.*)", re.IGNORECASE)
157
158        def parse_name(n):
159            if n.startswith('fedid:'): return fedid(n[len('fedid:'):])
160            else: return n
161
162        f = open(config, "r");
163        for line in f:
164            lineno += 1
165            line = line.strip();
166            if len(line) == 0 or line.startswith('#'):
167                continue
168
169            # Boolean attribute line
170            m = bool_re.match(line);
171            if m != None:
172                attr, val = m.group(1,2)
173                setattr(self, attr.lower(), bool(val.lower() == "true"))
174                continue
175
176            # String attribute line
177            m = string_re.match(line)
178            if m != None:
179                attr, val = m.group(1,2)
180                setattr(self, attr.lower(), val)
181                continue
182
183            # List attributes
184            m = list_re.match(line)
185            if m != None:
186                attr, val = m.group(1,2)
187                l = getattr(self, attr.lower())
188                l.append(val)
189                continue
190
191
192            # Extended (attribute: x value: y) attribute line
193            m = attr_re.match(line)
194            if m != None:
195                attr, val = m.group(1,2)
196                self.attrs[attr] = val
197                continue
198
199            # Access line (t, p, u) -> (ap, au) line
200            m = access_re.match(line)
201            if m != None:
202                access_key = tuple([ parse_name(x) for x in m.group(1,2,3)])
203                aps = m.group(4).split(":");
204                if aps[0] == 'fedid:':
205                    del aps[0]
206                    aps[0] = fedid(hexstr=aps[0])
207
208                au = m.group(5)
209                if au.startswith("fedid:"):
210                    au = fedid(hexstr=aus[len("fedid:"):])
211
212                access_val = (access_project(aps[0], aps[1:]), au)
213
214                self.access[access_key] = access_val
215                continue
216
217            # Trustfile inclusion
218            m = trustfile_re.match(line)
219            if m != None:
220                self.read_trust(m.group(1))
221                continue
222
223            # Nothing matched to here: unknown line - raise exception
224            f.close()
225            raise parse_error("Unknown statement at line %d of %s" % \
226                    (lineno, config))
227        f.close()
228
229if __name__ == '__main__':
230    if sys.argv[1]:
231        config = config_file(sys.argv[1])
232        for a in [ a for a in dir(config) if a[0] != '_'  \
233                and not callable(getattr(config,a))]:
234            print "%s: %s" % (a, getattr(config, a))
Note: See TracBrowser for help on using the repository browser.