revised type-checking on taggable classes - previous code would reject any tag
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 19 Jul 2009 07:55:00 +0000 (07:55 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Sun, 19 Jul 2009 07:55:00 +0000 (07:55 +0000)
PLC/Methods/AddInterface.py
PLC/Methods/AddNode.py
PLC/Methods/AddSlice.py
PLC/Methods/GetNodes.py
PLC/Methods/UpdateInterface.py
PLC/Methods/UpdateNode.py
PLC/Methods/UpdateSlice.py
PLC/Table.py

index 662d7fd..69e92ec 100644 (file)
@@ -12,7 +12,7 @@ from PLC.InterfaceTags import InterfaceTags
 from PLC.Methods.AddInterfaceTag import AddInterfaceTag
 from PLC.Methods.UpdateInterfaceTag import UpdateInterfaceTag
 
-can_update = ['interface_id', 'node_id']
+cannot_update = ['interface_id', 'node_id']
 
 class AddInterface(Method):
     """
@@ -33,7 +33,8 @@ class AddInterface(Method):
 
     roles = ['admin', 'pi', 'tech']
 
-    accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags], exclude=True)
+    accepted_fields = Row.accepted_fields(cannot_update, Interface.fields, exclude=True)
+    accepted_fields.update(Interface.tags)
 
     accepts = [
         Auth(),
@@ -47,9 +48,10 @@ class AddInterface(Method):
     
     def call(self, auth, node_id_or_hostname, interface_fields):
 
-        interface_fields = Row.check_fields (interface_fields, self.accepted_fields)
-
         [native,tags,rejected]=Row.split_fields(interface_fields,[Interface.fields,Interface.tags])
+
+        # type checking
+        native = Row.check_fields (native, self.accepted_fields)
         if rejected:
             raise PLCInvalidArgument, "Cannot add Interface with column(s) %r"%rejected
 
index b722585..d25e8b2 100644 (file)
@@ -27,7 +27,8 @@ class AddNode(Method):
 
     roles = ['admin', 'pi', 'tech']
 
-    accepted_fields = Row.accepted_fields(can_update, [Node.fields,Node.tags])
+    accepted_fields = Row.accepted_fields(can_update,Node.fields)
+    accepted_fields.update(Node.tags)
 
     accepts = [
         Auth(),
@@ -40,10 +41,10 @@ class AddNode(Method):
 
     def call(self, auth, site_id_or_login_base, node_fields):
 
-        node_fields = Row.check_fields (node_fields, self.accepted_fields)
-
         [native,tags,rejected]=Row.split_fields(node_fields,[Node.fields,Node.tags])
 
+        # type checking
+        native = Row.check_fields (native, self.accepted_fields)
         if rejected:
             raise PLCInvalidArgument, "Cannot add Node with column(s) %r"%rejected
 
index 3e2a89c..a29b41f 100644 (file)
@@ -35,7 +35,8 @@ class AddSlice(Method):
 
     roles = ['admin', 'pi']
 
-    accepted_fields = Row.accepted_fields(can_update, [Slice.fields,Slice.tags])
+    accepted_fields = Row.accepted_fields(can_update, Slice.fields)
+    accepted_fields.update(Slice.tags)
 
     accepts = [
         Auth(),
@@ -46,10 +47,10 @@ class AddSlice(Method):
 
     def call(self, auth, slice_fields):
 
-        slice_fields = Row.check_fields (slice_fields, self.accepted_fields)
-
         [native,tags,rejected]=Row.split_fields(slice_fields,[Slice.fields,Slice.tags])
 
+        # type checking
+        native = Row.check_fields (native, self.accepted_fields)
         if rejected:
             raise PLCInvalidArgument, "Cannot add Slice with column(s) %r"%rejected
 
index bc7dc7e..a5df248 100644 (file)
@@ -7,13 +7,19 @@ from PLC.Nodes import Node, Nodes
 from PLC.Persons import Person, Persons
 from PLC.Auth import Auth
 
+admin_only = ['key', 'session', 'boot_nonce' ]
+
 class v43GetNodes(Method):
     """
     Returns an array of structs containing details about nodes. If
     node_filter is specified and is an array of node identifiers or
     hostnames, or a struct of node attributes, only nodes matching the
-    filter will be returned. If return_fields is specified, only the
-    specified details will be returned.
+    filter will be returned. 
+
+    If return_fields is specified, only the specified details will be
+    returned. NOTE that if return_fields is unspecified, the complete
+    set of native fields are returned, which DOES NOT include tags at
+    this time.
 
     Some fields may only be viewed by admins.
     """
@@ -71,7 +77,7 @@ class v43GetNodes(Method):
 
            # remove remaining admin only fields
             for node in nodes:    
-               for field in ['boot_nonce', 'key', 'session', 'root_person_ids']:
+               for field in admin_only:
                     if field in node:
                         del node[field]
        
index 48f3822..64b37d9 100644 (file)
@@ -12,7 +12,7 @@ from PLC.Interfaces import Interface, Interfaces
 from PLC.Methods.AddInterfaceTag import AddInterfaceTag
 from PLC.Methods.UpdateInterfaceTag import UpdateInterfaceTag
 
-can_update = ['interface_id','node_id']
+cannot_update = ['interface_id','node_id']
 
 class UpdateInterface(Method):
     """
@@ -31,7 +31,8 @@ class UpdateInterface(Method):
 
     roles = ['admin', 'pi', 'tech']
 
-    accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags],exclude=True)
+    accepted_fields = Row.accepted_fields(cannot_update, Interface.fields,exclude=True)
+    accepted_fields.update(Interface.tags)
 
     accepts = [
         Auth(),
@@ -43,10 +44,10 @@ class UpdateInterface(Method):
 
     def call(self, auth, interface_id, interface_fields):
 
-        interface_fields = Row.check_fields (interface_fields, self.accepted_fields)
-
         [native,tags,rejected] = Row.split_fields(interface_fields,[Interface.fields,Interface.tags])
 
+        # type checking
+        native= Row.check_fields (native, self.accepted_fields)
         if rejected:
             raise PLCInvalidArgument, "Cannot update Interface column(s) %r"%rejected
 
index 6f60a46..1cf7a47 100644 (file)
@@ -11,8 +11,8 @@ from PLC.NodeTags import NodeTags
 from PLC.Methods.AddNodeTag import AddNodeTag
 from PLC.Methods.UpdateNodeTag import UpdateNodeTag
 
-can_update = ['hostname', 'boot_state', 'model', 'version','key', 'session', 'boot_nonce', 'site_id'] + \
-              Node.related_fields.keys()
+admin_only = [ 'key', 'session', 'boot_nonce', 'site_id']
+can_update = ['hostname', 'boot_state', 'model', 'version'] + admin_only 
 
 class UpdateNode(Method):
     """
@@ -27,7 +27,10 @@ class UpdateNode(Method):
 
     roles = ['admin', 'pi', 'tech']
 
-    accepted_fields = Row.accepted_fields(can_update,[Node.fields,Node.related_fields,Node.tags])
+    accepted_fields = Row.accepted_fields(can_update,Node.fields)
+    # xxx check the related_fields feature
+    accepted_fields.update(Node.related_fields)
+    accepted_fields.update(Node.tags)
 
     accepts = [
         Auth(),
@@ -40,17 +43,20 @@ class UpdateNode(Method):
 
     def call(self, auth, node_id_or_hostname, node_fields):
         
-        node_fields = Row.check_fields (node_fields, self.accepted_fields)
-
         # split provided fields 
         [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags])
 
+        # type checking
+        native = Row.check_fields (native, self.accepted_fields)
         if rejected:
             raise PLCInvalidArgument, "Cannot update Node column(s) %r"%rejected
 
+        # Authenticated function
+        assert self.caller is not None
+
        # Remove admin only fields
        if 'admin' not in self.caller['roles']:
-            for key in 'key', 'session', 'boot_nonce', 'site_id':
+            for key in admin_only:
                 if native.has_key(key):
                     del native[key]
 
@@ -63,9 +69,6 @@ class UpdateNode(Method):
         if node['peer_id'] is not None:
             raise PLCInvalidArgument, "Not a local node %r"%node_id_or_hostname
 
-        # Authenticated function
-        assert self.caller is not None
-
         # If we are not an admin, make sure that the caller is a
         # member of the site at which the node is located.
         if 'admin' not in self.caller['roles']:
index bc28a55..333bac1 100644 (file)
@@ -14,8 +14,7 @@ from PLC.SliceTags import SliceTags
 from PLC.Methods.AddSliceTag import AddSliceTag
 from PLC.Methods.UpdateSliceTag import UpdateSliceTag
 
-can_update = ['instantiation', 'url', 'description', 'max_nodes', 'expires'] + \
-    Slice.related_fields.keys()
+can_update = ['instantiation', 'url', 'description', 'max_nodes', 'expires'] 
 
 class UpdateSlice(Method):
     """
@@ -35,7 +34,10 @@ class UpdateSlice(Method):
 
     roles = ['admin', 'pi', 'user']
 
-    accepted_fields = Row.accepted_fields(can_update, [Slice.fields,Slice.related_fields,Slice.tags])
+    accepted_fields = Row.accepted_fields(can_update, Slice.fields)
+    # xxx check the related_fields feature
+    accepted_fields.update(Slice.related_fields)
+    accepted_fields.update(Slice.tags)
 
     accepts = [
         Auth(),
@@ -48,11 +50,11 @@ class UpdateSlice(Method):
 
     def call(self, auth, slice_id_or_name, slice_fields):
 
-        slice_fields = Row.check_fields (slice_fields, self.accepted_fields)
-
         # split provided fields 
         [native,related,tags,rejected] = Row.split_fields(slice_fields,[Slice.fields,Slice.related_fields,Slice.tags])
-
+        
+        # type checking
+        native = Row.check_fields (native, self.accepted_fields)
         if rejected:
             raise PLCInvalidArgument, "Cannot update Slice column(s) %r"%rejected
 
index fdd755e..e56f316 100644 (file)
@@ -228,8 +228,8 @@ class Row(dict):
         return dict ( [ (key,value) for (key,value) in obj.iteritems() 
                         if key in self.tags and Row.is_writable(key,value,self.tags) ] )
     
-    # takes in input a list of columns, returns 2 dicts and one list
-    # fields, tags, rejected
+    # takes as input a list of columns, sort native fields from tags
+    # returns 2 dicts and one list : fields, tags, rejected
     @classmethod
     def parse_columns (cls, columns):
         (fields,tags,rejected)=({},{},[])
@@ -239,20 +239,20 @@ class Row(dict):
             else: rejected.append(column)
         return (fields,tags,rejected)
 
-    # compute the accepts part of an update method from a list of column names, and a (list of) fields dict
+    # compute the 'accepts' part of a method, from a list of column names, and a fields dict
     # use exclude=True to exclude the column names instead
+    # typically accepted_fields (Node.fields,['hostname','model',...])
     @staticmethod
-    def accepted_fields (update_columns, fields, exclude=False):
-        if not isinstance(fields,list): fields = [fields]
+    def accepted_fields (update_columns, fields_dict, exclude=False):
         result={}
-        for fields_dict in fields:
-            for (k,v) in fields_dict.iteritems():
-                if (not exclude and k in update_columns) or (exclude and k not in update_columns):
-                    result[k]=v
+        for (k,v) in fields_dict.iteritems():
+            if (not exclude and k in update_columns) or (exclude and k not in update_columns):
+                result[k]=v
         return result
 
     # filter out user-provided fields that are not part of the declared acceptance list
-    # this could maybe have been integrated in split_fields, but for simplicity we keep it aside
+    # keep it separate from split_fields for simplicity
+    # typically check_fields (<user_provided_dict>,{'hostname':Parameter(str,...),'model':Parameter(..)...})
     @staticmethod
     def check_fields (user_dict, accepted_fields):
 # avoid the simple, but silent, version