Moved handle_filename code in a function.
[plcapi.git] / PLC / Methods / GetBootMedium.py
index 5abb295..6756356 100644 (file)
@@ -13,16 +13,22 @@ from PLC.Auth import Auth
 from PLC.Nodes import Node, Nodes
 from PLC.Interfaces import Interface, Interfaces
 from PLC.InterfaceTags import InterfaceTag, InterfaceTags
 from PLC.Nodes import Node, Nodes
 from PLC.Interfaces import Interface, Interfaces
 from PLC.InterfaceTags import InterfaceTag, InterfaceTags
-from PLC.NodeTags import NodeTags
 
 # could not define this in the class..
 
 # could not define this in the class..
-boot_medium_actions = [ 'node-preview',
-                        'node-floppy',
-                        'node-iso',
-                        'node-usb',
-                        'generic-iso',
-                        'generic-usb',
-                        ]
+# create a dict with the allowed actions for each type of node
+allowed_actions = {
+                 'regular' : [ 'node-preview',
+                              'node-floppy',
+                              'node-iso',
+                              'node-usb',
+                              'generic-iso',
+                              'generic-usb',
+                               ],
+                'dummynet' : [ 'node-preview',
+                               'dummynet-iso',
+                               'dummynet-usb',
+                             ],
+               }
 
 # compute a new key
 # xxx used by GetDummyBoxMedium
 
 # compute a new key
 # xxx used by GetDummyBoxMedium
@@ -116,7 +122,7 @@ class GetBootMedium(Method):
         Auth(),
         Mixed(Node.fields['node_id'],
               Node.fields['hostname']),
         Auth(),
         Mixed(Node.fields['node_id'],
               Node.fields['hostname']),
-        Parameter (str, "Action mode, expected in " + "|".join(boot_medium_actions)),
+        Parameter (str, "Action mode, expected value depends of the type of node"),
         Parameter (str, "Empty string for verbatim result, resulting file full path otherwise"),
         Parameter ([str], "Options"),
         ]
         Parameter (str, "Empty string for verbatim result, resulting file full path otherwise"),
         Parameter ([str], "Options"),
         ]
@@ -141,9 +147,15 @@ class GetBootMedium(Method):
             raise PLCInvalidArgument, "Node hostname %s is invalid"%node['hostname']
         return parts
         
             raise PLCInvalidArgument, "Node hostname %s is invalid"%node['hostname']
         return parts
         
-    # plnode.txt content
+    # Generate the node (plnode.txt) configuration content.
+    #
+    # This function will create the configuration file a node
+    # composed by:
+    #  - a common part, regardless of the 'node_type' tag
+    #  - XXX a special part, depending on the 'snode_type' tag value.
     def floppy_contents (self, node, renew_key):
 
     def floppy_contents (self, node, renew_key):
 
+        # Do basic checks
         if node['peer_id'] is not None:
             raise PLCInvalidArgument, "Not a local node"
 
         if node['peer_id'] is not None:
             raise PLCInvalidArgument, "Not a local node"
 
@@ -153,7 +165,7 @@ class GetBootMedium(Method):
             if node['site_id'] not in self.caller['site_ids']:
                 raise PLCPermissionDenied, "Not allowed to generate a configuration file for %s"%node['hostname']
 
             if node['site_id'] not in self.caller['site_ids']:
                 raise PLCPermissionDenied, "Not allowed to generate a configuration file for %s"%node['hostname']
 
-        # Get node networks for this node
+        # Get interface for this node
         primary = None
         interfaces = Interfaces(self.api, node['interface_ids'])
         for interface in interfaces:
         primary = None
         interfaces = Interfaces(self.api, node['interface_ids'])
         for interface in interfaces:
@@ -165,9 +177,9 @@ class GetBootMedium(Method):
 
         ( host, domain ) = self.split_hostname (node)
 
 
         ( host, domain ) = self.split_hostname (node)
 
+       # renew the key and save it on the database
         if renew_key:
             node['key'] = compute_key()
         if renew_key:
             node['key'] = compute_key()
