C# Example: A Job Submission Filter that Checks for Job Size

Applies To: Windows HPC Server 2008

Note

This code sample applies to HPC Server 2008. For updated filter code samples that apply to Windows HPC Server 2008 R2, you can download the code samples from the HPC Pack 2008 R2 SDK.

In Windows® HPC Server 2008, you can enforce site-specific job submission policies by writing a job submission filter application. A submission filter parses the job description file to check for options that you want to disallow or limit, or to make changes to the job description file.

Important

Before writing and installing a custom filter, ensure that you have installed the HPC Pack 2008 Fix for Job XML Import and Export Issues update (https://go.microsoft.com/fwlink/?LinkId=132745). This update affects the job XML schema.

Example submission filter code

The C# code sample in this topic provides an example of a job submission filter application. In this example, the submission filter checks the maximum number of units (cores, sockets, or nodes) that are requested by the job. If the maximum number of units is greater than one, the filter assigns a job template called “LargeJobTemplate” to the job, and adds an extended job term to the job description file. The extended term is called JobClass, and the value is set to MultipleUnit.

Note

The job schema is designed to handle arbitrary name/value pairs as part of the ExtendedTerms element. You can write submission and activation filters to manipulate these extended terms. For example, you can create a script that sets extended job terms. When a user submits a job with that script, the submission or activation filter can look for that property and then check for associated restraints or default values as appropriate.

Important

The following code sample is offered as a reference. You should modify it according to your specific configuration needs before using it in a production environment.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Configuration;



namespace SubmissionFilterDemo
{
    class JobSizeFilter
    {
        const int SuccessNoJobChange = 0;
        const int SuccessJobChanged = 1;
        const int FailureOpeningLogFile = -2;
        const int FailureParsingXml = -1;

        public static TextWriter logFile = null;
        static int Main(string[] args)
        {
            // Create the Log file for the filter.
            int retval;
            if ((retval=setupLogFile()) != 0)
            {
                return retval;
            }

            // Check that there is only one argument.
            if (args.Length != 1)
            {
                logFile.WriteLine("Takes exactly one parameter, ie the name of the job xml file");
            }

            String fileName = args[0];

            // Load the job file as an XmlDocument.
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(fileName);

                XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
                nsMgr.AddNamespace("hpc", "https://schemas.microsoft.com/HPCS2008/scheduler/");

                // Find the job node in the XML document.
                XmlNode job = doc.SelectSingleNode("/hpc:Job", nsMgr);

                if (job == null)
                {
                    throw new Exception("No job in the xml file");
                }

                // Find the UnitType attribute for the job.
                XmlAttributeCollection attrCol = job.Attributes;
                XmlAttribute unitTypeAttr = attrCol["UnitType"];
                string unitType = unitTypeAttr.Value;

                // Depending on the unit type, read in the maximum cores, sockets, or nodes specified in the job.
                int numMaxUnits = 0;
                switch (unitType)
                {
                    case "Core":
                        XmlAttribute maxCoreAttr = attrCol["MaxCores"];
                        numMaxUnits = Int32.Parse(maxCoreAttr.Value);
                        break;
                    case "Socket":
                        XmlAttribute maxSocketAttr = attrCol["MaxSockets"];
                        numMaxUnits = Int32.Parse(maxSocketAttr.Value);
                        break;
                    case "Node":
                        XmlAttribute maxNodeAttr = attrCol["MaxNodes"];
                        numMaxUnits = Int32.Parse(maxNodeAttr.Value);
                        break;
                    default:
                        throw new Exception("Invalid UnitType");

                }

                // If the maximum number of units specified is more than 1, then change the job's properties.
                if (numMaxUnits > 1)
                {
                    // Set the job to use the LargeJobTemplate.
                    XmlAttribute templateAttr = attrCol["JobTemplate"];
                    templateAttr.Value = "LargeJobTemplate";


                    // Check if extended terms are already defined.
                    XmlNode extendedTerms = job["ExtendedTerms"];
                    if (extendedTerms == null)
                    {
                        // If extended terms are not defined, add an XML element to the job for extended terms.
                        extendedTerms = doc.CreateElement("ExtendedTerms");
                        job.AppendChild(extendedTerms);
                    }

                    // Create a term to add to the extended terms of this job.
                    XmlNode term = doc.CreateElement("Term");

                    // Create the name value pair for this extended term.
                    // The name/value pair is
                    // <Name> JobClass </Name>
                    // <Value> MultipleUnit</Value>.
                    XmlNode name = doc.CreateElement("Name");
                    name.InnerText = "JobClass";

                    XmlNode value = doc.CreateElement("Value");
                    value.InnerText = "MultipleUnit";

                    // Add the name/value pair to the term.
                    term.AppendChild(name);
                    term.AppendChild(value);

                    // Add the term to the extended terms list.
                    extendedTerms.AppendChild(term);

                    // Save the changed job properties.
                    doc.Save(fileName);

                    // Return a value of 1 to indicate that the values were changed.
                    retval = SuccessJobChanged;

                }
                else
                {

                    // Return a value of 0 to indicate that no job properties were changed.
                    retval = SuccessNoJobChange;
                }
            }
            catch (IOException e)
            {
                logFile.WriteLine("Error Loading the XmlFile");
                logFile.WriteLine(e.ToString());
                retval = FailureParsingXml;
            }
            catch (Exception e)
            {
                logFile.WriteLine("Error Parsing the XmlFile");
                logFile.WriteLine(e.ToString());
                retval = FailureParsingXml;
            }
            finally
            {
                logFile.Close();
            }
            return retval;
        }

        private static int setupLogFile()
        {
            try
            {
                String logFileName = "SubmissionFilter.log";
                logFile = new StreamWriter(logFileName,true);
                return 0;
            }
            catch (Exception )
            {
                return FailureOpeningLogFile;
            }
        }

    }
}

Additional references