UIMA-6161 DUCC facilitate specification of machine list for user submitted work

git-svn-id: https://svn.apache.org/repos/asf/uima/uima-ducc/trunk@1871862 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/scripts/viaducc b/src/main/scripts/viaducc
index 71ec2c0..9b3f573 100755
--- a/src/main/scripts/viaducc
+++ b/src/main/scripts/viaducc
@@ -37,6 +37,7 @@
 global ducc_home
 
 ducc_class = 'fixed'
+ducc_mach_list = None
 java_cmd   = None
 ducc_home  = None       # tbd in a minute
 ducc_mem_size = None
@@ -70,6 +71,10 @@
     print "   -DDUCC_CLASS=ducc-scheduling-class"
     print "       The default is -DDUCC_CLASS=" + ducc_class
     print ""
+    print "   -DDUCC_MACHINE_LIST=list-of-machine-names"
+    print "       The default is no machine names.  The machine list string should be"
+    print '       blank-delimeted and quoted, for example: -DDUCC_MACHINE_LIST="machine01 machine02 machine03"'
+    print ""
     print "   -DDUCC_ENVIRONMENT=environment-settings"
     print "       The default is no additional environment.  The environment string should be"
     print '       blank-delimeted and quoted, for example: -DDUCC_ENVIRONMENT="A=B C=D"'
@@ -209,6 +214,7 @@
         usage()
 
     ducc_class = 'fixed'
+    ducc_mach_list = None
     java_cmd   = None
     ducc_env   = ''
     enable_attach = False
@@ -217,6 +223,7 @@
     # remember to add the '=' at the end if following value
     p_mem_size  = '-DDUCC_MEMORY_SIZE='
     p_class     = '-DDUCC_CLASS='
+    p_mach_list = '-DDUCC_MACHINE_LIST='
     p_jvm_dir   = '-DJAVA_BIN='
     p_ducc_home = '-DDUCC_HOME='
     p_env       = '-DDUCC_ENVIRONMENT='
@@ -245,6 +252,9 @@
         elif (arg.startswith(p_class) ):
             ducc_class = arg[len(p_class):]
 
+        elif (arg.startswith(p_mach_list) ):
+            ducc_mach_list = '"'+arg[len(p_mach_list):]+'"'
+            
         elif (arg.startswith(p_jvm_dir) ):
             java_cmd = arg[len(p_jvm_dir):] + '/java'
 
@@ -302,6 +312,9 @@
     CMD = CMD +       ' --wait_for_completion'
     CMD = CMD +       ' --process_memory_size ' + str(ducc_mem_size)
     CMD = CMD +       ' --scheduling_class ' + ducc_class
+    
+    if(ducc_mach_list != None):
+    	CMD = CMD +       ' --machine_list ' + ducc_mach_list
 
     if ducc_desc_set:
         CMD = CMD +       ' --description %r' % ducc_desc
diff --git a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java
index 527fd7d..e4c4761 100644
--- a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java
+++ b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java
@@ -57,6 +57,7 @@
 
         UiOption.Description,
         UiOption.SchedulingClass,
+        UiOption.MachineList,
 
         UiOption.WorkingDirectory,   // Must precede LogDirecory
         UiOption.LogDirectory,       // Must precede Environment
diff --git a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java
index de281fc..b85e7ce 100644
--- a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java
+++ b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java
@@ -52,6 +52,7 @@
         UiOption.ProcessExecutableArgs,
         UiOption.ProcessMemorySize,
         UiOption.SchedulingClass,
+        UiOption.MachineList,
         UiOption.Specification,
         UiOption.SuppressConsoleLog,
         UiOption.Timestamp,
diff --git a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccReservationSubmit.java b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccReservationSubmit.java
index b70d3df..a1bfc7f 100644
--- a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccReservationSubmit.java
+++ b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccReservationSubmit.java
@@ -79,6 +79,7 @@
 
         UiOption.Description,
         UiOption.SchedulingClass,
+        UiOption.MachineList,
         UiOption.Specification,
         UiOption.ReservationMemorySize,
         UiOption.Timestamp,
diff --git a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java
index d500c97..428b3bd 100644
--- a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java
+++ b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java
@@ -60,6 +60,7 @@
         UiOption.Description,
         UiOption.Administrators,
         UiOption.SchedulingClass,