-            # Save it
             node.sync()
 
         # Generate node configuration file suitable for BootCD
             node.sync()
 
         # Generate node configuration file suitable for BootCD
@@ -234,15 +246,11 @@ class GetBootMedium(Method):
             return (pldistro,arch)
 
         node_id=node['node_id']
             return (pldistro,arch)
 
         node_id=node['node_id']
-        # cannot use accessors in the API itself
-        # the 'arch' tag type is assumed to exist, see db-config
-        arch_tags = NodeTags (self.api, {'tagname':'arch','node_id':node_id},['tagvalue'])
-        if arch_tags:
-            arch=arch_tags[0]['tagvalue']
-        # ditto
-        pldistro_tags = NodeTags (self.api, {'tagname':'pldistro','node_id':node_id},['tagvalue'])
-        if pldistro_tags:
-            pldistro=pldistro_tags[0]['tagvalue']
+
+        tag=Nodes(self.api,[node_id],['arch'])[0]['arch']
+        if tag: arch=tag
+        tag=Nodes(self.api,[node_id],['pldistro'])[0]['pldistro']
+        if tag: pldistro=tag
 
         return (pldistro,arch)
 
 
         return (pldistro,arch)
 
@@ -259,12 +267,51 @@ class GetBootMedium(Method):
             else:
                 os.unlink(file)
 
             else:
                 os.unlink(file)
 
+    ### handle filename
+    # build the filename string 
+    # check for permissions and concurrency
+    # returns the filename
+    def handle_filename (self, filename, nodename, suffix, arch):
+        # allow to set filename to None or any other empty value
+        if not filename: filename=''
+        filename = filename.replace ("%d",self.WORKDIR)
+        filename = filename.replace ("%n",nodename)
+        filename = filename.replace ("%s",suffix)
+        filename = filename.replace ("%p",self.api.config.PLC_NAME)
+        # let's be cautious
+        try: filename = filename.replace ("%f", self.nodefamily)
+        except: pass
+        try: filename = filename.replace ("%a", arch)
+        except: pass
+        try: filename = filename.replace ("%v",self.bootcd_version())
+        except: pass
+
+        ### Check filename location
+        if filename != '':
+            if 'admin' not in self.caller['roles']:
+                if ( filename.index(self.WORKDIR) != 0):
+                    raise PLCInvalidArgument, "File %s not under %s"%(filename,self.WORKDIR)
+
+            ### output should not exist (concurrent runs ..)
+            if os.path.exists(filename):
+                raise PLCInvalidArgument, "Resulting file %s already exists"%filename
+
+            ### we can now safely create the file, 
+            ### either we are admin or under a controlled location
+            filedir=os.path.dirname(filename)
+            # dirname does not return "." for a local filename like its shell counterpart
+            if filedir:
+                if not os.path.exists(filedir):
+                    try:
+                        os.makedirs (filedir,0777)
+                    except:
+                        raise PLCPermissionDenied, "Could not create dir %s"%filedir
+
+        return filename
+
     def call(self, auth, node_id_or_hostname, action, filename, options = []):
 
         self.trash=[]
     def call(self, auth, node_id_or_hostname, action, filename, options = []):
 
         self.trash=[]
-        ### check action
-        if action not in boot_medium_actions:
-            raise PLCInvalidArgument, "Unknown action %s"%action
 
         ### compute file suffix and type
         if action.find("-iso") >= 0 :
 
         ### compute file suffix and type
         if action.find("-iso") >= 0 :
@@ -301,16 +348,26 @@ class GetBootMedium(Method):
                 else:
                     raise PLCInvalidArgument, "unknown option %s"%option
 
                 else:
                     raise PLCInvalidArgument, "unknown option %s"%option
 
