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' ]
42 # generates 2 method classes:
43 # Get<classname><methodsuffix> (auth, id_or_name) -> value or None
44 # Set<classname><methodsuffix> (auth, id_or_name, value) -> None
45 # value is always a string, no cast nor typecheck for now
47 # The expose_in_api flag tells whether this tag may be handled
48 # through the Add/Get/Update methods as a native field
50 # note: tag_min_role_id gets attached to the tagtype instance,
51 # while get_roles and set_roles get attached to the created methods
52 # this might need a cleanup
55 def define_accessors (module, objclass, methodsuffix, tagname,
56 category, description,
57 get_roles=['admin'], set_roles=['admin'],
58 tag_min_role_id=10, expose_in_api = False):
60 if objclass not in taggable_classes:
62 raise PLCInvalidArgument,"PLC.Accessors.Factory: unknown class %s"%objclass.__name__
64 raise PLCInvalidArgument,"PLC.Accessors.Factory: unknown class ??"
66 # side-effect on, say, Node.tags, if required
68 getattr(objclass,'tags')[tagname]=Parameter(str,"accessor")
70 classname=objclass.__name__
71 get_name = "Get" + classname + methodsuffix
72 set_name = "Set" + classname + methodsuffix
74 # create method objects under PLC.Method.Method
75 get_class = type (get_name, (Method,),
76 {"__doc__":"Accessor 'get' method designed for %s objects using tag %s"%\
78 set_class = type (set_name, (Method,),
79 {"__doc__":"Accessor 'set' method designed for %s objects using tag %s"%\
82 get_accepts = [ Auth () ]
83 primary_key=objclass.primary_key
85 secondary_key = taggable_classes[objclass]['secondary_key']
86 get_accepts += [ Mixed (objclass.fields[primary_key], objclass.fields[secondary_key]) ]
89 get_accepts += [ objclass.fields[primary_key] ]
90 # for set, idem set of arguments + one additional arg, the new value
91 set_accepts = get_accepts + [ Parameter (str,"New tag value") ]
94 get_returns = Mixed (Parameter (str), Parameter(NoneType))
95 set_returns = Parameter(NoneType)
98 setattr(get_class,'roles',get_roles)
99 setattr(get_class,'accepts',get_accepts)
100 setattr(get_class,'returns', get_returns)
101 setattr(get_class,'skip_typecheck',True)
103 setattr(set_class,'roles',set_roles)
104 setattr(set_class,'accepts',set_accepts)
105 setattr(set_class,'returns', set_returns)
106 setattr(set_class,'skip_typecheck',True)
108 table_class = taggable_classes[objclass]['table_class']
109 joins_class = taggable_classes[objclass]['joins_class']
110 join_class = taggable_classes[objclass]['join_class']
112 # body of the get method
113 def get_call (self, auth, id_or_name):
114 # search the tagtype - xxx - might need a cache
115 tag_types = TagTypes (self.api, {'tagname': tagname})
118 tag_type_id = tag_types[0]['tag_type_id']
119 filter = {'tag_type_id':tag_type_id}
120 if isinstance (id_or_name,int):
121 filter[primary_key]=id_or_name
123 filter[secondary_key]=id_or_name
124 joins = joins_class (self.api,filter,['value'])
126 # xxx - we return None even if id_or_name is not valid
129 return joins[0]['value']
132 setattr (get_class,"call",get_call)
134 # body of the set method
135 def set_call (self, auth, id_or_name, value):
137 if isinstance (id_or_name, int):
138 filter={primary_key:id_or_name}
140 filter={secondary_key:id_or_name}
141 objs = table_class(self.api, filter,[primary_key])
143 raise PLCInvalidArgument, "Cannot set tag on %s %r"%(objclass.__name__,id_or_name)
144 primary_id = objs[0][primary_key]
146 # search tag type & create if needed
147 tag_types = TagTypes (self.api, {'tagname':tagname})
149 tag_type = tag_types[0]
151 # not found: create it
152 tag_type_fields = {'tagname':tagname,
153 'category' : category,
154 'description' : description,
155 'min_role_id': tag_min_role_id}
156 tag_type = TagType (self.api, tag_type_fields)
158 tag_type_id = tag_type['tag_type_id']
160 # locate the join object (e.g. NodeTag, SliceTag or InterfaceTag)
161 filter = {'tag_type_id':tag_type_id}
162 if isinstance (id_or_name,int):
163 filter[primary_key]=id_or_name
165 filter[secondary_key]=id_or_name
166 joins = joins_class (self.api,filter)
167 # setting to something non void
168 if value is not None:
170 join = join_class (self.api)
171 join['tag_type_id']=tag_type_id
172 join[primary_key]=primary_id
176 joins[0]['value']=value
178 # providing an empty value means clean up
185 setattr (set_class,"call",set_call)
188 setattr(module,get_name,get_class)
189 setattr(module,set_name,set_class)
190 # add in <module>.methods
192 methods=getattr(module,'methods')
195 methods += [get_name,set_name]
196 setattr(module,'methods',methods)