SLIDER-365 slider "resolve" command to retrieve service record

Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/bfaea962
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/bfaea962
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/bfaea962

Branch: refs/heads/develop
Commit: bfaea9629ed7aa11e6c882e4a7533cc081cfc9dc
Parents: fa53ef9
Author: Steve Loughran <ste...@apache.org>
Authored: Thu Oct 9 11:29:10 2014 -0700
Committer: Steve Loughran <ste...@apache.org>
Committed: Thu Oct 9 11:32:26 2014 -0700

----------------------------------------------------------------------
 .../org/apache/slider/client/SliderClient.java  | 57 +++++-------
 .../slider/common/params/ActionResolveArgs.java | 95 ++++++++++++++++++--
 .../TestStandaloneYarnRegistryAM.groovy         | 64 ++++++++-----
 .../apache/slider/test/SliderTestUtils.groovy   | 21 ++++-
 4 files changed, 171 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/bfaea962/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
----------------------------------------------------------------------
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 7daa2b8..2944e2a 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
@@ -28,6 +28,7 @@ import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.hdfs.DFSConfigKeys;
 import org.apache.hadoop.hdfs.HdfsConfiguration;
 import org.apache.hadoop.net.NetUtils;
+import org.apache.hadoop.registry.client.binding.RegistryPathUtils;
 import org.apache.hadoop.registry.client.exceptions.InvalidRecordException;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.alias.CredentialProvider;
@@ -134,13 +135,11 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.net.InetSocketAddress;
 import java.net.URISyntaxException;
-import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -149,7 +148,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Properties;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -394,14 +392,7 @@ public class SliderClient extends 
AbstractSliderLaunchedService implements RunSe
     YarnAppListClient =
         new YarnAppListClient(yarnClient, getUsername(), getConfig());
     // create the filesystem
