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.InterfaceSettings import InterfaceSettings, InterfaceSetting
16 from PLC.Slices import Slices, Slice
17 from PLC.SliceAttributes import SliceAttributes, SliceAttribute
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 'value_key': 'tagvalue', 'secondary_key': 'hostname'},
28 Interface : {'table_class' : Interfaces,
29 'joins_class': InterfaceSettings, 'join_class': InterfaceSetting,
30 'value_key' : 'value' },
31 Slice: {'table_class' : Slices,
32 'joins_class': SliceAttributes, 'join_class': SliceAttribute,
33 'value_key' : 'value', '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) -> tagvalue or None
43 # Set<classname><methodsuffix> (auth, id_or_name, tagvalue) -> None
44 # tagvalue 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']
102 value_key = taggable_classes[objclass]['value_key']
104 # body of the get method
105 def get_call (self, auth, id_or_name):
106 # search the tagtype - xxx - might need a cache
107 tag_types = TagTypes (self.api, {'tagname': tagname})
110 tag_type_id = tag_types[0]['tag_type_id']
111 filter = {'tag_type_id':tag_type_id}
112 if isinstance (id_or_name,int):
113 filter[primary_key]=id_or_name
115 filter[secondary_key]=id_or_name
116 joins = joins_class (self.api,filter,[value_key])
118 # xxx - we return None even if id_or_name is not valid
121 return joins[0][value_key]
124 setattr (get_class,"call",get_call)
126 # body of the set method
127 def set_call (self, auth, id_or_name, tagvalue):
129 if isinstance (id_or_name, int):
130 filter={primary_key:id_or_name}
132 filter={secondary_key:id_or_name}
133 objs = table_class(self.api, filter,[primary_key])
135 raise PLCInvalidArgument, "Cannot set tag on %s %r"%(objclass.__name__,id_or_name)
136 primary_id = objs[0][primary_key]
138 # search tag type & create if needed
139 tag_types = TagTypes (self.api, {'tagname':tagname})
141 tag_type = tag_types[0]
143 # not found: create it
144 tag_type_fields = {'tagname':tagname,
145 'category' : category,
146 'description' : description,
147 'min_role_id': tag_min_role_id}
148 tag_type = TagType (self.api, tag_type_fields)
150 tag_type_id = tag_type['tag_type_id']
152 # locate the join object (e.g. NodeTag, SliceAttribute or InterfaceSetting)
153 filter = {'tag_type_id':tag_type_id}
154 if isinstance (id_or_name,int):
155 filter[primary_key]=id_or_name
157 filter[secondary_key]=id_or_name
158 joins = joins_class (self.api,filter)
159 # setting to something non void
160 if tagvalue is not None:
162 join = join_class (self.api)
163 join['tag_type_id']=tag_type_id
164 join[primary_key]=primary_id
165 join[value_key]=tagvalue
168 joins[0][value_key]=tagvalue
170 # providing an empty value means clean up
177 setattr (set_class,"call",set_call)
180 setattr(module,get_name,get_class)
181 setattr(module,set_name,set_class)
182 # add in <module>.methods
184 methods=getattr(module,'methods')
187 methods += [get_name,set_name]
188 setattr(module,'methods',methods)