Merge branch 'develop' of https://git-wip-us.apache.org/repos/asf/incubator-slider into develop
diff --git a/app-packages/accumulo/package/files/accumulo-metrics.xml b/app-packages/accumulo/package/files/accumulo-metrics.xml
index 60f9f8d..3b97809 100644
--- a/app-packages/accumulo/package/files/accumulo-metrics.xml
+++ b/app-packages/accumulo/package/files/accumulo-metrics.xml
@@ -33,10 +33,6 @@
     <enabled type="boolean">false</enabled>
     <logging type="boolean">false</logging>
   </master>
-  <logger>
-    <enabled type="boolean">false</enabled>
-    <logging type="boolean">false</logging>
-  </logger>
   <tserver>
     <enabled type="boolean">false</enabled>
     <logging type="boolean">false</logging>
@@ -57,4 +53,8 @@
     <enabled type="boolean">false</enabled>
     <logging type="boolean">false</logging>
   </thrift>
+  <replication>
+    <enabled type="boolean">false</enabled>
+    <logging type="boolean">false</logging>
+  </replication>
 </config>
diff --git a/app-packages/accumulo/package/files/log4j.properties b/app-packages/accumulo/package/files/log4j.properties
index a4bcb2e..f3eaddc 100644
--- a/app-packages/accumulo/package/files/log4j.properties
+++ b/app-packages/accumulo/package/files/log4j.properties
@@ -20,8 +20,9 @@
 # hide Jetty junk
 log4j.logger.org.mortbay.log=WARN,A1
 
-# hide "Got brand-new compresssor" messages
+# hide "Got brand-new compressor" messages
 log4j.logger.org.apache.hadoop.io.compress=WARN,A1
+log4j.logger.org.apache.accumulo.core.file.rfile.bcfile.Compression=WARN,A1
 
 # hide junk from TestRandomDeletes
 log4j.logger.org.apache.accumulo.test.TestRandomDeletes=WARN,A1
diff --git a/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py b/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py
index 3932287..119c926 100644
--- a/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py
+++ b/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py
@@ -22,6 +22,7 @@
 import os
 import json
 import pprint
+import random
 import sys
 import socket
 import posixpath
@@ -33,6 +34,7 @@
 import hostname
 import Constants
 
+MAX_ATTEMPTS = 5
 
 logger = logging.getLogger()
 
@@ -252,13 +254,13 @@
   Its of the form {component_name.ALLOCATED_PORT}[{DEFAULT_default_port}][{PER_CONTAINER}]
   Either a port gets allocated or if not then just set the value to "0"
   """
-
   def finalize_command(self, command, store_command, allocated_ports):
     component = command['componentName']
     allocated_for_this_component_format = "${{{0}.ALLOCATED_PORT}}"
     allocated_for_any = ".ALLOCATED_PORT}"
 
     port_allocation_req = allocated_for_this_component_format.format(component)
+    allowed_ports = self.get_allowed_ports(command)
     if 'configurations' in command:
       for key in command['configurations']:
         if len(command['configurations'][key]) > 0:
@@ -269,7 +271,7 @@
               value = value.replace("${AGENT_LOG_ROOT}",
                                     self.config.getLogPath())
               if port_allocation_req in value:
-                value = self.allocate_ports(value, port_allocation_req)
+                value = self.allocate_ports(value, port_allocation_req, allowed_ports)
                 allocated_ports[key + "." + k] = value
               elif allocated_for_any in value:
                 ## All unallocated ports should be set to 0
@@ -323,7 +325,7 @@
     append {DEFAULT_ and find the default value
     append {PER_CONTAINER} if it exists
   """
-  def allocate_ports(self, value, port_req_pattern):
+  def allocate_ports(self, value, port_req_pattern, allowed_ports=None):
     default_port_pattern = "{DEFAULT_"
     do_not_propagate_pattern = "{PER_CONTAINER}"
     index = value.find(port_req_pattern)
@@ -345,7 +347,7 @@
       if index == value.find(replaced_pattern + do_not_propagate_pattern):
         replaced_pattern = replaced_pattern + do_not_propagate_pattern
         pass
