checkpointing first - non functional - skeleton for shortcut methods
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Thu, 14 Aug 2008 22:16:40 +0000 (22:16 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Thu, 14 Aug 2008 22:16:40 +0000 (22:16 +0000)
Makefile
PLC/API.py
PLC/Methods/GetSliceTicket.py
PLC/Methods/__init__.py
PLC/Shell.py
PLC/Shortcuts/Factory.py [new file with mode: 0644]
PLC/Shortcuts/Shortcuts.py [new file with mode: 0644]
PLC/Shortcuts/__init__.py [new file with mode: 0644]

index e20b903..824730f 100644 (file)
--- 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:
index 5e97ebf..3c825b7 100644 (file)
@@ -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
index cd73f7b..f985c28 100644 (file)
@@ -1,3 +1,5 @@
+# $Id$
+
 import time
 
 from PLC.Faults import *
index 08d9f1f..aa324be 100644 (file)
@@ -1,4 +1,4 @@
-methods = """
+native_methods = """
 AddAddressType
 AddAddressTypeToAddress
 AddBootState
index 3ed0a75..7807c51 100644 (file)
@@ -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 (file)
index 0000000..c31b0a6
--- /dev/null
@@ -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<classname><methodsuffix> (auth, id_or_name) -> tagvalue or None
+# Set<classname><methodsuffix> (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 (file)
index 0000000..74abd07
--- /dev/null
@@ -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 (file)
index 0000000..63aa059
--- /dev/null
@@ -0,0 +1,4 @@
+# each module to define in "methods" the set of methods that it defines
+__all__ = """
+Shortcuts
+""".split()