Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 42A07200BD1 for ; Mon, 28 Nov 2016 22:16:11 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 417C6160B27; Mon, 28 Nov 2016 21:16:11 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 1BFC7160B22 for ; Mon, 28 Nov 2016 22:16:08 +0100 (CET) Received: (qmail 49017 invoked by uid 500); 28 Nov 2016 21:15:52 -0000 Mailing-List: contact common-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Delivered-To: mailing list common-commits@hadoop.apache.org Received: (qmail 46907 invoked by uid 99); 28 Nov 2016 21:15:51 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Nov 2016 21:15:51 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E0F74E0163; Mon, 28 Nov 2016 21:15:50 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: jianhe@apache.org To: common-commits@hadoop.apache.org Date: Mon, 28 Nov 2016 21:16:19 -0000 Message-Id: In-Reply-To: <3022f5161bb4468c92a2825216e9111f@git.apache.org> References: <3022f5161bb4468c92a2825216e9111f@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [31/63] [abbrv] hadoop git commit: YARN-5461. Initial code ported from slider-core module. (jianhe) archived-at: Mon, 28 Nov 2016 21:16:11 -0000 http://git-wip-us.apache.org/repos/asf/hadoop/blob/a379904d/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. + *

+ * 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 + * minAppState <= currentState <= maxAppState + * + * @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 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/a379904d/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 all 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 runninginstances 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 listInstances(String user) + throws YarnException, IOException { + return listDeployedInstances(user); + } + + /** + * List Slider deployedinstances belonging to a specific user. + *

+ * 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 listDeployedInstances(String user) + throws YarnException, IOException { + Preconditions.checkArgument(user != null, "Null User"); + Set types = new HashSet<>(1); + types.add(SliderKeys.APP_TYPE); + List allApps = getApplications(types); + List 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 findAllInstances(String user, + String appname) + throws IOException, YarnException { + Preconditions.checkArgument(appname != null, "Null application name"); + + List instances = listDeployedInstances(user); + List 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 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 findAllLiveInstances(String user, + String appname) throws + YarnException, + IOException { + Preconditions.checkArgument(StringUtils.isNotEmpty(appname), + "Null/empty application name"); + List instances = listDeployedInstances(user); + List results = + new ArrayList(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 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 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 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/a379904d/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/a379904d/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. + *

+ * 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. + *

+ * If there is no translation, the original exception is returned. + *

+ * 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 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 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/a379904d/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 convertNodeWireToClusterNodes(List nodes) + throws IOException { + List 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. + *

+ * 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 uuidList = innerListNodeUUIDSByRole(role); + String[] uuids = new String[uuidList.size()]; + return uuidList.toArray(uuids); + } + + public List 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 listClusterNodesInRole(String role) + throws IOException, YarnException { + + Collection 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 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 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 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 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 getContainers() throws IOException { + Messages.GetLiveContainersResponseProto response = appMaster + .getLiveContainers(Messages.GetLiveContainersRequestProto.newBuilder() + .build()); + return unmarshall(response); + } + + public Map 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 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/a379904d/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 —with + * exceptions uprated to IOExceptions when needed. + *

+ * 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 type expected + * @return an instance of the type T + * @throws IOException on any failure + */ + public T exec(HttpVerb method, WebResource resource, Class 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 type expected + * @return an instance of the type T + * @throws IOException on any failure + */ + public T exec(HttpVerb method, WebResource resource, GenericType 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 type expected + * @return an instance of the type T + * @throws IOException on any failure + */ + public T get(WebResource resource, Class 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/a379904d/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. + *

+ * + */ +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/a379904d/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 type expected + * @param subpath path + * @param c class to instantiate + * @return instance + * @throws IOException on any problem + */ + public T getApplicationResource(String subpath, Class c) + throws IOException { + return appResourceOperation(HttpVerb.GET, subpath, c); + } + + /** + * Get operation against a path under the Application + * @param type expected + * @param subpath path + * @param t type info + * @return instance + * @throws IOException on any problem + */ + public T getApplicationResource(String subpath, GenericType t) + throws IOException { + return appResourceOperation(HttpVerb.GET, subpath, t); + } + + /** + * + * @param method method to exec + * @param type expected + * @param subpath path + * @param c class to instantiate + * @return instance + * @throws IOException on any problem + */ + public T appResourceOperation(HttpVerb method, String subpath, Class c) + throws IOException { + return exec(method, applicationResource(subpath), c); + } + + + /** + * Get operation against a path under the Application + * @param type expected + * @param subpath path + * @param t type info + * @return instance + * @throws IOException on any problem + */ + public T appResourceOperation(HttpVerb method, String subpath, + GenericType 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 enumContainers() throws + IOException { + return getApplicationResource(LIVE_CONTAINERS, + new GenericType>() { + }); + } + + @Override + public ContainerInformation getContainer(String containerId) throws + IOException { + return getApplicationResource(LIVE_CONTAINERS + "/" + containerId, + ContainerInformation.class); + } + + @Override + public Map enumComponents() throws + IOException { + return getApplicationResource(LIVE_COMPONENTS, + new GenericType>() { }); + } + + @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/a379904d/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