-      port = self.allocate_port(def_port)
+      port = self.allocate_port(def_port, allowed_ports)
       value = value.replace(replaced_pattern, str(port), 1)
       logger.info("Allocated port " + str(port) + " for " + replaced_pattern)
       index = value.find(port_req_pattern)
@@ -354,24 +356,28 @@
     pass
 
 
-  def allocate_port(self, default_port=None):
+  def allocate_port(self, default_port=None, allowed_ports=None):
     if default_port != None:
       if self.is_port_available(default_port):
         return default_port
 
-    MAX_ATTEMPT = 5
-    iter = 0
+    port_list = [0] * MAX_ATTEMPTS
+    if allowed_ports != None:
+      port_list = allowed_ports
+
+    i = 0
     port = -1
-    while iter < MAX_ATTEMPT:
-      iter = iter + 1
+    itor = iter(port_list)
+    while i < min(len(port_list), MAX_ATTEMPTS):
       try:
         sock = socket.socket()
-        sock.bind(('', 0))
+        sock.bind(('', itor.next()))
         port = sock.getsockname()[1]
       except Exception, err:
-        logger.info("Encountered error while trying to opening socket - " + str(err))
+        logger.info("Encountered error while trying to open socket - " + str(err))
       finally:
         sock.close()
+      i = i + 1
       pass
     logger.info("Allocated dynamic port: " + str(port))
     return port
@@ -387,3 +393,43 @@
     return False
 
 
+  def get_allowed_ports(self, command):
+      allowed_ports = None
+      global_config = command['configurations'].get('global')
+      if global_config != None:
+          allowed_ports_value = global_config.get("slider.allowed.ports")
+          if allowed_ports_value:
+              allowed_ports = self.get_allowed_port_list(allowed_ports_value)
+
+      return allowed_ports
+
+
+  def get_allowed_port_list(self, allowedPortsOptionValue,
+                            num_values=MAX_ATTEMPTS):
+    selection = set()
+    invalid = set()
+    # tokens are comma seperated values
+    tokens = [x.strip() for x in allowedPortsOptionValue.split(',')]
+    for i in tokens:
+      try:
+        selection.add(int(i))
+      except:
+        # should be a range
+        try:
+          token = [int(k.strip()) for k in i.split('-')]
+          if len(token) > 1:
+            token.sort()
+            first = token[0]
+            last = token[len(token)-1]
+            for x in range(first, last+1):
+              selection.add(x)
+        except:
+          # not an int and not a range...
+          invalid.add(i)
+    selection = random.sample(selection, min (len(selection), num_values))
+    # Report invalid tokens before returning valid selection
+    logger.info("Allowed port values: " + str(selection))
+    logger.warning("Invalid port range values: " + str(invalid))
+    return selection
+
+
diff --git a/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py b/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py
index 6ada7fa..4f81ea9 100644
--- a/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py
+++ b/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py
@@ -544,6 +544,34 @@
     self.assertFalse(port == -1)
     self.assertTrue(port > 0)
 
+
+  def test_parse_allowed_port_values(self):
+    dummy_controller = MagicMock()
+    tempdir = tempfile.gettempdir()
+    tempWorkDir = tempdir + "W"
+    config = MagicMock()
+    config.get.return_value = "something"
+    config.getResolvedPath.return_value = tempdir
+    config.getWorkRootPath.return_value = tempWorkDir
+    config.getLogPath.return_value = tempdir
+
+    orchestrator = CustomServiceOrchestrator(config, dummy_controller, self.agentToggleLogger)
+    port_range = "48000-48005"
+    port_range_full_list = [48000, 48001, 48002, 48003, 48004, 48005]
+    allowed_ports = orchestrator.get_allowed_port_list(port_range, 3)
+    self.assertTrue(set(allowed_ports).issubset(port_range_full_list))
+
+    port_range = "48000 , 48005"
+    port_range_full_list = [48000, 48005]
+    allowed_ports = orchestrator.get_allowed_port_list(port_range, 1)
+    self.assertTrue(set(allowed_ports).issubset(port_range_full_list))
+
+    port_range = "48000 , 48004-48005"
+    port_range_full_list = [48000, 48004, 48005]
+    allowed_ports = orchestrator.get_allowed_port_list(port_range, 2)
+    self.assertTrue(set(allowed_ports).issubset(port_range_full_list))
+
+
   def tearDown(self):
     # enable stdout
     sys.stdout = sys.__stdout__
