UNPKG

node-deadline

Version:

Module to interface with Deadline Compute Management System by Thinkbox Software

387 lines (318 loc) 10.3 kB
var enums = require( "../utils/enums" ), utils = require( "../utils/utils" ), mongoUtils = require( "../utils/mongo" ), FrameRange = require( "./FrameRange" ), Err = require( "../utils/Error" ), settings = require( "../settings" ), Job = require( "./Job" ); var jobs = module.exports = {}, p, validParams = { status: "status", id: "id", department: "department", user: "user", machine: "machine", group: "group", pool: "pool", secondaryPool:"secondaryPool", eitherPool: "eitherPool", priority: "priority", extraInfo: "extraInfo" }; jobs.Job = Job; jobs.get = function( options, callback ) { jobs.parseQuery( options, function( err, query ) { if ( err ) { callback( err, null ); } //combine with $and if necessary if ( query.length > 1 ) { query = mongoUtils.and( query ); } else if ( query.length == 1 ) { query = query[ 0 ]; } else { query = {}; } //run the query jobs.get.find( query, function( err, results ) { //NOTE can we deal with some errors in here? callback( err, results ); } ); } ); }; jobs.get.find = function( query, callback ) { //do the find for the actual jobs mongoUtils.find( settings.database, "Jobs", query, function( err, res ) { //get the net config so that we can populate extra info names mongoUtils.findOne( settings.database, "DeadlineSettings", { _id: "deadline_network_settings" }, function( err, deadlineNetSet ) { var i; if ( err ) { utils.logError( new Err( Err.EXTERN, "unable to get custom extra info names", err.message ) ); } //if there are results, parse them into Job items if ( res && res.length ) { for ( i in res ) { res[ i ] = new Job( res[ i ], deadlineNetSet ); } } callback( err, res ); } ); } ); }; //build jobs.get.by via the valid params jobs.get.by = {}; function buildByFunction( param ) { return function( data, callback ) { var d = {}; d[ param ] = data; jobs.get( data, callback ); }; } for ( p in validParams ) { jobs.get.by[ p ] = buildByFunction( p ); } jobs.parseQuery = function( options, callback ) { var option, prop, query = [], started = 0, completed = 0; //to log completion and fire on success function complete() { completed++; if ( completed == started ) { callback( null, query ); } } //function to asynchronusly parse an option function parseOption( opt ) { started++; //the asyncronus is forces via a timout of 1ms setTimeout( function() { //set the option query to null var q = null; switch ( opt ) { //state is binary set of enums case "status": q = []; if ( options[ opt ] & enums.UNKNOWN ) { q.push( { Stat: enums.mapJobStateToDeadline( enums.UNKNOWN ) } ); } if ( options[ opt ] & enums.ACTIVE ) { q.push( { Stat: enums.mapJobStateToDeadline( enums.ACTIVE ) } ); } if ( options[ opt ] & enums.SUSPENDED ) { q.push( { Stat: enums.mapJobStateToDeadline( enums.SUSPENDED ) } ); } if ( options[ opt ] & enums.COMPLETED ) { q.push( { Stat: enums.mapJobStateToDeadline( enums.COMPLETED ) } ); } if ( options[ opt ] & enums.FAILED ) { q.push( { Stat: enums.mapJobStateToDeadline( enums.FAILED ) } ); } if ( options[ opt ] & enums.PENDING ) { q.push( { Stat: enums.mapJobStateToDeadline( enums.PENDING ) } ); } if ( q.length == 1 ) { query.push( { Stat: q[ 0 ] } ); break; } else if ( q.length === 0 ) { break; } //add the state list to the query query.push( { $or: q } ); break; //simple single or array case "id": q = utils.parseArrayOption( "_id", options[ opt ] ); query.push( q ); break; //simple single or array case "department": q = utils.parseArrayOption( "Props.Dept", options[ opt ] ); query.push( q ); break; //simple single or array case "user": q = utils.parseArrayOption( "Props.User", options[ opt ] ); query.push( q ); break; //simple single or array case "machine": q = utils.parseArrayOption( "Mach", options[ opt ] ); query.push( q ); break; //simple single or array case "group": q = utils.parseArrayOption( "Props.Grp", options[ opt ] ); query.push( q ); break; //simple single or array case "pool": q = utils.parseArrayOption( "Props.Pool", options[ opt ] ); query.push( q ); break; //simple single or array case "secondaryPool": q = utils.parseArrayOption( "Props.SecPool", options[ opt ] ); query.push( q ); break; //simple single or array, but need to combine multiple parse results case "eitherPool": if ( !Array.isArray( options[ opt ] ) ) { //simply parse them and combine q = [ utils.parseArrayOption( "Props.Pool", options[ opt ] ), utils.parseArrayOption( "Props.SecPool", options[ opt ] ) ]; } else { //parse them but combine the $or arrays and rebuild q = utils.combineArrays( utils.parseArrayOption( "Props.Pool", options[ opt ] ).$or, utils.parseArrayOption( "Props.SecPool", options[ opt ] ).$or ); } q = { $or: q }; query.push( q ); break; //takes single value, array, or frame range object case "priority": //we simply open up a frame range into a flat array if ( options[ opt ] instanceof FrameRange ) { options[ opt ] = options[ opt ].toArray(); } //continue normally q = utils.parseArrayOption( "Props.Pri", options[ opt ] ); query.push( q ); break; case "extraInfo": q = []; //need to get possible custom values from deadline mongoUtils.findOne( settings.database, "DeadlineSettings", { _id: "deadline_network_settings" }, function( err, deadlineNetSet ) { var final = {}, mapped; if ( err ) { callback( new Err( Err.EXTERN, err.message ), null ); return; } //first we convert named properties for ( prop in options[ opt ] ) { //ensure its a valid ex value or mapped value mapped = utils.unmapExtraJobProperty( prop, deadlineNetSet ); if ( null === mapped ) { callback( new Err( Err.PARAM, "Invalid extra property name: " + prop ), null ); } //append it to the finalized object //add new name if not there already if ( "undefined" == typeof final[ mapped ] ) { final[ mapped ] = options[ opt ][ prop ]; } else { //create an array if not one if ( !Array.isArray( final[ mapped ] ) ) { final[ mapped ] = [ final[ mapped ] ]; } //push or concat as necessary if ( Array.isArray( options[ opt ][ prop ] ) ) { final[ mapped ] = final[ mapped ].concat( options[ opt ][ prop ] ); } else { final[ mapped ].push( options[ opt ][ prop ] ); } } } //then we parse the finalized list for ( prop in final ) { //each one is a simple single/array query //combine with previous values q = utils.combineArrays( q, utils.parseArrayOption( "Props." + prop, final[ prop ] ) ); } query.push( { $and: q } ); complete(); return; } ); return; case "updated": if ( "undefined" != typeof options[ opt ].before ) { query.push( { LastWriteTime: { $lt: options[ opt ].before } } ); } if ( "undefined" != typeof options[ opt ].after ) { query.push( { LastWriteTime: { $gt: options[ opt ].after } } ); } break; default: callback( new Err( Err.PARAM, "Unrecognized property type in query: " + opt ), null ); return; } //default compelte call for synchronus code complete(); }, 1 ); }//parseOption //build a query from all of the given options for ( option in options ) { parseOption( option ); } //if the query was empty... if ( started === 0 ) { callback( null, [] ); } }; jobs.set = function( jobs, callback ) { var i, sent = 0, completed = 0, responses = []; if ( jobs instanceof Job ) { jobs = [ jobs ]; } //define the callback function onComplete( err, res ) { if ( err ) { callback( err, null ); return; } //all is well, save the response and mark complete completed++; responses.push( res ); //call callback if all finished if ( completed == sent ) { callback( null, responses ); } } for ( i in jobs ) { try { jobs[ i ]._calcChanges(); } catch ( e ) { callback( e ); } sent++; mongoUtils.update( settings.database, "Jobs", { _id: jobs[ i ].id }, { $set: jobs[ i ]._updated }, onComplete ); } };