You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by ji...@apache.org on 2016/12/07 21:10:31 UTC

[31/76] [abbrv] hadoop git commit: YARN-5461. Initial code ported from slider-core module. (jianhe)

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java
new file mode 100644
index 0000000..30f6ba9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java
@@ -0,0 +1,368 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client;
+
+import org.apache.hadoop.registry.client.api.RegistryOperations;
+import org.apache.hadoop.service.Service;
+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.api.types.NodeInformationList;
+import org.apache.slider.api.types.SliderInstanceDescription;
+import org.apache.slider.common.params.AbstractClusterBuildingActionArgs;
+import org.apache.slider.common.params.ActionAMSuicideArgs;
+import org.apache.slider.common.params.ActionClientArgs;
+import org.apache.slider.common.params.ActionDependencyArgs;
+import org.apache.slider.common.params.ActionDestroyArgs;
+import org.apache.slider.common.params.ActionDiagnosticArgs;
+import org.apache.slider.common.params.ActionEchoArgs;
+import org.apache.slider.common.params.ActionFlexArgs;
+import org.apache.slider.common.params.ActionFreezeArgs;
+import org.apache.slider.common.params.ActionInstallKeytabArgs;
+import org.apache.slider.common.params.ActionInstallPackageArgs;
+import org.apache.slider.common.params.ActionKeytabArgs;
+import org.apache.slider.common.params.ActionNodesArgs;
+import org.apache.slider.common.params.ActionPackageArgs;
+import org.apache.slider.common.params.ActionKillContainerArgs;
+import org.apache.slider.common.params.ActionListArgs;
+import org.apache.slider.common.params.ActionRegistryArgs;
+import org.apache.slider.common.params.ActionResolveArgs;
+import org.apache.slider.common.params.ActionResourceArgs;
+import org.apache.slider.common.params.ActionStatusArgs;
+import org.apache.slider.common.params.ActionThawArgs;
+import org.apache.slider.common.params.ActionUpgradeArgs;
+import org.apache.slider.core.exceptions.BadCommandArgumentsException;
+import org.apache.slider.core.exceptions.SliderException;
+import org.apache.slider.providers.AbstractClientProvider;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Interface of those method calls in the slider API that are intended
+ * for direct public invocation.
+ * <p>
+ * Stability: evolving
+ */
+public interface SliderClientAPI extends Service {
+  /**
+   * Destroy a cluster. There's two race conditions here
+   * #1 the cluster is started between verifying that there are no live
+   * clusters of that name.
+   */
+  int actionDestroy(String clustername, ActionDestroyArgs destroyArgs)
+      throws YarnException, IOException;
+
+  int actionDestroy(String clustername) throws YarnException,
+      IOException;
+
+  /**
+   * AM to commit an asynchronous suicide
+   */
+  int actionAmSuicide(String clustername,
+      ActionAMSuicideArgs args) throws YarnException, IOException;
+
+  /**
+   * Get the provider for this cluster
+   * @param provider the name of the provider
+   * @return the provider instance
+   * @throws SliderException problems building the provider
+   */
+  AbstractClientProvider createClientProvider(String provider)
+    throws SliderException;
+
+  /**
+   * Build up the cluster specification/directory
+   *
+   * @param clustername cluster name
+   * @param buildInfo the arguments needed to build the cluster
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   * @throws BadCommandArgumentsException bad arguments.
+   */
+  int actionBuild(String clustername,
+      AbstractClusterBuildingActionArgs buildInfo) throws YarnException, IOException;
+
+  /**
+   * Upload keytab to a designated sub-directory of the user home directory
+   *
+   * @param installKeytabInfo the arguments needed to upload the keytab
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   * @throws BadCommandArgumentsException bad arguments.
+   * @deprecated use #actionKeytab
+   */
+  int actionInstallKeytab(ActionInstallKeytabArgs installKeytabInfo)
+      throws YarnException, IOException;
+
+  /**
+   * Manage keytabs leveraged by slider
+   *
+   * @param keytabInfo the arguments needed to manage the keytab
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   * @throws BadCommandArgumentsException bad arguments.
+   */
+  int actionKeytab(ActionKeytabArgs keytabInfo)
+      throws YarnException, IOException;
+
+  /**
+   * Upload application package to user home directory
+   *
+   * @param installPkgInfo the arguments needed to upload the package
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   * @throws BadCommandArgumentsException bad arguments.
+   */
+  int actionInstallPkg(ActionInstallPackageArgs installPkgInfo)
+      throws YarnException, IOException;
+
+  /**
+   * Manage file resources leveraged by slider
+   *
+   * @param resourceInfo the arguments needed to manage the resource
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   * @throws BadCommandArgumentsException bad arguments.
+   */
+  int actionResource(ActionResourceArgs resourceInfo)
+      throws YarnException, IOException;
+
+  /**
+   * Perform client operations such as install or configure
+   *
+   * @param clientInfo the arguments needed for client operations
+   *
+   * @throws SliderException bad arguments.
+   * @throws IOException problems related to package and destination folders
+   */
+  int actionClient(ActionClientArgs clientInfo)
+      throws IOException, YarnException;
+
+  /**
+   * Managing slider application package
+   *
+   * @param pkgInfo the arguments needed to upload, delete or list the package
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   * @throws BadCommandArgumentsException bad arguments.
+   */
+  int actionPackage(ActionPackageArgs pkgInfo)
+      throws YarnException, IOException;
+
+  /**
+   * Update the cluster specification
+   *
+   * @param clustername cluster name
+   * @param buildInfo the arguments needed to update the cluster
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   */
+  int actionUpdate(String clustername,
+      AbstractClusterBuildingActionArgs buildInfo)
+      throws YarnException, IOException; 
+
+  /**
+   * Upgrade the cluster with a newer version of the application
+   *
+   * @param clustername cluster name
+   * @param buildInfo the arguments needed to upgrade the cluster
+   * @throws YarnException Yarn problems
+   * @throws IOException other problems
+   */
+  int actionUpgrade(String clustername,
+      ActionUpgradeArgs buildInfo)
+      throws YarnException, IOException; 
+
+  /**
+   * Get the report of a this application
+   * @return the app report or null if it could not be found.
+   * @throws IOException
+   * @throws YarnException
+   */
+  ApplicationReport getApplicationReport()
+      throws IOException, YarnException;
+
+  /**
+   * Kill the submitted application via YARN
+   * @throws YarnException
+   * @throws IOException
+   */
+  boolean forceKillApplication(String reason)
+    throws YarnException, IOException;
+
+  /**
+   * Implement the list action: list all nodes
+   * @return exit code of 0 if a list was created
+   */
+  int actionList(String clustername, ActionListArgs args) throws IOException, YarnException;
+
+  /**
+   * Enumerate slider instances for the current user, and the
+   * most recent app report, where available.
+   * @param listOnlyInState boolean to indicate that the instances should
+   * only include those in a YARN state
+   * <code> minAppState &lt;= currentState &lt;= maxAppState </code>
+   *
+   * @param minAppState minimum application state to include in enumeration.
+   * @param maxAppState maximum application state to include
+   * @return a map of application instance name to description
+   * @throws IOException Any IO problem
+   * @throws YarnException YARN problems
+   */
+  Map<String, SliderInstanceDescription> enumSliderInstances(
+      boolean listOnlyInState,
+      YarnApplicationState minAppState,
+      YarnApplicationState maxAppState)
+      throws IOException, YarnException;
+
+  /**
+   * Implement the islive action: probe for a cluster of the given name existing
+   * @return exit code
+   */
+  int actionFlex(String name, ActionFlexArgs args) throws YarnException, IOException;
+
+  /**
+   * Test for a cluster existing probe for a cluster of the given name existing
+   * in the filesystem. If the live param is set, it must be a live cluster
+   * @return exit code
+   */
+  int actionExists(String name, boolean checkLive) throws YarnException, IOException;
+
+  /**
+   * Kill a specific container of the cluster
+   * @param name cluster name
+   * @param args arguments
+   * @return exit code
+   * @throws YarnException
+   * @throws IOException
+   */
+  int actionKillContainer(String name, ActionKillContainerArgs args)
+      throws YarnException, IOException;
+
+  /**
+   * Echo operation (not currently wired up to command line)
+   * @param name cluster name
+   * @param args arguments
+   * @return the echoed text
+   * @throws YarnException
+   * @throws IOException
+   */
+  String actionEcho(String name, ActionEchoArgs args)
+      throws YarnException, IOException;
+
+  /**
+   * Status operation
+   *
+   * @param clustername cluster name
+   * @param statusArgs status arguments
+   * @return 0 -for success, else an exception is thrown
+   * @throws YarnException
+   * @throws IOException
+   */
+  int actionStatus(String clustername, ActionStatusArgs statusArgs)
+      throws YarnException, IOException;
+
+  /**
+   * Version Details
+   * @return exit code
+   */
+  int actionVersion();
+
+  /**
+   * Stop the cluster
+   *
+   * @param clustername cluster name
+   * @param freezeArgs arguments to the stop
+   * @return EXIT_SUCCESS if the cluster was not running by the end of the operation
+   */
+  int actionFreeze(String clustername, ActionFreezeArgs freezeArgs)
+      throws YarnException, IOException;
+
+  /**
+   * Restore a cluster
+   */
+  int actionThaw(String clustername, ActionThawArgs thaw) throws YarnException, IOException;
+
+  /**
+   * Registry operation
+   *
+   * @param args registry Arguments
+   * @return 0 for success, -1 for some issues that aren't errors, just failures
+   * to retrieve information (e.g. no configurations for that entry)
+   * @throws YarnException YARN problems
+   * @throws IOException Network or other problems
+   */
+  int actionResolve(ActionResolveArgs args)
+      throws YarnException, IOException;
+
+  /**
+   * Registry operation
+   *
+   * @param registryArgs registry Arguments
+   * @return 0 for success, -1 for some issues that aren't errors, just failures
+   * to retrieve information (e.g. no configurations for that entry)
+   * @throws YarnException YARN problems
+   * @throws IOException Network or other problems
+   */
+  int actionRegistry(ActionRegistryArgs registryArgs)
+      throws YarnException, IOException;
+
+  /**
+   * diagnostic operation
+   *
+   * @param diagnosticArgs diagnostic Arguments
+   * @return 0 for success, -1 for some issues that aren't errors, just
+   *         failures to retrieve information (e.g. no application name
+   *         specified)
+   * @throws YarnException YARN problems
+   * @throws IOException Network or other problems
+   */
+  int actionDiagnostic(ActionDiagnosticArgs diagnosticArgs);
+
+  /**
+   * Get the registry binding. As this may start the registry, it can take time
+   * and fail
+   * @return the registry 
+   */
+  RegistryOperations getRegistryOperations()
+      throws SliderException, IOException;
+
+  /**
+   * Upload all Slider AM and agent dependency libraries to HDFS, so that they
+   * do not need to be uploaded with every create call. This operation is
+   * Slider version specific. So it needs to be invoked for every single
+   * version of slider/slider-client.
+   * 
+   * @throws SliderException
+   * @throws IOException
+   */
+  int actionDependency(ActionDependencyArgs dependencyArgs) throws IOException,
+      YarnException;
+
+  /**
+   * List the nodes
+   * @param args
+   * @return
+   * @throws YarnException
+   * @throws IOException
+   */
+  NodeInformationList listYarnClusterNodes(ActionNodesArgs args)
+    throws YarnException, IOException;
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java
new file mode 100644
index 0000000..d471cdb
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/SliderYarnClientImpl.java
@@ -0,0 +1,410 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.yarn.api.ApplicationClientProtocol;
+import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationRequest;
+import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationResponse;
+import org.apache.hadoop.yarn.api.records.ApplicationId;
+import org.apache.hadoop.yarn.api.records.ApplicationReport;
+import org.apache.hadoop.yarn.api.records.NodeReport;
+import org.apache.hadoop.yarn.api.records.NodeState;
+import org.apache.hadoop.yarn.api.records.YarnApplicationState;
+import org.apache.hadoop.yarn.client.api.impl.YarnClientImpl;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.util.ConverterUtils;
+import org.apache.hadoop.yarn.util.Records;
+import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
+import org.apache.slider.common.SliderKeys;
+import org.apache.slider.common.params.ActionNodesArgs;
+import org.apache.slider.common.tools.CoreFileSystem;
+import org.apache.slider.common.tools.Duration;
+import org.apache.slider.common.tools.SliderFileSystem;
+import org.apache.slider.common.tools.SliderUtils;
+import org.apache.slider.core.exceptions.BadCommandArgumentsException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.BindException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class that extends visibility to some of the YarnClientImpl
+ * members and data structures, and factors out pure-YARN operations
+ * from the slider entry point service
+ */
+public class SliderYarnClientImpl extends YarnClientImpl {
+  protected static final Logger log = LoggerFactory.getLogger(SliderYarnClientImpl.class);
+
+  /**
+   * Keyword to use in the {@link #emergencyForceKill(String)}
+   * operation to force kill <i>all</i> application instances belonging
+   * to a specific user
+   */
+  public static final String KILL_ALL = "all";
+
+  @Override
+  protected void serviceInit(Configuration conf) throws Exception {
+    InetSocketAddress clientRpcAddress = SliderUtils.getRmAddress(conf);
+    if (!SliderUtils.isAddressDefined(clientRpcAddress)) {
+      // address isn't known; fail fast
+      throw new BindException("Invalid " + YarnConfiguration.RM_ADDRESS
+          + " value:" + conf.get(YarnConfiguration.RM_ADDRESS)
+          + " - see https://wiki.apache.org/hadoop/UnsetHostnameOrPort");
+    }
+    super.serviceInit(conf);
+  }
+
+  /**
+   * Get the RM Client RPC interface
+   * @return an RPC interface valid after initialization and authentication
+   */
+  public ApplicationClientProtocol getRmClient() {
+    return rmClient;
+  }
+
+  /**
+   * List Slider <i>running</i>instances belonging to a specific user.
+   * @deprecated use {@link #listDeployedInstances(String)}
+   * @param user user: "" means all users
+   * @return a possibly empty list of Slider AMs
+   */
+  public List<ApplicationReport> listInstances(String user)
+    throws YarnException, IOException {
+    return listDeployedInstances(user);
+  }
+
+  /**
+   * List Slider <i>deployed</i>instances belonging to a specific user.
+   * <p>
+   *   Deployed means: known about in the YARN cluster; it will include
+   *   any that are in the failed/finished state, as well as those queued
+   *   for starting.
+   * @param user user: "" means all users
+   * @return a possibly empty list of Slider AMs
+   */
+  public List<ApplicationReport> listDeployedInstances(String user)
+    throws YarnException, IOException {
+    Preconditions.checkArgument(user != null, "Null User");
+    Set<String> types = new HashSet<>(1);
+    types.add(SliderKeys.APP_TYPE);
+    List<ApplicationReport> allApps = getApplications(types);
+    List<ApplicationReport> results = new ArrayList<>();
+    for (ApplicationReport report : allApps) {
+      if (StringUtils.isEmpty(user) || user.equals(report.getUser())) {
+        results.add(report);
+      }
+    }
+    return results;
+  }
+
+  /**
+   * find all instances of a specific app -if there is more than one in the
+   * YARN cluster,
+   * this returns them all
+   * @param user user; use "" for all users
+   * @param appname application name
+   * @return the list of all matching application instances
+   */
+  public List<ApplicationReport> findAllInstances(String user,
+                                                  String appname)
+      throws IOException, YarnException {
+    Preconditions.checkArgument(appname != null, "Null application name");
+
+    List<ApplicationReport> instances = listDeployedInstances(user);
+    List<ApplicationReport> results =
+      new ArrayList<>(instances.size());
+    for (ApplicationReport report : instances) {
+      if (report.getName().equals(appname)) {
+        results.add(report);
+      }
+    }
+    return results;
+  }
+  
+  /**
+   * Helper method to determine if a cluster application is running -or
+   * is earlier in the lifecycle
+   * @param app application report
+   * @return true if the application is considered live
+   */
+  public boolean isApplicationLive(ApplicationReport app) {
+    Preconditions.checkArgument(app != null, "Null app report");
+
+    return app.getYarnApplicationState().ordinal() <= YarnApplicationState.RUNNING.ordinal();
+  }
+
+
+  /**
+   * Kill a running application
+   * @param applicationId app Id
+   * @param reason reason: reason for log
+   * @return the response
+   * @throws YarnException YARN problems
+   * @throws IOException IO problems
+   */
+  public  KillApplicationResponse killRunningApplication(ApplicationId applicationId,
+                                                         String reason)
+      throws YarnException, IOException {
+    Preconditions.checkArgument(applicationId != null, "Null application Id");
+    log.info("Killing application {} - {}", applicationId.getClusterTimestamp(),
+             reason);
+    KillApplicationRequest request =
+      Records.newRecord(KillApplicationRequest.class);
+    request.setApplicationId(applicationId);
+    return getRmClient().forceKillApplication(request);
+  }
+
+  private String getUsername() throws IOException {
+    return UserGroupInformation.getCurrentUser().getShortUserName();
+  }
+  
+  /**
+   * Force kill a yarn application by ID. No niceties here
+   * @param applicationId app Id. "all" means "kill all instances of the current user
+   * 
+   */
+  public void emergencyForceKill(String applicationId)
+      throws YarnException, IOException {
+
+    Preconditions.checkArgument(StringUtils.isNotEmpty(applicationId),
+        "Null/empty application Id");
+
+    if (KILL_ALL.equals(applicationId)) {
+      // user wants all instances killed
+      String user = getUsername();
+      log.info("Killing all applications belonging to {}", user);
+      Collection<ApplicationReport> instances = listDeployedInstances(user);
+      for (ApplicationReport instance : instances) {
+        if (isApplicationLive(instance)) {
+          ApplicationId appId = instance.getApplicationId();
+          log.info("Killing Application {}", appId);
+
+          killRunningApplication(appId, "forced kill");
+        }
+      }
+    } else {
+      ApplicationId appId = ConverterUtils.toApplicationId(applicationId);
+
+      log.info("Killing Application {}", applicationId);
+
+      killRunningApplication(appId, "forced kill");
+    }
+  }
+
+  /**
+   * Monitor the submitted application for reaching the requested state.
+   * Will also report if the app reaches a later state (failed, killed, etc)
+   * Kill application if duration!= null & time expires. 
+   * @param appId Application Id of application to be monitored
+   * @param duration how long to wait -must be more than 0
+   * @param desiredState desired state.
+   * @return the application report -null on a timeout
+   * @throws YarnException
+   * @throws IOException
+   */
+  public ApplicationReport monitorAppToState(
+    ApplicationId appId, YarnApplicationState desiredState, Duration duration)
+    throws YarnException, IOException {
+
+    if (appId == null) {
+      throw new BadCommandArgumentsException("null application ID");
+    }
+    if (duration.limit <= 0) {
+      throw new BadCommandArgumentsException("Invalid monitoring duration");
+    }
+    log.debug("Waiting {} millis for app to reach state {} ",
+              duration.limit,
+              desiredState);
+    duration.start();
+    try {
+      while (true) {
+        // Get application report for the appId we are interested in
+
+        ApplicationReport r = getApplicationReport(appId);
+
+        log.debug("queried status is\n{}",
+          new SliderUtils.OnDemandReportStringifier(r));
+
+        YarnApplicationState state = r.getYarnApplicationState();
+        if (state.ordinal() >= desiredState.ordinal()) {
+          log.debug("App in desired state (or higher) :{}", state);
+          return r;
+        }
+        if (duration.getLimitExceeded()) {
+          log.debug(
+            "Wait limit of {} millis to get to state {}, exceeded; app status\n {}",
+            duration.limit,
+            desiredState,
+            new SliderUtils.OnDemandReportStringifier(r));
+          return null;
+        }
+
+        // sleep 1s.
+        try {
+          Thread.sleep(1000);
+        } catch (InterruptedException ignored) {
+          log.debug("Thread sleep in monitoring loop interrupted");
+        }
+      }
+    } finally {
+      duration.close();
+    }
+  }
+
+  /**
+   * find all live instances of a specific app -if there is >1 in the cluster,
+   * this returns them all. State should be running or less
+   * @param user user
+   * @param appname application name
+   * @return the list of all matching application instances
+   */
+  public List<ApplicationReport> findAllLiveInstances(String user,
+                                                      String appname) throws
+                                                                      YarnException,
+                                                                      IOException {
+    Preconditions.checkArgument(StringUtils.isNotEmpty(appname),
+        "Null/empty application name");
+    List<ApplicationReport> instances = listDeployedInstances(user);
+    List<ApplicationReport> results =
+      new ArrayList<ApplicationReport>(instances.size());
+    for (ApplicationReport app : instances) {
+      if (app.getName().equals(appname)
+          && isApplicationLive(app)) {
+        results.add(app);
+      }
+    }
+    return results;
+  }
+
+  /**
+   * Find a cluster in the instance list; biased towards live instances
+   * @param instances list of instances
+   * @param appname application name
+   * @return the first found instance, else a failed/finished instance, or null
+   * if there are none of those
+   */
+  public ApplicationReport findClusterInInstanceList(List<ApplicationReport> instances,
+                                                     String appname) {
+    Preconditions.checkArgument(instances != null, "Null instances list");
+    Preconditions.checkArgument(StringUtils.isNotEmpty(appname),
+        "Null/empty application name");
+    // sort by most recent
+    SliderUtils.sortApplicationsByMostRecent(instances);
+    ApplicationReport found = null;
+    for (ApplicationReport app : instances) {
+      if (app.getName().equals(appname)) {
+        if (isApplicationLive(app)) {
+          return app;
+        }
+        // set the found value if not set
+        found = found != null ? found : app;
+      }
+    }
+    return found;
+  }
+
+  /**
+   * Find an app in the instance list in the desired state 
+   * @param instances instance list
+   * @param appname application name
+   * @param desiredState yarn state desired
+   * @return the match or null for none
+   */
+  public ApplicationReport findAppInInstanceList(List<ApplicationReport> instances,
+      String appname,
+      YarnApplicationState desiredState) {
+    Preconditions.checkArgument(instances != null, "Null instances list");
+    Preconditions.checkArgument(StringUtils.isNotEmpty(appname),
+        "Null/empty application name");
+    Preconditions.checkArgument(desiredState != null, "Null desiredState");
+    log.debug("Searching {} records for instance name {} in state '{}'",
+        instances.size(), appname, desiredState);
+    for (ApplicationReport app : instances) {
+      if (app.getName().equals(appname)) {
+
+        YarnApplicationState appstate =
+            app.getYarnApplicationState();
+        log.debug("app ID {} is in state {}", app.getApplicationId(), appstate);
+        if (appstate.equals(desiredState)) {
+          log.debug("match");
+          return app;
+        }
+      }
+    }
+    // nothing found in desired state
+    log.debug("No match");
+    return null;
+  }
+
+  /**
+   * List the nodes in the cluster, possibly filtering by node state or label.
+   *
+   * @param label label to filter by -or "" for any
+   * @param live flag to request running nodes only
+   * @return a possibly empty list of nodes in the cluster
+   * @throws IOException IO problems
+   * @throws YarnException YARN problems
+   */
+  public NodeInformationList listNodes(String label, boolean live)
+    throws IOException, YarnException {
+    Preconditions.checkArgument(label != null, "null label");
+    NodeState[] states;
+    if (live) {
+      states = new NodeState[1];
+      states[0] = NodeState.RUNNING;
+    } else {
+      states = new NodeState[0];
+    }
+    List<NodeReport> reports = getNodeReports(states);
+    NodeInformationList results = new NodeInformationList(reports.size());
+    for (NodeReport report : reports) {
+      if (live && report.getNodeState() != NodeState.RUNNING) {
+        continue;
+      }
+      if (!label.isEmpty() && !report.getNodeLabels().contains(label)) {
+        continue;
+      }
+      // build node info from report
+      NodeInformation info = new NodeInformation();
+      info.hostname = report.getNodeId().getHost();
+      info.healthReport  = report.getHealthReport();
+      info.httpAddress = report.getHttpAddress();
+      info.labels = SliderUtils.extractNodeLabel(report);
+      info.rackName = report.getRackName();
+      info.state = report.getNodeState().toString();
+      results.add(info);
+    }
+    return results;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/TokensOperation.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/TokensOperation.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/TokensOperation.java
new file mode 100644
index 0000000..9b9c141
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/TokensOperation.java
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.security.Credentials;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.yarn.client.api.impl.YarnClientImpl;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.slider.common.params.ActionTokensArgs;
+import org.apache.slider.core.exceptions.BadClusterStateException;
+import org.apache.slider.core.exceptions.NotFoundException;
+import static org.apache.slider.core.launch.CredentialUtils.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+
+public class TokensOperation {
+
+  private static final Logger log = LoggerFactory.getLogger(TokensOperation.class);
+  public static final String E_INSECURE
+      = "Cluster is not secure -tokens cannot be acquired";
+  public static final String E_MISSING_SOURCE_FILE = "Missing source file: ";
+  public static final String E_NO_KEYTAB = "No keytab: ";
+
+  public int actionTokens(ActionTokensArgs args, FileSystem fs,
+      Configuration conf,
+      YarnClientImpl yarnClient)
+      throws IOException, YarnException {
+    Credentials credentials;
+    String footnote = "";
+    UserGroupInformation user = UserGroupInformation.getCurrentUser();
+    boolean isSecure = UserGroupInformation.isSecurityEnabled();
+    if (args.keytab != null) {
+      File keytab = args.keytab;
+      if (!keytab.isFile()) {
+        throw new NotFoundException(E_NO_KEYTAB + keytab.getAbsolutePath());
+      }
+      String principal = args.principal;
+      log.info("Logging in as {} from keytab {}", principal, keytab);
+      user = UserGroupInformation.loginUserFromKeytabAndReturnUGI(
+          principal, keytab.getCanonicalPath());
+    }
+    Credentials userCredentials = user.getCredentials();
+    File output = args.output;
+    if (output != null) {
+      if (!isSecure) {
+        throw new BadClusterStateException(E_INSECURE);
+      }
+      credentials = new Credentials(userCredentials);
+      // filesystem
+      addRMRenewableFSDelegationTokens(conf, fs, credentials);
+      addRMDelegationToken(yarnClient, credentials);
+      if (maybeAddTimelineToken(conf, credentials) != null) {
+        log.debug("Added timeline token");
+      }
+      saveTokens(output, credentials);
+      String filename = output.getCanonicalPath();
+      footnote = String.format("%d tokens saved to %s\n" +
+              "To use these in the environment:\n" +
+              "export %s=%s",
+          credentials.numberOfTokens(),
+          filename, UserGroupInformation.HADOOP_TOKEN_FILE_LOCATION, filename);
+    } else if (args.source != null) {
+      File source = args.source;
+      log.info("Reading credentials from file {}", source);
+      if (!source.isFile()) {
+        throw new NotFoundException( E_MISSING_SOURCE_FILE + source.getAbsolutePath());
+      }
+      credentials = Credentials.readTokenStorageFile(args.source, conf);
+    } else {
+      StringBuffer origin = new StringBuffer();
+      File file = locateEnvCredentials(System.getenv(), conf,
+          origin);
+      if (file != null) {
+        log.info("Credential Source {}", origin);
+      } else {
+        log.info("Credential source: logged in user");
+      }
+      credentials = userCredentials;
+    }
+    // list the tokens
+    log.info("\n{}", dumpTokens(credentials, "\n"));
+    if (!footnote.isEmpty()) {
+      log.info(footnote);
+    }
+    return 0;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java
new file mode 100644
index 0000000..a007326
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderApplicationIpcClient.java
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client.ipc;
+
+import com.google.common.base.Preconditions;
+import org.apache.slider.api.SliderClusterProtocol;
+import org.apache.slider.api.types.ApplicationLivenessInformation;
+import org.apache.slider.api.types.ComponentInformation;
+import org.apache.slider.api.types.ContainerInformation;
+import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
+import org.apache.slider.api.types.PingInformation;
+import org.apache.slider.api.SliderApplicationApi;
+import org.apache.slider.core.conf.AggregateConf;
+import org.apache.slider.core.conf.ConfTree;
+import org.apache.slider.core.conf.ConfTreeOperations;
+import org.apache.slider.core.exceptions.NoSuchNodeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Implementation of the Slider RESTy Application API over IPC.
+ * <p>
+ * Operations are executed via the {@link SliderClusterOperations}
+ * instance passed in; raised exceptions may be converted into ones
+ * consistent with the REST API.
+ */
+public class SliderApplicationIpcClient implements SliderApplicationApi {
+
+  private static final Logger log =
+      LoggerFactory.getLogger(SliderApplicationIpcClient.class);
+
+  private final SliderClusterOperations operations;
+
+  public SliderApplicationIpcClient(SliderClusterOperations operations) {
+    Preconditions.checkArgument(operations != null, "null operations");
+    this.operations = operations;
+  }
+
+  /**
+   * Convert received (And potentially unmarshalled) local/remote
+   * exceptions into the equivalents in the REST API.
+   * Best effort. 
+   * <p>
+   * If there is no translation, the original exception is returned.
+   * <p>
+   * If a new exception was created, it will have the message of the 
+   * string value of the original exception, and that original
+   * exception will be the nested cause of this one
+   * @param exception IOException to convert
+   * @return an exception to throw
+   */
+  private IOException convert(IOException exception) {
+    IOException result = exception;
+    if (exception instanceof NoSuchNodeException) {
+      result = new FileNotFoundException(exception.toString());
+      result.initCause(exception);
+    } else {
+      // TODO: remap any other exceptions
+    }
+    return result;
+  }
+  
+  public SliderApplicationIpcClient(SliderClusterProtocol proxy) {
+    this(new SliderClusterOperations(proxy));
+  }
+
+  @Override
+  public AggregateConf getDesiredModel() throws IOException {
+    try {
+      return operations.getModelDesired();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ConfTreeOperations getDesiredAppconf() throws IOException {
+    try {
+      return operations.getModelDesiredAppconf();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ConfTreeOperations getDesiredResources() throws IOException {
+    try {
+      return operations.getModelDesiredResources();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+
+  @Override
+  public void putDesiredResources(ConfTree updated) throws IOException {
+    try {
+      operations.flex(updated);
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  
+  @Override
+  public AggregateConf getResolvedModel() throws IOException {
+    try {
+      return operations.getModelResolved();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ConfTreeOperations getResolvedAppconf() throws IOException {
+    try {
+      return operations.getModelResolvedAppconf();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ConfTreeOperations getResolvedResources() throws IOException {
+    try {
+      return operations.getModelResolvedResources();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ConfTreeOperations getLiveResources() throws IOException {
+    try {
+      return operations.getLiveResources();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public Map<String, ContainerInformation> enumContainers() throws IOException {
+    try {
+      return operations.enumContainers();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ContainerInformation getContainer(String containerId) throws
+      IOException {
+    try {
+      return operations.getContainer(containerId);
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public Map<String, ComponentInformation> enumComponents() throws IOException {
+    try {
+      return operations.enumComponents();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ComponentInformation getComponent(String componentName) throws IOException {
+    try {
+      return operations.getComponent(componentName);
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public NodeInformationList getLiveNodes() throws IOException {
+    try {
+      return operations.getLiveNodes();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public NodeInformation getLiveNode(String hostname) throws IOException {
+    try {
+      return operations.getLiveNode(hostname);
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public PingInformation ping(String text) throws IOException {
+    return null;
+  }
+
+  @Override
+  public void stop(String text) throws IOException {
+    try {
+      operations.stop(text);
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public ApplicationLivenessInformation getApplicationLiveness() throws
+      IOException {
+    try {
+      return operations.getApplicationLiveness();
+    } catch (IOException e) {
+      throw convert(e);
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "IPC implementation of SliderApplicationApi bonded to " + operations;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java
new file mode 100644
index 0000000..392f451
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client.ipc;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import org.apache.hadoop.yarn.api.records.NodeReport;
+import org.apache.hadoop.yarn.api.records.NodeState;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.slider.api.ClusterDescription;
+import org.apache.slider.api.ClusterNode;
+import org.apache.slider.api.SliderClusterProtocol;
+import org.apache.slider.api.StateValues;
+import org.apache.slider.api.proto.Messages;
+
+import static org.apache.slider.api.proto.RestTypeMarshalling.*;
+import org.apache.slider.api.types.ApplicationLivenessInformation;
+import org.apache.slider.api.types.ComponentInformation;
+import org.apache.slider.api.types.ContainerInformation;
+import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
+import org.apache.slider.api.types.PingInformation;
+import org.apache.slider.common.tools.Duration;
+import org.apache.slider.common.tools.SliderUtils;
+import org.apache.slider.core.conf.AggregateConf;
+import org.apache.slider.core.conf.ConfTree;
+import org.apache.slider.core.conf.ConfTreeOperations;
+import org.apache.slider.core.exceptions.NoSuchNodeException;
+import org.apache.slider.core.exceptions.SliderException;
+import org.apache.slider.core.exceptions.WaitTimeoutException;
+import org.apache.slider.core.persist.ConfTreeSerDeser;
+import org.apache.slider.server.services.security.SecurityStore;
+import org.apache.slider.server.services.security.SignCertResponse;
+import org.codehaus.jackson.JsonParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Cluster operations at a slightly higher level than the RPC code
+ */
+public class SliderClusterOperations {
+  protected static final Logger
+    log = LoggerFactory.getLogger(SliderClusterOperations.class);
+  
+  private final SliderClusterProtocol appMaster;
+  private static final Messages.EmptyPayloadProto EMPTY;
+  static {
+    EMPTY = Messages.EmptyPayloadProto.newBuilder().build(); 
+  }
+
+  public SliderClusterOperations(SliderClusterProtocol appMaster) {
+    this.appMaster = appMaster;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb =
+        new StringBuilder("SliderClusterOperations{");
+    sb.append("IPC binding=").append(appMaster);
+    sb.append('}');
+    return sb.toString();
+  }
+
+  /**
+   * Get a node from the AM
+   * @param uuid uuid of node
+   * @return deserialized node
+   * @throws IOException IO problems
+   * @throws NoSuchNodeException if the node isn't found
+   */
+  public ClusterNode getNode(String uuid)
+    throws IOException, NoSuchNodeException, YarnException {
+    Messages.GetNodeRequestProto req =
+      Messages.GetNodeRequestProto.newBuilder().setUuid(uuid).build();
+    Messages.GetNodeResponseProto node = appMaster.getNode(req);
+    return ClusterNode.fromProtobuf(node.getClusterNode());
+  }
+
+  /**
+   * Unmarshall a list of nodes from a protobud response
+   * @param nodes node list
+   * @return possibly empty list of cluster nodes
+   * @throws IOException
+   */
+  public List<ClusterNode> convertNodeWireToClusterNodes(List<Messages.RoleInstanceState> nodes)
+    throws IOException {
+    List<ClusterNode> nodeList = new ArrayList<>(nodes.size());
+    for (Messages.RoleInstanceState node : nodes) {
+      nodeList.add(ClusterNode.fromProtobuf(node));
+    }
+    return nodeList;
+  }
+
+  /**
+   * Echo text (debug action)
+   * @param text text
+   * @return the text, echoed back
+   * @throws YarnException
+   * @throws IOException
+   */
+  public String echo(String text) throws YarnException, IOException {
+    Messages.EchoRequestProto.Builder builder =
+      Messages.EchoRequestProto.newBuilder();
+    builder.setText(text);
+    Messages.EchoRequestProto req = builder.build();
+    Messages.EchoResponseProto response = appMaster.echo(req);
+    return response.getText();
+  }
+
+
+  /**
+   * Connect to a live cluster and get its current state
+   * @return its description
+   */
+  public ClusterDescription getClusterDescription()
+    throws YarnException, IOException {
+    
+    Messages.GetJSONClusterStatusRequestProto req =
+      Messages.GetJSONClusterStatusRequestProto.newBuilder().build();
+    Messages.GetJSONClusterStatusResponseProto resp =
+      appMaster.getJSONClusterStatus(req);
+    String statusJson = resp.getClusterSpec();
+    try {
+      return ClusterDescription.fromJson(statusJson);
+    } catch (JsonParseException e) {
+      log.error("Exception " + e + " parsing:\n" + statusJson, e);
+      throw e;
+    }
+  }
+
+  /**
+   * Get the AM instance definition.
+   * <p>
+   *   See {@link SliderClusterProtocol#getInstanceDefinition(Messages.GetInstanceDefinitionRequestProto)}
+   * @return current slider AM aggregate definition
+   * @throws YarnException
+   * @throws IOException
+   */
+  public AggregateConf getInstanceDefinition()
+    throws YarnException, IOException {
+    Messages.GetInstanceDefinitionRequestProto.Builder builder =
+      Messages.GetInstanceDefinitionRequestProto.newBuilder();
+
+    Messages.GetInstanceDefinitionRequestProto request = builder.build();
+    Messages.GetInstanceDefinitionResponseProto response =
+      appMaster.getInstanceDefinition(request);
+
+    ConfTreeSerDeser confTreeSerDeser = new ConfTreeSerDeser();
+
+    ConfTree internal = confTreeSerDeser.fromJson(response.getInternal());
+    ConfTree resources = confTreeSerDeser.fromJson(response.getResources());
+    ConfTree app = confTreeSerDeser.fromJson(response.getApplication());
+    AggregateConf instanceDefinition =
+      new AggregateConf(resources, app, internal);
+    return instanceDefinition;
+  }
+  /**
+   * Kill a container
+   * @param id container ID
+   * @return a success flag
+   * @throws YarnException
+   * @throws IOException
+   */
+  public boolean killContainer(String id) throws
+                                          YarnException,
+                                          IOException {
+    Messages.KillContainerRequestProto.Builder builder =
+      Messages.KillContainerRequestProto.newBuilder();
+    builder.setId(id);
+    Messages.KillContainerRequestProto req = builder.build();
+    Messages.KillContainerResponseProto response = appMaster.killContainer(req);
+    return response.getSuccess();
+  }
+
+  /**
+   * List all node UUIDs in a role
+   * @param role role name or "" for all
+   * @return an array of UUID strings
+   * @throws IOException
+   * @throws YarnException
+   */
+  public String[] listNodeUUIDsByRole(String role) throws IOException, YarnException {
+    Collection<String> uuidList = innerListNodeUUIDSByRole(role);
+    String[] uuids = new String[uuidList.size()];
+    return uuidList.toArray(uuids);
+  }
+
+  public List<String> innerListNodeUUIDSByRole(String role) throws IOException, YarnException {
+    Messages.ListNodeUUIDsByRoleRequestProto req =
+      Messages.ListNodeUUIDsByRoleRequestProto
+              .newBuilder()
+              .setRole(role)
+              .build();
+    Messages.ListNodeUUIDsByRoleResponseProto resp = appMaster.listNodeUUIDsByRole(req);
+    return resp.getUuidList();
+  }
+
+  /**
+   * List all nodes in a role. This is a double round trip: once to list
+   * the nodes in a role, another to get their details
+   * @param role
+   * @return an array of ContainerNode instances
+   * @throws IOException
+   * @throws YarnException
+   */
+  public List<ClusterNode> listClusterNodesInRole(String role)
+      throws IOException, YarnException {
+
+    Collection<String> uuidList = innerListNodeUUIDSByRole(role);
+    Messages.GetClusterNodesRequestProto req =
+      Messages.GetClusterNodesRequestProto
+              .newBuilder()
+              .addAllUuid(uuidList)
+              .build();
+    Messages.GetClusterNodesResponseProto resp = appMaster.getClusterNodes(req);
+    return convertNodeWireToClusterNodes(resp.getClusterNodeList());
+  }
+
+  /**
+   * Get the details on a list of uuids
+   * @param uuids instance IDs
+   * @return a possibly empty list of node details
+   * @throws IOException
+   * @throws YarnException
+   */
+  @VisibleForTesting
+  public List<ClusterNode> listClusterNodes(String[] uuids)
+      throws IOException, YarnException {
+
+    Messages.GetClusterNodesRequestProto req =
+      Messages.GetClusterNodesRequestProto
+              .newBuilder()
+              .addAllUuid(Arrays.asList(uuids))
+              .build();
+    Messages.GetClusterNodesResponseProto resp = appMaster.getClusterNodes(req);
+    return convertNodeWireToClusterNodes(resp.getClusterNodeList());
+  }
+
+  /**
+   * Wait for an instance of a named role to be live (or past it in the lifecycle)
+   * @param role role to look for
+   * @param timeout time to wait
+   * @return the state. If still in CREATED, the cluster didn't come up
+   * in the time period. If LIVE, all is well. If >LIVE, it has shut for a reason
+   * @throws IOException IO
+   * @throws SliderException Slider
+   * @throws WaitTimeoutException if the wait timed out
+   */
+  @VisibleForTesting
+  public int waitForRoleInstanceLive(String role, long timeout)
+    throws WaitTimeoutException, IOException, YarnException {
+    Duration duration = new Duration(timeout);
+    duration.start();
+    boolean live = false;
+    int state = StateValues.STATE_CREATED;
+
+    log.info("Waiting {} millis for a live node in role {}", timeout, role);
+    try {
+      while (!live) {
+        // see if there is a node in that role yet
+        List<String> uuids = innerListNodeUUIDSByRole(role);
+        String[] containers = uuids.toArray(new String[uuids.size()]);
+        int roleCount = containers.length;
+        ClusterNode roleInstance = null;
+        if (roleCount != 0) {
+  
+          // if there is, get the node
+          roleInstance = getNode(containers[0]);
+          if (roleInstance != null) {
+            state = roleInstance.state;
+            live = state >= StateValues.STATE_LIVE;
+          }
+        }
+        if (!live) {
+          if (duration.getLimitExceeded()) {
+            throw new WaitTimeoutException(
+              String.format("Timeout after %d millis" +
+                            " waiting for a live instance of type %s; " +
+                            "instances found %d %s",
+                            timeout, role, roleCount,
+                            (roleInstance != null
+                             ? (" instance -\n" + roleInstance.toString())
+                             : "")
+                           ));
+          } else {
+            try {
+              Thread.sleep(1000);
+            } catch (InterruptedException ignored) {
+              // ignored
+            }
+          }
+        }
+      }
+    } finally {
+      duration.close();
+    }
+    return state;
+  }
+
+  /**
+   * Flex operation
+   * @param resources new resources
+   * @return the response
+   * @throws IOException
+   */
+  public boolean flex(ConfTree resources) throws IOException {
+    Messages.FlexClusterRequestProto request =
+      Messages.FlexClusterRequestProto.newBuilder()
+              .setClusterSpec(resources.toJson())
+              .build();
+    Messages.FlexClusterResponseProto response = appMaster.flexCluster(request);
+    return response.getResponse();
+  }
+
+
+  /**
+   * Commit (possibly delayed) AM suicide
+   *
+   * @param signal exit code
+   * @param text text text to log
+   * @param delay delay in millis
+   * @throws YarnException
+   * @throws IOException
+   */
+  public void amSuicide(String text, int signal, int delay)
+      throws IOException {
+    Messages.AMSuicideRequestProto.Builder builder =
+      Messages.AMSuicideRequestProto.newBuilder();
+    if (text != null) {
+      builder.setText(text);
+    }
+    builder.setSignal(signal);
+    builder.setDelay(delay);
+    Messages.AMSuicideRequestProto req = builder.build();
+    appMaster.amSuicide(req);
+  }
+
+  /**
+   * Get the application liveness
+   * @return current liveness information
+   * @throws IOException
+   */
+  public ApplicationLivenessInformation getLivenessInformation() throws IOException {
+    Messages.GetApplicationLivenessRequestProto.Builder builder =
+        Messages.GetApplicationLivenessRequestProto.newBuilder();
+    Messages.ApplicationLivenessInformationProto wire =
+        appMaster.getLivenessInformation(builder.build());
+    return unmarshall(wire);
+
+  }
+
+  public AggregateConf getModelDesired() throws IOException {
+    return unmarshallToAggregateConf(appMaster.getModelDesired(EMPTY));
+  }
+
+  
+  public ConfTreeOperations getModelDesiredAppconf() throws IOException {
+    return unmarshallToCTO(appMaster.getModelDesiredAppconf(EMPTY));
+  }
+
+  
+  public ConfTreeOperations getModelDesiredResources() throws IOException {
+    return unmarshallToCTO(appMaster.getModelDesiredResources(EMPTY));
+  }
+
+  
+  public AggregateConf getModelResolved() throws IOException {
+    return unmarshallToAggregateConf(appMaster.getModelResolved(EMPTY));
+  }
+
+  
+  public ConfTreeOperations getModelResolvedAppconf() throws IOException {
+    return unmarshallToCTO(appMaster.getModelResolvedAppconf(EMPTY));
+  }
+
+  
+  public ConfTreeOperations getModelResolvedResources() throws IOException {
+    return unmarshallToCTO(appMaster.getModelDesiredResources(EMPTY));
+  }
+
+  
+  public ConfTreeOperations getLiveResources() throws IOException {
+    return unmarshallToCTO(appMaster.getLiveResources(EMPTY));
+  }
+
+  
+  public Map<String, ContainerInformation> enumContainers() throws IOException {
+    Messages.GetLiveContainersResponseProto response =
+        appMaster.getLiveContainers(
+            Messages.GetLiveContainersRequestProto.newBuilder().build());
+
+    int namesCount = response.getNamesCount();
+    int records = response.getContainersCount();
+    if (namesCount != records) {
+      throw new IOException("Number of names returned (" + namesCount
+                      + ") does not match the number of records returned: " 
+                      + records);
+    }
+    Map<String, ContainerInformation> map = new HashMap<>(namesCount);
+    for (int i = 0; i < namesCount; i++) {
+      map.put(response.getNames(i), unmarshall(response.getContainers(i)));
+    }
+    return map;
+  }
+
+  
+  public ContainerInformation getContainer(String containerId) throws
+      IOException {
+    Messages.ContainerInformationProto response =
+        appMaster.getLiveContainer(
+            Messages.GetLiveContainerRequestProto.newBuilder()
+                                                 .setContainerId(containerId)
+                                                 .build());
+    return unmarshall(response);
+  }
+
+  public List<ContainerInformation> getContainers() throws IOException {
+    Messages.GetLiveContainersResponseProto response = appMaster
+        .getLiveContainers(Messages.GetLiveContainersRequestProto.newBuilder()
+                                                                 .build());
+    return unmarshall(response);
+  }
+
+  public Map<String, ComponentInformation> enumComponents() throws IOException {
+    Messages.GetLiveComponentsResponseProto response =
+        appMaster.getLiveComponents(
+            Messages.GetLiveComponentsRequestProto.newBuilder().build());
+
+    int namesCount = response.getNamesCount();
+    int records = response.getComponentsCount();
+    if (namesCount != records) {
+      throw new IOException(
+          "Number of names returned (" + namesCount + ")" +
+          " does not match the number of records returned: " + records);
+    }
+    Map<String, ComponentInformation> map = new HashMap<>(namesCount);
+    for (int i = 0; i < namesCount; i++) {
+      map.put(response.getNames(i), unmarshall(response.getComponents(i)));
+    }
+    return map;
+  }
+
+  public ComponentInformation getComponent(String componentName)
+      throws IOException {
+    Messages.GetLiveComponentRequestProto.Builder builder =
+        Messages.GetLiveComponentRequestProto.newBuilder();
+    builder.setName(componentName);
+    Messages.ComponentInformationProto proto = appMaster.getLiveComponent(builder.build());
+    return unmarshall(proto);
+  }
+
+  public NodeInformationList getLiveNodes() throws IOException {
+    Messages.GetLiveNodesResponseProto response =
+      appMaster.getLiveNodes(Messages.GetLiveNodesRequestProto.newBuilder().build());
+
+    int records = response.getNodesCount();
+    NodeInformationList nil = new NodeInformationList(records);
+    for (int i = 0; i < records; i++) {
+      nil.add(unmarshall(response.getNodes(i)));
+    }
+    return nil;
+  }
+
+  public NodeInformation getLiveNode(String hostname) throws IOException {
+    Messages.GetLiveNodeRequestProto.Builder builder =
+        Messages.GetLiveNodeRequestProto.newBuilder();
+    builder.setName(hostname);
+    return unmarshall(appMaster.getLiveNode(builder.build()));
+  }
+
+  public PingInformation ping(String text) throws IOException {
+    return null;
+  }
+
+  public void stop(String text) throws IOException {
+    amSuicide(text, 3, 0);
+  }
+
+  public ApplicationLivenessInformation getApplicationLiveness() throws
+      IOException {
+    Messages.ApplicationLivenessInformationProto proto =
+        appMaster.getLivenessInformation(
+            Messages.GetApplicationLivenessRequestProto.newBuilder().build()
+        );
+    return unmarshall(proto);
+  }
+
+  public byte[] getClientCertificateStore(String hostname, String clientId,
+      String password, String type) throws IOException {
+    Messages.GetCertificateStoreRequestProto.Builder
+        builder = Messages.GetCertificateStoreRequestProto.newBuilder();
+    if (hostname != null) {
+      builder.setHostname(hostname);
+    }
+    Messages.GetCertificateStoreRequestProto requestProto =
+        builder.setRequesterId(clientId)
+               .setPassword(password)
+               .setType(type)
+               .build();
+    Messages.GetCertificateStoreResponseProto response =
+        appMaster.getClientCertificateStore(requestProto);
+
+    return unmarshall(response);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/BaseRestClient.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/BaseRestClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/BaseRestClient.java
new file mode 100644
index 0000000..d936a22
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/BaseRestClient.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client.rest;
+
+import com.google.common.base.Preconditions;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.GenericType;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.WebResource;
+import org.apache.slider.core.exceptions.ExceptionConverter;
+import org.apache.slider.core.restclient.HttpVerb;
+import org.apache.slider.core.restclient.UgiJerseyBinding;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.net.URI;
+
+
+/**
+ * This is a base class for Jersey REST clients in Slider.
+ * It supports the execution of operations \u2014with
+ * exceptions uprated to IOExceptions when needed.
+ * <p>
+ * Subclasses can use these operations to provide an API-like view
+ * of the REST model
+ */
+public class BaseRestClient  {
+  private static final Logger log =
+      LoggerFactory.getLogger(BaseRestClient.class);
+  private final Client client;
+
+  public BaseRestClient(
+      Client client) {
+    Preconditions.checkNotNull(client, "null jersey client");
+    this.client = client;
+  }
+
+  /**
+   * Get the jersey client
+   * @return jersey client
+   */
+  public Client getClient() {
+    return client;
+  }
+
+  /**
+   * Execute the operation. Failures are raised as IOException subclasses
+   * @param method method to execute
+   * @param resource resource to work against
+   * @param c class to build
+   * @param <T> type expected
+   * @return an instance of the type T
+   * @throws IOException on any failure
+   */
+  public <T> T exec(HttpVerb method, WebResource resource, Class<T> c)
+      throws IOException {
+    try {
+      Preconditions.checkArgument(c != null);
+      log.debug("{}} {}", method, resource.getURI());
+      return resource.accept(MediaType.APPLICATION_JSON_TYPE)
+              .method(method.getVerb(), c);
+    } catch (ClientHandlerException ex) {
+      throw ExceptionConverter.convertJerseyException(method.getVerb(),
+          resource.getURI().toString(),
+          ex);
+    } catch (UniformInterfaceException ex) {
+      throw UgiJerseyBinding.uprateFaults(method,
+          resource.getURI().toString(),
+          ex);
+    }
+  }
+
+  /**
+   * Execute the operation. Failures are raised as IOException subclasses
+   * @param method method to execute
+   * @param resource resource to work against
+   * @param t type to work with
+   * @param <T> type expected
+   * @return an instance of the type T
+   * @throws IOException on any failure
+   */
+  public <T> T exec(HttpVerb method, WebResource resource, GenericType<T> t)
+      throws IOException {
+    try {
+      Preconditions.checkArgument(t != null);
+      log.debug("{}} {}", method, resource.getURI());
+      resource.accept(MediaType.APPLICATION_JSON_TYPE);
+      return resource.method(method.getVerb(), t);
+    } catch (ClientHandlerException ex) {
+      throw ExceptionConverter.convertJerseyException(method.getVerb(),
+          resource.getURI().toString(),
+          ex);
+    } catch (UniformInterfaceException ex) {
+      throw UgiJerseyBinding.uprateFaults(method, resource.getURI().toString(),
+          ex);
+    }
+  }
+
+
+  /**
+   * Execute the  GET operation. Failures are raised as IOException subclasses
+   * @param resource resource to work against
+   * @param c class to build
+   * @param <T> type expected
+   * @return an instance of the type T
+   * @throws IOException on any failure
+   */
+  public <T> T get(WebResource resource, Class<T> c) throws IOException {
+    return exec(HttpVerb.GET, resource, c);
+  }
+
+  /**
+   * Create a Web resource from the client.
+   *
+   * @param u the URI of the resource.
+   * @return the Web resource.
+   */
+  public WebResource resource(URI u) {
+    return client.resource(u);
+  }
+
+  /**
+   * Create a Web resource from the client.
+   *
+   * @param u the URI of the resource.
+   * @return the Web resource.
+   */
+
+  public WebResource resource(String url) {
+    return client.resource(url);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/RestClientFactory.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/RestClientFactory.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/RestClientFactory.java
new file mode 100644
index 0000000..4286596
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/RestClientFactory.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client.rest;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.WebResource;
+import org.apache.hadoop.registry.client.api.RegistryOperations;
+import org.apache.slider.client.ClientRegistryBinder;
+import org.apache.slider.api.SliderApplicationApi;
+import org.apache.slider.core.registry.info.CustomRegistryConstants;
+
+import java.io.IOException;
+
+import static org.apache.slider.server.appmaster.web.rest.RestPaths.SLIDER_PATH_APPLICATION;
+
+/**
+ * Factory for the Rest client; hides the lookup and instantiation.
+ * <p>
+ * 
+ */
+public class RestClientFactory {
+
+  private final ClientRegistryBinder binder;
+  private final Client jerseyClient;
+  private final String user, serviceclass, instance;
+
+  public RestClientFactory(RegistryOperations operations,
+      Client jerseyClient,
+      String user,
+      String serviceclass,
+      String instance) {
+    this.jerseyClient = jerseyClient;
+    this.user = user;
+    this.serviceclass = serviceclass;
+    this.instance = instance;
+    binder = new ClientRegistryBinder(operations);
+  }
+
+  /**
+   * Locate the AM
+   * @return a resource to the AM
+   * @throws IOException any failure to resolve to the AM
+   */
+  private WebResource locateAppmaster() throws IOException {
+    String restAPI = binder.lookupExternalRestAPI(user, serviceclass, instance,
+        CustomRegistryConstants.AM_REST_BASE);
+    return jerseyClient.resource(restAPI);
+  }
+
+  /**
+   * Locate the slider AM then instantiate a client instance against
+   * its Application API.
+   * @return the instance
+   * @throws IOException on any failure
+   */
+  public SliderApplicationApi createSliderAppApiClient() throws IOException {
+    WebResource appmaster = locateAppmaster();
+    return createSliderAppApiClient(appmaster);
+  }
+
+   /**
+   * Create a Slider application API client instance against
+   * its Application API.
+   * @param appmaster The AM to work against.
+   * @return the instance
+   * @throws IOException on any failure
+   */
+  public SliderApplicationApi createSliderAppApiClient(WebResource appmaster) {
+    WebResource appResource = appmaster.path(SLIDER_PATH_APPLICATION);
+    return new SliderApplicationApiRestClient(jerseyClient, appResource);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java
new file mode 100644
index 0000000..4283ee8
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/client/rest/SliderApplicationApiRestClient.java
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.client.rest;
+
+import com.google.common.base.Preconditions;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.GenericType;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.representation.Form;
+import org.apache.commons.lang.StringUtils;
+import org.apache.slider.api.types.ApplicationLivenessInformation;
+import org.apache.slider.api.types.ComponentInformation;
+import org.apache.slider.api.types.ContainerInformation;
+import org.apache.slider.api.SliderApplicationApi;
+import org.apache.slider.api.types.NodeInformation;
+import org.apache.slider.api.types.NodeInformationList;
+import org.apache.slider.core.conf.AggregateConf;
+import org.apache.slider.core.conf.ConfTree;
+import org.apache.slider.core.conf.ConfTreeOperations;
+import org.apache.slider.core.exceptions.ExceptionConverter;
+import org.apache.slider.core.restclient.HttpVerb;
+import org.apache.slider.api.types.PingInformation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.util.Map;
+
+import static org.apache.slider.server.appmaster.web.rest.RestPaths.*;
+
+/**
+ * Implementation of the {@link SliderApplicationApi}
+ */
+public class SliderApplicationApiRestClient extends BaseRestClient
+      implements SliderApplicationApi {
+  private static final Logger log =
+      LoggerFactory.getLogger(SliderApplicationApiRestClient.class);
+  private WebResource appResource;
+
+  /**
+   * Create an instance
+   * @param jerseyClient jersey client for operations
+   * @param appResource resource of application API
+   */
+  public SliderApplicationApiRestClient(Client jerseyClient,
+      WebResource appResource) {
+    super(jerseyClient);
+    this.appResource = appResource;
+  }
+
+  /**
+   * Create an instance
+   * @param jerseyClient jersey client for operations
+   * @param appmaster URL of appmaster/proxy to AM
+   */
+  public SliderApplicationApiRestClient(Client jerseyClient, String appmaster) {
+    super(jerseyClient);
+    WebResource amResource = jerseyClient.resource(appmaster);
+    amResource.type(MediaType.APPLICATION_JSON);
+    this.appResource = amResource.path(SLIDER_PATH_APPLICATION);
+  }
+
+
+  @Override
+  public String toString() {
+    final StringBuilder sb =
+        new StringBuilder("SliderApplicationApiRestClient{");
+    sb.append("appResource=").append(appResource);
+    sb.append('}');
+    return sb.toString();
+  }
+
+  /**
+   * Create a resource under the application path
+   * @param subpath path under application
+   * @return a resource under the application path
+   */
+  public WebResource applicationResource(String subpath) {
+    Preconditions.checkArgument(!StringUtils.isEmpty(subpath),
+        "empty path");
+    Preconditions.checkNotNull(appResource, "Null app resource");
+    return appResource.path(subpath);
+  }
+  
+  /**
+   * Get operation against a path under the Application
+   * @param <T> type expected
+   * @param subpath path
+   * @param c class to instantiate
+   * @return instance
+   * @throws IOException on any problem
+   */
+  public <T> T getApplicationResource(String subpath, Class<T> c)
+      throws IOException {
+    return appResourceOperation(HttpVerb.GET, subpath, c);
+  } 
+  
+  /**
+   * Get operation against a path under the Application
+   * @param <T> type expected
+   * @param subpath path
+   * @param t type info
+   * @return instance
+   * @throws IOException on any problem
+   */
+  public <T> T getApplicationResource(String subpath, GenericType<T> t)
+      throws IOException {
+    return appResourceOperation(HttpVerb.GET, subpath, t);
+  }
+
+  /**
+   * 
+   * @param method method to exec
+   * @param <T> type expected
+   * @param subpath path
+   * @param c class to instantiate
+   * @return instance
+   * @throws IOException on any problem
+   */
+  public <T> T appResourceOperation(HttpVerb method, String subpath, Class<T> c)
+      throws IOException {
+    return exec(method, applicationResource(subpath), c);
+  }
+  
+  
+  /**
+   * Get operation against a path under the Application
+   * @param <T> type expected
+   * @param subpath path
+   * @param t type info
+   * @return instance
+   * @throws IOException on any problem
+   */
+  public <T> T appResourceOperation(HttpVerb method, String subpath,
+      GenericType<T> t)
+      throws IOException {
+    return exec(method, applicationResource(subpath), t);
+  }
+
+
+  @Override
+  public AggregateConf getDesiredModel() throws IOException {
+    return getApplicationResource(MODEL_DESIRED, AggregateConf.class);
+  }
+  
+  @Override
+  public ConfTreeOperations getDesiredAppconf() throws IOException {
+    ConfTree resource =
+        getApplicationResource(MODEL_DESIRED_APPCONF, ConfTree.class);
+    return new ConfTreeOperations(resource); 
+  }
+
+  @Override
+  public ConfTreeOperations getDesiredResources() throws IOException {
+    ConfTree resource =
+        getApplicationResource(MODEL_DESIRED_RESOURCES, ConfTree.class);
+    return new ConfTreeOperations(resource); 
+  }
+
+  @Override
+  public void putDesiredResources(ConfTree updated) throws IOException {
+    WebResource resource = applicationResource(MODEL_DESIRED_RESOURCES);
+    try {
+
+      // put operation. The result is discarded; it does help validate
+      // that the operation returned a JSON data structure as well as a 200
+      // response.
+
+      resource.accept(MediaType.APPLICATION_JSON_TYPE)
+              .type(MediaType.APPLICATION_JSON_TYPE)
+              .entity(updated)
+              .put(ConfTree.class);
+    } catch (ClientHandlerException ex) {
+        throw ExceptionConverter.convertJerseyException("PUT",
+            resource.getURI().toString(),
+            ex);
+      } catch (UniformInterfaceException ex) {
+      throw ExceptionConverter.convertJerseyException("PUT",
+          resource.getURI().toString(), ex);
+      }
+  }
+
+  @Override
+  public AggregateConf getResolvedModel() throws IOException {
+    return getApplicationResource(MODEL_RESOLVED, AggregateConf.class);
+  }
+
+
+  @Override
+  public ConfTreeOperations getResolvedAppconf() throws IOException {
+    ConfTree resource =
+        getApplicationResource(MODEL_RESOLVED_APPCONF, ConfTree.class);
+    return new ConfTreeOperations(resource); 
+  }
+
+  @Override
+  public ConfTreeOperations getResolvedResources() throws IOException {
+    ConfTree resource =
+        getApplicationResource(MODEL_RESOLVED_RESOURCES, ConfTree.class);
+    return new ConfTreeOperations(resource); 
+  }
+
+  @Override
+  public ConfTreeOperations getLiveResources() throws IOException {
+    ConfTree resource =
+        getApplicationResource(LIVE_RESOURCES, ConfTree.class);
+    return new ConfTreeOperations(resource); 
+  }
+
+  @Override
+  public Map<String, ContainerInformation> enumContainers() throws
+      IOException {
+    return getApplicationResource(LIVE_CONTAINERS,
+        new GenericType<Map<String, ContainerInformation>>() {
+        });
+  }
+
+  @Override
+  public ContainerInformation getContainer(String containerId) throws
+      IOException {
+    return getApplicationResource(LIVE_CONTAINERS + "/" + containerId,
+        ContainerInformation.class);
+  }
+
+  @Override
+  public Map<String, ComponentInformation> enumComponents() throws
+      IOException {
+    return getApplicationResource(LIVE_COMPONENTS,
+        new GenericType<Map<String, ComponentInformation>>() { });
+  }
+
+  @Override
+  public ComponentInformation getComponent(String componentName) throws
+      IOException {
+    return getApplicationResource(LIVE_COMPONENTS + "/" + componentName,
+        ComponentInformation.class);
+  }
+
+  @Override
+  public NodeInformationList getLiveNodes() throws IOException {
+    return getApplicationResource(LIVE_NODES, NodeInformationList.class);
+  }
+
+  @Override
+  public NodeInformation getLiveNode(String hostname) throws IOException {
+    return getApplicationResource(LIVE_NODES + "/" + hostname,
+        NodeInformation.class);
+  }
+
+  @Override
+  public PingInformation ping(String text) throws IOException {
+    return pingPost(text);
+  }
+  
+  /**
+   * Ping as a GET
+   * @param text text to include
+   * @return the response
+   * @throws IOException on any failure
+   */
+  public PingInformation pingGet(String text) throws IOException {
+    WebResource pingResource = applicationResource(ACTION_PING);
+    pingResource.getUriBuilder().queryParam("body", text);
+    return pingResource.get(PingInformation.class);
+  }
+  
+  /**
+   * Ping as a POST
+   * @param text text to include
+   * @return the response
+   * @throws IOException on any failure
+   */
+  public PingInformation pingPost(String text) throws IOException {
+    WebResource pingResource = applicationResource(ACTION_PING);
+    Form f = new Form();
+    f.add("text", text);
+    return pingResource
+        .type(MediaType.APPLICATION_JSON_TYPE)
+        .post(PingInformation.class, f);
+  }
+  
+  /**
+   * Ping as a POST
+   * @param text text to include
+   * @return the response
+   * @throws IOException on any failure
+   */
+  public PingInformation pingPut(String text) throws IOException {
+    WebResource pingResource = applicationResource(ACTION_PING);
+    Form f = new Form();
+    return pingResource
+        .type(MediaType.TEXT_PLAIN)
+        .put(PingInformation.class, text);
+  }
+
+  @Override
+  public void stop(String text) throws IOException {
+    WebResource resource = applicationResource(ACTION_STOP);
+    resource.post(text);
+  }
+
+  @Override
+  public ApplicationLivenessInformation getApplicationLiveness() throws IOException {
+    return getApplicationResource(LIVE_LIVENESS,
+        ApplicationLivenessInformation.class);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/d8cab88d/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/common/Constants.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/common/Constants.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/common/Constants.java
new file mode 100644
index 0000000..0e3559a
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-slider/hadoop-yarn-slider-core/src/main/java/org/apache/slider/common/Constants.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package org.apache.slider.common;
+
+public class Constants {
+  public static final int CONNECT_TIMEOUT = 10000;
+  public static final int RPC_TIMEOUT = 15000;
+
+  public static final String HADOOP_JAAS_DEBUG = "HADOOP_JAAS_DEBUG";
+  public static final String KRB5_CCNAME = "KRB5CCNAME";
+  public static final String JAVA_SECURITY_KRB5_CONF
+    = "java.security.krb5.conf";
+  public static final String JAVA_SECURITY_KRB5_REALM
+    = "java.security.krb5.realm";
+  public static final String SUN_SECURITY_KRB5_DEBUG
+    = "sun.security.krb5.debug";
+  public static final String SUN_SECURITY_SPNEGO_DEBUG
+    = "sun.security.spnego.debug";
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org