diff --git a/slider-assembly/pom.xml b/slider-assembly/pom.xml
index e0a5e8d..d3cb928 100644
--- a/slider-assembly/pom.xml
+++ b/slider-assembly/pom.xml
@@ -38,6 +38,7 @@
     <src.confdir>src/conf-hdp</src.confdir>
     <src.libdir>${project.build.directory}/lib</src.libdir>
     <src.agent.ini.dir>${project.build.directory}/../../slider-agent/conf</src.agent.ini.dir>
+    <skipTests>false</skipTests>
   </properties>
 
   <build>
@@ -63,6 +64,32 @@
           </execution>
         </executions>
       </plugin>
+
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>${maven-exec-plugin.version}</version>
+        <executions>
+          <execution>
+            <configuration>
+              <executable>python</executable>
+              <workingDirectory>src/test/python</workingDirectory>
+              <arguments>
+                <argument>unitTests.py</argument>
+              </arguments>
+              <environmentVariables>
+                <PYTHONPATH>${project.basedir}/src/main/scripts:${project.basedir}/../slider-agent/src/test/python/mock:${project.basedir}/src/test/python/scripts</PYTHONPATH>
+              </environmentVariables>
+              <skip>${skipTests}</skip>
+            </configuration>
+            <id>python-test</id>
+            <phase>test</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
       
       <!-- pull in all dependencies -->
       <plugin>
diff --git a/slider-assembly/src/main/scripts/slider b/slider-assembly/src/main/scripts/slider
index 80b5f32..51ec060 100755
--- a/slider-assembly/src/main/scripts/slider
+++ b/slider-assembly/src/main/scripts/slider
@@ -58,7 +58,7 @@
 slider_confdir_opts="-Dslider.confdir=${confdir}"
 libdir_jvm_opts="-Dslider.libdir=${libdir}"
 
-slider_jvm_opts="-Djava.net.preferIPv4Stack=true -Djava.awt.headless=true ${libdir_jvm_opts} -Xmx256m"
+slider_jvm_opts="-Djava.net.preferIPv4Stack=true -Djava.awt.headless=true -Xmx256m"
 slider_jvm_opts=${SLIDER_JVM_OPTS:-$slider_jvm_opts}
 
 # allow for an extra classpath
@@ -90,4 +90,4 @@
 #echo $javabin
 #type ${javabin}java 2>&1
 
-exec ${javabin}java ${slider_jvm_opts} ${slider_confdir_opts} ${launcher} $@
+exec ${javabin}java ${slider_jvm_opts} ${slider_confdir_opts} ${libdir_jvm_opts} ${launcher} $@
diff --git a/slider-assembly/src/main/scripts/slider.py b/slider-assembly/src/main/scripts/slider.py
index c72fc0d..969f972 100644
--- a/slider-assembly/src/main/scripts/slider.py
+++ b/slider-assembly/src/main/scripts/slider.py
@@ -34,6 +34,7 @@
 
 SLIDER_CLASSNAME = "org.apache.slider.Slider"
 SLIDER_CONFDIR_OPTS ="-Dslider.confdir=%s"
+SLIDER_LIBDIR_OPTS ="-Dslider.libdir=%s"
 DEFAULT_JVM_OPTS = "-Djava.net.preferIPv4Stack=true -Djava.awt.headless=true -Xmx256m"
 
 ON_POSIX = 'posix' in sys.builtin_module_names
@@ -245,12 +246,19 @@
   libdir = dirMustExist(libDir(slider_home))
   confdir = dirMustExist(confDir(slider_home))
   executeEnvSh(confdir)
+
+  #create sys property for conf dirs
   jvm_opts_list = (SLIDER_CONFDIR_OPTS % confdir).split()
+
+  #extend with libdir
+  libdir_jvm_opts = (SLIDER_LIBDIR_OPTS % libdir)
+  jvm_opts_list.extend(libdir_jvm_opts.split())
+
+  #append user specified additional properties
   default_jvm_opts = DEFAULT_JVM_OPTS
