From dbb08a26109fbe6cd0b8f96666eeb58cc25ecb03 Mon Sep 17 00:00:00 2001 From: Ganesh Chandrasekaran Date: Mon, 23 Jul 2018 16:47:14 +0900 Subject: Saltstack now aligned with APPC Issue-ID: CCSDK-394 Change-Id: Ie6d2b12f596c148d26bc45c0053e6aff975ace25 Signed-off-by: Ganesh Chandrasekaran --- .../SaltstackAdapterPropertiesProvider.java | 8 +- .../adaptors/saltstack/impl/ConnectionBuilder.java | 53 ++++++------ .../saltstack/impl/SaltstackAdapterImpl.java | 26 +++--- .../SaltstackAdapterPropertiesProviderImpl.java | 8 +- .../sli/adaptors/saltstack/impl/SshConnection.java | 93 ++++++++-------------- .../saltstack/model/SaltstackMessageParser.java | 17 +++- .../saltstack/model/SaltstackResultCodes.java | 1 + .../saltstack/model/SaltstackServerEmulator.java | 4 + 8 files changed, 102 insertions(+), 108 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/SaltstackAdapterPropertiesProvider.java b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/SaltstackAdapterPropertiesProvider.java index 3731ef72..a6b707af 100755 --- a/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/SaltstackAdapterPropertiesProvider.java +++ b/saltstack-adapter/saltstack-adapter-provider/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/SaltstackAdapterPropertiesProvider.java @@ -1,9 +1,11 @@ /*- * ============LICENSE_START======================================================= - * onap + * ONAP : CCSDK * ================================================================================ - * Copyright (C) 2016 - 2017 ONAP + * 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 @@ -15,6 +17,8 @@ * 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========================================================= */ 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 6e5feb4e..25a15fcc 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 @@ -26,12 +26,16 @@ package org.onap.ccsdk.sli.adaptors.saltstack.impl; import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; +import org.onap.appc.adapter.ssh.SshException; import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResult; import org.onap.ccsdk.sli.adaptors.saltstack.model.SaltstackResultCodes; import java.io.ByteArrayOutputStream; import java.io.IOException; +//import org.onap.appc.adapter.ssh.SshConnection; +//import org.onap.appc.adapter.ssh.SshAdapter; + /** * Returns a custom SSH client * - based on options @@ -54,19 +58,12 @@ public class ConnectionBuilder { /** * Constructor that initializes an ssh client based on ssh certificate + * This is still not supported in 1.3.0 version **/ public ConnectionBuilder(String host, String port, String certFile) { sshConnection = new SshConnection(host, Integer.parseInt(port), certFile); } - /** - * Constructor that initializes an ssh client based on ssh username password and certificate - **/ - public ConnectionBuilder(String host, String port, String userName, String userPasswd, - String certFile) { - - sshConnection = new SshConnection(host, Integer.parseInt(port), userName, userPasswd, certFile); - } /** * 1. Connect to SSH server. @@ -77,7 +74,7 @@ public class ConnectionBuilder { * @return command execution status */ public SaltstackResult connectNExecute(String cmd, long execTimeout) throws IOException { - return connectNExecute(cmd, -1, -1, execTimeout); + return connectNExecute(cmd, false, execTimeout); } /** @@ -85,12 +82,11 @@ 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 retryDelay delay between retry to make a SSH connection. - * @param retryCount number of count retry to make a SSH connection. + * @param cmd Commands to execute + * @param withRetry make a SSH connection with default retry. * @return command execution status */ - public SaltstackResult connectNExecute(String cmd, int retryCount, int retryDelay, long execTimeout) + public SaltstackResult connectNExecute(String cmd, boolean withRetry, long execTimeout) throws IOException { SaltstackResult result = new SaltstackResult(); @@ -101,29 +97,34 @@ public class ConnectionBuilder { } try { - if (retryCount != -1) { - result = sshConnection.connectWithRetry(retryCount, retryDelay); + if (withRetry) { + sshConnection.connectWithRetry(); } else { - result = sshConnection.connect(); - } - if (result.getStatusCode() != SaltstackResultCodes.SUCCESS.getValue()) { - return result; + sshConnection.connect(); } out = new ByteArrayOutputStream(); errs = new ByteArrayOutputStream(); - result = sshConnection.execCommand(cmd, out, errs, result); + int resultCode = sshConnection.execCommand(cmd, out, errs); sshConnection.disconnect(); - if (result.getSshExitStatus() != 0) { - return sortExitStatus(result.getSshExitStatus(), errs.toString(), cmd); - } - if (result.getStatusCode() != SaltstackResultCodes.SUCCESS.getValue()) { - return result; + if (resultCode != 0) { + return sortExitStatus(resultCode, errs.toString(), cmd); } + result.setStatusCode(SaltstackResultCodes.SUCCESS.getValue()); result.setStatusMessage("Success"); result.setOutputMessage(out); + } catch (SshException io) { + if (io.toString().equalsIgnoreCase("Authentication failed")) { + logger.error(io.toString()); + result.setStatusCode(SaltstackResultCodes.USER_UNAUTHORIZED.getValue()); + result.setStatusMessage(io.toString()); + return result; + } + logger.error("Caught Exception", io); + result.setStatusCode(SaltstackResultCodes.SSH_EXCEPTION.getValue()); + result.setStatusMessage(io.getMessage()); } catch (Exception io) { logger.error("Caught Exception", io); - result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); + result.setStatusCode(SaltstackResultCodes.SSH_EXCEPTION.getValue()); result.setStatusMessage(io.getMessage()); } finally { if (out != null) { 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 a48b67ad..ef54104e 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 @@ -61,8 +61,7 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { */ @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"; + public static final String CONNECTION_RETRY = "withRetry"; private static final String APPC_EXCEPTION_CAUGHT = "APPCException caught"; /** * Adapter Name @@ -187,15 +186,6 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { String sshPort = reqServerPort(props); logger.info("Creating ssh client with ssh KEY from " + sshKey); sshClient = new ConnectionBuilder(sshHost, sshPort, sshKey); - } else if ("BOTH".equalsIgnoreCase(clientType)) { - // set path to keystore file - String sshKey = props.getProperty(SS_SERVER_SSH_KEY); - String sshHost = props.getProperty(SS_SERVER_HOSTNAME); - String sshUserName = props.getProperty(SS_SERVER_USERNAME); - String sshPassword = props.getProperty(SS_SERVER_PASSWD); - String sshPort = reqServerPort(props); - logger.info("Creating ssh client with ssh KEY from " + sshKey); - sshClient = new ConnectionBuilder(sshHost, sshPort, sshUserName, sshPassword, sshKey); } else { logger.info("No saltstack-adapter.properties defined so reading from DG props"); sshClient = null; @@ -425,13 +415,19 @@ public class SaltstackAdapterImpl implements SaltstackAdapter { long execTimeout) throws SvcLogicException { + //convert execTimeout to Milliseconds + execTimeout = execTimeout * 1000; SaltstackResult testResult = new SaltstackResult(); try { - 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 (params.get(CONNECTION_RETRY) == null) { + if (!testMode) { + testResult = sshClient.connectNExecute(commandToExecute, execTimeout); + } else { + testResult = testServer.mockReqExec(params); + } + } else if (params.get(CONNECTION_RETRY).equalsIgnoreCase("true")) { if (!testMode) { - testResult = sshClient.connectNExecute(commandToExecute, retryCount, retryDelay, execTimeout); + testResult = sshClient.connectNExecute(commandToExecute, true, execTimeout); } 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 a4156558..8f0d9857 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 @@ -1,9 +1,11 @@ /*- * ============LICENSE_START======================================================= - * onap + * ONAP : CCSDK * ================================================================================ - * Copyright (C) 2016 - 2017 ONAP + * 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 @@ -15,6 +17,8 @@ * 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========================================================= */ 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 71ca5cf7..988183fc 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 @@ -34,9 +34,11 @@ 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 org.onap.appc.adapter.ssh.Constants; +import org.onap.appc.adapter.ssh.SshException; +import org.onap.appc.configuration.Configuration; +import org.onap.appc.configuration.ConfigurationFactory; 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 java.io.OutputStream; import java.security.KeyPair; @@ -46,11 +48,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 = 120; + private static final long EXEC_TIMEOUT = 120000; + private static final Configuration configuration = ConfigurationFactory.getConfiguration(); private String host; private int port; private String username; @@ -76,8 +78,7 @@ class SshConnection { this(host, port, null, null, keyFile); } - public SaltstackResult connect() { - SaltstackResult result = new SaltstackResult(); + public void connect() { sshClient = SshClient.setUpDefaultClient(); sshClient.start(); try { @@ -85,8 +86,7 @@ class SshConnection { sshClient.connect(EncryptionTool.getInstance().decrypt(username), host, port).await().getSession(); if (password != null) { clientSession.addPasswordIdentity(EncryptionTool.getInstance().decrypt(password)); - } - if (keyFile != null) { + } else if (keyFile != null) { KeyPairProvider keyPairProvider = new FileKeyPairProvider(new String[]{ keyFile }); @@ -96,42 +96,32 @@ class SshConnection { AuthFuture authFuture = clientSession.auth(); authFuture.await(AUTH_TIMEOUT); if (!authFuture.isSuccess()) { - String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port - + "]. Authentication failed."; - result.setStatusCode(SaltstackResultCodes.USER_UNAUTHORIZED.getValue()); - result.setStatusMessage(errMessage); + throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + + "]. Authentication failed."); } } catch (RuntimeException e) { - String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]." + - "Runtime Exception : " + e.getMessage(); - result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); - result.setStatusMessage(errMessage); + throw e; } catch (Exception e) { - String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]." + - "Host Unknown : " + e.getMessage(); - result.setStatusCode(SaltstackResultCodes.HOST_UNKNOWN.getValue()); - result.setStatusMessage(errMessage); + throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + "].", + e); } if (logger.isDebugEnabled()) { logger.debug("SSH: connected to [" + toString() + "]"); } - result.setStatusCode(SaltstackResultCodes.SUCCESS.getValue()); - return result; } - public SaltstackResult connectWithRetry(int retryCount, int retryDelay) { + public void 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; - } + retryCount = configuration.getIntegerProperty(Constants.CONNECTION_RETRY_COUNT, + Constants.DEFAULT_CONNECTION_RETRY_COUNT); + retryDelay = configuration.getIntegerProperty(Constants.CONNECTION_RETRY_DELAY, + Constants.DEFAULT_CONNECTION_RETRY_DELAY); retriesLeft = retryCount + 1; do { try { - result = this.connect(); + this.connect(); break; } catch (RuntimeException e) { if (retriesLeft > 1) { @@ -145,7 +135,6 @@ class SshConnection { } } } while (retriesLeft > 0); - return result; } public void disconnect() { @@ -162,21 +151,18 @@ class SshConnection { } public void setExecTimeout(long timeout) { - //convert seconds to milliseconds - this.timeout = timeout * 1000; + this.timeout = timeout; } - public SaltstackResult execCommand(String cmd, OutputStream out, OutputStream err, SaltstackResult result) { - return execCommand(cmd, out, err, false, result); + public int execCommand(String cmd, OutputStream out, OutputStream err) { + return execCommand(cmd, out, err, false); } - public SaltstackResult execCommandWithPty(String cmd, OutputStream out, SaltstackResult result) { - return execCommand(cmd, out, out, true, result); + public int execCommandWithPty(String cmd, OutputStream out) { + return execCommand(cmd, out, out, true); } - private SaltstackResult execCommand(String cmd, OutputStream out, OutputStream err, - boolean usePty, SaltstackResult result) { - + private int execCommand(String cmd, OutputStream out, OutputStream err, boolean usePty) { try { if (logger.isDebugEnabled()) { logger.debug("SSH: executing command"); @@ -192,31 +178,20 @@ class SshConnection { openFuture.verify(); Integer exitStatusI = client.getExitStatus(); if (exitStatusI == null) { - String errMessage = "Error executing command [" + cmd + "] over SSH [" + username + "@" + host - + ":" + port + "]. SSH operation timed out."; - result.setStatusCode(SaltstackResultCodes.OPERATION_TIMEOUT.getValue()); - result.setStatusMessage(errMessage); - return result; + throw new SshException("Error executing command [" + cmd + "] over SSH [" + username + "@" + host + + ":" + port + "]. Operation timed out."); } exitStatus = exitStatusI; } finally { client.close(false); } - result.setSshExitStatus(exitStatus); - return result; + return exitStatus; } catch (RuntimeException e) { - String errMessage = "Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]." + - "Runtime Exception : " + e.getMessage(); - result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); - result.setStatusMessage(errMessage); + throw e; } catch (Exception e1) { - String errMessage = "Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + - port + "]" + e1.getMessage(); - result.setStatusCode(SaltstackResultCodes.UNKNOWN_EXCEPTION.getValue()); - result.setStatusMessage(errMessage); + throw new SshException( + "Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + port + "]", e1); } - result.setStatusCode(SaltstackResultCodes.SUCCESS.getValue()); - return result; } private void waitForConnection(int retryDelay) { 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 2d810aee..50d08e23 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 @@ -311,9 +311,10 @@ public class SaltstackMessageParser { if (code != SaltstackResultCodes.SUCCESS.getValue()) { return saltstackResult; } - ByteArrayOutputStream str = saltstackResult.getOutputMessage(); + ByteArrayOutputStream outStream = saltstackResult.getOutputMessage(); + String outMessage = outStream.toString(); try { - Map mm = JsonParser.convertToProperties(str.toString()); + Map mm = JsonParser.convertToProperties(outMessage); if (mm != null) { for (Map.Entry entry : mm.entrySet()) { if (entry.getKey().contains("retcode")) { @@ -337,16 +338,24 @@ public class SaltstackMessageParser { return new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "error parsing response file" + " : " + e.getMessage()); } finally { - if (str != null) { - str.close(); + if (outStream != null) { + outStream.close(); } } if (slsExec) { if (!retCodeFound) { + if (outMessage != null && !outMessage.equalsIgnoreCase("")) { + return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(), + outMessage); + } return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(), "error in executing configuration at the server, check your command input"); } if (!executionStatus) { + if (outMessage != null && !outMessage.equalsIgnoreCase("")) { + return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(), + outMessage); + } return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(), "error in executing configuration at the server, check your command input"); } 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 92a61168..93255498 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 @@ -46,6 +46,7 @@ public enum SaltstackResultCodes { UNKNOWN_EXCEPTION(699), OPERATION_TIMEOUT(659), SSL_EXCEPTION(697), + SSH_EXCEPTION(695), INVALID_COMMAND(698), INVALID_RESPONSE(601), INVALID_RESPONSE_FILE(600), 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 bac2cfe5..78976562 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 @@ -36,6 +36,7 @@ import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -61,6 +62,9 @@ public class SaltstackServerEmulator { result = rejectRequest(result, "Mocked: Fail"); } else { String fileName = params.get(SALTSTATE_FILE_NAME); + if (fileName == null) { + throw new FileNotFoundException("No response file found"); + } result = acceptRequest(result, fileName); } } catch (Exception e) { -- cgit 1.2.3-korg