1 # Thierry Parmentelat - INRIA
4 from types import NoneType
6 from PLC.Method import Method
7 from PLC.Auth import Auth
8 from PLC.Parameter import Parameter, Mixed
10 from PLC.Faults import *
12 from PLC.Nodes import Nodes, Node
13 from PLC.NodeTags import NodeTags, NodeTag
14 from PLC.Interfaces import Interfaces, Interface
15 from PLC.InterfaceTags import InterfaceTags, InterfaceTag
16 from PLC.Slices import Slices, Slice
17 from PLC.SliceTags import SliceTags, SliceTag
19 # this is another story..
20 #from PLC.Ilinks import Ilink
22 from PLC.TagTypes import TagTypes, TagType
24 # known classes : { class -> secondary_key }
25 taggable_classes = { Node : {'table_class' : Nodes,
26 'joins_class' : NodeTags, 'join_class' : NodeTag,
27 'secondary_key': 'hostname'},
28 Interface : {'table_class' : Interfaces,
29 'joins_class': InterfaceTags, 'join_class': InterfaceTag,
31 Slice: {'table_class' : Slices,
32 'joins_class': SliceTags, 'join_class': SliceTag,
33 'secondary_key':'login_base'},
37 # xxx probably defined someplace else
38 all_roles = [ 'admin', 'pi', 'tech', 'user', 'node' ]
39 tech_roles = [ 'admin', 'pi', 'tech' ]
41 # generates 2 method classes:
42 # Get<classname><methodsuffix> (auth, id_or_name) -> value or None
43 # Set<classname><methodsuffix> (auth, id_or_name, value) -> None
44 # value is always a string, no cast nor typecheck for now
46 # note: tag_min_role_id gets attached to the tagtype instance,
47 # while get_roles and set_roles get attached to the created methods
49 # returns a tuple (get_method, set_method)
50 # See Accessors* for examples
52 def define_accessors (module, objclass, methodsuffix,
53 tagname, category, description, tag_min_role_id=10,
54 get_roles=['admin'], set_roles=['admin']):
56 if objclass not in taggable_classes:
58 raise PLCInvalidArgument,"PLC.Accessors.Factory: unknown class %s"%objclass.__name__
60 raise PLCInvalidArgument,"PLC.Accessors.Factory: unknown class ??"
61 classname=objclass.__name__
62 get_name = "Get" + classname + methodsuffix
63 set_name = "Set" + classname + methodsuffix
65 # create method objects under PLC.Method.Method
66 get_class = type (get_name, (Method,),
67 {"__doc__":"Accessor 'get' method designed for %s objects using tag %s"%\
69 set_class = type (set_name, (Method,),
70 {"__doc__":"Accessor 'set' method designed for %s objects using tag %s"%\
73 get_accepts = [ Auth () ]
74 primary_key=objclass.primary_key
76 secondary_key = taggable_classes[objclass]['secondary_key']
77 get_accepts += [ Mixed (objclass.fields[primary_key], objclass.fields[secondary_key]) ]
80 get_accepts += [ objclass.fields[primary_key] ]
81 # for set, idem set of arguments + one additional arg, the new value
82 set_accepts = get_accepts + [ Parameter (str,"New tag value") ]
85 get_returns = Mixed (Parameter (str), Parameter(NoneType))
86 set_returns = Parameter(NoneType)
89 setattr(get_class,'roles',get_roles)
90 setattr(get_class,'accepts',get_accepts)
91 setattr(get_class,'returns', get_returns)
92 setattr(get_class,'skip_typecheck',True)
94 setattr(set_class,'roles',set_roles)
95 setattr(set_class,'accepts',set_accepts)
96 setattr(set_class,'returns', set_returns)
97 setattr(set_class,'skip_typecheck',True)
99 table_class = taggable_classes[objclass]['table_class']
100 joins_class = taggable_classes[objclass]['joins_class']
101 join_class = taggable_classes[objclass]['join_class']
103 # body of the get method
104 def get_call (self, auth, id_or_name):
105 # search the tagtype - xxx - might need a cache
106 tag_types = TagTypes (self.api, {'tagname': tagname})
109 tag_type_id = tag_types[0]['tag_type_id']
110 filter = {'tag_type_id':tag_type_id}
111 if isinstance (id_or_name,int):
112 filter[primary_key]=id_or_name
114 filter[secondary_key]=id_or_name
115 joins = joins_class (self.api,filter,['value'])
117 # xxx - we return None even if id_or_name is not valid
120 return joins[0]['value']
123 setattr (get_class,"call",get_call)
125 # body of the set method
126 def set_call (self, auth, id_or_name, value):
128 if isinstance (id_or_name, int):
129 filter={primary_key:id_or_name}
131 filter={secondary_key:id_or_name}
132 objs = table_class(self.api, filter,[primary_key])
134 raise PLCInvalidArgument, "Cannot set tag on %s %r"%(objclass.__name__,id_or_name)
135 primary_id = objs[0][primary_key]
137 # search tag type & create if needed
138 tag_types = TagTypes (self.api, {'tagname':tagname})
140 tag_type = tag_types[0]
142 # not found: create it
143 tag_type_fields = {'tagname':tagname,
144 'category' : category,
145 'description' : description,
146 'min_role_id': tag_min_role_id}
147 tag_type = TagType (self.api, tag_type_fields)
149 tag_type_id = tag_type['tag_type_id']
151 # locate the join object (e.g. NodeTag, SliceTag or InterfaceTag)
152 filter = {'tag_type_id':tag_type_id}
153 if isinstance (id_or_name,int):
154 filter[primary_key]=id_or_name
156 filter[secondary_key]=id_or_name
157 joins = joins_class (self.api,filter)
158 # setting to something non void
159 if value is not None:
161 join = join_class (self.api)
162 join['tag_type_id']=tag_type_id
163 join[primary_key]=primary_id
167 joins[0]['value']=value
169 # providing an empty value means clean up
176 setattr (set_class,"call",set_call)
179 setattr(module,get_name,get_class)
180 setattr(module,set_name,set_class)
181 # add in <module>.methods
183 methods=getattr(module,'methods')
186 methods += [get_name,set_name]
187 setattr(module,'methods',methods)