boot manager assumes the tagname is identical to the initscript conventions
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Fri, 5 Dec 2008 19:53:39 +0000 (19:53 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Fri, 5 Dec 2008 19:53:39 +0000 (19:53 +0000)
PLC/Accessors/Accessors_wireless.py
PLC/Methods/AddNode.py
PLC/Methods/UpdateNode.py
PLC/Nodes.py
PLC/Table.py

index 1b8a7ce..986ebe6 100644 (file)
@@ -13,7 +13,7 @@ current_module = sys.modules[__name__]
 
 #### Wireless
 
-define_accessors(current_module, Interface, "WifiMode", "wifi_mode", "interface/wifi", "Wifi operation mode - see iwconfig",
+define_accessors(current_module, Interface, "WifiMode", "mode", "interface/wifi", "Wifi operation mode - see iwconfig",
                  get_roles=all_roles, set_roles=tech_roles)
 define_accessors(current_module, Interface, "Essid", "essid", "interface/wifi", "Wireless essid - see iwconfig",
                  get_roles=all_roles, set_roles=tech_roles)
index 5ddb467..a7f7406 100644 (file)
@@ -2,13 +2,13 @@
 from PLC.Faults import *
 from PLC.Method import Method
 from PLC.Parameter import Parameter, Mixed
+from PLC.Table import Row
 from PLC.Nodes import Node, Nodes
 from PLC.NodeGroups import NodeGroup, NodeGroups
 from PLC.Sites import Site, Sites
 from PLC.Auth import Auth
 
-can_update = lambda (field, value): field in \
-             ['hostname', 'node_type', 'boot_state', 'model', 'version']
+can_update = ['hostname', 'node_type', 'boot_state', 'model', 'version']
 
 class AddNode(Method):
     """
@@ -23,19 +23,23 @@ class AddNode(Method):
 
     roles = ['admin', 'pi', 'tech']
 
-    node_fields = dict(filter(can_update, Node.fields.items()))
+    accepted_fields = Row.accepted_fields(can_update, [Node.fields,Node.tags])
 
     accepts = [
         Auth(),
         Mixed(Site.fields['site_id'],
               Site.fields['login_base']),
-        node_fields
+        accepted_fields
         ]
 
     returns = Parameter(int, 'New node_id (> 0) if successful')
 
     def call(self, auth, site_id_or_login_base, node_fields):
-        node_fields = dict(filter(can_update, node_fields.items()))
+
+        [native,tags,rejected]=Row.split_fields(node_fields,[Node.fields,Node.tags])
+
+        if rejected:
+            raise PLCInvalidArgument, "Cannot add Node with column(s) %r"%rejected
 
         # Get site information
         sites = Sites(self.api, [site_id_or_login_base])
@@ -56,10 +60,15 @@ class AddNode(Method):
             else:
                 assert self.caller['person_id'] in site['person_ids']
 
-        node = Node(self.api, node_fields)
+        node = Node(self.api, native)
         node['site_id'] = site['site_id']
         node.sync()
 
+        if tags:
+            print 'AddNode: warning, tags not handled yet'
+            for (k,v) in tags.iteritems():
+                print 'tag',k,v
+
        self.event_objects = {'Site': [site['site_id']],
                             'Node': [node['node_id']]} 
        self.message = "Node %s created" % node['node_id']
index d6c9e45..9163fa1 100644 (file)
@@ -2,14 +2,12 @@
 from PLC.Faults import *
 from PLC.Method import Method
 from PLC.Parameter import Parameter, Mixed
+from PLC.Table import Row
 from PLC.Nodes import Node, Nodes
 from PLC.Auth import Auth
 
-related_fields = Node.related_fields.keys()
-can_update = lambda (field, value): field in \
-             ['hostname', 'boot_state', 'model', 'version',
-              'key', 'session', 'boot_nonce', 'site_id'] + \
-            related_fields
+can_update = ['hostname', 'boot_state', 'model', 'version','key', 'session', 'boot_nonce', 'site_id'] + \
+              Node.related_fields.keys()
 
 class UpdateNode(Method):
     """
@@ -24,7 +22,7 @@ class UpdateNode(Method):
 
     roles = ['admin', 'pi', 'tech']
 
-    node_fields = dict(filter(can_update, Node.fields.items() + Node.related_fields.items()))
+    node_fields = Row.accepted_fields(can_update,[Node.fields,Node.related_fields,Node.tags])
 
     accepts = [
         Auth(),
@@ -37,22 +35,26 @@ class UpdateNode(Method):
 
     def call(self, auth, node_id_or_hostname, node_fields):
         
-       node_fields = dict(filter(can_update, node_fields.items()))
+        # split provided fields 
+        [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags])
+
+        if rejected:
+            raise PLCInvalidArgument, "Cannot update column(s) %r"%rejected
 
        # Remove admin only fields
        if 'admin' not in self.caller['roles']:
             for key in 'key', 'session', 'boot_nonce', 'site_id':
-                if node_fields.has_key(key):
-                    del node_fields[key]
+                if native.has_key(key):
+                    del native[key]
 
         # Get account information
         nodes = Nodes(self.api, [node_id_or_hostname])
         if not nodes:
-            raise PLCInvalidArgument, "No such node"
+            raise PLCInvalidArgument, "No such node %r"%node_id_or_hostname
         node = nodes[0]
 
         if node['peer_id'] is not None:
-            raise PLCInvalidArgument, "Not a local node"
+            raise PLCInvalidArgument, "Not a local node %r"%node_id_or_hostname
 
         # Authenticated function
         assert self.caller is not None
@@ -64,14 +66,17 @@ class UpdateNode(Method):
                 raise PLCPermissionDenied, "Not allowed to delete nodes from specified site"
 
         # Make requested associations
-        for field in related_fields:
-            if field in node_fields:
-                node.associate(auth, field, node_fields[field])
-                node_fields.pop(field)
-
-       node.update(node_fields)
-       node.update_last_updated(False)
-        node.sync()
+        for (k,v) in related.iteritems():
+            node.associate(auth, k,v)
+
+        if tags:
+            print 'UpdateNode: warning, tags not handled yet'
+            for (k,v) in tags.iteritems():
+                print 'tag',k,v
+
+       node.update(native)
+       node.update_last_updated(commit=False)
+        node.sync(commit=True)
        
        # Logging variables
        self.event_objects = {'Node': [node['node_id']]}
index a1cea70..db62aae 100644 (file)
@@ -72,8 +72,6 @@ class Node(Row):
     related_fields = {
        'interfaces': [Mixed(Parameter(int, "Interface identifier"),
                              Filter(Interface.fields))],
-       'nodegroups': [Mixed(Parameter(int, "NodeGroup identifier"),
-                             Parameter(str, "NodeGroup name"))],
        'conf_files': [Parameter(int, "ConfFile identifier")],
        'slices': [Mixed(Parameter(int, "Slice identifier"),
                          Parameter(str, "Slice name"))],
@@ -82,6 +80,7 @@ class Node(Row):
        }
 
     view_tags_name = "view_node_tags"
+    # tags declared here should also be defined as Accessors to ensure that the TagType is created
     tags = {
         # regular
         'arch': Parameter(str, "node/config", ro=True),
index 2ce8bb7..a86e21e 100644 (file)
@@ -223,17 +223,48 @@ 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 three lists
+    # takes in input a list of columns, returns 2 dicts and one list
     # fields, tags, rejected
     @classmethod
     def parse_columns (cls, columns):
-        (fields,tags,rejected)=({},{},{})
+        (fields,tags,rejected)=({},{},[])
         for column in columns:
             if column in cls.fields: fields[column]=cls.fields[column]
             elif column in cls.tags: tags[column]=cls.tags[column]
             else: rejected.append(column)
         return (fields,tags,rejected)
 
+    # given a dict (typically passed to an Update method), we check and sort
+    # them against a list of dicts, e.g. [Node.fields, Node.related_fields]
+    # return is a list that contains n+1 dicts, last one has the rejected fields
+    @staticmethod
+    def split_fields (fields, dicts):
+        result=[]
+        for x in dicts: result.append({})
+        rejected={}
+        for (field,value) in fields.iteritems():
+            found=False
+            for i in range(len(dicts)):
+                candidate_dict=dicts[i]
+                if field in candidate_dict.keys():
+                    result[i][field]=value
+                    found=True
+                    break 
+            if not found: rejected[field]=value
+        result.append(rejected)
+        return result
+
+    # compute the accepts part of an update method from a list of column names, and a (list of) field dict
+    @staticmethod
+    def accepted_fields (can_update_columns, fields):
+        result={}
+        if not isinstance(fields,list): fields = [fields]
+        for dict in fields:
+            for (k,v) in dict.iteritems():
+                if k in can_update_columns:
+                    result[k]=v
+        return result
+
     @classmethod
     def tagvalue_view_name (cls, tagname):
         return "tagvalue_view_%s_%s"%(cls.primary_key,tagname)