SSHApiCallNode sshExec API Impl 69/57269/7
authorGanesh Chandrasekaran <ganesh.c@samsung.com>
Tue, 24 Jul 2018 07:40:14 +0000 (16:40 +0900)
committerGanesh Chandrasekaran <ganesh.c@samsung.com>
Tue, 24 Jul 2018 09:05:43 +0000 (18:05 +0900)
Issue-ID: CCSDK-385

Change-Id: I430f9075ced10edb49062fc12091774e91611b32
Signed-off-by: Ganesh Chandrasekaran <ganesh.c@samsung.com>
17 files changed:
restapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/restapicall/RestapiCallNode.java
sshapi-call-node/features/ccsdk-sshapi-call-node/pom.xml
sshapi-call-node/provider/pom.xml
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/AuthType.java [deleted file]
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/SshapiCallNodeImpl.java [deleted file]
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/AuthType.java [moved from sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryException.java with 71% similarity]
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Format.java [moved from sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Format.java with 96% similarity]
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Parameters.java [moved from sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Parameters.java with 83% similarity]
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java [new file with mode: 0644]
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicy.java [deleted file]
sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicyStore.java [deleted file]
sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml
sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml
sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml
sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/sshapicall/TestJsonParser.java

index 5168b3e..42462f0 100644 (file)
@@ -90,7 +90,7 @@ public class RestapiCallNode implements SvcLogicJavaPlugin {
 
      /**
      * Allows Directed Graphs  the ability to interact with REST APIs.
-     * @param parameters HashMap<String,String> of parameters passed by the DG to this function
+     * @param paramMap HashMap<String,String> of parameters passed by the DG to this function
      * <table border="1">
      *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead>
      *  <tbody>
index 12ec068..7b74d6d 100644 (file)
@@ -36,7 +36,7 @@
             </dependency>
         </dependencies>
     </dependencyManagement>
-
+<!--
     <dependencies>
 
         <dependency>
@@ -52,4 +52,5 @@
             <version>${project.version}</version>
         </dependency>
     </dependencies>
+    -->
 </project>
index 165003f..e380d7c 100755 (executable)
             <groupId>org.onap.ccsdk.sli.core</groupId>
             <artifactId>sli-provider</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.onap.appc</groupId>
+            <artifactId>appc-ssh-adapter-api</artifactId>
+            <version>1.3.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
index 4efddec..e4b082c 100644 (file)
@@ -1,10 +1,11 @@
 /*-
  * ============LICENSE_START=======================================================
- * openECOMP : SDN-C
+ * ONAP : APPC
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights
- *                     reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
  * Licensed 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
  * 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.
+ *
  * ============LICENSE_END=========================================================
  */
 
 package org.onap.ccsdk.sli.plugins.sshapicall;
 
-import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.base.Strings;
+import org.json.JSONObject;
+import org.onap.appc.adapter.ssh.SshAdapter;
+import org.onap.appc.adapter.ssh.SshConnection;
 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
 import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
-import java.io.OutputStream;
-import java.util.Map;
+import org.onap.ccsdk.sli.plugins.sshapicall.model.AuthType;
+import org.onap.ccsdk.sli.plugins.sshapicall.model.Parameters;
+import org.onap.ccsdk.sli.plugins.sshapicall.model.ParseParam;
+
+
+public class SshApiCallNode implements SvcLogicJavaPlugin {
+
+    private static final EELFLogger logger = EELFManager.getInstance().getApplicationLogger();
+
+    /**
+     * Output parameter - SSH command execution status.
+     */
+    String PARAM_OUT_status = "status";
+
+    /**
+     * Output parameter - content of SSH command stdout.
+     */
+    String PARAM_OUT_stdout = "stdout";
+
+    /**
+     * Output parameter - content of SSH command stderr.
+     */
+    String PARAM_OUT_stderr = "stderr";
+
+    /**
+     * Default success status.
+     */
+    int DEF_SUCCESS_STATUS = 0;
+
+    private SshAdapter sshAdapter;
 
-public interface SshApiCallNode extends SvcLogicJavaPlugin {
+    public void setSshAdapter(SshAdapter sshAdapter) {
+        this.sshAdapter = sshAdapter;
+    }
 
     /**
      * Allows Directed Graphs  the ability to interact with SSH APIs.
-     * @param paramMap HashMap<String,String> of parameters passed by the DG to this function
+     * @param params HashMap<String,String> of parameters passed by the DG to this function
      * <table border="1">
      *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead>
      *  <tbody>
      *      <tr><td>templateFileName</td><td>Optional</td><td>full path to template file that can be used to build a request</td><td>/sdncopt/bvc/sshapi/templates/vnf_service-configuration-operation_minimal.json</td></tr>
-     *      <tr><td>sshapiUrl</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr>
-     *      <tr><td>sshapiUser</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr>
-     *      <tr><td>sshapiPassword</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr>
-     *      <tr><td>sshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr>
-     *      <tr><td>cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr>
-     *      <tr><td>responsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td><td>tmp.sshapi.result</td></tr>
+     *      <tr><td>Url</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr>
+     *      <tr><td>Port</td><td>Mandatory</td><td>port to make the SSH connection request to.</td></tr>
+     *      <tr><td>User</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr>
+     *      <tr><td>Password</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr>
+     *      <tr><td>SshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr>
+     *      <tr><td>ExecTimeout</td><td>Optional</td><td>SSH command execution timeout</td><td>plain_key</td></tr>
+     *      <tr><td>Retry</td><td>Optional</td><td>Make ssh connection with default retry policy</td><td>plain_key</td></tr>
+     *      <tr><td>Cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr>
+     *      <tr><td>ResponsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td><td>tmp.sshapi.result</td></tr>
+     *      <tr><td>ResponseType</td><td>Optional</td><td>If we know the response is to be in a specific format (supported are JSON, XML and NONE) </td><td>tmp.sshapi.result</td></tr>
      *      <tr><td>listName[i]</td><td>Optional</td><td>Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details<td></td></tr>
-     *      <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr>
-     *      <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes ssh response content to context memory</td><td>true or false</td></tr>
-     *      <tr><td>returnRequestPayload</td><td>Optional</td><td>used to return payload built in the request</td><td>true or false</td></tr>
+     *      <tr><td>ConvertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr>
+     *      <tr><td>AuthType</td><td>Optional</td><td>Type of authentiation to be used BASIC or sshKey based</td><td>true or false</td></tr>
+     *      <tr><td>EnvParameters</td><td>Optional</td><td>A JSON dictionary which should list key value pairs to be passed to the command execution.
+     *               These values would correspond to instance specific parameters that a command may need to execute an action.</td></tr>
+     *      <tr><td>FileParameters</td><td>Optional</td><td>A JSON dictionary where keys are filenames and values are contents of files.
+     *               The SSH Server will utilize this feature to generate files with keys as filenames and values as content.
+     *               This attribute can be used to generate files that a command may require as part of execution.</td></tr>
      *  </tbody>
      * </table>
      * Exec remote command over SSH. Return command execution status.
@@ -53,32 +107,140 @@ public interface SshApiCallNode extends SvcLogicJavaPlugin {
      *
      * @param ctx Reference to context memory
      */
-    void execCommand(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException;
+
+    public void execCommand(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
+        ParseParam parser = new ParseParam();
+        Parameters p = parser.getParameters(params);
+        logger.debug("=> Connecting to SSH server...");
+        SshConnection sshConnection = getSshConnection(p);
+        sshConnection.connect();
+        try {
+            logger.debug("=> Connected to SSH server...");
+            logger.debug("=> Running SSH command...");
+            sshConnection.setExecTimeout(p.sshExecTimeout);
+            ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+            ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+            int status = sshConnection.execCommand(parser.makeCommand(params), stdout, stderr);
+            String stdoutRes = stdout.toString();
+            String stderrRes = stderr.toString();
+            logger.debug("=> executed SSH command");
+
+            if(status == DEF_SUCCESS_STATUS) {
+                parser.parseOutput(ctx, stdoutRes);
+            }
+            ctx.setAttribute(PARAM_OUT_status, String.format("%01d", status));
+            ctx.setAttribute(PARAM_OUT_stdout, stdoutRes);
+            ctx.setAttribute(PARAM_OUT_stderr, stderrRes);
+        } finally {
+            sshConnection.disconnect();
+        }
+    }
+
+    private SshConnection getSshConnection(Parameters p) throws SvcLogicException{
+        if (p.authtype == AuthType.BASIC)
+            return sshAdapter.getConnection(p.sshapiUrl, p.sshapiPort, p.sshapiUser, p.sshapiPassword);
+        // This is not supported yet in the API, patch has already been added to APPC
+        else if (p.authtype == AuthType.KEY){
+            //return sshAdapter.getConnection(p.sshapiUrl, p.sshapiPort, p.sshKey);
+            throw new SvcLogicException("SSH Key based Auth method not supported");
+        }
+        else if (p.authtype == AuthType.NONE){
+            //return sshAdapter.getConnection(p.sshapiUrl, p.sshapiPort, p.sshKey);
+            throw new SvcLogicException("SSH Auth type required, BASIC auth in support");
+        }
+        else if (p.authtype == AuthType.UNSPECIFIED){
+            if (p.sshapiUser != null && p.sshapiPassword != null)
+                return sshAdapter.getConnection(p.sshapiUrl, p.sshapiPort, p.sshapiUser, p.sshapiPassword);
+            else if (p.sshKey != null)
+                throw new SvcLogicException("SSH Key based Auth method not supported");
+        }
+        throw new SvcLogicException("SSH Auth type required, BASIC auth in support");
+    }
+
 
     /**
      * Allows Directed Graphs  the ability to interact with SSH APIs.
-     * @param paramMap HashMap<String,String> of parameters passed by the DG to this function
+     * @param params HashMap<String,String> of parameters passed by the DG to this function
      * <table border="1">
      *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead>
      *  <tbody>
      *      <tr><td>templateFileName</td><td>Optional</td><td>full path to template file that can be used to build a request</td><td>/sdncopt/bvc/sshapi/templates/vnf_service-configuration-operation_minimal.json</td></tr>
-     *      <tr><td>sshapiUrl</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr>
-     *      <tr><td>sshapiUser</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr>
-     *      <tr><td>sshapiPassword</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr>
-     *      <tr><td>sshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr>
-     *      <tr><td>cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr>
-     *      <tr><td>responsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td><td>tmp.sshapi.result</td></tr>
+     *      <tr><td>Url</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr>
+     *      <tr><td>Port</td><td>Mandatory</td><td>port to make the SSH connection request to.</td></tr>
+     *      <tr><td>User</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr>
+     *      <tr><td>Password</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr>
+     *      <tr><td>SshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr>
+     *      <tr><td>ExecTimeout</td><td>Optional</td><td>SSH command execution timeout</td><td>plain_key</td></tr>
+     *      <tr><td>Retry</td><td>Optional</td><td>Make ssh connection with default retry policy</td><td>plain_key</td></tr>
+     *      <tr><td>Cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr>
+     *      <tr><td>ResponsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td><td>tmp.sshapi.result</td></tr>
+     *      <tr><td>ResponseType</td><td>Optional</td><td>If we know the response is to be in a specific format (supported are JSON, XML and NONE) </td><td>tmp.sshapi.result</td></tr>
      *      <tr><td>listName[i]</td><td>Optional</td><td>Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details<td></td></tr>
-     *      <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr>
-     *      <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes ssh response content to context memory</td><td>true or false</td></tr>
-     *      <tr><td>returnRequestPayload</td><td>Optional</td><td>used to return payload built in the request</td><td>true or false</td></tr>
+     *      <tr><td>ConvertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr>
+     *      <tr><td>AuthType</td><td>Optional</td><td>Type of authentiation to be used BASIC or sshKey based</td><td>true or false</td></tr>
+     *      <tr><td>EnvParameters</td><td>Optional</td><td>A JSON dictionary which should list key value pairs to be passed to the command execution.
+     *               These values would correspond to instance specific parameters that a command may need to execute an action.</td></tr>
+     *      <tr><td>FileParameters</td><td>Optional</td><td>A JSON dictionary where keys are filenames and values are contents of files.
+     *               The SSH Server will utilize this feature to generate files with keys as filenames and values as content.
+     *               This attribute can be used to generate files that a command may require as part of execution.</td></tr>
      *  </tbody>
      * </table>
-     * Exec remote command over SSH with pseudo-tty. Return command execution status.
-     * Command output is written to out stream only as pseudo-tty writes to one stream only.
+     * Exec remote command over SSH. Return command execution status.
+     * Command output is written to out or err stream.
      *
-     *  @param ctx Reference to context memory
+     * @param ctx Reference to context memory
+     */
+
+    public void execWithStatusCheck(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
+        execCommand(params, ctx);
+        int status = Integer.parseInt(ctx.getAttribute(PARAM_OUT_status));
+        if(status != DEF_SUCCESS_STATUS) {
+            StringBuilder errmsg = new StringBuilder();
+            errmsg.append("SSH command returned error status [").append(status).append(']');
+            String stderrRes = ctx.getAttribute(PARAM_OUT_stderr);
+            String stdoutRes = ctx.getAttribute(PARAM_OUT_stdout);
+            if((stderrRes != null) && !stderrRes.isEmpty()) {
+                errmsg.append(". Error: [").append(stderrRes).append(']');
+            } else if ((stdoutRes != null) && !stdoutRes.isEmpty()) {
+                errmsg.append(". Error: [").append(stdoutRes).append(']');
+            }
+            throw new SvcLogicException(errmsg.toString());
+        }
+    }
+
+    /**
+     * Allows Directed Graphs  the ability to interact with SSH APIs.
+     * @param params HashMap<String,String> of parameters passed by the DG to this function
+     * <table border="1">
+     *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead>
+     *  <tbody>
+     *      <tr><td>templateFileName</td><td>Optional</td><td>full path to template file that can be used to build a request</td><td>/sdncopt/bvc/sshapi/templates/vnf_service-configuration-operation_minimal.json</td></tr>
+     *      <tr><td>Url</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr>
+     *      <tr><td>Port</td><td>Mandatory</td><td>port to make the SSH connection request to.</td></tr>
+     *      <tr><td>User</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr>
+     *      <tr><td>Password</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr>
+     *      <tr><td>SshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr>
+     *      <tr><td>ExecTimeout</td><td>Optional</td><td>SSH command execution timeout</td><td>plain_key</td></tr>
+     *      <tr><td>Retry</td><td>Optional</td><td>Make ssh connection with default retry policy</td><td>plain_key</td></tr>
+     *      <tr><td>Cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr>
+     *      <tr><td>ResponsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td><td>tmp.sshapi.result</td></tr>
+     *      <tr><td>ResponseType</td><td>Optional</td><td>If we know the response is to be in a specific format (supported are JSON, XML and NONE) </td><td>tmp.sshapi.result</td></tr>
+     *      <tr><td>listName[i]</td><td>Optional</td><td>Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details<td></td></tr>
+     *      <tr><td>ConvertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr>
+     *      <tr><td>AuthType</td><td>Optional</td><td>Type of authentiation to be used BASIC or sshKey based</td><td>true or false</td></tr>
+     *      <tr><td>EnvParameters</td><td>Optional</td><td>A JSON dictionary which should list key value pairs to be passed to the command execution.
+     *               These values would correspond to instance specific parameters that a command may need to execute an action.</td></tr>
+     *      <tr><td>FileParameters</td><td>Optional</td><td>A JSON dictionary where keys are filenames and values are contents of files.
+     *               The SSH Server will utilize this feature to generate files with keys as filenames and values as content.
+     *               This attribute can be used to generate files that a command may require as part of execution.</td></tr>
+     *  </tbody>
+     * </table>
+     * Exec remote command over SSH. Return command execution status.
+     * Command output is written to out or err stream.
+     *
+     * @param ctx Reference to context memory
      */
-    void execCommandWithPty(Map<String, String> paramMap, SvcLogicContext ctx)  throws SvcLogicException ;
+    public void execCommandWithPty(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
 
+    }
 }
diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/AuthType.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/AuthType.java
deleted file mode 100644 (file)
index 3081622..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.onap.ccsdk.sli.plugins.sshapicall.impl;
-
-public enum AuthType {
-    NONE, BASIC, DIGEST, OAUTH, Unspecified;
-
-    public static AuthType fromString(String s) {
-        if ("basic".equalsIgnoreCase(s))
-            return BASIC;
-        if ("digest".equalsIgnoreCase(s))
-            return DIGEST;
-        if ("oauth".equalsIgnoreCase(s))
-            return OAUTH;
-        if ("none".equalsIgnoreCase(s))
-            return NONE;
-        if ("unspecified".equalsIgnoreCase(s))
-            return Unspecified;
-        throw new IllegalArgumentException("Invalid value for format: " + s);
-    }
-}
diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/SshapiCallNodeImpl.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/SshapiCallNodeImpl.java
deleted file mode 100644 (file)
index 9283b8b..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * openECOMP : SDN-C
- * ================================================================================
- * * Copyright (C) 2017 AT&T Intellectual Property.
- * ================================================================================
- * Copyright (C) 2018 Samsung Electronics. All rights
- *                     reserved.
- * ================================================================================
- * Licensed 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.ccsdk.sli.plugins.sshapicall.impl;
-
-import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
-import org.onap.ccsdk.sli.core.sli.SvcLogicException;
-import org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode;
-
-import java.io.OutputStream;
-import java.util.Map;
-
-public class SshapiCallNodeImpl implements SshApiCallNode {
-    @Override
-    public void execCommand(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
-        //TODO: Implementation
-    }
-
-    @Override
-    public void execCommandWithPty(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
-        //TODO: Implementation
-    }
-}
@@ -7,12 +7,13 @@
  * Copyright (C) 2018 Samsung Electronics. All rights
  *                     reserved.
  * ================================================================================
+ *
  * Licensed 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.
 
 package org.onap.ccsdk.sli.plugins.sshapicall.model;
 
-public class RetryException extends Exception {
+public enum AuthType {
+    NONE, BASIC, KEY, UNSPECIFIED;
 
-    public RetryException(String message) {
-        super(message);
+    public static AuthType fromString(String s) {
+        if ("basic".equalsIgnoreCase(s))
+            return BASIC;
+        if ("key".equalsIgnoreCase(s))
+            return KEY;
+        if ("unspecified".equalsIgnoreCase(s))
+            return UNSPECIFIED;
+        if ("none".equalsIgnoreCase(s))
+            return NONE;
+        throw new IllegalArgumentException("Invalid value for format: " + s);
     }
-
 }
index e840053..f40f1ad 100644 (file)
@@ -47,11 +47,10 @@ public final class JsonParser {
 
     @SuppressWarnings("unchecked")
     public static Map<String, String> convertToProperties(String s)
-        throws SvcLogicException {
+        throws JSONException {
 
         checkNotNull(s, "Input should not be null.");
 
-        try {
             JSONObject json = new JSONObject(s);
             Map<String, Object> wm = new HashMap<>();
             Iterator<String> ii = json.keys();
@@ -89,8 +88,5 @@ public final class JsonParser {
                     }
                 }
             return mm;
-        } catch (JSONException e) {
-            throw new SvcLogicException("Unable to convert JSON to properties" + e.getLocalizedMessage(), e);
-        }
     }
 }
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.ccsdk.sli.plugins.sshapicall.impl;
+package org.onap.ccsdk.sli.plugins.sshapicall.model;
 
 import java.util.Set;
 
 public class Parameters {
-    public String templateFileName;
     public String sshapiUrl;
+    public int sshapiPort;
     public String sshapiUser;
     public String sshapiPassword;
-    public Format sshKey;
+    public String sshKey;
+    public long sshExecTimeout;
+    public String sshFileParameters;
+    public String sshEnvParameters;
+    public boolean sshWithRetry;
     public String cmd;
     public String responsePrefix;
+    public Format responseType;
+
     public Set<String> listNameList;
     public boolean convertResponse;
-    public Boolean dumpHeaders;
-    public String requestBody;
     public AuthType authtype;
-    public Boolean returnRequestPayload;
 }
diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java
new file mode 100644 (file)
index 0000000..caf49ef
--- /dev/null
@@ -0,0 +1,274 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : SDN-C
+ * ================================================================================
+ * * Copyright (C) 2017 AT&T Intellectual Property.
+ * ================================================================================
+ * Copyright (C) 2018 Samsung Electronics. All rights
+ *                     reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.ccsdk.sli.plugins.sshapicall.model;
+
+import com.google.common.base.Strings;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
+import org.onap.ccsdk.sli.core.sli.SvcLogicException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+public class ParseParam {
+    private static final Logger log = LoggerFactory.getLogger(ParseParam.class);
+    /**
+     * Default SSH command timeout
+     */
+    private long dEF_timeout = 12000;
+    /**
+     * Default SSH connection port.
+     */
+    private int dEF_port = 22;
+    /**
+     * Default SSH command timeout
+     */
+    private final String FILE_PARAMETERS_OPT_KEY = "FileParameters";
+    /**
+     * Default SSH connection port.
+     */
+    private final String ENV_PARAMETERS_OPT_KEY = "EnvParameters";
+    private Parameters p = new Parameters();
+
+    public Parameters getParameters(Map<String, String> paramMap) throws SvcLogicException {
+        p.sshapiUrl = parseParam(paramMap, "Url", true, null);
+        p.sshapiPort = Integer.parseInt(parseParam(paramMap, "Port", true, Integer.toString(dEF_port)));
+        p.sshapiUser = parseParam(paramMap, "User", false, null);
+        p.sshapiPassword = parseParam(paramMap, "Password", false, null);
+        p.sshKey = parseParam(paramMap, "SshKey", false, null);
+        p.sshExecTimeout = Long.parseLong(parseParam(paramMap, "ExecTimeout", false, Long.toString(dEF_timeout)));
+        p.sshWithRetry = Boolean.valueOf(parseParam(paramMap, "Retry", false, "false"));
+        p.cmd = parseParam(paramMap, "Cmd", true, null);
+        p.responsePrefix = parseParam(paramMap, "ResponsePrefix", false, null);
+        p.responseType = Format.fromString(parseParam(paramMap, "ResponseType", false, "none"));
+        p.listNameList = getListNameList(paramMap);
+        p.convertResponse = Boolean.valueOf(parseParam(paramMap, "ConvertResponse", false, "true"));
+        p.authtype = AuthType.fromString(parseParam(paramMap, "AuthType", false, "unspecified"));
+
+        return p;
+    }
+
+    public void parseOutput (SvcLogicContext ctx, String outMessage) throws SvcLogicException {
+        if (p.convertResponse) {
+            if (p.responseType == Format.NONE) {
+                classifyOutput(ctx, outMessage);
+            } else if (p.responseType == Format.JSON) {
+                classifyOutput(ctx, outMessage);
+            } else if (p.responseType == Format.XML) {
+                classifyOutput(ctx, outMessage, p.listNameList);
+            }
+        }
+    }
+
+    private void classifyOutput(SvcLogicContext ctx, String outMessage, Set<String> listNameList) throws SvcLogicException {
+        Map<String, String> mm = XmlParser.convertToProperties(outMessage, p.listNameList);
+        toCtx (ctx, mm);
+    }
+
+    private void toCtx (SvcLogicContext ctx, Map<String, String> mm) {
+        if (mm != null) {
+            for (Map.Entry<String, String> entry : mm.entrySet()) {
+                if (p.responsePrefix != null) {
+                    ctx.setAttribute(p.responsePrefix + "." + entry.getKey(), entry.getValue());
+                    log.info("+++ " + p.responsePrefix + "." + entry.getKey() + ": [" + entry.getValue() + "]");
+                } else {
+                    ctx.setAttribute(entry.getKey(), entry.getValue());
+                    log.info("+++ " + entry.getKey() + ": [" + entry.getValue() + "]");
+                }
+            }
+        }
+    }
+
+    private void classifyOutput(SvcLogicContext ctx, String outMessage) throws SvcLogicException {
+        try {
+            Map<String, String> mm = JsonParser.convertToProperties(outMessage);
+            toCtx (ctx, mm);
+        } catch (org.codehaus.jettison.json.JSONException e) {
+            log.info("Output not in JSON format");
+            putToProperties(ctx, p.responsePrefix);
+        } catch (Exception e) {
+            throw  new SvcLogicException("error parsing response file");
+        }
+    }
+
+    private void putToProperties(SvcLogicContext ctx, String outMessage) throws SvcLogicException {
+
+        try {
+            Properties prop = new Properties();
+            prop.load(new ByteArrayInputStream(outMessage.getBytes(StandardCharsets.UTF_8)));
+            for (Object key : prop.keySet()) {
+                String name = (String) key;
+                String value = prop.getProperty(name);
+                if (value != null && value.trim().length() > 0) {
+                    if (p.responsePrefix != null) {
+                        ctx.setAttribute(p.responsePrefix + "." + name, value.trim());
+                        log.info("+++ " + p.responsePrefix + "." + name + ": [" + value + "]");
+                    } else {
+                        ctx.setAttribute(name, value.trim());
+                        log.info("+++ " + name + ": [" + value + "]");
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw  new SvcLogicException( "Error parsing response file.");
+        }
+    }
+
+    public String makeCommand (Map<String, String> params) {
+        JSONObject jsonPayload = new JSONObject();
+        final String[] optionalTestParams = {ENV_PARAMETERS_OPT_KEY, FILE_PARAMETERS_OPT_KEY};
+        parseParam(params, optionalTestParams, jsonPayload);
+        JSONObject envParams = (JSONObject) jsonPayload.remove(ENV_PARAMETERS_OPT_KEY);
+        JSONObject fileParams = (JSONObject) jsonPayload.remove(FILE_PARAMETERS_OPT_KEY);
+
+        StringBuilder constructedCommand = new StringBuilder();
+        constructedCommand.append(parseFileParam(fileParams)).append(p.cmd).append(" ").append(parseEnvParam(envParams));
+
+        return constructedCommand.toString();
+    }
+
+    private String parseEnvParam(JSONObject envParams) {
+        StringBuilder envParamBuilder = new StringBuilder();
+        if (envParams != null) {
+            for (Object key : envParams.keySet()) {
+                if (envParamBuilder.length() > 0) {
+                    envParamBuilder.append(", ");
+                }
+                envParamBuilder.append(key + "=" + envParams.get((String) key));
+            }
+        }
+        return envParamBuilder.toString();
+    }
+
+    private String parseFileParam(JSONObject fileParams) {
+        StringBuilder fileParamBuilder = new StringBuilder();
+        if (fileParams != null) {
+            for (Object key : fileParams.keySet()) {
+                fileParamBuilder.append("echo -e \"" + fileParams.get((String) key) + "\" > /srv/salt/" + key).append("; ");
+            }
+        }
+        return fileParamBuilder.toString();
+    }
+
+    private void parseParam(Map<String, String> params, String[] optionalTestParams, JSONObject jsonPayload)
+            throws JSONException {
+
+        Set<String> optionalParamsSet = new HashSet<>();
+        Collections.addAll(optionalParamsSet, optionalTestParams);
+
+        //@formatter:off
+        params.entrySet()
+                .stream()
+                .filter(entry -> optionalParamsSet.contains(entry.getKey()))
+                .filter(entry -> !Strings.isNullOrEmpty(entry.getValue()))
+                .forEach(entry -> parseParam(entry, jsonPayload));
+        //@formatter:on
+    }
+
+    private void parseParam(Map.Entry<String, String> params, JSONObject jsonPayload)
+            throws JSONException {
+        String key = params.getKey();
+        String payload = params.getValue();
+
+        switch (key) {
+            case ENV_PARAMETERS_OPT_KEY:
+                JSONObject paramsJson = new JSONObject(payload);
+                jsonPayload.put(key, paramsJson);
+                break;
+
+            case FILE_PARAMETERS_OPT_KEY:
+                jsonPayload.put(key, getFilePayload(payload));
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Return payload with escaped newlines
+     */
+    private JSONObject getFilePayload(String payload) {
+        String formattedPayload = payload.replace("\n", "\\n").replace("\r", "\\r");
+        return new JSONObject(formattedPayload);
+    }
+
+    private Set<String> getListNameList(Map<String, String> paramMap) {
+        Set<String> ll = new HashSet<>();
+        for (Map.Entry<String,String> entry : paramMap.entrySet())
+            if (entry.getKey().startsWith("listName"))
+                ll.add(entry.getValue());
+        return ll;
+    }
+
+    private String parseParam(Map<String, String> paramMap, String name, boolean required, String def)
+            throws SvcLogicException {
+        String s = paramMap.get(name);
+
+        if (s == null || s.trim().length() == 0) {
+            if (!required)
+                return def;
+            throw new SvcLogicException("Parameter " + name + " is required in sshapiCallNode");
+        }
+
+        s = s.trim();
+        StringBuilder value = new StringBuilder();
+        int i = 0;
+        int i1 = s.indexOf('%');
+        while (i1 >= 0) {
+            int i2 = s.indexOf('%', i1 + 1);
+            if (i2 < 0)
+                break;
+
+            String varName = s.substring(i1 + 1, i2);
+            String varValue = System.getenv(varName);
+            if (varValue == null)
+                varValue = "%" + varName + "%";
+
+            value.append(s.substring(i, i1));
+            value.append(varValue);
+
+            i = i2 + 1;
+            i1 = s.indexOf('%', i);
+        }
+        value.append(s.substring(i));
+
+        log.info("Parameter {}: [{}]", name, value);
+        return value.toString();
+    }
+}
diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicy.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicy.java
deleted file mode 100644 (file)
index fef0f81..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * openECOMP : SDN-C
- * ================================================================================
- * * Copyright (C) 2017 AT&T Intellectual Property.
- * ================================================================================
- * Copyright (C) 2018 Samsung Electronics. All rights
- *                     reserved.
- * ================================================================================
- * Licensed 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.ccsdk.sli.plugins.sshapicall.model;
-
-public class RetryPolicy {
-    private String[] hostnames;
-    private Integer maximumRetries;  
-
-    public Integer getMaximumRetries() {
-        return maximumRetries;
-    }
-    
-    public String getNextHostName(String uri) throws RetryException {
-        Integer position = null;
-
-        for (int i = 0; i < hostnames.length; i++) {
-            if (uri.contains(hostnames[i])) {
-                position = i;
-                break;
-            }
-        }
-
-        if(position == null){
-            throw new RetryException("No match found for the provided uri[" + uri + "] " +
-                    "so the next host name could not be retreived");
-        }
-        position++;
-
-        if (position > hostnames.length - 1) {
-            position = 0;
-        }
-        return hostnames[position];
-    }
-
-    public RetryPolicy(String[] hostnames, Integer maximumRetries){
-        this.hostnames = hostnames;
-        this.maximumRetries = maximumRetries;
-    }
-    
-
-}
diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicyStore.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicyStore.java
deleted file mode 100644 (file)
index 65575b8..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * openECOMP : SDN-C
- * ================================================================================
- * * Copyright (C) 2017 AT&T Intellectual Property.
- * ================================================================================
- * Copyright (C) 2018 Samsung Electronics. All rights
- *                     reserved.
- * ================================================================================
- * Licensed 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.
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.ccsdk.sli.plugins.sshapicall.model;
-
-import java.util.HashMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RetryPolicyStore {
-    private static final Logger log = LoggerFactory.getLogger(RetryPolicyStore.class);
-
-    HashMap<String, RetryPolicy> retryPolicies;
-    public String proxyServers;
-
-    public String getProxyServers() {
-        return proxyServers;
-    }
-
-    public void setProxyServers(String admServers) {
-        this.proxyServers = admServers;
-        String[] adminServersArray = admServers.split(",");
-        RetryPolicy adminPortalRetry = new RetryPolicy(adminServersArray, adminServersArray.length);
-        retryPolicies.put("dme2proxy", adminPortalRetry);
-    }
-
-    public RetryPolicyStore() {
-        retryPolicies = new HashMap<>();
-    }
-    
-    public RetryPolicy getRetryPolicy(String policyName) {
-        return (this.retryPolicies.get(policyName));
-    }
-
-}
index 4cce6ff..50c9b2a 100644 (file)
 
     <!-- context:property-placeholder location="file:${SDNC_CONFIG_DIR}/ueb.properties" /-->
 
-    <bean id="sshapiCallNode" class="org.onap.ccsdk.sli.plugins.sshapicall.impl.SshapiCallNodeImpl">
+    <bean id="sshapiCallNode" class="org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode">
         <property name="uebServers" value="${servers}" />
-        <property name="retryPolicyStore" ref="retryPolicyStore"/>
     </bean>
 
-    <bean id="retryPolicyStore" class="org.onap.ccsdk.sli.plugins.sshapicall.model.RetryPolicyStore">
-        <property name="proxyServers" value="${proxyUrl}" />
-    </bean>
 </beans>
index c8e9a99..25631d6 100644 (file)
@@ -29,6 +29,6 @@
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-    <service ref="sshapiCallNode" interface="org.onap.ccsdk.sli.plugins.sshapicall.impl.SshapiCallNodeImpl" />
+    <service ref="sshapiCallNode" interface="org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode" />
 
 </beans:beans>
index b24aaf1..7a54243 100755 (executable)
@@ -3,7 +3,7 @@
            xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
            odl:use-default-for-reference-types="true">
 
-    <bean id="sshapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.sshapicall.impl.SshapiCallNodeImpl" />
+    <bean id="sshapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode" />
 
 
 
index 9df790a..66be730 100644 (file)
@@ -31,6 +31,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import org.codehaus.jettison.json.JSONException;
 import org.junit.Test;
 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
 import org.onap.ccsdk.sli.plugins.sshapicall.model.JsonParser;
@@ -50,8 +51,12 @@ public class TestJsonParser {
         String line;
         while ((line = in.readLine()) != null)
             b.append(line).append('\n');
-
-        Map<String, String> mm = JsonParser.convertToProperties(b.toString());
+        Map<String, String> mm = null;
+        try {
+            mm = JsonParser.convertToProperties(b.toString());
+        } catch (JSONException e){
+            throw new SvcLogicException(e.getMessage());
+        }
 
         logProperties(mm);
 
@@ -60,7 +65,12 @@ public class TestJsonParser {
 
     @Test(expected = NullPointerException.class)
     public void testNullString() throws SvcLogicException {
-        JsonParser.convertToProperties(null);
+        Map<String, String> mm = null;
+        try {
+            mm = JsonParser.convertToProperties(null);
+        } catch (JSONException e){
+            throw new SvcLogicException(e.getMessage());
+        }
     }
 
     private void logProperties(Map<String, String> mm) {