From 67c775f8adfce8b0e139ce9e6b70386047090c69 Mon Sep 17 00:00:00 2001 From: Ganesh Chandrasekaran Date: Tue, 10 Jul 2018 18:27:17 +0900 Subject: saltstack reqExecSls implemented as adaptor Issue-ID: CCSDK-330 Change-Id: Icdb2c70d94d4901f1b18713b8b33666169a2b6d9 Signed-off-by: Ganesh Chandrasekaran --- .../sli/adaptors/saltstack/SaltstackAdapter.java | 12 +- .../adaptors/saltstack/impl/ConnectionBuilder.java | 49 +++-- .../saltstack/impl/SaltstackAdapterImpl.java | 200 +++++++++++++-------- .../SaltstackAdapterPropertiesProviderImpl.java | 51 +++--- .../sli/adaptors/saltstack/impl/SshConnection.java | 51 +++--- .../sli/adaptors/saltstack/model/JsonParser.java | 74 ++++---- .../saltstack/model/SaltstackMessageParser.java | 196 ++++++++++++++++---- .../adaptors/saltstack/model/SaltstackResult.java | 36 ++-- .../saltstack/model/SaltstackResultCodes.java | 6 +- .../saltstack/model/SaltstackServerEmulator.java | 58 ++---- 10 files changed, 447 insertions(+), 286 deletions(-) (limited to 'saltstack-adapter/saltstack-adapter-provider/src/main') diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/SaltstackAdapter.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/SaltstackAdapter.java index 2f70a79a..1cbb495c 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/SaltstackAdapter.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/SaltstackAdapter.java @@ -24,14 +24,14 @@ package org.onap.ccsdk.sli.adaptors.saltstack; -import java.util.Map; import org.onap.ccsdk.sli.core.sli.SvcLogicContext; import org.onap.ccsdk.sli.core.sli.SvcLogicException; import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +import java.util.Map; + /** * This interface defines the operations that the Saltstack adapter exposes. - * */ public interface SaltstackAdapter extends SvcLogicJavaPlugin { /** @@ -46,11 +46,16 @@ public interface SaltstackAdapter extends SvcLogicJavaPlugin { * to context for DGs access, with a certain prefix*/ void reqExecCommand(Map params, SvcLogicContext ctx) throws SvcLogicException; + /* Method for execution of saltstack SLS command on SaltState server + * The response from Saltstack comes in json format and it is automatically put + * to context for DGs access, with a certain prefix*/ + void reqExecSLS(Map params, SvcLogicContext ctx) throws SvcLogicException; + /* When SLS file is created/available then this Method can be used to post * the file to saltstack server and execute the SLS file on SaltState server * The response from Saltstack comes in json format and it is automatically put * to context for DGs access, with a certain prefix*/ - void reqExecSLS(Map params, SvcLogicContext ctx) throws SvcLogicException; + void reqExecSLSFile(Map params, SvcLogicContext ctx) throws SvcLogicException; /* Method to get log of a saltState execution request * The response from Saltstack comes in json format and it is automatically put @@ -59,6 +64,7 @@ public interface SaltstackAdapter extends SvcLogicJavaPlugin { /** * Set the command execution timeout + * * @param timeout time in milliseconds */ void setExecTimeout(long timeout); diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/ConnectionBuilder.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/ConnectionBuilder.java index 5dee9f5e..65ab598d 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/ConnectionBuilder.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/ConnectionBuilder.java @@ -24,7 +24,13 @@ package org.onap.ccsdk.sli.adaptors.saltstack.impl; -import java.io.BufferedOutputStream; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.RandomStringUtils; +import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResult; +import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResultCodes; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -32,15 +38,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; -import java.util.List; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.RandomStringUtils; -import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResult; -import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResultCodes; -import org.onap.ccsdk.sli.core.sli.SvcLogicException; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; /** * Returns a custom SSH client @@ -88,7 +85,7 @@ public class ConnectionBuilder { * @return command execution status */ public SaltstackResult connectNExecute(String cmd) { - return connectNExecute(cmd,-1,-1); + return connectNExecute(cmd, -1, -1); } /** @@ -96,7 +93,7 @@ public class ConnectionBuilder { * 2. Exec remote command over SSH. Return command execution status. * Command output is written to out or err stream. * - * @param cmd Commands to execute + * @param cmd Commands to execute * @param retryDelay delay between retry to make a SSH connection. * @param retryCount number of count retry to make a SSH connection. * @return command execution status @@ -113,8 +110,8 @@ public class ConnectionBuilder { if (result.getStatusCode() != SaltstackResultCodes.SUCCESS.getValue()) { return result; } - String outFilePath = "/tmp/"+ RandomStringUtils.random(5,true,true); - String errFilePath = "/tmp/"+ RandomStringUtils.random(5,true,true); + String outFilePath = "/tmp/" + RandomStringUtils.random(5, true, true); + String errFilePath = "/tmp/" + RandomStringUtils.random(5, true, true); OutputStream out = new FileOutputStream(outFilePath); OutputStream errs = new FileOutputStream(errFilePath); result = sshConnection.execCommand(cmd, out, errs); @@ -137,40 +134,42 @@ public class ConnectionBuilder { return result; } - public SaltstackResult sortExitStatus (int exitStatus, String errFilePath, String cmd) { + public SaltstackResult sortExitStatus(int exitStatus, String errFilePath, String cmd) { SaltstackResult result = new SaltstackResult(); - String err; + String err = ""; StringWriter writer = new StringWriter(); try { IOUtils.copy(new FileInputStream(new File(errFilePath)), writer, "UTF-8"); err = writer.toString(); - } catch (Exception e){ - err = ""; + } catch (FileNotFoundException e){ + logger.info("Error stream file doesn't exist"); + } catch (IOException e){ + logger.info("Error stream file doesn't exist"); } if (exitStatus == 255 || exitStatus == 1) { String errMessage = "Error executing command [" + cmd + "] over SSH [" + sshConnection.toString() + "]. Exit Code " + exitStatus + " and Error message : " + - "Malformed configuration. "+ err; + "Malformed configuration. " + err; logger.error(errMessage); result.setStatusCode(SaltstackResultCodes.INVALID_COMMAND.getValue()); result.setStatusMessage(errMessage); } else if (exitStatus == 5 || exitStatus == 65) { String errMessage = "Error executing command [" + cmd + "] over SSH [" + sshConnection.toString() + "]. Exit Code " + exitStatus + " and Error message : " + - "Host not allowed to connect. "+ err; + "Host not allowed to connect. " + err; logger.error(errMessage); result.setStatusCode(SaltstackResultCodes.USER_UNAUTHORIZED.getValue()); result.setStatusMessage(errMessage); } else if (exitStatus == 67 || exitStatus == 73) { String errMessage = "Error executing command [" + cmd + "] over SSH [" + sshConnection.toString() + "]. Exit Code " + exitStatus + " and Error message : " + - "Key exchange failed. "+ err; + "Key exchange failed. " + err; logger.error(errMessage); result.setStatusCode(SaltstackResultCodes.CERTIFICATE_ERROR.getValue()); result.setStatusMessage(errMessage); } else { String errMessage = "Error executing command [" + cmd + "] over SSH [" + sshConnection.toString() - + "]. Exit Code " + exitStatus + " and Error message : "+ err; + + "]. Exit Code " + exitStatus + " and Error message : " + err; logger.error(errMessage); result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); result.setStatusMessage(errMessage); @@ -183,7 +182,7 @@ public class ConnectionBuilder { * 2. Exec remote command over SSH. Return command execution status. * Command output is written to out or err stream. * - * @param commands list of commands to execute + * @param commands list of commands to execute * @param payloadSLS has the SLS file location that is to be sent to server * @param retryDelay delay between retry to make a SSH connection. * @param retryCount number of count retry to make a SSH connection. @@ -205,7 +204,7 @@ public class ConnectionBuilder { /** * Disconnect from SSH server. */ - public SaltstackResult disConnect(){ + public SaltstackResult disConnect() { SaltstackResult result = new SaltstackResult(); try { @@ -225,7 +224,7 @@ public class ConnectionBuilder { * @param cmd command to execute * @return command execution status */ - public SaltstackResult execute(String cmd) { + public SaltstackResult connectNExecuteLog(String cmd) { SaltstackResult result = new SaltstackResult(); diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterImpl.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterImpl.java index 5fe130fc..e3046dba 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterImpl.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterImpl.java @@ -24,11 +24,8 @@ package org.onap.ccsdk.sli.adaptors.saltstack.impl; -import java.util.Map; -import java.util.Properties; -import org.apache.commons.lang.StringUtils; -import org.json.JSONException; -import org.json.JSONObject; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; import org.onap.ccsdk.sli.adaptors.saltstack.SaltstackAdapter; import org.onap.ccsdk.sli.adaptors.saltstack.SaltstackAdapterPropertiesProvider; import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackMessageParser; @@ -37,8 +34,14 @@ import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResultCodes; import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackServerEmulator; import org.onap.ccsdk.sli.core.sli.SvcLogicContext; import org.onap.ccsdk.sli.core.sli.SvcLogicException; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; /** * This class implements the {@link SaltstackAdapter} interface. This interface defines the behaviors @@ -46,56 +49,45 @@ import com.att.eelf.configuration.EELFManager; */ public class SaltstackAdapterImpl implements SaltstackAdapter { - private static final long EXEC_TIMEOUT = 120000; - private long timeout = EXEC_TIMEOUT; - /** * The constant used to define the service name in the mapped diagnostic context */ @SuppressWarnings("nls") public static final String MDC_SERVICE = "service"; - /** * The constant for the status code for a failed outcome */ @SuppressWarnings("nls") public static final String OUTCOME_FAILURE = "failure"; - /** * The constant for the status code for a successful outcome */ @SuppressWarnings("nls") public static final String OUTCOME_SUCCESS = "success"; - + public static final String CONNECTION_RETRY_DELAY = "retryDelay"; + public static final String CONNECTION_RETRY_COUNT = "retryCount"; + private static final long EXEC_TIMEOUT = 120000; /** * Adapter Name */ private static final String ADAPTER_NAME = "Saltstack Adapter"; private static final String APPC_EXCEPTION_CAUGHT = "APPCException caught"; - private static final String RESULT_CODE_ATTRIBUTE_NAME = "org.onap.appc.adapter.saltstack.result.code"; private static final String MESSAGE_ATTRIBUTE_NAME = "org.onap.appc.adapter.saltstack.message"; private static final String RESULTS_ATTRIBUTE_NAME = "org.onap.appc.adapter.saltstack.results"; private static final String ID_ATTRIBUTE_NAME = "org.onap.appc.adapter.saltstack.Id"; private static final String LOG_ATTRIBUTE_NAME = "org.onap.appc.adapter.saltstack.log"; - - public static final String CONNECTION_RETRY_DELAY = "retryDelay"; - public static final String CONNECTION_RETRY_COUNT = "retryCount"; - private static final String CLIENT_TYPE_PROPERTY_NAME = "org.onap.appc.adapter.saltstack.clientType"; private static final String SS_SERVER_HOSTNAME = "org.onap.appc.adapter.saltstack.host"; private static final String SS_SERVER_PORT = "org.onap.appc.adapter.saltstack.port"; private static final String SS_SERVER_USERNAME = "org.onap.appc.adapter.saltstack.userName"; private static final String SS_SERVER_PASSWORD = "org.onap.appc.adapter.saltstack.userPasswd"; private static final String SS_SERVER_SSH_KEY = "org.onap.appc.adapter.saltstack.sshKey"; - - /** * The logger to be used */ private static final EELFLogger logger = EELFManager.getInstance().getLogger(SaltstackAdapterImpl.class); - - + private long timeout = EXEC_TIMEOUT; /** * Connection object **/ @@ -122,6 +114,7 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { public SaltstackAdapterImpl() { initialize(new SaltstackAdapterPropertiesProviderImpl()); } + public SaltstackAdapterImpl(SaltstackAdapterPropertiesProvider propProvider) { initialize(propProvider); } @@ -150,9 +143,10 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { public void setExecTimeout(long timeout) { this.timeout = timeout; } + /** - * Method posts info to Context memory in case of an error and throws a - * SvcLogicException causing SLI to register this as a failure + * Method posts info to Context memory in case of an error and throws a + * SvcLogicException causing SLI to register this as a failure */ @SuppressWarnings("static-method") private void doFailure(SvcLogicContext svcLogic, int code, String message) throws SvcLogicException { @@ -160,7 +154,6 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { svcLogic.setStatus(OUTCOME_FAILURE); svcLogic.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(code)); svcLogic.setAttribute(MESSAGE_ATTRIBUTE_NAME, message); - throw new SvcLogicException("Saltstack Adapter Error = " + message); } @@ -222,16 +215,8 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { logger.info("Initialized Saltstack Adapter"); } - // Public Method to post single command request to execute saltState. Posts the following back - // to Svc context memory - // org.onap.appc.adapter.saltstack.req.code : 100 if successful - // org.onap.appc.adapter.saltstack.req.messge : any message - // org.onap.appc.adapter.saltstack.req.Id : a unique uuid to reference the request - @Override - public void reqExecCommand(Map params, SvcLogicContext ctx) throws SvcLogicException { - String reqID; - SaltstackResult testResult; - if (sshClient == null){ + private void setSSHClient(Map params) throws SvcLogicException { + if (sshClient == null) { logger.info("saltstack-adapter.properties not defined so reading saltstack host and " + "auth details from DG's parameters"); String sshHost = messageProcessor.reqHostNameResult(params); @@ -239,59 +224,130 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { String sshUserName = messageProcessor.reqUserNameResult(params); String sshPassword = messageProcessor.reqPasswordResult(params); logger.info("Creating ssh client with BASIC Auth"); - if(!testMode) + if (!testMode) { sshClient = new ConnectionBuilder(sshHost, sshPort, sshUserName, sshPassword); + } } + } + + private String putToCommands(SvcLogicContext ctx, String slsFileName, + String reqID, String applyTo) throws SvcLogicException { + String constructedCommand = ""; try { - reqID = params.get("Id"); - String commandToExecute = params.get("cmd"); - testResult = execCommand(params, commandToExecute); - testResult = messageProcessor.parseResponse(ctx, reqID, testResult); - - // Check status of test request returned by Agent - if (testResult.getStatusCode() == SaltstackResultCodes.FINAL_SUCCESS.getValue()) { - logger.info(String.format("Execution of request-ID : %s successful.", reqID)); - testResult.setResults("Success"); + File file = new File(slsFileName); + InputStream in = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + in.read(data); + String str = new String(data, "UTF-8"); + in.close(); + constructedCommand = "echo "+str+" > /srv/salt/"+reqID+".sls; salt '"+applyTo+"' state.apply "+reqID+" --out=json --static"; + } catch (FileNotFoundException e) { + doFailure(ctx, SaltstackResultCodes.IO_EXCEPTION.getValue(), "Input SLS file " + + "not found in path : " + slsFileName+". "+ e.getMessage()); + } catch (IOException e) { + doFailure(ctx, SaltstackResultCodes.IO_EXCEPTION.getValue(), "Input SLS file " + + "error in path : " + slsFileName +". "+ e.getMessage()); + } + logger.info("Command to be executed on server : " + constructedCommand); + return constructedCommand; + } + + private String putToCommands(String slsName, String applyTo) { + String + constructedCommand = "cd /srv/salt/; salt '"+applyTo+"' state.apply "+slsName+" --out=json --static"; + + logger.info("Command to be executed on server : " + constructedCommand); + return constructedCommand; + } + + private void checkResponseStatus(SaltstackResult testResult, SvcLogicContext ctx, String reqID, boolean slsExec) + throws SvcLogicException { + + // Check status of test request returned by Agent + if (testResult.getStatusCode() != SaltstackResultCodes.FINAL_SUCCESS.getValue()) { + doFailure(ctx, testResult.getStatusCode(), "Request for execution of command failed. Reason = " + testResult.getStatusMessage()); + ctx.setAttribute(ID_ATTRIBUTE_NAME, reqID); + return; + } else { + logger.info(String.format("Execution of request : successful.")); + if (slsExec) { + ctx.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(testResult.getStatusCode())); + ctx.setAttribute(MESSAGE_ATTRIBUTE_NAME, "success"); } else { - doFailure(ctx, testResult.getStatusCode(), "Request for execution of command failed. Reason = " + testResult.getStatusMessage()); - return; + ctx.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(SaltstackResultCodes.CHECK_CTX_FOR_CMD_SUCCESS.getValue())); + ctx.setAttribute(MESSAGE_ATTRIBUTE_NAME, "check context for execution status"); } - } catch (SvcLogicException e) { - logger.error(APPC_EXCEPTION_CAUGHT, e); - doFailure(ctx, SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue(), - "Request for execution of command failed. Reason = " - + e.getMessage()); - return; - } catch (Exception e) { - logger.error("Exception caught", e); - doFailure(ctx, SaltstackResultCodes.INVALID_COMMAND.getValue(), - "Request for execution of command failed. Reason = " - + e.getMessage()); - return; + ctx.setAttribute(ID_ATTRIBUTE_NAME, reqID); } - ctx.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(testResult.getStatusCode())); - ctx.setAttribute(MESSAGE_ATTRIBUTE_NAME, testResult.getResults()); - ctx.setAttribute(ID_ATTRIBUTE_NAME, reqID); + } + + // Public Method to post single command request to execute saltState. Posts the following back + // to Svc context memory + // org.onap.appc.adapter.saltstack.req.code : 100 if successful + // org.onap.appc.adapter.saltstack.req.messge : any message + // org.onap.appc.adapter.saltstack.req.Id : a unique uuid to reference the request + @Override + public void reqExecCommand(Map params, SvcLogicContext ctx) throws SvcLogicException { + String reqID; + boolean slsExec; + SaltstackResult testResult; + setSSHClient(params); + reqID = messageProcessor.reqId(params); + String commandToExecute = messageProcessor.reqCmd(params); + slsExec = messageProcessor.reqIsSLSExec(params); + testResult = execCommand(params, commandToExecute); + testResult = messageProcessor.parseResponse(ctx, reqID, testResult, slsExec); + checkResponseStatus(testResult, ctx, reqID, slsExec); } /** - * Public Method to post SLS file request to execute saltState. Posts the following back + * Public Method to post SLS command request to execute saltState on server. Posts the following back * to Svc context memory - * - * org.onap.appc.adapter.saltstack.req.code : 100 if successful + *

+ * org.onap.appc.adapter.saltstack.req.code : 200 if successful * org.onap.appc.adapter.saltstack.req.messge : any message * org.onap.appc.adapter.saltstack.req.Id : a unique uuid to reference the request */ @Override public void reqExecSLS(Map params, SvcLogicContext ctx) throws SvcLogicException { - //TODO: to implement + String reqID; + SaltstackResult testResult; + setSSHClient(params); + reqID = messageProcessor.reqId(params); + String slsName = messageProcessor.reqSlsName(params); + String applyTo = messageProcessor.reqApplyToDevices(params); + String commandToExecute = putToCommands(slsName, applyTo); + testResult = execCommand(params, commandToExecute); + testResult = messageProcessor.parseResponse(ctx, reqID, testResult, true); + checkResponseStatus(testResult, ctx, reqID, true); + } + /** + * Public Method to post SLS file request to execute saltState. Posts the following back + * to Svc context memory + *

+ * org.onap.appc.adapter.saltstack.req.code : 100 if successful + * org.onap.appc.adapter.saltstack.req.messge : any message + * org.onap.appc.adapter.saltstack.req.Id : a unique uuid to reference the request + */ + @Override + public void reqExecSLSFile(Map params, SvcLogicContext ctx) throws SvcLogicException { + String reqID; + SaltstackResult testResult; + setSSHClient(params); + reqID = messageProcessor.reqId(params); + String slsFile = messageProcessor.reqSlsFile(params); + String applyTo = messageProcessor.reqApplyToDevices(params); + String commandToExecute = putToCommands(ctx, slsFile, reqID, applyTo); + testResult = execCommand(params, commandToExecute); + testResult = messageProcessor.parseResponse(ctx, reqID, testResult, true); + checkResponseStatus(testResult, ctx, reqID, true); } /** * Public method to get logs from saltState execution for a specific request Posts the following back * to Svc context memory - * + *

* It blocks till the Saltstack Server responds or the session times out very similar to * reqExecResult logs are returned in the DG context variable org.onap.appc.adapter.saltstack.log */ @@ -301,20 +357,20 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { } - public SaltstackResult execCommand(Map params, String commandToExecute){ + public SaltstackResult execCommand(Map params, String commandToExecute) { SaltstackResult testResult; if (params.get(CONNECTION_RETRY_DELAY) != null && params.get(CONNECTION_RETRY_COUNT) != null) { int retryDelay = Integer.parseInt(params.get(CONNECTION_RETRY_DELAY)); int retryCount = Integer.parseInt(params.get(CONNECTION_RETRY_COUNT)); - if(!testMode) + if (!testMode) { testResult = sshClient.connectNExecute(commandToExecute, retryCount, retryDelay); - else { + } else { testResult = testServer.MockReqExec(params); } } else { - if(!testMode) + if (!testMode) { testResult = sshClient.connectNExecute(commandToExecute); - else { + } else { testResult = testServer.MockReqExec(params); } } diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterPropertiesProviderImpl.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterPropertiesProviderImpl.java index 24308851..a4156558 100755 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterPropertiesProviderImpl.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterPropertiesProviderImpl.java @@ -20,13 +20,6 @@ package org.onap.ccsdk.sli.adaptors.saltstack.impl; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Optional; -import java.util.Properties; -import java.util.Vector; import org.onap.ccsdk.sli.adaptors.saltstack.SaltstackAdapterPropertiesProvider; import org.onap.ccsdk.sli.core.sli.ConfigurationException; import org.onap.ccsdk.sli.core.utils.JREFileResolver; @@ -37,11 +30,19 @@ import org.onap.ccsdk.sli.core.utils.common.SdncConfigEnvVarFileResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; +import java.util.Vector; + /** * Responsible for determining the properties file to use and instantiating the * SqlResource Service. The priority for properties file * resolution is as follows: - * + *

*

    *
  1. A directory identified by the system environment variable * SDNC_CONFIG_DIR
  2. @@ -93,8 +94,8 @@ public class SaltstackAdapterPropertiesProviderImpl implements SaltstackAdapterP properties.load(fileInputStream); } catch (final IOException e) { LOG.error("Failed to load properties for file: {}", propertiesFile.toString(), - new ConfigurationException("Failed to load properties for file: " + propertiesFile.toString(), - e)); + new ConfigurationException("Failed to load properties for file: " + propertiesFile.toString(), + e)); } } else { // Try to read properties as resource @@ -123,23 +124,12 @@ public class SaltstackAdapterPropertiesProviderImpl implements SaltstackAdapterP } } - /** - * Extract svclogic config properties. - * - * @return the svclogic config properties - */ - public Properties getProperties() { - return properties; - } - /** * Reports the method chosen for properties resolution to the * Logger. * - * @param message - * Some user friendly message - * @param fileOptional - * The file location of the chosen properties file + * @param message Some user friendly message + * @param fileOptional The file location of the chosen properties file * @return the file location of the chosen properties file */ private static File reportSuccess(final String message, final Optional fileOptional) { @@ -155,16 +145,23 @@ public class SaltstackAdapterPropertiesProviderImpl implements SaltstackAdapterP * Reports fatal errors. This is the case in which no properties file could be * found. * - * @param message - * An appropriate fatal error message - * @param configurationException - * An exception describing what went wrong during resolution + * @param message An appropriate fatal error message + * @param configurationException An exception describing what went wrong during resolution */ private static void reportFailure(final String message, final ConfigurationException configurationException) { LOG.error("{}", message, configurationException); } + /** + * Extract svclogic config properties. + * + * @return the svclogic config properties + */ + public Properties getProperties() { + return properties; + } + /** * Determines the sql-resource properties file to use based on the following priority: *
      diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SshConnection.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SshConnection.java index 41e6102d..96ed7d2d 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SshConnection.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SshConnection.java @@ -9,22 +9,23 @@ * 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. - * + * * ECOMP is a trademark and service mark of AT&T Intellectual Property. * ============LICENSE_END========================================================= */ package org.onap.ccsdk.sli.adaptors.saltstack.impl; -import org.onap.appc.encryption.EncryptionTool; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; import org.apache.sshd.ClientChannel; import org.apache.sshd.ClientSession; import org.apache.sshd.SshClient; @@ -33,12 +34,9 @@ import org.apache.sshd.client.future.AuthFuture; import org.apache.sshd.client.future.OpenFuture; import org.apache.sshd.common.KeyPairProvider; import org.apache.sshd.common.keyprovider.FileKeyPairProvider; - -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.onap.appc.encryption.EncryptionTool; import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResult; import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResultCodes; -import org.onap.ccsdk.sli.core.sli.SvcLogicException; import java.io.OutputStream; import java.security.KeyPair; @@ -48,11 +46,11 @@ import java.security.KeyPair; */ class SshConnection { + public static final int DEFAULT_CONNECTION_RETRY_DELAY = 60; + public static final int DEFAULT_CONNECTION_RETRY_COUNT = 5; private static final EELFLogger logger = EELFManager.getInstance().getApplicationLogger(); - private static final long AUTH_TIMEOUT = 60000; private static final long EXEC_TIMEOUT = 120000; - private String host; private int port; private String username; @@ -62,9 +60,6 @@ class SshConnection { private SshClient sshClient; private ClientSession clientSession; - public static final int DEFAULT_CONNECTION_RETRY_DELAY = 60; - public static final int DEFAULT_CONNECTION_RETRY_COUNT = 5; - public SshConnection(String host, int port, String username, String password, String keyFile) { this.host = host; this.port = port; @@ -87,13 +82,13 @@ class SshConnection { sshClient.start(); try { clientSession = - sshClient.connect(EncryptionTool.getInstance().decrypt(username), host, port).await().getSession(); + sshClient.connect(EncryptionTool.getInstance().decrypt(username), host, port).await().getSession(); if (password != null) { clientSession.addPasswordIdentity(EncryptionTool.getInstance().decrypt(password)); } if (keyFile != null) { - KeyPairProvider keyPairProvider = new FileKeyPairProvider(new String[] { - keyFile + KeyPairProvider keyPairProvider = new FileKeyPairProvider(new String[]{ + keyFile }); KeyPair keyPair = keyPairProvider.loadKeys().iterator().next(); clientSession.addPublicKeyIdentity(keyPair); @@ -102,18 +97,18 @@ class SshConnection { authFuture.await(AUTH_TIMEOUT); if (!authFuture.isSuccess()) { String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port - + "]. Authentication failed."; + + "]. Authentication failed."; result.setStatusCode(SaltstackResultCodes.USER_UNAUTHORIZED.getValue()); result.setStatusMessage(errMessage); } } catch (RuntimeException e) { String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]." + - "Runtime Exception : "+ e.getMessage(); + "Runtime Exception : " + e.getMessage(); result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); result.setStatusMessage(errMessage); } catch (Exception e) { String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]." + - "Host Unknown : " + e.getMessage(); + "Host Unknown : " + e.getMessage(); result.setStatusCode(SaltstackResultCodes.HOST_UNKNOWN.getValue()); result.setStatusMessage(errMessage); } @@ -127,10 +122,12 @@ class SshConnection { public SaltstackResult connectWithRetry(int retryCount, int retryDelay) { int retriesLeft; SaltstackResult result = new SaltstackResult(); - if(retryCount == 0) - retryCount = DEFAULT_CONNECTION_RETRY_COUNT; - if(retryDelay == 0) - retryDelay = DEFAULT_CONNECTION_RETRY_DELAY; + if (retryCount == 0) { + retryCount = DEFAULT_CONNECTION_RETRY_COUNT; + } + if (retryDelay == 0) { + retryDelay = DEFAULT_CONNECTION_RETRY_DELAY; + } retriesLeft = retryCount + 1; do { try { @@ -142,11 +139,11 @@ class SshConnection { waitForConnection(retryDelay); retriesLeft--; logger.debug("Retrying SSH connection. Attempt [" + Integer.toString(retryCount - retriesLeft + 1) - + "] out of [" + retryCount + "]"); + + "] out of [" + retryCount + "]"); } else { throw e; } - } + } } while (retriesLeft > 0); return result; } @@ -207,12 +204,12 @@ class SshConnection { return result; } catch (RuntimeException e) { String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]." + - "Runtime Exception : "+ e.getMessage(); + "Runtime Exception : " + e.getMessage(); result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); result.setStatusMessage(errMessage); } catch (Exception e1) { String errMessage = "Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + - port + "]"+ e1.getMessage(); + port + "]" + e1.getMessage(); result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); result.setStatusMessage(errMessage); } diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/JsonParser.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/JsonParser.java index f33799fd..be1fa574 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/JsonParser.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/JsonParser.java @@ -8,9 +8,9 @@ * 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. @@ -44,46 +44,46 @@ public final class JsonParser { @SuppressWarnings("unchecked") public static Map convertToProperties(String s) - throws JSONException { + throws JSONException { checkNotNull(s, "Input should not be null."); - JSONObject json = new JSONObject(s); - Map wm = new HashMap<>(); - Iterator ii = json.keys(); - while (ii.hasNext()) { - String key1 = ii.next(); - wm.put(key1, json.get(key1)); - } - - Map mm = new HashMap<>(); - - while (!wm.isEmpty()) - for (String key : new ArrayList<>(wm.keySet())) { - Object o = wm.get(key); - wm.remove(key); - - if (o instanceof Boolean || o instanceof Number || o instanceof String) { - mm.put(key, o.toString()); - - log.info("Added property: {} : {}", key, o.toString()); - } else if (o instanceof JSONObject) { - JSONObject jo = (JSONObject) o; - Iterator i = jo.keys(); - while (i.hasNext()) { - String key1 = i.next(); - wm.put(key + "." + key1, jo.get(key1)); - } - } else if (o instanceof JSONArray) { - JSONArray ja = (JSONArray) o; - mm.put(key + "_length", String.valueOf(ja.length())); + JSONObject json = new JSONObject(s); + Map wm = new HashMap<>(); + Iterator ii = json.keys(); + while (ii.hasNext()) { + String key1 = ii.next(); + wm.put(key1, json.get(key1)); + } + + Map mm = new HashMap<>(); + + while (!wm.isEmpty()) + for (String key : new ArrayList<>(wm.keySet())) { + Object o = wm.get(key); + wm.remove(key); + + if (o instanceof Boolean || o instanceof Number || o instanceof String) { + mm.put(key, o.toString()); + + log.info("Added property: {} : {}", key, o.toString()); + } else if (o instanceof JSONObject) { + JSONObject jo = (JSONObject) o; + Iterator i = jo.keys(); + while (i.hasNext()) { + String key1 = i.next(); + wm.put(key + "." + key1, jo.get(key1)); + } + } else if (o instanceof JSONArray) { + JSONArray ja = (JSONArray) o; + mm.put(key + "_length", String.valueOf(ja.length())); - log.info("Added property: {}_length: {}", key, String.valueOf(ja.length())); + log.info("Added property: {}_length: {}", key, String.valueOf(ja.length())); - for (int i = 0; i < ja.length(); i++) - wm.put(key + '[' + i + ']', ja.get(i)); - } + for (int i = 0; i < ja.length(); i++) + wm.put(key + '[' + i + ']', ja.get(i)); } - return mm; + } + return mm; } } diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackMessageParser.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackMessageParser.java index 1ea31516..372d5657 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackMessageParser.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackMessageParser.java @@ -28,6 +28,16 @@ package org.onap.ccsdk.sli.adaptors.saltstack.model; * This module implements the APP-C/Saltstack Server interface * based on the REST API specifications */ + +import com.google.common.base.Strings; +import org.json.JSONArray; +import org.codehaus.jettison.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.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -39,14 +49,6 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.UUID; -import org.json.JSONArray; -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 com.google.common.base.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Class that validates and constructs requests sent/received from @@ -63,6 +65,12 @@ public class SaltstackMessageParser { private static final String SS_AGENT_PORT_KEY = "Port"; private static final String PASS_KEY = "Password"; private static final String USER_KEY = "User"; + private static final String CMD_EXEC = "cmd"; + private static final String IS_SLS_EXEC = "slsExec"; + private static final String SS_REQ_ID = "Id"; + private static final String SLS_FILE_LOCATION = "slsFile"; + private static final String SLS_NAME = "slsName"; + private static final String MINION_TO_APPLY = "applyTo"; private static final String LOCAL_PARAMETERS_OPT_KEY = "LocalParameters"; private static final String FILE_PARAMETERS_OPT_KEY = "FileParameters"; @@ -78,12 +86,11 @@ public class SaltstackMessageParser { * Accepts a map of strings and * a) validates if all parameters are appropriate (else, throws an exception) and * b) if correct returns a JSON object with appropriate key-value pairs to send to the server. - * + *

      * Mandatory parameters, that must be in the supplied information to the Saltstack Adapter * 1. URL to connect to * 2. credentials for URL (assume username password for now) * 3. SaltState name - * */ public JSONObject reqMessage(Map params) throws SvcLogicException { final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SALTSTATE_NAME_KEY, USER_KEY, PASS_KEY}; @@ -113,7 +120,8 @@ public class SaltstackMessageParser { */ public String reqPortResult(Map params) throws SvcLogicException { - final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, PASS_KEY}; + final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, + PASS_KEY}; for (String key : mandatoryTestParams) { throwIfMissingMandatoryParam(params, key); @@ -128,7 +136,8 @@ public class SaltstackMessageParser { */ public String reqHostNameResult(Map params) throws SvcLogicException { - final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, PASS_KEY}; + final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, + PASS_KEY}; for (String key : mandatoryTestParams) { throwIfMissingMandatoryParam(params, key); @@ -136,6 +145,109 @@ public class SaltstackMessageParser { return params.get(SS_AGENT_HOSTNAME_KEY); } + /** + * Method that validates that the Map has enough information + * to query Saltstack server for a result. If so, it returns + * the appropriate request ID. + */ + public String reqId(Map params) { + + if (params.get(SaltstackMessageParser.SS_REQ_ID) == null) { + return UUID.randomUUID().toString(); + } else if (params.get(SaltstackMessageParser.SS_REQ_ID).equalsIgnoreCase("")) { + return UUID.randomUUID().toString(); + } + return params.get(SaltstackMessageParser.SS_REQ_ID); + } + + /** + * Method that validates that the Map has enough information + * to query Saltstack server for a result. If so, it returns + * the appropriate command to execute. + */ + public String reqCmd(Map params) throws SvcLogicException { + + final String[] mandatoryTestParams = {CMD_EXEC, IS_SLS_EXEC}; + + for (String key : mandatoryTestParams) { + throwIfMissingMandatoryParam(params, key); + } + + return params.get(SaltstackMessageParser.CMD_EXEC); + } + + /** + * Method that validates that the Map has enough information + * to query Saltstack server for a result. If so, it returns + * the appropriate SLS file location to execute. + */ + public String reqSlsFile(Map params) throws SvcLogicException { + + final String[] mandatoryTestParams = {SLS_FILE_LOCATION}; + + for (String key : mandatoryTestParams) { + throwIfMissingMandatoryParam(params, key); + } + + return params.get(SaltstackMessageParser.SLS_FILE_LOCATION); + } + + /** + * Method that validates that the Map has enough information + * to query Saltstack server for a result. If so, it returns + * the appropriate SLS file location to execute. + */ + public String reqSlsName(Map params) throws SvcLogicException { + + final String[] mandatoryTestParams = {SLS_NAME}; + + for (String key : mandatoryTestParams) { + throwIfMissingMandatoryParam(params, key); + } + String slsName = params.get(SaltstackMessageParser.SLS_NAME); + if(slsName.substring(slsName.lastIndexOf("."), slsName.length()).equalsIgnoreCase(".sls")) + return stripExtension(slsName); + return slsName; + } + + private String stripExtension (String str) { + if (str == null) return null; + int pos = str.lastIndexOf("."); + if (pos == -1) return str; + return str.substring(0, pos); + } + + /** + * Method that validates that the Map has enough information + * to query Saltstack server for a result. If so, it returns + * the appropriate minions/vnfc to execute the SLS file to. + */ + public String reqApplyToDevices(Map params) { + + if (params.get(SaltstackMessageParser.MINION_TO_APPLY) == null) { + return "*"; + } else if (params.get(SaltstackMessageParser.MINION_TO_APPLY).equalsIgnoreCase("")) { + return "*"; + } + return params.get(SaltstackMessageParser.MINION_TO_APPLY); + } + + /** + * Method that validates that the Map has enough information + * to query Saltstack server for a result. If so, it returns + * the appropriate IsSLSExec true or false. + */ + public boolean reqIsSLSExec(Map params) throws SvcLogicException { + + final String[] mandatoryTestParams = {CMD_EXEC, IS_SLS_EXEC}; + + for (String key : mandatoryTestParams) { + throwIfMissingMandatoryParam(params, key); + } + + return params.get(SaltstackMessageParser.IS_SLS_EXEC).equalsIgnoreCase("true"); + } + /** * Method that validates that the Map has enough information * to query Saltstack server for a result. If so, it returns @@ -143,7 +255,8 @@ public class SaltstackMessageParser { */ public String reqUserNameResult(Map params) throws SvcLogicException { - final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, PASS_KEY}; + final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, + PASS_KEY}; for (String key : mandatoryTestParams) { throwIfMissingMandatoryParam(params, key); @@ -158,7 +271,8 @@ public class SaltstackMessageParser { */ public String reqPasswordResult(Map params) throws SvcLogicException { - final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, PASS_KEY}; + final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY, + PASS_KEY}; for (String key : mandatoryTestParams) { throwIfMissingMandatoryParam(params, key); @@ -170,8 +284,10 @@ public class SaltstackMessageParser { * This method parses response from the Saltstack Server when we do a post * and returns an SaltstackResult object. */ - public SaltstackResult parseResponse(SvcLogicContext ctx, String pfx, SaltstackResult saltstackResult) { + public SaltstackResult parseResponse(SvcLogicContext ctx, String pfx, + SaltstackResult saltstackResult, boolean slsExec) { int code = saltstackResult.getStatusCode(); + boolean executionStatus = true, retCodeFound = false; if (code != SaltstackResultCodes.SUCCESS.getValue()) { return saltstackResult; } @@ -184,20 +300,34 @@ public class SaltstackMessageParser { in.close(); Map mm = JsonParser.convertToProperties(str); if (mm != null) { - for (Map.Entry entry : mm.entrySet()) { - ctx.setAttribute(pfx + entry.getKey(), entry.getValue()); - LOGGER.info("+++ " + pfx + entry.getKey() + ": [" + entry.getValue() + "]"); + for (Map.Entry entry : mm.entrySet()) { + if (entry.getKey().contains("retcode")) { + retCodeFound = true; + if (!entry.getValue().equalsIgnoreCase("0")) { + executionStatus = false; + } + } + ctx.setAttribute(pfx + "." + entry.getKey(), entry.getValue()); + LOGGER.info("+++ " + pfx + "." + entry.getKey() + ": [" + entry.getValue() + "]"); } } - } catch (FileNotFoundException e){ - return new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "Error parsing response file = " - + saltstackResult.getOutputFileName() + ". Error = " + e.getMessage()); + } catch (FileNotFoundException e) { + return new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "error parsing response file " + + saltstackResult.getOutputFileName() + " : " + e.getMessage()); } catch (JSONException e) { LOGGER.info("Output not in JSON format"); return putToProperties(ctx, pfx, saltstackResult); } catch (Exception e) { - return new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "Error parsing response file = " - + saltstackResult.getOutputFileName() + ". Error = " + e.getMessage()); + return new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "error parsing response file " + + saltstackResult.getOutputFileName() + " : " + e.getMessage()); + } + if (slsExec) { + if (!retCodeFound) + return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(), + "error in parsing response Json after SLS file execution in server"); + if (!executionStatus) + return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(), + "error in parsing response Json after SLS file execution in server"); } saltstackResult.setStatusCode(SaltstackResultCodes.FINAL_SUCCESS.getValue()); return saltstackResult; @@ -222,8 +352,10 @@ public class SaltstackMessageParser { saltstackResult = new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "Error parsing response file = " + saltstackResult.getOutputFileName() + ". Error = " + e.getMessage()); } + saltstackResult.setStatusCode(SaltstackResultCodes.FINAL_SUCCESS.getValue()); return saltstackResult; } + /** * This method parses response from an Saltstack server when we do a GET for a result * and returns an SaltstackResult object. @@ -235,14 +367,14 @@ public class SaltstackMessageParser { try { JSONObject postResponse = new JSONObject(input); saltstackResult = parseGetResponseNested(saltstackResult, postResponse); - } catch (JSONException e) { + } catch (Exception e) { saltstackResult = new SaltstackResult(SaltstackResultCodes.INVALID_COMMAND.getValue(), - "Error parsing response = " + input + ". Error = " + e.getMessage(), "", -1); + "Error parsing response = " + input + ". Error = " + e.getMessage(), "", -1); } return saltstackResult; } - private SaltstackResult parseGetResponseNested(SaltstackResult saltstackResult, JSONObject postRsp) throws SvcLogicException { + private SaltstackResult parseGetResponseNested(SaltstackResult saltstackResult, JSONObject postRsp) throws SvcLogicException { int codeStatus = postRsp.getInt(STATUS_CODE_KEY); String messageStatus = postRsp.getString(STATUS_MESSAGE_KEY); @@ -253,7 +385,7 @@ public class SaltstackMessageParser { if (!valCode) { throw new SvcLogicException("Invalid FinalResponse code = " + codeStatus + " received. MUST be one of " - + SaltstackResultCodes.CODE.getValidCodes(SaltstackResultCodes.FINALRESPONSE.getValue())); + + SaltstackResultCodes.CODE.getValidCodes(SaltstackResultCodes.FINALRESPONSE.getValue())); } saltstackResult.setStatusCode(codeStatus); @@ -285,7 +417,7 @@ public class SaltstackMessageParser { if (subCode != 200 || !message.equals("SUCCESS")) { finalCode = SaltstackResultCodes.REQ_FAILURE.getValue(); } - } catch (JSONException e) { + } catch (Exception e) { saltstackResult.setStatusCode(SaltstackResultCodes.INVALID_RESPONSE.getValue()); saltstackResult.setStatusMessage(String.format( "Error processing response message = %s from host %s", results.getString(host), host)); @@ -312,10 +444,10 @@ public class SaltstackMessageParser { //@formatter:off params.entrySet() - .stream() - .filter(entry -> optionalParamsSet.contains(entry.getKey())) - .filter(entry -> !Strings.isNullOrEmpty(entry.getValue())) - .forEach(entry -> parseOptionalParam(entry, jsonPayload)); + .stream() + .filter(entry -> optionalParamsSet.contains(entry.getKey())) + .filter(entry -> !Strings.isNullOrEmpty(entry.getValue())) + .forEach(entry -> parseOptionalParam(entry, jsonPayload)); //@formatter:on } diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResult.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResult.java index 05873024..f6ea0b42 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResult.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResult.java @@ -24,10 +24,8 @@ package org.onap.ccsdk.sli.adaptors.saltstack.model; -import java.io.OutputStream; - /** - * Simple class to store code and message returned by POST/GET to an Saltstack Server + * Simple class to store code and message returned by POST/GET to an Saltstack Server */ public class SaltstackResult { @@ -54,44 +52,44 @@ public class SaltstackResult { sshExitStatus = sshCode; } - public void setStatusCode(int code) { - this.statusCode = code; - } - - public void setStatusMessage(String message) { - this.statusMessage = message; - } - - public void setResults(String results) { - this.results = results; - } - void set(int code, String message, String results) { this.statusCode = code; this.statusMessage = message; this.results = results; } - public void setOutputFileName (String out) { - this.out = out; - } - public String getOutputFileName() { return out; } + public void setOutputFileName(String out) { + this.out = out; + } + public int getStatusCode() { return this.statusCode; } + public void setStatusCode(int code) { + this.statusCode = code; + } + public String getStatusMessage() { return this.statusMessage; } + public void setStatusMessage(String message) { + this.statusMessage = message; + } + public String getResults() { return this.results; } + public void setResults(String results) { + this.results = results; + } + public int getSshExitStatus() { return sshExitStatus; } diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResultCodes.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResultCodes.java index ab88c212..32871ff0 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResultCodes.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackResultCodes.java @@ -52,6 +52,8 @@ public enum SaltstackResultCodes { PENDING(100), REJECTED(101), FINAL_SUCCESS(200), + CHECK_CTX_FOR_CMD_SUCCESS(250), + COMMAND_EXEC_FAILED_STATUS(670), REQ_FAILURE(401), MESSAGE(1), CODE(0), @@ -67,7 +69,9 @@ public enum SaltstackResultCodes { SaltstackResultCodes(int value) { this.value = value; - }; + } + + ; public int getValue() { return value; diff --git a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackServerEmulator.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackServerEmulator.java index 9737efd3..ecb36fb8 100644 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackServerEmulator.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/model/SaltstackServerEmulator.java @@ -32,23 +32,21 @@ package org.onap.ccsdk.sli.adaptors.saltstack.model; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.apache.commons.lang.StringUtils; +import org.json.JSONObject; + import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; -import org.json.JSONException; -import org.json.JSONObject; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; public class SaltstackServerEmulator { - private final EELFLogger logger = EELFManager.getInstance().getLogger(SaltstackServerEmulator.class); - - private static final String SALTSTATE_NAME = "SaltStateName"; + private static final String SALTSTATE_FILE_NAME = "fileName"; private static final String STATUS_CODE = "StatusCode"; private static final String STATUS_MESSAGE = "StatusMessage"; - + private final EELFLogger logger = EELFManager.getInstance().getLogger(SaltstackServerEmulator.class); private String saltStateName = "test_saltState.yaml"; /** @@ -62,9 +60,13 @@ public class SaltstackServerEmulator { try { if (params.get("Test") == "fail") { - result = rejectRequest(result, "Must provide a valid Id"); + result = rejectRequest(result, "Mocked: Fail"); } else { - result = acceptRequest(result); + String fileName = params.get(SALTSTATE_FILE_NAME); + if (fileName == null) + result = acceptRequest(result, ""); + else + result = acceptRequest(result, fileName); } } catch (Exception e) { logger.error("JSONException caught", e); @@ -73,42 +75,11 @@ public class SaltstackServerEmulator { return result; } - /** - * Method that emulates the response from an Saltstack Server - * when presented with a request to execute a saltState - * Returns an saltstack object result. The response code is always the ssh code 200 (i.e connection successful) - * payload is json string as would be sent back by Saltstack Server - **/ - //TODO: This class is to be altered completely based on the SALTSTACK server communicaiton. - public SaltstackResult Connect(Map params) { - SaltstackResult result = new SaltstackResult(); - - try { - // Request must be a JSON object - - JSONObject message = new JSONObject(); - if (message.isNull("Id")) { - rejectRequest(result, "Must provide a valid Id"); - } else if (message.isNull(SALTSTATE_NAME)) { - rejectRequest(result, "Must provide a saltState Name"); - } else if (!message.getString(SALTSTATE_NAME).equals(saltStateName)) { - rejectRequest(result, "SaltState " + message.getString(SALTSTATE_NAME) + " not found in catalog"); - } else { - acceptRequest(result); - } - } catch (JSONException e) { - logger.error("JSONException caught", e); - rejectRequest(result, e.getMessage()); - } - return result; - } - /** * Method to emulate response from an Saltstack * Server when presented with a GET request * Returns an saltstack object result. The response code is always the ssh code 200 (i.e connection successful) * payload is json string as would be sent back by Saltstack Server - * **/ public SaltstackResult Execute(String agentUrl) { @@ -149,9 +120,10 @@ public class SaltstackServerEmulator { return result; } - private SaltstackResult acceptRequest(SaltstackResult result) { + private SaltstackResult acceptRequest(SaltstackResult result, String fileName) { result.setStatusCode(SaltstackResultCodes.SUCCESS.getValue()); result.setStatusMessage("Success"); + result.setOutputFileName(fileName); return result; } } \ No newline at end of file -- cgit 1.2.3-korg