-  libdir_jvm_opts = "-Dslider.libdir={0}".format(libdir)
-  default_jvm_opts = "{0} {1}".format(default_jvm_opts, libdir_jvm_opts)
   slider_jvm_opts = os.environ.get(SLIDER_JVM_OPTS, default_jvm_opts)
   jvm_opts_list.extend(slider_jvm_opts.split())
+
   slider_classpath_extra = os.environ.get(SLIDER_CLASSPATH_EXTRA, "")
   hadoop_conf_dir = os.environ.get(HADOOP_CONF_DIR, "")
   p = os.pathsep    # path separator
diff --git a/slider-assembly/src/test/python/scripts/TestSlider.py b/slider-assembly/src/test/python/scripts/TestSlider.py
new file mode 100644
index 0000000..6fe2a47
--- /dev/null
+++ b/slider-assembly/src/test/python/scripts/TestSlider.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+import StringIO
+import sys
+
+from mock import MagicMock, patch, ANY
+import unittest
+import logging
+import slider
+import os
+
+logger = logging.getLogger()
+
+class TestSlider(unittest.TestCase):
+
+  @patch.object(slider, "confDir")
+  @patch.object(slider, "libDir")
+  @patch.object(slider, "executeEnvSh")
+  @patch("os.path.exists")
+  @patch.object(slider, "java")
+  def test_main(self, java_mock, exists_mock, executeEnvSh_mock, libDir_mock, confDir_mock):
+    sys.argv = ["slider", "list"]
+    exists_mock.return_value = True
+    libDir_mock.return_value = "/dir/libdir"
+    confDir_mock.return_value = "/dir/confdir"
+    slider.main()
+    self.assertTrue(java_mock.called)
+    java_mock.assert_called_with(
+      'org.apache.slider.Slider',
+      ['list'],
+      '/dir/libdir/*:/dir/confdir::',
+      ['-Dslider.confdir=/dir/confdir', '-Dslider.libdir=/dir/libdir', '-Djava.net.preferIPv4Stack=true', '-Djava.awt.headless=true', '-Xmx256m'])
+    pass
+
+
+if __name__ == "__main__":
+  logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
+  unittest.main()
\ No newline at end of file
diff --git a/slider-assembly/src/test/python/unitTests.py b/slider-assembly/src/test/python/unitTests.py
new file mode 100644
index 0000000..aebf4ba
--- /dev/null
+++ b/slider-assembly/src/test/python/unitTests.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import unittest
+from os.path import isdir
+import logging
+import os
+import sys
+
+LOG_FILE_NAME='tests.log'
+SELECTED_PREFIX = "_"
+PY_EXT='.py'
+ignoredDirs = ["mock"]
+
+class TestAgent(unittest.TestSuite):
+  def run(self, result, debug=False):
+    run = unittest.TestSuite.run
+    run(self, result, debug)
+    return result
+
+
+def parent_dir(path):
+  if isdir(path):
+    if path.endswith(os.sep):
+      path = os.path.dirname(path)
+    parent = os.path.dirname(path)
+  else:
+    parent = os.path.dirname(os.path.dirname(path))
+
+  return parent
+
+
+def all_tests_suite():
+  root_dir = os.getcwd()
+  files_list = []
+  for directory in os.listdir(root_dir):
+    if os.path.isdir(directory) and not directory in ignoredDirs:
+      files_list += os.listdir(root_dir + os.sep + directory)
+  ## temporarily deleting to add more predictability
+  ## shuffle(files_list)
+  files_list.sort()
+  tests_list = []
+
+  logger.info('------------------------TESTS LIST:-------------------------------------')
+  # If test with special name exists, run only this test
+  selected_test = None
+  for file_name in files_list:
+    if file_name.endswith(PY_EXT) and not file_name == __file__ and file_name.startswith(SELECTED_PREFIX):
+      logger.info("Running only selected test " + str(file_name))
+      selected_test = file_name
+  if selected_test is not None:
+      tests_list.append(selected_test.replace(PY_EXT, ''))
+  else:
+    for file_name in files_list:
+      if file_name.endswith(PY_EXT) and not file_name == __file__:
+        replaced = file_name.replace(PY_EXT, '')
+        logger.info(replaced)
+        tests_list.append(replaced)
+  logger.info('------------------------------------------------------------------------')
+
+  suite = unittest.TestLoader().loadTestsFromNames(tests_list)
+  return TestAgent([suite])
+
+def main():
+
+  logger.info('------------------------------------------------------------------------')
+  logger.info('PYTHON SCRIPT TESTS')
+  logger.info('------------------------------------------------------------------------')
+  runner = unittest.TextTestRunner(verbosity=2, stream=sys.stdout)
+  suite = all_tests_suite()
+  status = runner.run(suite).wasSuccessful()
+
+  if not status:
+    logger.error('-----------------------------------------------------------------------')
+    logger.error('Python unit tests failed')
+    logger.error('Find detailed logs in ' + path)
+    logger.error('-----------------------------------------------------------------------')
+    exit(1)
+  else:
+    logger.info('------------------------------------------------------------------------')
+    logger.info('Python unit tests finished succesfully')
+    logger.info('------------------------------------------------------------------------')
+
+if __name__ == '__main__':
+
+  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
+  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + os.sep + 'main' + os.sep + 'python')
+  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + os.sep + 'main' + os.sep + 'python' + os.sep + 'agent')
+  logger = logging.getLogger()
+  logger.setLevel(logging.INFO)
+  formatter = logging.Formatter("[%(levelname)s] %(message)s")
+  src_dir = os.getcwd()
+  target_dir = parent_dir(parent_dir(parent_dir(src_dir))) + os.sep + 'target'
+  if not os.path.exists(target_dir):
+    os.mkdir(target_dir)
+  path = target_dir + os.sep + LOG_FILE_NAME
+  file=open(path, "w")
+  consoleLog = logging.StreamHandler(file)
+  consoleLog.setFormatter(formatter)
+  logger.addHandler(consoleLog)
+  main()
diff --git a/slider-core/src/main/java/org/apache/slider/common/SliderKeys.java b/slider-core/src/main/java/org/apache/slider/common/SliderKeys.java
index 048dfa7..5f16e56 100644
--- a/slider-core/src/main/java/org/apache/slider/common/SliderKeys.java
+++ b/slider-core/src/main/java/org/apache/slider/common/SliderKeys.java
@@ -189,5 +189,5 @@
   String AM_FILTER_NAME =
       "org.apache.hadoop.yarn.server.webproxy.amfilter.AmFilterInitializer";
 
