From 42b6acee776a37d45221a13b37ede58a6578b831 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Tue, 26 Jan 2010 16:43:37 +0000 Subject: [PATCH] revised accessor factory; tagtype gets created on Get... methods, and maintain a cache in the Accessor (singleton) class --- PLC/Accessor.py | 58 ++++++++++++++++++++++++++++ PLC/Accessors/Accessors_site.py | 9 ++++- PLC/Accessors/Accessors_standard.py | 14 ++++++- PLC/Accessors/Factory.py | 59 ++++++++++++++++++----------- 4 files changed, 114 insertions(+), 26 deletions(-) create mode 100644 PLC/Accessor.py diff --git a/PLC/Accessor.py b/PLC/Accessor.py new file mode 100644 index 0000000..8a8d16d --- /dev/null +++ b/PLC/Accessor.py @@ -0,0 +1,58 @@ +# $Id$ +# $URL$ +# +# Thierry Parmentelat - INRIA +# +# +# just a placeholder for storing accessor-related tag checkers +# this is filled by the accessors factory + +from PLC.TagTypes import TagTypes, TagType + +# implementation +class Accessor (object) : + """This is placeholder for storing accessor-related tag checkers +methods in this class are defined by the accessors factory + +This is implemented as a singleton, so we can cache results over time""" + + _instance = None + + def __init__ (self, api): + self.api=api + # 'tagname'=>'tag_id' + self.cache={} + + def has_cache (self,tagname): return self.cache.has_key(tagname) + def get_cache (self,tagname): return self.cache[tagname] + def set_cache (self,tagname,tag_id): self.cache[tagname]=tag_id + + def locate_or_create_tag (self,tagname,category, description, min_role_id): + "search tag type from tagname & create if needed" + + # cached ? + if self.has_cache (tagname): + return self.get_cache(tagname) + # search + tag_types = TagTypes (self.api, {'tagname':tagname}) + if tag_types: + tag_type = tag_types[0] + else: + # not found: create it + tag_type_fields = {'tagname':tagname, + 'category' : category, + 'description' : description, + 'min_role_id': min_role_id} + tag_type = TagType (self.api, tag_type_fields) + tag_type.sync() + tag_type_id = tag_type['tag_type_id'] + self.set_cache(tagname,tag_type_id) + return tag_type_id + + +#################### +# make it a singleton so we can cache stuff in there over time +def AccessorSingleton (api): + if not Accessor._instance: + Accessor._instance = Accessor(api) + return Accessor._instance diff --git a/PLC/Accessors/Accessors_site.py b/PLC/Accessors/Accessors_site.py index 0eadebc..f27cd8d 100644 --- a/PLC/Accessors/Accessors_site.py +++ b/PLC/Accessors/Accessors_site.py @@ -2,8 +2,11 @@ # $Id$ # $URL$ # -# Shortcuts_site.py is the place where you can define your own tag accessors -# this will not be overwritten through rpm upgrades in a myplc-devel packaging +# Accessors_site.py is the place where you can define your own local tag accessors +# this will not be overwritten through rpm upgrades +# +# Now that Sites are taggable too, the name may be confusing, think of is as +# Accessors_local.py # # methods denotes the set of methods (names) that get inserted into the API # it is updated by define_accessors @@ -13,6 +16,8 @@ methods=[] from PLC.Nodes import Node from PLC.Interfaces import Interface from PLC.Slices import Slice +from PLC.Sites import Site +from PLC.Persons import Person #from PLC.Ilinks import Ilink from PLC.Accessors.Factory import define_accessors, all_roles, tech_roles diff --git a/PLC/Accessors/Accessors_standard.py b/PLC/Accessors/Accessors_standard.py index 1e28b87..9d3c1e1 100644 --- a/PLC/Accessors/Accessors_standard.py +++ b/PLC/Accessors/Accessors_standard.py @@ -5,6 +5,9 @@ from PLC.Nodes import Node from PLC.Interfaces import Interface from PLC.Slices import Slice +from PLC.Slices import Slice +from PLC.Sites import Site +from PLC.Persons import Person #from PLC.Ilinks import Ilink from PLC.Accessors.Factory import define_accessors, all_roles, tech_roles @@ -44,14 +47,16 @@ define_accessors(current_module, Slice, "Fcdistro", "fcdistro", "node/slice/config", "Fedora or CentOS distribution to use for node or slivers", get_roles=all_roles, set_roles=["admin"], expose_in_api=True) -# node architecture +# Ditto for the GetNodeFlavour method define_accessors(current_module, Node, "Arch", "arch", "node/slice/config", "node arch or slivers arch", get_roles=all_roles, set_roles=tech_roles, expose_in_api=True) -# distribution to be deployed define_accessors(current_module, Node, "Pldistro", "pldistro", "node/slice/config", "PlanetLab distribution to use for node or slivers", get_roles=all_roles, set_roles=["admin"], expose_in_api=True) +define_accessors(current_module, Node, "Fcdistro", "fcdistro", + "node/slice/config", "Fedora or CentOS distribution to use for node or slivers", + get_roles=all_roles, set_roles=["admin"], expose_in_api=True) # node deployment (alpha, beta, ...) define_accessors(current_module, Node, "Deployment", "deployment", "node/operation", 'typically "alpha", "beta", or "production"', @@ -88,3 +93,8 @@ define_accessors(current_module, Interface, "Driver", "driver", define_accessors(current_module, Interface, "Alias", "alias", "interface/config", "interface alias", get_roles=all_roles, set_roles=tech_roles) + +# site +define_accessors(current_module, Site, "Foo", "foo", + "site/test", "some name", + get_roles=all_roles, set_roles=all_roles, expose_in_api=True) diff --git a/PLC/Accessors/Factory.py b/PLC/Accessors/Factory.py index 02de440..2dd2a73 100644 --- a/PLC/Accessors/Factory.py +++ b/PLC/Accessors/Factory.py @@ -4,11 +4,12 @@ from types import NoneType -from PLC.Method import Method +from PLC.Faults import * + from PLC.Auth import Auth from PLC.Parameter import Parameter, Mixed - -from PLC.Faults import * +from PLC.Method import Method +from PLC.Accessor import Accessor, AccessorSingleton from PLC.Nodes import Nodes, Node from PLC.NodeTags import NodeTags, NodeTag @@ -16,6 +17,10 @@ from PLC.Interfaces import Interfaces, Interface from PLC.InterfaceTags import InterfaceTags, InterfaceTag from PLC.Slices import Slices, Slice from PLC.SliceTags import SliceTags, SliceTag +from PLC.Sites import Sites, Site +from PLC.SiteTags import SiteTags, SiteTag +from PLC.Persons import Persons, Person +from PLC.PersonTags import PersonTags, PersonTag # this is another story.. #from PLC.Ilinks import Ilink @@ -32,6 +37,12 @@ taggable_classes = { Node : {'table_class' : Nodes, Slice: {'table_class' : Slices, 'joins_class': SliceTags, 'join_class': SliceTag, 'secondary_key':'name'}, + Site: {'table_class' : Sites, + 'joins_class': SiteTags, 'join_class': SiteTag, + 'secondary_key':'login_base'}, + Person: {'table_class' : Persons, + 'joins_class': PersonTags, 'join_class': PersonTag, + 'secondary_key':'email'}, # Ilink : xxx } @@ -52,6 +63,8 @@ tech_roles = [ 'admin', 'pi', 'tech' ] # while get_roles and set_roles get attached to the created methods # this might need a cleanup # +# in addition a convenience method like e.g. LocateNodeArch is defined +# in the Accessor class; its purpose is to retrieve the tag, or to create it if needed def define_accessors (module, objclass, methodsuffix, tagname, category, description, @@ -71,14 +84,16 @@ def define_accessors (module, objclass, methodsuffix, tagname, classname=objclass.__name__ get_name = "Get" + classname + methodsuffix set_name = "Set" + classname + methodsuffix + locator_name = "Locate" + classname + methodsuffix - # create method objects under PLC.Method.Method + # accessor method objects under PLC.Method.Method get_class = type (get_name, (Method,), {"__doc__":"Accessor 'get' method designed for %s objects using tag %s"%\ (classname,tagname)}) set_class = type (set_name, (Method,), {"__doc__":"Accessor 'set' method designed for %s objects using tag %s"%\ (classname,tagname)}) + # accepts get_accepts = [ Auth () ] primary_key=objclass.primary_key @@ -106,13 +121,23 @@ def define_accessors (module, objclass, methodsuffix, tagname, joins_class = taggable_classes[objclass]['joins_class'] join_class = taggable_classes[objclass]['join_class'] + # locate the tag and create it if needed + # this method is attached to the Accessor class + def locate_or_create_tag (self): + return self.locate_or_create_tag (tagname=tagname, + category=category, + description=description, + min_role_id=tag_min_role_id) + + # attach it to the Accessor class + setattr(Accessor,locator_name,locate_or_create_tag) + # body of the get method def get_call (self, auth, id_or_name): - # search the tagtype - xxx - might need a cache - tag_types = TagTypes (self.api, {'tagname': tagname}) - if not tag_types: - return None - tag_type_id = tag_types[0]['tag_type_id'] + # locate the tag, see above + locator = getattr(Accessor,locator_name) + tag_type_id = locator(AccessorSingleton(self.api)) + filter = {'tag_type_id':tag_type_id} if isinstance (id_or_name,int): filter[primary_key]=id_or_name @@ -140,19 +165,9 @@ def define_accessors (module, objclass, methodsuffix, tagname, raise PLCInvalidArgument, "Cannot set tag on %s %r"%(objclass.__name__,id_or_name) primary_id = objs[0][primary_key] - # search tag type & create if needed - tag_types = TagTypes (self.api, {'tagname':tagname}) - if tag_types: - tag_type = tag_types[0] - else: - # not found: create it - tag_type_fields = {'tagname':tagname, - 'category' : category, - 'description' : description, - 'min_role_id': tag_min_role_id} - tag_type = TagType (self.api, tag_type_fields) - tag_type.sync() - tag_type_id = tag_type['tag_type_id'] + # locate the tag, see above + locator = getattr(Accessor,locator_name) + tag_type_id = locator(AccessorSingleton(self.api)) # locate the join object (e.g. NodeTag, SliceTag or InterfaceTag) filter = {'tag_type_id':tag_type_id} -- 2.43.0