-        ### check node if needed
-        if action.find("node-") == 0:
-            nodes = Nodes(self.api, [node_id_or_hostname])
-            if not nodes:
-                raise PLCInvalidArgument, "No such node %r"%node_id_or_hostname
-            node = nodes[0]
-            nodename = node['hostname']
+        ### check for node existence and get node_type
+        nodes = Nodes(self.api, [node_id_or_hostname])
+        if not nodes:
+            raise PLCInvalidArgument, "No such node %r"%node_id_or_hostname
+        node = nodes[0]
+
+       if self.DEBUG: print "%s required on node %s. Node type is: %s" \
+                % (action, node['node_id'], node['node_type'])
 
 
+       # checks required action against the node type
+       node_type = node['node_type']
+       if action not in allowed_actions[node_type]:
+               raise PLCInvalidArgument, "Action %s not valid for %s nodes, valid actions are %s" \
+                        % (action, node_type, "|".join(allowed_actions[node_type]))
+
+        # compute nodename
+        if action.find("node-") == 0 or action.find("dummynet-") == 0:
+            nodename = node['hostname']
         else:
         else:
-            node = None
+            node = None        # XXX
             # compute a 8 bytes random number
             tempbytes = random.sample (xrange(0,256), 8);
             def hexa2 (c): return chr((c>>4)+65) + chr ((c&16)+65)
             # compute a 8 bytes random number
             tempbytes = random.sample (xrange(0,256), 8);
             def hexa2 (c): return chr((c>>4)+65) + chr ((c&16)+65)
@@ -319,46 +376,12 @@ class GetBootMedium(Method):
         # get nodefamily
         (pldistro,arch) = self.get_nodefamily(node)
         self.nodefamily="%s-%s"%(pldistro,arch)
         # get nodefamily
         (pldistro,arch) = self.get_nodefamily(node)
         self.nodefamily="%s-%s"%(pldistro,arch)
+
         # apply on globals
         for attr in [ "BOOTCDDIR", "BOOTCDBUILD", "GENERICDIR" ]:
             setattr(self,attr,getattr(self,attr).replace("@NODEFAMILY@",self.nodefamily))
             
         # apply on globals
         for attr in [ "BOOTCDDIR", "BOOTCDBUILD", "GENERICDIR" ]:
             setattr(self,attr,getattr(self,attr).replace("@NODEFAMILY@",self.nodefamily))
             
-        ### handle filename
-        # allow to set filename to None or any other empty value
-        if not filename: filename=''
-        filename = filename.replace ("%d",self.WORKDIR)
-        filename = filename.replace ("%n",nodename)
-        filename = filename.replace ("%s",suffix)
-        filename = filename.replace ("%p",self.api.config.PLC_NAME)
-        # let's be cautious
-        try: filename = filename.replace ("%f", self.nodefamily)
-        except: pass
-        try: filename = filename.replace ("%a", arch)
-        except: pass
-        try: filename = filename.replace ("%v",self.bootcd_version())
-        except: pass
-
-        ### Check filename location
-        if filename != '':
-            if 'admin' not in self.caller['roles']:
-                if ( filename.index(self.WORKDIR) != 0):
-                    raise PLCInvalidArgument, "File %s not under %s"%(filename,self.WORKDIR)
-
-            ### output should not exist (concurrent runs ..)
-            if os.path.exists(filename):
-                raise PLCInvalidArgument, "Resulting file %s already exists"%filename
-
-            ### we can now safely create the file, 
-            ### either we are admin or under a controlled location
-            filedir=os.path.dirname(filename)
-            # dirname does not return "." for a local filename like its shell counterpart
-            if filedir:
-                if not os.path.exists(filedir):
-                    try:
-                        os.makedirs (filedir,0777)
-                    except:
-                        raise PLCPermissionDenied, "Could not create dir %s"%filedir
-
+       filename = self.handle_filename(filename, nodename, suffix, arch)
         
         # log call
         if node:
         
         # log call
         if node:
@@ -481,4 +504,3 @@ class GetBootMedium(Method):
                 
         # we're done here, or we missed something
         raise PLCAPIError,'Unhandled action %s'%action
                 
         # we're done here, or we missed something
         raise PLCAPIError,'Unhandled action %s'%action
-