source: cows_wps/trunk/cows_wps/utils/role_handler.py @ 7535

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows_wps/trunk/cows_wps/utils/role_handler.py@7575
Revision 7535, 6.4 KB checked in by astephen, 9 years ago (diff)

Fixed to async argument handler working.

Line 
1"""
2role_handler.py
3===============
4
5Holds RoleHandler class for handling user roles as provided in:
6
7 roles_info.ini
8
9configuration file.
10
11"""
12
13# Standard library imports
14import re
15
16# Local imports
17from cows_wps.utils.parse_roles_config import roles_info
18
19
20
21class RoleHandler(object):
22    """
23    Uses the roles_info dictionary to provide a set of useful methods that allow:
24     * mapping of role strings to numeric codes used in download URLs
25     * mapping of process IDs to roles
26     * mapping of role strings to role patterns used in request arguments
27    """
28
29    def __init__(self):
30        self.roles = roles_info["roles"]
31        self.proc_role_map = roles_info["proc_role_map"]
32        self.pattern_role_map = roles_info["pattern_role_map"]
33
34    def getRoleNumber(self, role):
35        "Maps a role string to a role number."
36        if role not in self.roles.keys():
37            raise KeyError("Role '%s' not known." % role)
38
39        return self.roles[role]
40
41    def getRoleFromProcessIDAndArgs(self, proc_id, arg_dict):
42        "Maps a process ID and request arguments dict to a role string."
43        if proc_id not in self.proc_role_map.keys():
44            raise KeyError("Process '%s' not known in proc_role_map configuration (see: roles_info.ini file)." % proc_id)
45
46        role_map = self.proc_role_map[proc_id]
47
48        # Need to analyse the role_map to see if it requires special attention
49        if role_map.find("use:") == 0: 
50            role = self._mapRequestArgsToRole(role_map, arg_dict)
51        else:
52            role = role_map
53
54        return role
55
56    def getRoleNumberFromProcessIDAndArgs(self, proc_id, arg_dict):
57        "Maps a process ID and request arguments dict to a role number."
58        role = self.getRoleFromProcessIDAndArgs(proc_id, arg_dict)
59
60        return self.getRoleNumber(role)
61
62
63    def _mapRequestArgsToRole(self, role_map, arg_dict):
64        "Maps arg values to a role string."
65        arg_required, pattern = role_map.split(":")[-1].split("=")
66
67        if arg_required not in arg_dict.keys():
68            raise ItemError("Request arguments does not contain the required parameter '%s' to map authorised roles." % arg_required)
69
70        # Now use the pattern to match to the argument
71        match = re.match(pattern, arg_dict[arg_required])
72
73        if not match:
74            raise Exception("No match for value of argument '%s' to role pattern." % arg_required)
75
76        role_code = match.groups()[0]
77        role = self.getRoleFromRoleCode(role_code)
78        return role
79       
80       
81    def getRoleFromRoleCode(self, role_code):
82        """
83        Maps a role code to a role string. 
84        E.g. maps "ecmwf-e40" to "era".
85        """
86        if role_code not in self.pattern_role_map.keys():
87            raise KeyError("Role code '%s' not found in pattern role maps to authorised roles." % role_code)
88
89        return self.pattern_role_map[role_code]
90
91
92if __name__ == "__main__":
93
94    rh = RoleHandler()
95
96    print "Role --> role number..."
97    for role in ("surface", "ecmwfop"):
98        rn = rh.getRoleNumber(role)
99        print "\t%s --> %s" % (role, rn)
100
101    try:
102        rh.getRoleNumber("bizarre")
103    except KeyError:
104        print "Test 1 fail worked OK"
105
106    print "Proc Id & Args --> role (and role number)..."
107    inputs = [("GetWeatherStations", {}), 
108              ("DoubleIt", {}),
109              ("SubsetPPFile", {"FilePath": "/badc/ukmo-um/data/global/ag/ap/2010/01/01/agap2010010100_00023_00.pp"}),
110              ("NCDumpIt", {"FilePath": "/badc/ecmwf-op/data/gg/ap/myfile.nc"}),
111              ("NCDumpIt", {"FilePath": "/badc/ukmo-um/data/foo/baa"})]
112
113    for (proc_id, arg_dict) in inputs:
114        role = rh.getRoleFromProcessIDAndArgs(proc_id, arg_dict)
115        rn = rh.getRoleNumberFromProcessIDAndArgs(proc_id, arg_dict)
116        print "\t%s & %s --> %s (%s)" % (proc_id, str(arg_dict), role, rn)
117
118    try:
119        rh.getRoleFromProcessIDAndArgs("UnknownProc", {})
120    except KeyError:
121        print "Test 2 fail worked OK"
122
123    print "Role code --> role..."
124    for rc in ("ecmwf-e40", "ecmwf-op", "ukmo-um"):
125        r = rh.getRoleFromRoleCode(rc)
126        print "\t%s --> %s" % (rc, r)
127
128    try:
129        rh.getRoleFromRoleCode("Scooby")
130    except:
131        print "Test 3 fail worked OK"
132
133
134"""
135class RoleMapper(object):
136    " To handle multiple roles.  NOT IMPLEMENTED YET."
137
138    def __init__(self, config = None):
139        if config == None:
140            self._parseConfig()
141
142    def _parseConfig(self, conf_file = "../../roles.ini"):
143        if not os.path.isfile(conf_file):
144            raise Exception("No such file: %s" % conf_file)
145
146        self.roles = {}
147        conf = ConfigParser.ConfigParser()
148        conf.read(conf_file)
149
150        for indx in conf.options("roles"):
151            i = int(indx)
152            value = conf.get("roles", indx)
153            self.roles[i] = value
154
155        return self.roles
156
157    def _isBitSwitchedOnAt(self, number, position):
158        "Returns boolean of whether the particular bit at ``position`` is ON (or 1 or True) in ``number``."
159        return (number >> position) & 1
160
161    def _checkRoleString(self, role_string):
162        if not len(role_string) % 2 == 0:
163            raise Exception("Role string must be even in length, this is not: '%s'" % role_string)
164
165        if not re.match("^[a-fA-F0-9]+$", role_string):
166            raise Exception("Role string must be valid hexidecimal characters.")
167
168    def lookupRole(self, indx):
169        "Returns role name or raises exception if not matched."
170        if indx not in self.roles.keys():
171            raise Exception("Role number '%s' not known." % indx)
172
173        return self.roles[indx]
174
175    def mapRoles(self, role_string):
176        "Takes role string and returns a list of valid roles."
177        self._checkRoleString(role_string)
178
179        rs = role_string
180        roles = []
181        indx_count = 1
182
183        while len(rs) > 0:
184            roles_code = int(rs[-2:], 16)
185
186            for i in range(8):
187                if self._isBitSwitchedOnAt(roles_code, i):
188                    role = self.lookupRole(indx_count)
189                    roles.append(role)
190#                    print roles_code, rs, i, role
191                   
192
193                indx_count += 1
194
195            rs = rs[:-2]
196
197        return roles
198
199
200if __name__ == "__main__":
201
202    rh = RoleHandler()
203    for i in ("aa", "00", "03", "ff", "fa", "80", "02fa", "05ff"):
204         print "Code: %s (%d) -> %s" % (i, int(i, 16),  " ".join(rh.mapRoles(i)))
205
206    try:
207        print rh.mapRoles("ffff")
208    except:
209        print "Failed to map excess roles which is good!"
210"""
Note: See TracBrowser for help on using the repository browser.