SLIDER-5 CLI to list and fetch configurations - work in progress
git-svn-id: https://svn.apache.org/repos/asf/incubator/slider/trunk@1592520 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/slider-core/pom.xml b/slider-core/pom.xml
index d0e881d..ca39be6 100644
--- a/slider-core/pom.xml
+++ b/slider-core/pom.xml
@@ -573,7 +573,6 @@
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
- <version>${jersey.version}</version>
</dependency>
<dependency>
diff --git a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
index b89077a..054fc66 100644
--- a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
+++ b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
@@ -84,7 +84,10 @@
import org.apache.slider.core.persist.ConfPersister;
import org.apache.slider.core.persist.LockAcquireFailedException;
import org.apache.slider.core.registry.YARNRegistryClient;
+import org.apache.slider.core.registry.docstore.PublishedConfigSet;
+import org.apache.slider.core.registry.docstore.PublishedConfiguration;
import org.apache.slider.core.registry.info.ServiceInstanceData;
+import org.apache.slider.core.registry.retrieve.RegistryRetriever;
import org.apache.slider.core.registry.zk.ZKPathBuilder;
import org.apache.slider.providers.AbstractClientProvider;
import org.apache.slider.providers.SliderProviderFactory;
@@ -94,7 +97,7 @@
import org.apache.slider.server.appmaster.rpc.RpcBinder;
import org.apache.slider.server.services.curator.CuratorServiceInstance;
import org.apache.slider.server.services.curator.RegistryBinderService;
-import org.apache.slider.server.services.docstore.utility.AbstractSliderLaunchedService;
+import org.apache.slider.server.services.utility.AbstractSliderLaunchedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -105,7 +108,6 @@
import java.io.StringWriter;
import java.io.Writer;
import java.net.InetSocketAddress;
-import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -117,9 +119,7 @@
*/
public class SliderClient extends AbstractSliderLaunchedService implements RunService,
- SliderExitCodes,
- SliderKeys,
- ErrorStrings {
+ SliderExitCodes, SliderKeys, ErrorStrings {
private static final Logger log = LoggerFactory.getLogger(SliderClient.class);
private ClientArgs serviceArgs;
@@ -1939,41 +1939,128 @@
/**
- * Status operation
+ * Registry operation
*
* @param registryArgs registry Arguments
- * @throws YarnException
- * @throws IOException
+ * @throws YarnException YARN problems
+ * @throws IOException Network or other problems
*/
@VisibleForTesting
public int actionRegistry(ActionRegistryArgs registryArgs) throws
YarnException,
IOException {
- maybeStartRegistry();
- List<CuratorServiceInstance<ServiceInstanceData>> instances =
- registry.listInstances(SliderKeys.APP_TYPE);
-
- for (CuratorServiceInstance<ServiceInstanceData> instance : instances) {
- log.info("{} at http://{}:{}/", instance.id, instance.address,
- instance.port);
+ // as this is also a test entry point, validate
+ // the arguments
+ registryArgs.validate();
+ int exitCode = EXIT_SUCCESS;
+ if (registryArgs.list) {
+ actionRegistryList(registryArgs);
+ } else if (registryArgs.listConf) {
+ // list the configurations
+ actionRegistryListConfigs(registryArgs);
+ } else {
+ exitCode = EXIT_FALSE;
}
- return EXIT_SUCCESS;
+ return exitCode;
}
/**
- * List names in the registry
- * @return
- * @throws IOException
- * @throws YarnException
+ * Registry operation
+ *
+ * @param registryArgs registry Arguments
+ * @throws YarnException YARN problems
+ * @throws IOException Network or other problems
*/
- public Collection<String> listRegistryNames() throws IOException, YarnException {
- Collection<String> names;
- verifyBindingsDefined();
+ private void actionRegistryList(ActionRegistryArgs registryArgs)
+ throws YarnException, IOException {
+ List<CuratorServiceInstance<ServiceInstanceData>> instances =
+ getRegistry().listInstances(registryArgs.serviceType);
- return getRegistry().queryForNames();
+ for (CuratorServiceInstance<ServiceInstanceData> instance : instances) {
+ if (!registryArgs.verbose) {
+ log.info("{}", instance.id);
+ } else {
+ log.info("{} ", instance);
+ }
+ }
}
/**
+ * Registry operation
+ *
+ * @param registryArgs registry Arguments
+ * @throws YarnException YARN problems
+ * @throws IOException Network or other problems
+ */
+ public void actionRegistryListConfigs(ActionRegistryArgs registryArgs)
+ throws YarnException, IOException {
+ ServiceInstanceData instance = lookupInstance(registryArgs);
+
+ RegistryRetriever retriever = new RegistryRetriever(instance);
+ PublishedConfigSet configurations =
+ retriever.getConfigurations(!registryArgs.internal);
+
+ for (String configName : configurations.keys()) {
+ if (!registryArgs.verbose) {
+ log.info("{}", configName);
+ } else {
+ PublishedConfiguration published =
+ configurations.get(configName);
+ log.info("{} : {}",
+ configName,
+ published.description);
+ }
+ }
+ }
+
+
+ /**
+ * Look up an instance
+ * @param id instance ID
+ * @param serviceType service type
+ * @return instance data
+ * @throws UnknownApplicationInstanceException no match
+ * @throws SliderException other failures
+ * @throws IOException IO problems or wrapped exceptions
+ */
+ private ServiceInstanceData lookupInstance(ActionRegistryArgs registryArgs) throws
+ UnknownApplicationInstanceException,
+ SliderException,
+ IOException {
+ return lookupInstance(registryArgs.name, registryArgs.serviceType);
+ }
+
+ /**
+ * Look up an instance
+ * @param id instance ID
+ * @param serviceType service type
+ * @return instance data
+ * @throws UnknownApplicationInstanceException no match
+ * @throws SliderException other failures
+ * @throws IOException IO problems or wrapped exceptions
+ */
+ private ServiceInstanceData lookupInstance(String id,
+ String serviceType) throws
+ UnknownApplicationInstanceException,
+ SliderException,
+ IOException {
+ try {
+ CuratorServiceInstance<ServiceInstanceData> csi =
+ getRegistry().queryForInstance(serviceType, id);
+ if (csi == null) {
+ throw new UnknownApplicationInstanceException(
+ "instance %s of type %s not found",
+ id, serviceType);
+ }
+ return csi.getPayload();
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }
+
+ /**
* List instances in the registry
* @return
* @throws IOException
diff --git a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
index 44fecea..1cec75e 100644
--- a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
+++ b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java
@@ -48,6 +48,7 @@
String ARG_HELP = "--help";
String ARG_ID = "--id";
String ARG_IMAGE = "--image";
+ String ARG_INTERNAL = "--internal";
String ARG_LIST = "--list";
String ARG_LISTFILES = "--listfiles";
String ARG_LISTCONF = "--listconf";
@@ -57,7 +58,7 @@
String ARG_MESSAGE = "--message";
String ARG_OPTION = "--option";
String ARG_OPTION_SHORT = "-O";
- // String ARG_NAME = "--name";
+ String ARG_NAME = "--name";
String ARG_OUTPUT = "--out";
String ARG_OUTPUT_SHORT = "-o";
String ARG_PACKAGE = "--package";
@@ -68,8 +69,10 @@
String ARG_RESOURCE_MANAGER = "--rm";
String ARG_RESOURCE_OPT = "--resopt";
String ARG_RESOURCE_OPT_SHORT = "-ro";
+ String ARG_SERVICETYPE = "--servictype";
String ARG_SYSPROP = "-S";
String ARG_TEMPLATE = "--template";
+ String ARG_VERBOSE = "--verbose";
String ARG_WAIT = "--wait";
String ARG_ZKPATH = "--zkpath";
String ARG_ZKPORT = "--zkport";
diff --git a/slider-core/src/main/java/org/apache/slider/core/exceptions/ExceptionConverter.java b/slider-core/src/main/java/org/apache/slider/core/exceptions/ExceptionConverter.java
new file mode 100644
index 0000000..98dc028
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/core/exceptions/ExceptionConverter.java
@@ -0,0 +1,55 @@
+/*
+ * 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.core.exceptions;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * static methods to convert exceptions into different types, including
+ * extraction of details and finer-grained conversions.
+ */
+public class ExceptionConverter {
+
+ /**
+ * Convert a Jersey Exception into an IOE or subclass
+ * @param targetURL URL being targeted
+ * @param exception original exception
+ * @return a new exception, the original one nested as a cause
+ */
+ public static IOException convertJerseyException(String targetURL,
+ UniformInterfaceException exception) {
+
+ ClientResponse response = exception.getResponse();
+ if (response != null) {
+ int status = response.getStatus();
+ if (status >= 400 && status < 500) {
+ FileNotFoundException fnfe =
+ new FileNotFoundException(targetURL);
+ fnfe.initCause(exception);
+ return fnfe;
+ }
+ }
+
+ return new IOException("Failed to GET " + targetURL + ": " + exception, exception);
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java b/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java
new file mode 100644
index 0000000..1202cb8
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/core/registry/retrieve/RegistryRetriever.java
@@ -0,0 +1,108 @@
+/*
+ * 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.core.registry.retrieve;
+
+import com.beust.jcommander.Strings;
+import com.sun.jersey.api.client.Client;
+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.registry.docstore.PublishedConfigSet;
+import org.apache.slider.core.registry.info.RegistryView;
+import org.apache.slider.core.registry.info.ServiceInstanceData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.MediaType;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * Registry retriever.
+ * This hides the HTTP operations that take place to
+ * get the actual content
+ */
+public class RegistryRetriever {
+ private static final Logger log = LoggerFactory.getLogger(RegistryRetriever.class);
+
+ private final ServiceInstanceData instance;
+ private static final Client jerseyClient;
+
+ static {
+ jerseyClient = Client.create();
+ jerseyClient.setFollowRedirects(true);
+ }
+
+
+ public RegistryRetriever(ServiceInstanceData instance) {
+ this.instance = instance;
+ }
+
+ /**
+ * Get the appropriate view for the flag
+ * @param external
+ * @return
+ */
+ private RegistryView getRegistryView(boolean external) {
+ return external ? instance.externalView : instance.internalView;
+ }
+
+ private String destination(boolean external) {
+ return external ? "external" : "internal";
+ }
+
+ /**
+ * Does a bonded registry retriever have a configuration?
+ * @param external flag to indicate that it is the external entries to fetch
+ * @return true if there is a URL to the configurations defined
+ */
+ public boolean hasConfigurations(boolean external) {
+ String confURL = getRegistryView(external).configurationsURL;
+ return !Strings.isStringEmpty(confURL);
+ }
+
+ /**
+ * Get the configurations of the registry
+ * @param external flag to indicate that it is the external entries to fetch
+ * @return the configuration sets
+ */
+ public PublishedConfigSet getConfigurations(boolean external) throws
+ FileNotFoundException, IOException {
+
+ String confURL = getRegistryView(external).configurationsURL;
+ if (Strings.isStringEmpty(confURL)) {
+ throw new FileNotFoundException("No configuration URL at "
+ + destination(external) + " view");
+ }
+ WebResource webResource = jerseyClient.resource(confURL);
+ try {
+ PublishedConfigSet configSet =
+ webResource.type(MediaType.APPLICATION_JSON)
+ .get(PublishedConfigSet.class);
+ return configSet;
+ } catch (UniformInterfaceException e) {
+ throw ExceptionConverter.convertJerseyException(confURL, e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " - " + instance;
+ }
+}
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
index 7b4ed06..5eaa618 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
@@ -111,10 +111,10 @@
import org.apache.slider.server.services.curator.RegistryBinderService;
import org.apache.slider.server.services.curator.RegistryConsts;
import org.apache.slider.server.services.curator.RegistryNaming;
-import org.apache.slider.server.services.docstore.utility.AbstractSliderLaunchedService;
-import org.apache.slider.server.services.docstore.utility.EventCallback;
-import org.apache.slider.server.services.docstore.utility.RpcService;
-import org.apache.slider.server.services.docstore.utility.WebAppService;
+import org.apache.slider.server.services.utility.AbstractSliderLaunchedService;
+import org.apache.slider.server.services.utility.EventCallback;
+import org.apache.slider.server.services.utility.RpcService;
+import org.apache.slider.server.services.utility.WebAppService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneRegistryAM.groovy b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneRegistryAM.groovy
index 7a4500a..0069e73 100644
--- a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneRegistryAM.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneRegistryAM.groovy
@@ -26,11 +26,13 @@
import org.apache.slider.api.ClusterNode
import org.apache.slider.client.SliderClient
import org.apache.slider.common.SliderKeys
+import org.apache.slider.common.params.ActionRegistryArgs
import org.apache.slider.core.main.ServiceLauncher
import org.apache.slider.core.persist.JsonSerDeser
import org.apache.slider.core.registry.docstore.PublishedConfigSet
import org.apache.slider.core.registry.info.CustomRegistryConstants
import org.apache.slider.core.registry.info.ServiceInstanceData
+import org.apache.slider.core.registry.retrieve.RegistryRetriever
import org.apache.slider.server.appmaster.web.rest.RestPaths
import org.apache.slider.server.services.curator.CuratorServiceInstance
import org.apache.slider.server.services.curator.RegistryBinderService
@@ -163,8 +165,42 @@
log.info(GET(registryURL, RestPaths.REGISTRY_SERVICE ))
+ describe "Registry Retrieval"
+ // retrieval
- describe "teardown of cluster"
+ RegistryRetriever retriever = new RegistryRetriever(serviceInstanceData)
+ log.info retriever.toString()
+
+ assert retriever.hasConfigurations(true)
+ def externalConf = retriever.getConfigurations(true)
+ externalConf.keys().each { String key ->
+ def config = externalConf.get(key)
+ log.info "$key -- ${config.description} -- size ${config.size}"
+ }
+
+ describe "Internal configurations"
+ assert !retriever.hasConfigurations(false)
+ try {
+ retriever.getConfigurations(false)
+ fail( "expected a failure")
+ } catch (FileNotFoundException fnfe) {
+ //expected
+ }
+
+ // retrieval via API
+ ActionRegistryArgs registryArgs = new ActionRegistryArgs()
+ registryArgs.name = amInstance;
+ registryArgs.verbose = true
+ registryArgs.list = true;
+ assert client.actionRegistry(registryArgs)
+
+ registryArgs.list = false;
+ registryArgs.listConf = true
+ assert client.actionRegistry(registryArgs)
+
+
+
+ describe "freeze cluster"
//now kill that cluster
assert 0 == clusterActionFreeze(client, clustername)
//list it & See if it is still there
diff --git a/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestLocalRegistry.groovy b/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestLocalRegistry.groovy
index 3af4a06..cf8dbd9 100644
--- a/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestLocalRegistry.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestLocalRegistry.groovy
@@ -21,6 +21,7 @@
import org.apache.hadoop.yarn.conf.YarnConfiguration
import org.apache.slider.common.SliderKeys
import org.apache.slider.core.registry.info.ServiceInstanceData
+import org.apache.slider.core.registry.retrieve.RegistryRetriever
import org.apache.slider.server.services.curator.CuratorHelper
import org.apache.slider.server.services.curator.RegistryBinderService
import org.apache.slider.server.services.curator.RegistryNaming
@@ -154,6 +155,9 @@
SliderTestUtils.dumpRegistryInstances(instances)
assert instances.size() == 2
+ // now set up a registry retriever
+ RegistryRetriever retriever = new RegistryRetriever()
+
}
}
diff --git a/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestRegistryRestResources.groovy b/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestRegistryRestResources.groovy
index 1a7ee5a..d631a62 100644
--- a/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestRegistryRestResources.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/registry/curator/TestRegistryRestResources.groovy
@@ -49,8 +49,9 @@
class TestRegistryRestResources extends AgentTestBase {
public static final String REGISTRY_URI = RestPaths.SLIDER_PATH_REGISTRY;
+ public static final String WADL = "vnd.sun.wadl+xml"
-
+
private String id(String instanceName) {
RegistryNaming.createUniqueInstanceId(
@@ -120,7 +121,7 @@
ClientResponse response = webResource.type(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
assert response.status == 200
- assert response.getType() == (new MediaType("application", "vnd.sun.wadl+xml"))
+ assert response.type == (new MediaType("application", WADL))
// test the available GET URIs
webResource = client.resource(
diff --git a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
index a64370d..9ccae32 100644
--- a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
@@ -35,6 +35,7 @@
import org.apache.slider.client.SliderClient
import org.apache.slider.common.params.Arguments
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.exceptions.BadClusterStateException
import org.apache.slider.core.exceptions.SliderException
@@ -362,19 +363,8 @@
return fetchWebPageWithoutError(s)
}
- def static String appendToURL(String base, String path) {
- StringBuilder fullpath = new StringBuilder(base)
- if (!base.endsWith("/")) {
- fullpath.append("/")
- }
- if (path.startsWith("/")) {
- fullpath.append(path.substring(1))
- } else {
- fullpath.append(path)
- }
-
- def s = fullpath.toString()
- return s
+ public static String appendToURL(String base, String path) {
+ return SliderUtils.appendToURL(base, path)
}
/**