-  String KEY_AM_ALLOWED_PORT_RANGE = "slider.am.allowed.port.range";
+  String KEY_ALLOWED_PORT_RANGE = "site.global.slider.allowed.ports";
 }
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
index 7a1711f..bb198a1 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
@@ -917,8 +917,8 @@
       throws SliderException {
     int portToRequest = 0;
     String portRange = instanceDefinition.
-        getAppConfOperations().getComponent(SliderKeys.COMPONENT_AM)
-        .getOption(SliderKeys.KEY_AM_ALLOWED_PORT_RANGE , "0");
+        getAppConfOperations().getGlobalOptions().
+          getOption(SliderKeys.KEY_ALLOWED_PORT_RANGE, "0");
     if (!"0".equals(portRange)) {
       if (portScanner == null) {
         portScanner = new PortScanner();
diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentAM.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentAM.groovy
index 60b4dd8..f04583e 100644
--- a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentAM.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneAgentAM.groovy
@@ -20,17 +20,23 @@
 
 import groovy.transform.CompileStatic
 import groovy.util.logging.Slf4j
+import org.apache.hadoop.fs.Path
 import org.apache.hadoop.yarn.api.records.ApplicationId
 import org.apache.hadoop.yarn.api.records.ApplicationReport
 import org.apache.hadoop.yarn.api.records.YarnApplicationState
+import org.apache.hadoop.yarn.exceptions.YarnException
 import org.apache.slider.agent.AgentMiniClusterTestBase
 import org.apache.slider.api.ClusterNode
 import org.apache.slider.client.SliderClient
 import org.apache.slider.common.SliderKeys
 import org.apache.slider.common.params.ActionRegistryArgs
+import org.apache.slider.core.build.InstanceBuilder
+import org.apache.slider.core.conf.AggregateConf
 import org.apache.slider.core.exceptions.SliderException
+import org.apache.slider.core.launch.LaunchedApplication
 import org.apache.slider.core.main.LauncherExitCodes
 import org.apache.slider.core.main.ServiceLauncher
+import org.apache.slider.core.persist.LockAcquireFailedException
 import org.junit.Test
 
 @CompileStatic
@@ -159,8 +165,49 @@
         clustername)
     assert instance3.yarnApplicationState >= YarnApplicationState.FINISHED
 
+    //create another AM, this time with a port range
+    setSliderClientClassName(TestSliderClient.name)
+    try {
+      launcher = createStandaloneAM(clustername, true, true)
+      client = launcher.service
+      i2AppID = client.applicationId
 
+      reportFor = client.getApplicationReport(i2AppID)
+      URI uri = new URI(reportFor.originalTrackingUrl)
+      assert uri.port in [60000, 60001, 60002, 60003]
+      assert reportFor.rpcPort in [60000, 60001, 60002, 60003]
+
+      assert 0 == clusterActionFreeze(client, clustername)
+
+    } finally {
+      setSliderClientClassName(SliderClient.name)
+    }
   }
 
 
+  static class TestSliderClient extends SliderClient {
+    @Override
+    protected void persistInstanceDefinition(boolean overwrite,
+                                             Path appconfdir,
+                                             InstanceBuilder builder)
+    throws IOException, SliderException, LockAcquireFailedException {
+      AggregateConf conf = builder.getInstanceDescription()
+      conf.getAppConfOperations().getGlobalOptions().put(
+          SliderKeys.KEY_ALLOWED_PORT_RANGE,
+          "60000-60003")
+      super.persistInstanceDefinition(overwrite, appconfdir, builder)
+    }
+
+    @Override
+    LaunchedApplication launchApplication(String clustername,
+                                          Path clusterDirectory,
+                                          AggregateConf instanceDefinition,
+                                          boolean debugAM)
+    throws YarnException, IOException {
+      instanceDefinition.getAppConfOperations().getGlobalOptions().put(
+          SliderKeys.KEY_ALLOWED_PORT_RANGE,
+          "60000-60003")
+      return super.launchApplication(clustername, clusterDirectory, instanceDefinition, debugAM)
+    }
+  }
 }
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
index eb5baae..ec999f5 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
@@ -31,8 +31,8 @@
 
 /**
  * SETUP FOR THE TEST
- * Create valid labels, red and blue [yarn rmadmin -addLabels red,blue]
- * Add nodes with label [yarn rmadmin -setNodeToLabels host1:blue]
+ * Create valid labels, red and blue [yarn rmadmin -addToClusterNodeLabels red,blue]
+ * Add nodes with label [yarn rmadmin -replaceLabelsOnNode host1,red,blue]
  * Perform refresh queue [yarn rmadmin -refreshQueues]
  *
  * Create a queue with access to labels - these are changes to capacity scheduler configuration
@@ -45,7 +45,9 @@
  *       yarn.scheduler.capacity.root.labeled.state=RUNNING
  *       yarn.scheduler.capacity.root.labeled.maximum-capacity=80
  *   Have queue access the label
- *       yarn.scheduler.capacity.root.labeled.labels=red,blue
+ *       yarn.scheduler.capacity.root.labeled.accessible-node-labels=red,blue
+ *       yarn.scheduler.capacity.root.labeled.accessible-node-labels.blue.capacity=100
+ *       yarn.scheduler.capacity.root.labeled.accessible-node-labels.red.capacity=100
  *
  * After specifying the new configuration call refresh [yarn rmadmin -refreshQueues]
  *
@@ -98,7 +100,7 @@
             APPLICATION_NAME,
             ARG_COMPONENT,
             COMMAND_LOGGER,
-            "2"])
+            "3"])
 
     // sleep till the new instance starts
     ensureApplicationIsUp(APPLICATION_NAME)