+        UiOption.MachineList,
         UiOption.WorkingDirectory,   // Must precede LogDirecory
         UiOption.LogDirectory,       // Must precede Environment
         UiOption.Jvm,
diff --git a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java
index f3946da..3578899 100644
--- a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java
+++ b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java
@@ -49,6 +49,7 @@
         UiOption.Administrators,      // ( not used directly here, but is allowed in registration )
 
         UiOption.SchedulingClass,
+        UiOption.MachineList,
         UiOption.WorkingDirectory,   // Must precede LogDirecory
         UiOption.LogDirectory,       // Must precede Environment
         UiOption.Jvm,
diff --git a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/IUiOptions.java b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/IUiOptions.java
index 7aea499..c04d940 100644
--- a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/IUiOptions.java
+++ b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/IUiOptions.java
@@ -211,6 +211,13 @@
             public boolean required()   { return true; }
         },
         
+        MachineList { 
+            public String pname()       { return JobSpecificationProperties.key_machine_list; }
+            public String argname()     { return "list of machines"; }
+            public String description() { return "Blank separated list of one or more machines to use from the associated scheduling class.  If this option is not specified, then any machines associated with the scheduling class are eligible."; }
+            public String example()     { return "machine01 machine02 machine03"; }
+        }, 
+        
         ManagedReservationId { 
             public String pname()       { return JobRequestProperties.key_id; }
             public String argname()     { return "string"; }
diff --git a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/aio/AllInOneLauncher.java b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/aio/AllInOneLauncher.java
index 122dae4..c7c0835 100644
--- a/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/aio/AllInOneLauncher.java
+++ b/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/aio/AllInOneLauncher.java
@@ -81,6 +81,7 @@
     private String description = null;
     
     private String scheduling_class = null;
+    private String machine_list = null;
     
     private String specification = null;
     
@@ -385,6 +386,26 @@
         mh.frameworkTrace(cid, mid, exit);
     }
     
+    private void examine_machine_list() throws Exception {
+        String mid = "examine_machine_list";
+        mh.frameworkTrace(cid, mid, enter);
+        String pname = UiOption.MachineList.pname();
+        if (jobRequestProperties.containsKey(pname)) {
+          try {
+            machine_list = jobRequestProperties.getProperty(pname);
+            String message = pname + "=" + machine_list + " [original]";
+            if (isLocal()) {
+                message = pname + "=" + machine_list + " not considered";
+                mh.debug(cid, mid, message);
+            }
+            used(pname);
+          } catch (Exception e) {
+              throw new IllegalConfigurationException("Error in DUCC configuration files - see administrator", e);
+          }
+        }
+        mh.frameworkTrace(cid, mid, exit);
+    }
+    
     private void examine_signature() {
         String mid = "examine_signature";
         mh.frameworkTrace(cid, mid, enter);
@@ -663,6 +684,9 @@
         // scheduling_class
         examine_scheduling_class();
         
+        // machine_list
+        examine_machine_list();
+        
         // wait_for_completion & cancel
         examine_wait_for_completion();
         examine_cancel_on_interrupt();
diff --git a/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/ReservationFactory.java b/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/ReservationFactory.java
index ef9a336..7b8114e 100644
--- a/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/ReservationFactory.java
+++ b/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/ReservationFactory.java
@@ -61,6 +61,7 @@
 		DuccSchedulingInfo schedulingInfo = new DuccSchedulingInfo();
 		duccWorkReservation.setSchedulingInfo(schedulingInfo);
 		schedulingInfo.setSchedulingClass(reservationRequestProperties.getProperty(ReservationSpecificationProperties.key_scheduling_class));
+		schedulingInfo.setMachineList(reservationRequestProperties.getProperty(ReservationSpecificationProperties.key_machine_list));
 		String memorySize = reservationRequestProperties.getProperty(ReservationSpecificationProperties.key_memory_size);
 		MemorySpecification memorySpecification = new MemorySpecification(memorySize);
 		schedulingInfo.setMemorySizeRequested(memorySpecification.getSize());
diff --git a/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/factory/JobFactory.java b/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/factory/JobFactory.java
index ffd0c0c..fc3baa7 100644
--- a/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/factory/JobFactory.java
+++ b/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/factory/JobFactory.java
@@ -515,6 +515,7 @@
 			schedulingInfo.setMemorySizeRequested(""+jpGB);
 		}
 		schedulingInfo.setSchedulingClass(jobRequestProperties.getProperty(JobSpecificationProperties.key_scheduling_class));
