From b7e454465c4cb7ee3698de9778ed2d4f2d131aa3 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Thu, 14 Aug 2008 22:16:40 +0000 Subject: [PATCH] checkpointing first - non functional - skeleton for shortcut methods --- Makefile | 22 ++------- PLC/API.py | 31 +++++++----- PLC/Methods/GetSliceTicket.py | 2 + PLC/Methods/__init__.py | 2 +- PLC/Shell.py | 2 +- PLC/Shortcuts/Factory.py | 92 +++++++++++++++++++++++++++++++++++ PLC/Shortcuts/Shortcuts.py | 29 +++++++++++ PLC/Shortcuts/__init__.py | 4 ++ 8 files changed, 151 insertions(+), 33 deletions(-) create mode 100644 PLC/Shortcuts/Factory.py create mode 100644 PLC/Shortcuts/Shortcuts.py create mode 100644 PLC/Shortcuts/__init__.py diff --git a/Makefile b/Makefile index e20b903a..824730fe 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ # $Id$ # -# Metafiles -init := PLC/__init__.py PLC/Methods/__init__.py PLC/Legacy/__init__.py +# Metafiles - manage Legacy/ and Shortcuts by hand +init := PLC/__init__.py PLC/Methods/__init__.py # python-pycurl and python-psycopg2 avail. from fedora 5 # we used to ship our own version of psycopg2 and pycurl, for fedora4 @@ -76,23 +76,7 @@ ifneq ($(METHODS_now),$(METHODS_files)) PLC/Methods/__init__.py: force endif PLC/Methods/__init__.py: - (echo 'methods = """' ; cd PLC/Methods; ls -1 *.py system/*.py | grep -v __init__ | sed -e 's,.py$$,,' -e 's,system/,system.,' ; echo '""".split()') > $@ - -########## Legacy/ -# the current content of __init__.py -LEGACY_now := $(sort $(shell fgrep -v '"' PLC/Legacy/__init__.py 2>/dev/null)) -# what should be declared -LEGACY_paths := $(filter-out %/__init__.py, $(wildcard PLC/Legacy/*.py)) -LEGACY_files := $(sort $(notdir $(LEGACY_paths:.py=))) - -ifneq ($(LEGACY_now),$(LEGACY_files)) -PLC/Legacy/__init__.py: force -endif -PLC/Legacy/__init__.py: - (echo '# each module to define in "methods" the set of methods that it defines' ;\ - echo '__all__ = """' ; \ - cd PLC/Legacy; ls -1 *.py | grep -v __init__ | sed -e 's,.py$$,,' ; \ - echo '""".split()') > $@ + (echo 'native_methods = """' ; cd PLC/Methods; ls -1 *.py system/*.py | grep -v __init__ | sed -e 's,.py$$,,' -e 's,system/,system.,' ; echo '""".split()') > $@ ########## force: diff --git a/PLC/API.py b/PLC/API.py index 5e97ebf1..3c825b7a 100644 --- a/PLC/API.py +++ b/PLC/API.py @@ -83,6 +83,7 @@ except ImportError: from PLC.Config import Config from PLC.Faults import * import PLC.Methods +import PLC.Shortcuts import PLC.Legacy def import_deep(name): @@ -95,15 +96,21 @@ def import_deep(name): class PLCAPI: # flat list of method names - methods = PLC.Methods.methods - - # dict {methodname:module} - legacy_map={} - for module in PLC.Legacy.__all__ : - for method in getattr(import_deep("PLC.Legacy."+module),"methods"): - legacy_map[method]=module - - all_methods = methods+legacy_map.keys() + native_methods = PLC.Methods.native_methods + + # other_methods_map : dict {methodname: fullpath} + # e.g. 'Shortcuts' -> 'PLC.Shortcuts.Shortcuts' + other_methods_map={} + for subdir in [ 'Shortcuts', 'Legacy']: + path="PLC."+subdir + # scan e.g. PLC.Shortcuts.__all__ + pkg = __import__(path).__dict__[subdir] + for modulename in getattr(pkg,"__all__"): + fullpath=path+"."+modulename + for method in getattr(import_deep(fullpath),"methods"): + other_methods_map[method] = fullpath + + all_methods = native_methods + other_methods_map.keys() def __init__(self, config = "/etc/planetlab/plc_config", encoding = "utf-8"): self.encoding = encoding @@ -135,12 +142,12 @@ class PLCAPI: # Get new instance of method try: classname = method.split(".")[-1] - if method in self.methods: + if method in self.native_methods: module = __import__("PLC.Methods." + method, globals(), locals(), [classname]) return getattr(module, classname)(self) else: - modulename=self.legacy_map[method] - module = __import__("PLC.Legacy." + modulename, globals(), locals(), [classname]) + fullpath=self.other_methods_map[method] + module = __import__(fullpath, globals(), locals(), [classname]) return getattr(module, classname)(self) except ImportError, AttributeError: raise PLCInvalidAPIMethod, method diff --git a/PLC/Methods/GetSliceTicket.py b/PLC/Methods/GetSliceTicket.py index cd73f7b6..f985c281 100644 --- a/PLC/Methods/GetSliceTicket.py +++ b/PLC/Methods/GetSliceTicket.py @@ -1,3 +1,5 @@ +# $Id$ + import time from PLC.Faults import * diff --git a/PLC/Methods/__init__.py b/PLC/Methods/__init__.py index 08d9f1fb..aa324bee 100644 --- a/PLC/Methods/__init__.py +++ b/PLC/Methods/__init__.py @@ -1,4 +1,4 @@ -methods = """ +native_methods = """ AddAddressType AddAddressTypeToAddress AddBootState diff --git a/PLC/Shell.py b/PLC/Shell.py index 3ed0a75a..7807c51d 100644 --- a/PLC/Shell.py +++ b/PLC/Shell.py @@ -165,7 +165,7 @@ class Shell: if role is not None: self.auth['Role'] = role - for method in PLC.Methods.methods + PLC.API.PLCAPI.legacy_map.keys(): + for method in PLC.API.PLCAPI.all_methods: api_function = self.api.callable(method) if self.server is None: diff --git a/PLC/Shortcuts/Factory.py b/PLC/Shortcuts/Factory.py new file mode 100644 index 00000000..c31b0a6a --- /dev/null +++ b/PLC/Shortcuts/Factory.py @@ -0,0 +1,92 @@ +# Thierry Parmentelat - INRIA +# $Id$ + +from types import NoneType + +from PLC.Method import Method +from PLC.Auth import Auth +from PLC.Parameter import Parameter, Mixed + +from PLC.Faults import * + +from PLC.Nodes import Node +from PLC.Interfaces import Interface +from PLC.Slices import Slice +from PLC.Ilinks import Ilink + +# known classes : { class -> secondary_key } +taggable_classes = { Node : 'hostname', Interface : None, Slice: 'login_base', Ilink : None} + +# generates 2 method classes: +# Get (auth, id_or_name) -> tagvalue or None +# Set (auth, id_or_name, tagvalue) -> None +# tagvalue is always a string, no cast nor typecheck for now +# +# note: tag_min_role_id gets attached to the tagtype instance, +# while get_roles and set_roles get attached to the created methods +# +# returns a tuple (get_method, set_method) +# See Shortcuts.py for examples + +def get_set_factory (objclass, methodsuffix, + tagname, category, description, tag_min_role_id=10, + get_roles=['admin'], set_roles=['admin']): + + if objclass not in taggable_classes: + try: + raise PLCInvalidArgument,"PLC.Shortcuts.Factory: unknown class %s"%objclass.__name__ + except: + raise PLCInvalidArgument,"PLC.Shortcuts.Factory: unknown class ??" + classname=objclass.__name__ + get_name = "Get" + classname + methodsuffix + set_name = "Set" + classname + methodsuffix + + # create method objects under PLC.Method.Method + get_class = type (get_name, (Method,), + {"__doc__":"Shortcut 'get' method designed for %s objects using tag %s"%\ + (classname,tagname)}) + set_class = type (set_name, (Method,), + {"__doc__":"Shortcut 'set' method designed for %s objects using tag %s"%\ + (classname,tagname)}) + # accepts + get_accepts = [ Auth () ] + primary_key=objclass.primary_key + secondary_key = taggable_classes[objclass] + if not secondary_key: + get_accepts += [ objclass.fields[primary_key] ] + else: + get_accepts += [ Mixed (objclass.fields[primary_key], objclass.fields[secondary_key]) ] + # for set, idem + one additional arg + set_accepts = get_accepts + [ Parameter (str,"New tag value") ] + + # returns + get_returns = Mixed (Parameter (str), Parameter(NoneType)) + set_returns = Parameter(NoneType) + + # store in classes + setattr(get_class,'roles',get_roles) + setattr(get_class,'accepts',get_accepts) + setattr(get_class,'returns', get_returns) + setattr(get_class,'skip_typecheck',True) + + setattr(set_class,'roles',set_roles) + setattr(set_class,'accepts',set_accepts) + setattr(set_class,'returns', set_returns) + setattr(set_class,'skip_typecheck',True) + + # body of the get method + def get_call (self, auth, id_or_name): + print 'Automagical Shortcut get method',classname,get_name,tagname,primary_key,secondary_key + print 'Warning: PLC/Shortcuts/Factory is an ongoing work' + return 'foobar' + setattr (get_class,"call",get_call) + + # body of the set method + def set_call (self, auth, id_or_name, tagvalue): + print 'Automagical Shortcut set method',classname,get_name,tagname,primary_key,secondary_key + print 'Warning: PLC/Shortcuts/Factory is an ongoing work' + return None + setattr (set_class,"call",set_call) + + return ( get_class, set_class ) + diff --git a/PLC/Shortcuts/Shortcuts.py b/PLC/Shortcuts/Shortcuts.py new file mode 100644 index 00000000..74abd079 --- /dev/null +++ b/PLC/Shortcuts/Shortcuts.py @@ -0,0 +1,29 @@ +# Thierry Parmentelat - INRIA +# $Id$ + +from PLC.Nodes import Node +from PLC.Interfaces import Interface +from PLC.Slices import Slice +from PLC.Ilinks import Ilink + +from PLC.Shortcuts.Factory import get_set_factory + +# xxx probably defined someplace else +all_roles = [ 'admin', 'pi', 'tech', 'user', 'node' ] + +methods=[] + +# example : node architecture +(GetNodeArch, SetNodeArch) = \ + get_set_factory ( Node, "Arch", 'arch', 'node/config', 'architecture name', + tag_min_role_id=40, + get_roles=all_roles, + set_roles=['admin', 'pi', 'tech'] ) +methods += [ 'GetNodeArch', 'SetNodeArch' ] + +# example : vlan ids on interfaces +(GetInterfaceVlan, SetInterfaceVlan) = \ + get_set_factory ( Interface, "Vlan", "vlan","interface/general", "tag for setting VLAN id", + get_roles=all_roles, + set_roles=['admin', 'pi', 'tech'] ) +methods += [ 'GetInterfaceVlan', 'SetInterfaceVlan' ] diff --git a/PLC/Shortcuts/__init__.py b/PLC/Shortcuts/__init__.py new file mode 100644 index 00000000..63aa0595 --- /dev/null +++ b/PLC/Shortcuts/__init__.py @@ -0,0 +1,4 @@ +# each module to define in "methods" the set of methods that it defines +__all__ = """ +Shortcuts +""".split() -- 2.45.2