From 8b39ca99c8a49197b05f8fea7de9a1606c810e63 Mon Sep 17 00:00:00 2001 From: Ganesh Chandrasekaran Date: Tue, 24 Jul 2018 16:40:14 +0900 Subject: [PATCH] SSHApiCallNode sshExec API Impl Issue-ID: CCSDK-385 Change-Id: I430f9075ced10edb49062fc12091774e91611b32 Signed-off-by: Ganesh Chandrasekaran --- .../sli/plugins/restapicall/RestapiCallNode.java | 2 +- .../features/ccsdk-sshapi-call-node/pom.xml | 3 +- sshapi-call-node/provider/pom.xml | 10 + .../sli/plugins/sshapicall/SshApiCallNode.java | 226 ++++++++++++++--- .../sli/plugins/sshapicall/impl/AuthType.java | 19 -- .../sshapicall/impl/SshapiCallNodeImpl.java | 43 ---- .../model/{RetryException.java => AuthType.java} | 21 +- .../plugins/sshapicall/{impl => model}/Format.java | 2 +- .../sli/plugins/sshapicall/model/JsonParser.java | 6 +- .../sshapicall/{impl => model}/Parameters.java | 15 +- .../sli/plugins/sshapicall/model/ParseParam.java | 274 +++++++++++++++++++++ .../sli/plugins/sshapicall/model/RetryPolicy.java | 62 ----- .../plugins/sshapicall/model/RetryPolicyStore.java | 56 ----- .../META-INF/spring/sshapi-call-node-context.xml | 6 +- .../spring/sshapi-call-node-osgi-context.xml | 2 +- .../blueprint/sshapi-call-node-blueprint.xml | 2 +- .../sli/plugins/sshapicall/TestJsonParser.java | 16 +- 17 files changed, 523 insertions(+), 242 deletions(-) delete mode 100644 sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/AuthType.java delete mode 100644 sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/SshapiCallNodeImpl.java rename sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/{RetryException.java => AuthType.java} (71%) rename sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/{impl => model}/Format.java (96%) rename sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/{impl => model}/Parameters.java (83%) create mode 100644 sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java delete mode 100644 sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicy.java delete mode 100644 sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicyStore.java diff --git a/restapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/restapicall/RestapiCallNode.java b/restapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/restapicall/RestapiCallNode.java index 5168b3ec..42462f0e 100644 --- a/restapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/restapicall/RestapiCallNode.java +++ b/restapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/restapicall/RestapiCallNode.java @@ -90,7 +90,7 @@ public class RestapiCallNode implements SvcLogicJavaPlugin { /** * Allows Directed Graphs the ability to interact with REST APIs. - * @param parameters HashMap of parameters passed by the DG to this function + * @param paramMap HashMap of parameters passed by the DG to this function * * * diff --git a/sshapi-call-node/features/ccsdk-sshapi-call-node/pom.xml b/sshapi-call-node/features/ccsdk-sshapi-call-node/pom.xml index 12ec0686..7b74d6de 100644 --- a/sshapi-call-node/features/ccsdk-sshapi-call-node/pom.xml +++ b/sshapi-call-node/features/ccsdk-sshapi-call-node/pom.xml @@ -36,7 +36,7 @@ - + diff --git a/sshapi-call-node/provider/pom.xml b/sshapi-call-node/provider/pom.xml index 165003ff..e380d7c2 100755 --- a/sshapi-call-node/provider/pom.xml +++ b/sshapi-call-node/provider/pom.xml @@ -39,6 +39,16 @@ org.onap.ccsdk.sli.coresli-provider + + org.onap.appc + appc-ssh-adapter-api + 1.3.0 + provided + + + org.json + json + org.slf4j slf4j-api diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java index 4efddec8..e4b082cd 100644 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java +++ b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java @@ -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 @@ -16,36 +17,89 @@ * 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 of parameters passed by the DG to this function + * @param params HashMap of parameters passed by the DG to this function *
parameterMandatory/Optionaldescriptionexample values
* * * - * - * - * - * - * - * + * + * + * + * + * + * + * + * + * + * * vpn-information.vrf-details - * - * - * + * + * + * + * * *
parameterMandatory/Optionaldescriptionexample values
templateFileNameOptionalfull path to template file that can be used to build a request/sdncopt/bvc/sshapi/templates/vnf_service-configuration-operation_minimal.json
sshapiUrlMandatoryurl to make the SSH connection request to.
sshapiUserOptionaluser name to use for ssh basic authenticationsdnc_ws
sshapiPasswordOptionalunencrypted password to use for ssh basic authenticationplain_password
sshKeyOptionalConsumer SSH key to use for ssh authenticationplain_key
cmdMandatoryssh command to be executed on the server.get post put delete patch
responsePrefixOptionallocation the response will be written to in context memorytmp.sshapi.result
UrlMandatoryurl to make the SSH connection request to.
PortMandatoryport to make the SSH connection request to.
UserOptionaluser name to use for ssh basic authenticationsdnc_ws
PasswordOptionalunencrypted password to use for ssh basic authenticationplain_password
SshKeyOptionalConsumer SSH key to use for ssh authenticationplain_key
ExecTimeoutOptionalSSH command execution timeoutplain_key
RetryOptionalMake ssh connection with default retry policyplain_key
CmdMandatoryssh command to be executed on the server.get post put delete patch
ResponsePrefixOptionallocation the response will be written to in context memorytmp.sshapi.result
ResponseTypeOptionalIf we know the response is to be in a specific format (supported are JSON, XML and NONE) tmp.sshapi.result
listName[i]OptionalUsed for processing XML responses with repeating elements.
convertResponse Optionalwhether the response should be convertedtrue or false
dumpHeadersOptionalwhen true writes ssh response content to context memorytrue or false
returnRequestPayloadOptionalused to return payload built in the requesttrue or false
ConvertResponse Optionalwhether the response should be convertedtrue or false
AuthTypeOptionalType of authentiation to be used BASIC or sshKey basedtrue or false
EnvParametersOptionalA 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.
FileParametersOptionalA 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.
* 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 paramMap, SvcLogicContext ctx) throws SvcLogicException; + + public void execCommand(Map 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 of parameters passed by the DG to this function + * @param params HashMap of parameters passed by the DG to this function * * * * - * - * - * - * - * - * + * + * + * + * + * + * + * + * + * + * * vpn-information.vrf-details - * - * - * + * + * + * + * * *
parameterMandatory/Optionaldescriptionexample values
templateFileNameOptionalfull path to template file that can be used to build a request/sdncopt/bvc/sshapi/templates/vnf_service-configuration-operation_minimal.json
sshapiUrlMandatoryurl to make the SSH connection request to.
sshapiUserOptionaluser name to use for ssh basic authenticationsdnc_ws
sshapiPasswordOptionalunencrypted password to use for ssh basic authenticationplain_password
sshKeyOptionalConsumer SSH key to use for ssh authenticationplain_key
cmdMandatoryssh command to be executed on the server.get post put delete patch
responsePrefixOptionallocation the response will be written to in context memorytmp.sshapi.result
UrlMandatoryurl to make the SSH connection request to.
PortMandatoryport to make the SSH connection request to.
UserOptionaluser name to use for ssh basic authenticationsdnc_ws
PasswordOptionalunencrypted password to use for ssh basic authenticationplain_password
SshKeyOptionalConsumer SSH key to use for ssh authenticationplain_key
ExecTimeoutOptionalSSH command execution timeoutplain_key
RetryOptionalMake ssh connection with default retry policyplain_key
CmdMandatoryssh command to be executed on the server.get post put delete patch
ResponsePrefixOptionallocation the response will be written to in context memorytmp.sshapi.result
ResponseTypeOptionalIf we know the response is to be in a specific format (supported are JSON, XML and NONE) tmp.sshapi.result
listName[i]OptionalUsed for processing XML responses with repeating elements.
convertResponse Optionalwhether the response should be convertedtrue or false
dumpHeadersOptionalwhen true writes ssh response content to context memorytrue or false
returnRequestPayloadOptionalused to return payload built in the requesttrue or false
ConvertResponse Optionalwhether the response should be convertedtrue or false
AuthTypeOptionalType of authentiation to be used BASIC or sshKey basedtrue or false
EnvParametersOptionalA 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.
FileParametersOptionalA 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.
- * 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 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 of parameters passed by the DG to this function + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * vpn-information.vrf-details + * + * + * + * + * + *
parameterMandatory/Optionaldescriptionexample values
templateFileNameOptionalfull path to template file that can be used to build a request/sdncopt/bvc/sshapi/templates/vnf_service-configuration-operation_minimal.json
UrlMandatoryurl to make the SSH connection request to.
PortMandatoryport to make the SSH connection request to.
UserOptionaluser name to use for ssh basic authenticationsdnc_ws
PasswordOptionalunencrypted password to use for ssh basic authenticationplain_password
SshKeyOptionalConsumer SSH key to use for ssh authenticationplain_key
ExecTimeoutOptionalSSH command execution timeoutplain_key
RetryOptionalMake ssh connection with default retry policyplain_key
CmdMandatoryssh command to be executed on the server.get post put delete patch
ResponsePrefixOptionallocation the response will be written to in context memorytmp.sshapi.result
ResponseTypeOptionalIf we know the response is to be in a specific format (supported are JSON, XML and NONE) tmp.sshapi.result
listName[i]OptionalUsed for processing XML responses with repeating elements.
ConvertResponse Optionalwhether the response should be convertedtrue or false
AuthTypeOptionalType of authentiation to be used BASIC or sshKey basedtrue or false
EnvParametersOptionalA 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.
FileParametersOptionalA 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.
+ * 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 paramMap, SvcLogicContext ctx) throws SvcLogicException ; + public void execCommandWithPty(Map 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 index 30816227..00000000 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/AuthType.java +++ /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 index 9283b8b5..00000000 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/SshapiCallNodeImpl.java +++ /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 paramMap, SvcLogicContext ctx) throws SvcLogicException { - //TODO: Implementation - } - - @Override - public void execCommandWithPty(Map paramMap, SvcLogicContext ctx) throws SvcLogicException { - //TODO: Implementation - } -} diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryException.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/AuthType.java similarity index 71% rename from sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryException.java rename to sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/AuthType.java index 9a1d3a31..2ec48c70 100644 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryException.java +++ b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/AuthType.java @@ -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. @@ -23,10 +24,18 @@ 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); } - } diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Format.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Format.java similarity index 96% rename from sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Format.java rename to sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Format.java index 75604de6..e50a96c6 100644 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Format.java +++ b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Format.java @@ -22,7 +22,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.ccsdk.sli.plugins.sshapicall.impl; +package org.onap.ccsdk.sli.plugins.sshapicall.model; public enum Format { JSON, XML, NONE; diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java index e840053f..f40f1ad7 100644 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java +++ b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java @@ -47,11 +47,10 @@ public final class JsonParser { @SuppressWarnings("unchecked") public static Map convertToProperties(String s) - throws SvcLogicException { + throws JSONException { checkNotNull(s, "Input should not be null."); - try { JSONObject json = new JSONObject(s); Map wm = new HashMap<>(); Iterator 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); - } } } diff --git a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Parameters.java b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Parameters.java similarity index 83% rename from sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Parameters.java rename to sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Parameters.java index a392cc73..a22da5bc 100644 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/impl/Parameters.java +++ b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Parameters.java @@ -21,22 +21,25 @@ * ============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 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 index 00000000..caf49ef9 --- /dev/null +++ b/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java @@ -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 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 listNameList) throws SvcLogicException { + Map mm = XmlParser.convertToProperties(outMessage, p.listNameList); + toCtx (ctx, mm); + } + + private void toCtx (SvcLogicContext ctx, Map mm) { + if (mm != null) { + for (Map.Entry 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 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 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 params, String[] optionalTestParams, JSONObject jsonPayload) + throws JSONException { + + Set 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 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 getListNameList(Map paramMap) { + Set ll = new HashSet<>(); + for (Map.Entry entry : paramMap.entrySet()) + if (entry.getKey().startsWith("listName")) + ll.add(entry.getValue()); + return ll; + } + + private String parseParam(Map 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 index fef0f81a..00000000 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicy.java +++ /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 index 65575b8c..00000000 --- a/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/RetryPolicyStore.java +++ /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 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)); - } - -} diff --git a/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml b/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml index 4cce6ffa..50c9b2aa 100644 --- a/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml +++ b/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml @@ -40,12 +40,8 @@ - + - - - - diff --git a/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml b/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml index c8e9a99e..25631d6a 100644 --- a/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml +++ b/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml @@ -29,6 +29,6 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - + diff --git a/sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml b/sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml index b24aaf1e..7a542432 100755 --- a/sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml +++ b/sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml @@ -3,7 +3,7 @@ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" odl:use-default-for-reference-types="true"> - + diff --git a/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/sshapicall/TestJsonParser.java b/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/sshapicall/TestJsonParser.java index 9df790ae..66be7300 100644 --- a/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/sshapicall/TestJsonParser.java +++ b/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/sshapicall/TestJsonParser.java @@ -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 mm = JsonParser.convertToProperties(b.toString()); + Map 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 mm = null; + try { + mm = JsonParser.convertToProperties(null); + } catch (JSONException e){ + throw new SvcLogicException(e.getMessage()); + } } private void logProperties(Map mm) { -- 2.16.6