+		schedulingInfo.setMachineList(jobRequestProperties.getProperty(JobSpecificationProperties.key_machine_list));
 		schedulingInfo.setSchedulingPriority(jobRequestProperties.getProperty(JobSpecificationProperties.key_scheduling_priority));
 		schedulingInfo.setProcessesMax(jobRequestProperties.getProperty(JobSpecificationProperties.key_process_deployments_max));
 		schedulingInfo.setProcessesMin(jobRequestProperties.getProperty(JobSpecificationProperties.key_process_deployments_min));
diff --git a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/JobManagerConverter.java b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/JobManagerConverter.java
index ca00591..8181f9b 100644
--- a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/JobManagerConverter.java
+++ b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/JobManagerConverter.java
@@ -22,6 +22,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.uima.ducc.common.Node;
@@ -567,6 +568,15 @@
         j.setUserPriority(user_priority);
         j.setNQuestions(total_work, remaining_work, 0.0);
         j.setClassName(className);
+        
+        List<String> machineList = si.getMachineList();
+        j.setMachineList(machineList);
+        if(machineList != null) {
+        	if(!machineList.isEmpty()) {
+        		String message = "machine list: "+String.join(" ", machineList);
+        		logger.info(methodName, job.getDuccId(), message);
+        	}
+        }
 
         switch (si.getMemoryUnits()) {
             case GB:
diff --git a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/IRmJob.java b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/IRmJob.java
index be87e97..86405e4 100644
--- a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/IRmJob.java
+++ b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/IRmJob.java
@@ -19,6 +19,7 @@
 package org.apache.uima.ducc.rm.scheduler;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.uima.ducc.common.persistence.rm.IDbJob;
@@ -202,6 +203,13 @@
      * non-zero.  This is an extreme corner case it's best to be safe.
      */
     public int countNShares();
+    
+    /**
+     * Number of eligible machines subject to user machine list
+     */
+    public int getEligibleMachinesCount();
+    public void setEligibleMachinesCount(int value);
+    public void incEligibleMachinesCount();
 
     /**
      * Can't schedudle this nohow.  Here's why.
@@ -251,6 +259,9 @@
 
     // public String getClassName();         UIMA 4577 IDbJob
     public void   setClassName(String n);
+    
+    public void setMachineList(List<String> ms);
+    public List<String> getMachineList();
 
     public int getSchedulingPriority();
 
diff --git a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodePool.java b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodePool.java
index 1914ac8..461f7c9 100644
--- a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodePool.java
+++ b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodePool.java
@@ -1382,6 +1382,38 @@
         return np.doVaryOn(node);         // must pass to the right nodepool, can't do it "here"
     }
 
+    /*
+     * limit eligible machines to those in the user specified --machines_list
+     */
+    boolean isCompatible(Machine m, IRmJob j)
+    {
+    	String methodName = "isCompatible";
+    	boolean retVal = true;
+    	try {
+    		List<String> mlist = j.getMachineList();
+        	if(!mlist.isEmpty()) {
+        		retVal = false;
+        		NodeIdentity ni = m.getNodeIdentity();
+        		String lname = ni.getCanonicalName();
+        		String sname = ni.getShortName();
+        		for(String mname : mlist) {
+        			if(mname.equals(lname)) {
+        				retVal = true;
+        				break;
+        			}
+        			if(mname.equals(sname)) {
+        				retVal = true;
+        				break;
+        			}
+        		}
+        	}
+    	}
+    	catch(Exception e) {
+    		logger.error(methodName, j.getId(), e);
+    	}
+    	return retVal;
+    }
+    
     boolean isSchedulable(Machine m)
     {
         if ( m.isBlacklisted() )                         return false;
@@ -1513,6 +1545,10 @@
         while ( iter.hasNext() && (given < needed) ) {
             Machine m = iter.next();
             logger.info(methodName, j.getId(), "Examining", m.getId());
+            if ( !isCompatible(m,j) ) {
+                logger.info(methodName, j.getId(), "Bypass because machine", m.getId(), "is not in user machine list");
+                continue;
+            }
             if ( !isSchedulable(m) ) {
               logger.info(methodName, j.getId(), "Bypass because machine", m.getId(), "is offline or unresponsive or blacklisted");
               continue;
@@ -1699,7 +1735,7 @@
         //machs = sortedForReservation(machinesByOrder.get(order));
 
         for ( Machine mm : machinesByOrder.get(order).values() ) {
-            if ( isSchedulable(mm) && mm.isFree() ) {
+            if ( isCompatible(mm,job) && isSchedulable(mm) && mm.isFree() ) {
                 Share s = new Share(mm, job, mm.getShareOrder());
                 s.setFixed();
                 connectShare(s, mm, job, mm.getShareOrder());
@@ -1916,6 +1952,8 @@
 
         logger.debug(methodName, j.getId(), "counted", counted, "current", current, "needed", needed, "order", order, "given", given);
 
+        j.setEligibleMachinesCount(0);
+        
         if ( needed > 0 ) {
             whatof: {
                 for ( int i = order; i < getArraySize(); i++ ) {
@@ -1928,6 +1966,8 @@
                     ml.addAll(machs.values());
 
                     for ( Machine m : ml ) {                                // look for space
+                    	if ( !isCompatible(m,j) ) continue;                 // nope
+                    	j.incEligibleMachinesCount();
                         if ( !isSchedulable(m) ) continue;                  // nope
                         if ( (!allowVertical) && (m.hasVerticalConflict(j)) ) continue;  // UIMA-4712
                         int g = Math.min(needed, m.countFreeShares(order)); // adjust by the order supported on the machine
@@ -2011,7 +2051,14 @@
             } else {
                 sb.append("notfound ");
             }
-            if ( j.countNShares() == 0 ) j.setReason("Waiting for preemptions.");
+            if ( j.countNShares() == 0 ) {
+            	j.setReason("Waiting for preemptions.");
+            	if(j.getEligibleMachinesCount() == 0) {
+            		if(j.getMachineList().size() > 0) {
+            			j.setReason("No machines match user specified list.");
+            		}
+            	}
+            }
         }
         logger.info(methodName, null, sb.toString());
         return expansions;
diff --git a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodepoolScheduler.java b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodepoolScheduler.java
index 84839db..1715d67 100644
--- a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodepoolScheduler.java
+++ b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/NodepoolScheduler.java
@@ -1464,7 +1464,14 @@
                 // or defrag.
                 //
                 if ( j.countNShares() == 0 ) {
-                    j.setReason("Waiting for preemptions.");
+                	if ( j.countNShares() == 0 ) {
+                        j.setReason("Waiting for preemptions.");
+                        if(j.getEligibleMachinesCount() == 0) {
+                        	if(j.getMachineList().size() > 0) {
+                        		j.setReason("No machines match user specified list.");
+                        	}
+                        }
+                    }
                 }                
             }
         }
@@ -1644,7 +1651,14 @@
                 // fully allocated. Nothing more to do here.
                 //
                 if ( j.countNShares() == 0 ) {
-                    j.setReason("Waiting for preemptions.");
+                	if ( j.countNShares() == 0 ) {
+                        j.setReason("Waiting for preemptions.");
+                        if(j.getEligibleMachinesCount() == 0) {
+                        	if(j.getMachineList().size() > 0) {
+                        		j.setReason("No machines match user specified list.");
+                        	}
+                        }
+                    }
                 }
             }
         }
diff --git a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/RmJob.java b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/RmJob.java
index 62a0832..b258c6f 100644
--- a/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/RmJob.java
+++ b/uima-ducc-rm/src/main/java/org/apache/uima/ducc/rm/scheduler/RmJob.java
@@ -50,6 +50,7 @@
     protected String name;                            // user's name for job
     protected String resource_class_name;             // Name of the res class, from incoming job parms
     protected ResourceClass resource_class;           // The actual class, assigned as job is received in scheduler.
+    protected List<String> resource_machine_list;     // List of eligible machine (if any), from incoming job parms
     protected int    user_priority;                   // user "priority", really apportionment 
 
     // @deprecated
@@ -95,6 +96,8 @@
     Map<Machine, Map<Share, Share>> sharesByMachine = new HashMap<Machine, Map<Share, Share>>();
     Map<Machine, Machine> machineList = new HashMap<Machine, Machine>();
 
+    private int eligibleMachinesCount;                   // during scheduling, how many machines were in users machine set
+    
     // protected int shares_given;                       // during scheduling, how many N-shares we get
     int[] given_by_order;                                // during scheduling, how many N-shares we get
     int[] wanted_by_order;                               // during scheduling, how many N-shares we we want - volatile, changes during countJobsByOrder
@@ -916,6 +919,16 @@
         return assignedShares.size() + pendingShares.size() - pendingRemoves.size();
     }
 
+    public int getEligibleMachinesCount() {
+    	return eligibleMachinesCount;
+    }
+    public void setEligibleMachinesCount(int value) {
+    	eligibleMachinesCount = value;
+    }
+    public void incEligibleMachinesCount() {
+    	eligibleMachinesCount += 1;
+    }
+    
     public void refuse(String refusal)
     {
         String methodName = "refuse";
@@ -1235,6 +1248,14 @@
         this.resource_class_name = class_name;
     }
 
+    public List<String> getMachineList() {
+        return resource_machine_list;
+    }
+
+    public void setMachineList(List<String> machine_list) {
+        this.resource_machine_list = machine_list;
+    }
+    
     public int getSchedulingPriority() {
         return resource_class.getPriority();
     }
diff --git a/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java b/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java
index 1b68bef..a50524f 100644
--- a/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java
+++ b/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java
@@ -43,6 +43,7 @@
 	
 	public static String key_description = "description";
 	
+	public static String key_machine_list = "machine_list";
 	public static String key_scheduling_class = "scheduling_class";
 	
 	public static String key_specification = "specification";
diff --git a/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/DuccSchedulingInfo.java b/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/DuccSchedulingInfo.java
index 1855040..529e338 100644
--- a/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/DuccSchedulingInfo.java
+++ b/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/DuccSchedulingInfo.java
@@ -18,6 +18,8 @@
 */
 package org.apache.uima.ducc.transport.event.common;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.uima.ducc.common.jd.files.perf.PerformanceMetricsSummaryMap;
@@ -34,6 +36,7 @@
 	 */
 	private static final long serialVersionUID = 1L;
 	private String schedulingClass = defaultSchedulingClass;
+	private List<String> machineList = defaultMachineList;
 	private String schedulingPriority = defaultSchedulingPriority;
 	@Deprecated
 	private String shareMemorySize = defaultMemorySize;
@@ -82,6 +85,25 @@
 	}
 
 	
+	public List<String> getMachineList() {
+		return machineList;
+	}
+
+	
+	public void setMachineList(List<String> machineList) {
+		if(machineList != null) {
+			this.machineList = machineList;
+		}
+	}
+	public void setMachineList(String string) {
+		if(string != null) {
+			String[] array = string.trim().split("\\s+");
+			if(array.length > 0) {
+				setMachineList(Arrays.asList(array));
+			}
+		}
+	}
+	
 	public String getSchedulingPriority() {
 		return schedulingPriority;
 	}
diff --git a/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/IDuccSchedulingInfo.java b/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/IDuccSchedulingInfo.java
index 293a06c..ffc9dbe 100644
--- a/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/IDuccSchedulingInfo.java
+++ b/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/common/IDuccSchedulingInfo.java
@@ -19,6 +19,8 @@
 package org.apache.uima.ducc.transport.event.common;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.uima.ducc.common.jd.files.perf.PerformanceMetricsSummaryMap;
@@ -29,6 +31,7 @@
 public interface IDuccSchedulingInfo extends Serializable {
 	
 	public static final String defaultSchedulingClass = "normal";
+	public static final List<String> defaultMachineList = new ArrayList<String>();
 	public static final String defaultSchedulingPriority = "0";
 	public static final String defaultMemorySize = "1";
 	public static final MemoryUnits defaultMemoryUnits = MemoryUnits.GB;
@@ -58,6 +61,9 @@
 	public String getSchedulingClass();
 	public void setSchedulingClass(String schedulingClass);
 	
+	public List<String> getMachineList();
+	public void setMachineList(List<String> machineList);
+	
 	public String getSchedulingPriority();
 	public void setSchedulingPriority(String schedulingPriority);