-    sliderFileSystem = new SliderFileSystem(getConfig());
-
-    // and the registry
-/*
-    YARNRegistryClient =
-        new YARNRegistryClient(yarnClient, getUsername(), getConfig());
-*/
-    
+    sliderFileSystem = new SliderFileSystem(getConfig());    
   }
 
   /**
@@ -2211,40 +2202,38 @@ public class SliderClient extends 
AbstractSliderLaunchedService implements RunSe
     args.validate();
     RegistryOperations operations = getRegistryOperations();
     String path = args.path;
-    Collection<ServiceRecord> serviceRecords;
     ServiceRecordMarshal serviceRecordMarshal = new ServiceRecordMarshal();
-    File outputPath = args.out;
     try {
       if (args.list) {
+        File destDir = args.destdir;
+
         Map<String, ServiceRecord> recordMap =
             listServiceRecords(operations, path);
-        serviceRecords = recordMap.values();
-        // list records out
-        StringBuilder builder = new StringBuilder(1024);
-        for (Entry<String, ServiceRecord> recordEntry : recordMap
-            .entrySet()) {
+
+        for (Entry<String, ServiceRecord> recordEntry : recordMap.entrySet()) {
+          String name = recordEntry.getKey();
           ServiceRecord instance = recordEntry.getValue();
-          builder.append("\"").append(recordEntry.getKey()).append("\":\n");
-          builder.append(serviceRecordMarshal.toJson(instance));
-          builder.append("}\n");
-        }
-        String records = builder.toString();
-        if (outputPath == null) {
-          print(records);
-        } else {
-          SliderUtils.write(outputPath, records.getBytes("UTF-8"), false);
+          String json = serviceRecordMarshal.toJson(instance);
+          if (destDir == null) {
+            print(name);
+            print(json);
+          } else {
+            String filename = RegistryPathUtils.lastPathEntry(name) + ".json";
+            File jsonFile = new File(destDir, filename);
+            SliderUtils.write(jsonFile,
+                serviceRecordMarshal.toBytes(instance), true);
+          }
         }
       } else  {
         // resolve single entry
         ServiceRecord instance = resolve(path);
-        serviceRecords = new ArrayList<ServiceRecord>(1);
-        serviceRecords.add(instance);
-        // write out JSON content
-        if (outputPath != null) {
-          byte[] data = serviceRecordMarshal.toBytes(instance);
-          SliderUtils.write(outputPath, data, false);
+        File outFile = args.out;
+        if (args.destdir != null) {
+          outFile = new File(args.destdir, 
RegistryPathUtils.lastPathEntry(path));
+        }
+        if (outFile != null) {
+          SliderUtils.write(outFile, serviceRecordMarshal.toBytes(instance), 
true);
         } else {
-          // print to the console
           print(serviceRecordMarshal.toJson(instance));
         }
       }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/bfaea962/slider-core/src/main/java/org/apache/slider/common/params/ActionResolveArgs.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/common/params/ActionResolveArgs.java
 
b/slider-core/src/main/java/org/apache/slider/common/params/ActionResolveArgs.java
index cf5611c..944be1b 100644
--- 
a/slider-core/src/main/java/org/apache/slider/common/params/ActionResolveArgs.java
+++ 
b/slider-core/src/main/java/org/apache/slider/common/params/ActionResolveArgs.java
@@ -20,7 +20,7 @@ package org.apache.slider.common.params;
 
 import com.beust.jcommander.Parameter;
 import com.beust.jcommander.Parameters;
-import org.apache.slider.common.SliderKeys;
+import org.apache.commons.lang.StringUtils;
 import org.apache.slider.core.exceptions.BadCommandArgumentsException;
 import org.apache.slider.core.exceptions.UsageException;
 
@@ -45,10 +45,11 @@ public class ActionResolveArgs extends AbstractActionArgs {
   public static final String USAGE =
       "Usage: " + SliderActions.ACTION_RESOLVE
       + " "
-      + Arguments.ARG_PATH + " <path> "
-      + "[" + Arguments.ARG_LIST + "] "
-      + "[" + Arguments.ARG_VERBOSE + "] "
-      + "[" + Arguments.ARG_OUTPUT + " <filename> ] "
+      + ARG_PATH + " <path> "
+      + "[" + ARG_LIST + "] "
+      + "[" + ARG_VERBOSE + "] "
+      + "[" + ARG_OUTPUT + " <filename> ] "
+      + "[" + ARG_DESTDIR + " <directory> ] "
       ;
   public ActionResolveArgs() {
   }
@@ -71,17 +72,95 @@ public class ActionResolveArgs extends AbstractActionArgs {
       description = "list services")
   public boolean list;
 
-
   @Parameter(names = {ARG_PATH},
       description = "resolve a path")
   public String path;
 
+  @Parameter(names = {ARG_DESTDIR},
+      description = "destination directory for operations")
+  public File destdir;
+
   @Parameter(names = {ARG_OUTPUT, ARG_OUTPUT_SHORT},
-      description = "Output destination")
+      description = "dest file")
   public File out;
 
  @Parameter(names = {ARG_VERBOSE},
       description = "verbose output")
   public boolean verbose;
-  
+
+  @Override
+  public String toString() {
+    final StringBuilder sb =
+        new StringBuilder(ACTION_RESOLVE).append(" ");
+    sb.append(ARG_PATH).append(" ").append(path).append(" ");
+    if (list) {
+      sb.append(ARG_LIST).append(" ");
+    }
+    if (destdir != null) {
+      sb.append(ARG_DESTDIR).append(" ").append(destdir).append(" ");
+    }
+    if (out != null) {
+      sb.append(ARG_OUTPUT).append(" ").append(out).append(" ");
+    }
+    return sb.toString();
+  }
+
+  @Override
+  public void validate() throws BadCommandArgumentsException, UsageException {
+    super.validate();
+    if (StringUtils.isEmpty(path)) {
+      throw new BadCommandArgumentsException("Missing mandatory argument "
+                                             + ARG_PATH);
+    }
+    if (list && out != null) {
+      throw new BadCommandArgumentsException("Argument "
+                                             + ARG_OUTPUT +
+                                             " not supported for " + ARG_LIST);
+    }
+    if (out != null && destdir != null) {
+      throw new BadCommandArgumentsException(
+          ARG_OUTPUT + " and " + ARG_DESTDIR + " cannot be used together"
+      );
+    }
+  }
+
+  public String getPath() {
+    return path;
+  }
+
+  public void setPath(String path) {
+    this.path = path;
+  }
+
+  public boolean isList() {
+    return list;
+  }
+
+  public void setList(boolean list) {
+    this.list = list;
+  }
+
+  public File getDestdir() {
+    return destdir;
+  }
+
+  public void setDestdir(File destdir) {
+    this.destdir = destdir;
+  }
+
+  public File getOut() {
+    return out;
+  }
+
+  public void setOut(File out) {
+    this.out = out;
+  }
+
+  public boolean isVerbose() {
+    return verbose;
+  }
+
+  public void setVerbose(boolean verbose) {
+    this.verbose = verbose;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/bfaea962/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneYarnRegistryAM.groovy
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneYarnRegistryAM.groovy
 
b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneYarnRegistryAM.groovy
index 84dcc50..ca200fd 100644
--- 
a/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneYarnRegistryAM.groovy
+++ 
b/slider-core/src/test/groovy/org/apache/slider/agent/standalone/TestStandaloneYarnRegistryAM.groovy
@@ -20,6 +20,8 @@ package org.apache.slider.agent.standalone
 
 import groovy.transform.CompileStatic
 import groovy.util.logging.Slf4j
+import org.apache.commons.io.IOUtils
+import org.apache.hadoop.fs.FileUtil
 import org.apache.hadoop.fs.PathNotFoundException
 import org.apache.hadoop.yarn.api.records.ApplicationReport
 import org.apache.hadoop.yarn.api.records.YarnApplicationState
@@ -31,7 +33,10 @@ import 
org.apache.hadoop.registry.client.types.RegistryPathStatus
 import org.apache.hadoop.registry.client.types.ServiceRecord
 import org.apache.hadoop.registry.client.types.yarn.YarnRegistryAttributes
 import org.apache.slider.common.params.ActionResolveArgs
+import org.apache.slider.common.params.Arguments
+import org.apache.slider.core.exceptions.BadCommandArgumentsException
 import org.apache.slider.core.exceptions.UnknownApplicationInstanceException
+import org.apache.slider.core.main.LauncherExitCodes
 
 import static org.apache.hadoop.registry.client.binding.RegistryUtils.*
 import org.apache.slider.agent.AgentMiniClusterTestBase
@@ -174,37 +179,52 @@ class TestStandaloneYarnRegistryAM extends 
AgentMiniClusterTestBase {
     assert null != serviceRecord.getInternalEndpoint(AGENT_SECURE_REST_API)
 
     // use the resolve operation
+
     describe "resolve CLI action"
-    ActionResolveArgs resolveArgs = new ActionResolveArgs()
-    resolveArgs.path = recordsPath;
-    resolveArgs.list = true;
+    File destDir= new File("target/resolve")
+    ServiceRecordMarshal serviceRecordMarshal = new ServiceRecordMarshal()
+    FileUtil.fullyDelete(destDir)
+    File resolveListDir= new File(destDir, "list")
+    ActionResolveArgs resolveList = new ActionResolveArgs(
+        path:recordsPath,
+        list:true,
+        verbose:true)
+
     // to stdout
-    client.actionResolve(resolveArgs)
+    client.actionResolve(resolveList)
     // to a file
-    File destFile = new File("target/resolve.json")
-    destFile.delete()
-    resolveArgs.out = destFile
-    client.actionResolve(resolveArgs)
-    assert destFile.exists()
-    destFile.delete()
+    resolveList.out = resolveListDir;
+    try {
+      client.actionResolve(resolveList)
+    } catch (BadCommandArgumentsException ex) {
+      assertExceptionDetails(ex, LauncherExitCodes.EXIT_COMMAND_ARGUMENT_ERROR,
+          Arguments.ARG_OUTPUT)
+    }
+    resolveList.out = null
+    resolveList.destdir = resolveListDir
+    client.actionResolve(resolveList)
+    File resolvedFile = new File(resolveListDir, clustername+".json")
+    assertFileExists("resolved file", resolvedFile)
+    def recordFromList = serviceRecordMarshal.fromFile(resolvedFile)
     
     // look at a single record
-    resolveArgs.out = null;
-    resolveArgs.list = false;
-    resolveArgs.path = recordsPath +"/"+ clustername
+    ActionResolveArgs resolveRecordCommand = new ActionResolveArgs(
+        path: recordsPath + "/" + clustername)
     // to stdout
-    client.actionResolve(resolveArgs)
-    resolveArgs.out = destFile
-    client.actionResolve(resolveArgs)
-    assert destFile.exists()
-    ServiceRecordMarshal serviceRecordMarshal = new ServiceRecordMarshal()
-    def recordFromFile = serviceRecordMarshal.fromFile(destFile)
+    client.actionResolve(resolveRecordCommand)
+    
+    // then to a file
+    FileUtil.fullyDelete(destDir)
+    File singleFile = new File(destDir, "singlefile.json")
+    singleFile.delete()
+    resolveRecordCommand.out = singleFile
+    client.actionResolve(resolveRecordCommand)
+    assertFileExists("\"slider $resolveRecordCommand\"", singleFile)
+    def recordFromFile = serviceRecordMarshal.fromFile(singleFile)
     assert recordFromFile[YarnRegistryAttributes.YARN_ID] ==
            serviceRecord[YarnRegistryAttributes.YARN_ID]
     assert recordFromFile[YarnRegistryAttributes.YARN_PERSISTENCE] ==
            serviceRecord[YarnRegistryAttributes.YARN_PERSISTENCE]
-    
-    
 
     // hit the registry web page
     def registryEndpoint = serviceRecord.getExternalEndpoint(
@@ -402,7 +422,7 @@ class TestStandaloneYarnRegistryAM extends 
AgentMiniClusterTestBase {
     // create a new registry args with the defaults back in
     registryArgs = new ActionRegistryArgs(clustername)
     registryArgs.getConf = yarn_site_config
-    registryArgs.dest = outputDir
+    registryArgs.out = outputDir
     describe registryArgs.toString()
     client.actionRegistry(registryArgs)
     assert new File(outputDir, yarn_site_config + ".xml").exists()

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/bfaea962/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
----------------------------------------------------------------------
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 0b45a5d..d09d280 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
@@ -79,13 +79,13 @@ class SliderTestUtils extends Assert {
   }
 
   public static void skip(String message) {
-    log.warn("Skipping test: " + message)
+    log.warn("Skipping test: {}", message)
     Assume.assumeTrue(message, false);
   }
 
   public static void assume(boolean condition, String message) {
     if (!condition) {
-      log.warn("Skipping test: " + message)
+      log.warn("Skipping test: {}",  message)
       Assume.assumeTrue(message, false);
     }
   }
@@ -793,4 +793,21 @@ class SliderTestUtils extends Assert {
   public String toURIArg(File file) {
     file.absoluteFile.toURI().toString()
   }
+
+  /**
+   * Assert a file exists; fails with a listing of the parent dir
+   * @param text text for front of message
+   * @param file file to look for
+   * @throws FileNotFoundException
+   */
+  public void assertFileExists(String text, File file) {
+    if (!file.exists()) {
+      def parent = file.parentFile
+      def files = parent.list()
+      StringBuilder builder = new StringBuilder()
+      builder.append("${parent.absolutePath}:\n")
+      files.each { String name-> builder.append("  $name\n")}
+      throw new FileNotFoundException("$text: file $file not found in 
$builder")
+    }
+  }
 }

Reply via email to