diff options
author | Singal, Kapil (ks220y) <ks220y@att.com> | 2021-04-09 16:13:38 -0400 |
---|---|---|
committer | Singal, Kapil (ks220y) <ks220y@att.com> | 2021-04-09 16:32:28 -0400 |
commit | 19c7de1f524478ea351f4d2dcd76508455a75ba8 (patch) | |
tree | 4c743f17cf7a929c762d4441e721db82235a0caf | |
parent | b7ec07f694f42f50fd2d32e1bed919e9ca27aa53 (diff) |
Moving ssh-adaptor from APPC to CCSDK
Issue-ID: CCSDK-3198
Signed-off-by: Singal, Kapil (ks220y) <ks220y@att.com>
Change-Id: Icb363093d49595fba8d60045cb7cab49ce4198bc
37 files changed, 5261 insertions, 11 deletions
diff --git a/adaptors/features/ccsdk-chef-adaptor/pom.xml b/adaptors/features/ccsdk-chef-adaptor/pom.xml index 5f709f9ce..1ac1dd82c 100644 --- a/adaptors/features/ccsdk-chef-adaptor/pom.xml +++ b/adaptors/features/ccsdk-chef-adaptor/pom.xml @@ -17,7 +17,6 @@ <name>ccsdk-sli-adaptors :: features :: ${project.artifactId}</name> <dependencies> - <dependency> <groupId>org.onap.ccsdk.sli.core</groupId> <artifactId>ccsdk-sli</artifactId> @@ -26,7 +25,6 @@ <classifier>features</classifier> <scope>provided</scope> </dependency> - <dependency> <groupId>${project.groupId}</groupId> <artifactId>chef-adaptor-bundle</artifactId> @@ -38,6 +36,5 @@ </exclusion> </exclusions> </dependency> - </dependencies> </project> diff --git a/adaptors/features/ccsdk-ssh-adaptor/pom.xml b/adaptors/features/ccsdk-ssh-adaptor/pom.xml new file mode 100644 index 000000000..26f36d694 --- /dev/null +++ b/adaptors/features/ccsdk-ssh-adaptor/pom.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 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 + + 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========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>single-feature-parent</artifactId> + <version>2.2.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ccsdk-ssh-adaptor</artifactId> + <version>1.3.0-SNAPSHOT</version> + <packaging>feature</packaging> + + <name>ccsdk-sli-adaptors :: features :: ${project.artifactId}</name> + + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-sli</artifactId> + <version>${project.version}</version> + <type>xml</type> + <classifier>features</classifier> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>ssh-adaptor-bundle</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + +</project> diff --git a/adaptors/features/pom.xml b/adaptors/features/pom.xml index ceec46d08..74dd2c2d3 100755 --- a/adaptors/features/pom.xml +++ b/adaptors/features/pom.xml @@ -18,17 +18,22 @@ <modules> <module>ccsdk-aai-service</module> + <module>ccsdk-base-http</module> + <module>ccsdk-ansible-adaptor</module> <module>ccsdk-chef-adaptor</module> - <module>ccsdk-base-http</module> + <module>ccsdk-saltstack-adaptor</module> + <module>ccsdk-ssh-adaptor</module> + <module>ccsdk-mdsal-resource</module> <module>ccsdk-messagerouter-consumer</module> <module>ccsdk-messagerouter-publisher</module> <module>ccsdk-netbox-client</module> + <module>ccsdk-resource-assignment</module> - <module>ccsdk-saltstack-adaptor</module> <module>ccsdk-sql-resource</module> <module>ccsdk-sli-adaptors-all</module> + <module>features-sli-adaptors</module> <module>installer</module> </modules> diff --git a/adaptors/pom.xml b/adaptors/pom.xml index f55e488d6..2a818cbba 100755 --- a/adaptors/pom.xml +++ b/adaptors/pom.xml @@ -22,15 +22,19 @@ <modules> <module>aai-service</module> + <module>base</module> + <module>ansible-adaptor</module> - <module>saltstack-adaptor</module> <module>chef-adaptor</module> - <module>netbox-client</module> + <module>saltstack-adaptor</module> + <module>ssh-adaptor</module> + + <module>message-router</module> <module>mdsal-resource</module> + <module>netbox-client</module> <module>resource-assignment</module> <module>sql-resource</module> - <module>base</module> - <module>message-router</module> + <module>features</module> <module>artifacts</module> </modules> diff --git a/adaptors/ssh-adaptor/pom.xml b/adaptors/ssh-adaptor/pom.xml new file mode 100644 index 000000000..b57be0401 --- /dev/null +++ b/adaptors/ssh-adaptor/pom.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 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 + + 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========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>odlparent-lite</artifactId> + <version>2.2.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ssh-adaptor</artifactId> + <version>1.3.0-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-adaptors :: ${project.artifactId}</name> + + <modules> + <module>ssh-adaptor-bundle</module> + </modules> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ssh-adaptor-features</artifactId> + <version>${project.version}</version> + <type>xml</type> + <classifier>features</classifier> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ssh-adaptor-bundle</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + +</project> diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/pom.xml b/adaptors/ssh-adaptor/ssh-adaptor-bundle/pom.xml new file mode 100644 index 000000000..359ecade6 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/pom.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 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 + + 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========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>2.2.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ssh-adaptor-bundle</artifactId> + <version>1.3.0-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>ccsdk-sli-adaptors :: ${project.artifactId}</name> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-core-artifacts</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-core</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>dblib-provider</artifactId> + </dependency> + <dependency> + <groupId>com.att.eelf</groupId> + <artifactId>eelf-core</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Export-Service>org.onap.ccsdk.sli.adaptors.ssh.SshAdaptor</Export-Service> + <Export-Package>org.onap.ccsdk.sli.adaptors.ssh</Export-Package> + <Import-Package> + !org.slf4j.impl, + !org.apache.log, + !org.apache.commons.logging, + !groovy.lang,!javax.jms, + !org.codehaus.commons.compiler, + !org.codehaus.groovy.*, + !org.codehaus.janino, + !com.ibm.icu.*, + !com.sun.faces.*, + !org.jasypt.*, + * + </Import-Package> + <Embed-Dependency> + jasypt, + eelf-core, + logback-core, + logback-classic;scope=compile|runtime;inline=false + </Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <executions> + <execution> + <id>attach-javadocs</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/Constants.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/Constants.java new file mode 100644 index 000000000..513b86e4a --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/Constants.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +public class Constants { + + private Constants(){} + + // tables and fields + public static final String NETCONF_SCHEMA = "sdnctl"; + public static final String SDNCTL_SCHEMA = "sdnctl"; + public static final String DEVICE_AUTHENTICATION_TABLE_NAME = "DEVICE_AUTHENTICATION"; + public static final String CONFIGFILES_TABLE_NAME = "CONFIGFILES"; + public static final String DEVICE_INTERFACE_LOG_TABLE_NAME = "DEVICE_INTERFACE_LOG"; + public static final String FILE_CONTENT_TABLE_FIELD_NAME = "FILE_CONTENT"; + public static final String FILE_NAME_TABLE_FIELD_NAME = "FILE_NAME"; + public static final String USER_NAME_TABLE_FIELD_NAME = "USER_NAME"; + public static final String PASSWORD_TABLE_FIELD_NAME = "PASSWORD"; + public static final String PORT_NUMBER_TABLE_FIELD_NAME = "PORT_NUMBER"; + public static final String VNF_TYPE_TABLE_FIELD_NAME = "VNF_TYPE"; + public static final String SERVICE_INSTANCE_ID_FIELD_NAME = "SERVICE_INSTANCE_ID"; + public static final String REQUEST_ID_FIELD_NAME = "REQUEST_ID"; + public static final String CREATION_DATE_FIELD_NAME = "CREATION_DATE"; + public static final String LOG_FIELD_NAME = "LOG"; + public static final String SDC_ARTIFACTS_TABLE_NAME = "ASDC_ARTIFACTS"; + + // input fields names + public static final String PAYLOAD = "payload"; + + public static final String CONNECTION_RETRY_DELAY = "org.onap.appc.ssh.connection.retry.delay"; + public static final String CONNECTION_RETRY_COUNT = "org.onap.appc.ssh.connection.retry.count"; + public static final int DEFAULT_CONNECTION_RETRY_DELAY = 60; + public static final int DEFAULT_CONNECTION_RETRY_COUNT = 5; + + public static final int DEFAULT_SSH_COMMAND_RETRY_COUNT = 3; + + public static final int DEFAULT_CHECKACTIVE_RETRY_COUNT = 3; + public static final int DEFAULT_CHECKACTIVE_RETRY_DELAY = 30; + + public static final int DEFAULT_STOP_RETRY_COUNT = 3; + public static final int DEFAULT_STOP_RETRY_DELAY = 30; //seconds + + public static final String PARAM_IN_CONNECTION_DETAILS = "connection-details"; + public static final String PARAM_IN_NODE_NAME = "node-name"; + public static final String PARAM_IN_NODE_STATUS = "node-status"; + public static final String PARAM_IN_VM_URL = "vm-url"; + public static final String SKIP_EXECUTION_INSTALLER_BIN_FILE = "Skip-execution-installer-bin-file"; + public static final String SKIP_DEPLOY = "Skip-deploy"; + public static final String UPGRADE_VERSION = "upgrade-version"; + + //command to get number of UP hosts + public static final String STATE_COMMAND = "/opt/jnetx/skyfall-scp/asp-state.sh | grep -o UP | wc -l"; + //command to get each VNFC status + public static final String VNFC_STATE_COMMAND = "/opt/jnetx/skyfall-scp/asp-state.sh"; + //command to restart node + public static final String RESTART_NODE_COMMAND = "/opt/jnetx/skyfall-scp/asp-stop.sh --restart -f --nodes"; + //command to start node + public static final String START_NODE_COMMAND = "/opt/jnetx/skyfall-scp/asp-start.sh -f --nodes"; + //command to stop node + public static final String STOP_NODE_COMMAND = "/opt/jnetx/skyfall-scp/asp-stop.sh -f --nodes"; + public static final int STATE_COMMAND_RESULT = 18; + //commands to check FE hosts + public static final String FE_STATE_TRUE_TEST_COMMAND = "ssh -t -q fe1 /opt/omni/bin/swmml -e display-platform-status | grep -o TRUE | wc -l"; + public static final int FE_STATE_TRUE_TEST_RESULT = 22; + public static final String FE_STATE_FALSE_TEST_COMMAND = "ssh -t -q fe1 /opt/omni/bin/swmml -e display-platform-status | grep -o FALSE | wc -l"; + public static final int FE_STATE_FALSE_TEST_RESULT = 2; + public static final String FE_OPERATIONAL_TEST_COMMAND = "ssh -t -q fe1 /opt/omni/bin/swmml -e display-platform-status | grep -o 'NOT FULLY OPERATIONAL' | wc -l"; + public static final int FE_OPERATIONAL_TEST_RESULT = 2; + + //smp commands + public static final String SMP_CHECK_ACTIVE_STATE_COMMAND = "cat skyfall-scp/runtime/SCP_SMP_*/smp/log/system.log| grep SSS | tail -1"; + public static final String SMP_STATE_ACTIVE="SMP is active"; + public static final String SMP_STATE_INACTIVE="SMP is not active"; + + //rsync command + public static final String RSYNC_COMMAND = "yes n | /opt/jnetx/skyfall-scp/asp-rsync.sh --check | grep -o 'is active' | wc -l"; + public static final int RSYNC_COMMAND_RESULT = 9; + + public static final String PARAM_IN_TIMEOUT = "timeout"; + public static final String PARAM_IN_FILE_URL = "source-file-url"; + public static final String DOWNLOAD_COMMAND = "wget -N %s"; + + // pre-define VM names + public static final String[] VM_NAMES = {"fe1", "fe2", "be1", "be2", "be3", "be4", "be5", "smp1", "smp2"}; + + public static final String DEFAULT_DISK_SPACE = "10240000"; + public static final String DF_COMMAND_TEMPLATE = "ssh %s df | grep vda1 | grep -v grep | tr -s ' '|cut -d ' ' -f4"; + + public static final String DG_OUTPUT_STATUS_MESSAGE = "output.status.message"; + public static final String ATTRIBUTE_ERROR_MESSAGE = "error-message"; + + + // constants for DG + public static final String CONNECTION_DETAILS_FIELD_NAME = PARAM_IN_CONNECTION_DETAILS; + public static final String VNF_HOST_IP_ADDRESS_FIELD_NAME = "vnf-host-ip-address"; + public static final String VNF_HOST_IP2_ADDRESS_FIELD_NAME = "vnf-host-ip2-address"; + public static final String DG_ERROR_FIELD_NAME = "org.openecom.appc.dg.error"; +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshAdaptor.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshAdaptor.java new file mode 100644 index 000000000..eed7f4e3b --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshAdaptor.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +/** + * Factory class for creating SshConnection instances. + */ +public interface SshAdaptor { + + /** + * Creates instance of SshConnection. + * + * @param host remote host to open SSH connection to + * @param port remote SSH port + * @param username SSH connection user name + * @param password SSH connection password + * @return instance of SshConnection + */ + SshConnection getConnection(String host, int port, String username, String password); + + /** + * Creates instance of SshConnection. + * + * @param host remote host to open SSH connection to + * @param port remote SSH port + * @param keyFile SSH connection key file location + * @return instance of SshConnection + */ + SshConnection getConnection(String host, int port, String keyFile); + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnection.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnection.java new file mode 100644 index 000000000..9fc8216b1 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnection.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +import java.io.OutputStream; + +/** + * Provides utility method(s) to call commands on remote host via SSH. + */ +public interface SshConnection { + + /** + * Connect to SSH server. + */ + void connect(); + + /** + * Connect to SSH Server using a retry mechanism + */ + void connectWithRetry(); + + /** + * Disconnect from SSH server. + */ + void disconnect(); + + /** + * Exec remote command over SSH. Return command execution status. + * Command output is written to out or err stream. + * + * @param cmd command to execute + * @param out content of sysout will go to this stream + * @param err content of syserr will go to this stream + * @return command execution status + */ + int execCommand(String cmd, OutputStream out, OutputStream err); + + /** + * 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. + * + * @param cmd command to execute + * @param out content of sysout will go to this stream + * @return command execution status + */ + int execCommandWithPty(String cmd, OutputStream out); + + /** + * Set the command execution timeout + * @param timeout time in milliseconds + */ + void setExecTimeout(long timeout); +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnectionDetails.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnectionDetails.java new file mode 100644 index 000000000..318287cd7 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnectionDetails.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +/** + * Provides details required for connecting to device. + */ +public class SshConnectionDetails { + + private static int DEFAULT_PORT = 22; + + private String host; + private int port = DEFAULT_PORT; + private String username; + private String password; + + public SshConnectionDetails() { + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshDataAccessException.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshDataAccessException.java new file mode 100644 index 000000000..a04a043c2 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshDataAccessException.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + + + +public class SshDataAccessException extends RuntimeException { + + private static final long serialVersionUID = -155423437162622414L; + + public SshDataAccessException(){ + } + + public SshDataAccessException(String message){ + super(message); + } + + public SshDataAccessException(Throwable cause){ + super(cause); + } + + public SshDataAccessException(String message , Throwable cause){ + super(message , cause); + } + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshDataAccessService.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshDataAccessService.java new file mode 100644 index 000000000..48165e823 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshDataAccessService.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +import org.onap.ccsdk.sli.core.dblib.DbLibService; + + +@SuppressWarnings("JavaDoc") +public interface SshDataAccessService { + + /** + * + * @param schema + */ + void setSchema(String schema); + + /** + *@param dbLibService + */ + void setDbLibService(DbLibService dbLibService); + + /** + * + * @param xmlID + * @return + * @throws SshDataAccessException + */ + String retrieveConfigFileName(String xmlID) throws SshDataAccessException; + + /** + * + * @param vnfType + * @param connectionDetails + * @return + * @throws SshException + */ + boolean retrieveConnectionDetails(String vnfType, SshConnectionDetails connectionDetails) throws SshDataAccessException; + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshException.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshException.java new file mode 100644 index 000000000..52f102620 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/SshException.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +public class SshException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * Constructor with message. + * + * @param message exception message + */ + public SshException(String message) { + super(message); + } + + /** + * Constructor with message and cause exception. + * + * @param message exception message + * @param cause exception cause + */ + public SshException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorSshd.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorSshd.java new file mode 100644 index 000000000..e7a2c9a38 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorSshd.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh.sshd; + +import org.onap.ccsdk.sli.adaptors.ssh.SshAdaptor; +import org.onap.ccsdk.sli.adaptors.ssh.SshConnection; + +public class SshAdaptorSshd implements SshAdaptor { + + //@Override + public SshConnection getConnection(String host, int port, String username, String password) { + return new SshConnectionSshd(host, port, username, password); + } + + // @Override + public SshConnection getConnection(String host, int port, String keyFile) { + return new SshConnectionSshd(host, port, keyFile); + } + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshConnectionSshd.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshConnectionSshd.java new file mode 100644 index 000000000..4194159fe --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshConnectionSshd.java @@ -0,0 +1,233 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh.sshd; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.OutputStream; +import java.nio.file.Paths; +import java.security.KeyPair; +import java.util.Collections; +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.channel.ChannelExec; +import org.apache.sshd.client.channel.ClientChannelEvent; +import org.apache.sshd.client.future.AuthFuture; +import org.apache.sshd.client.future.OpenFuture; +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.common.keyprovider.FileKeyPairProvider; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.onap.ccsdk.sli.adaptors.ssh.Constants; +import org.onap.ccsdk.sli.adaptors.ssh.SshConnection; +import org.onap.ccsdk.sli.adaptors.ssh.SshException; +import org.onap.ccsdk.sli.core.utils.configuration.Configuration; +import org.onap.ccsdk.sli.core.utils.configuration.ConfigurationFactory; +import org.onap.ccsdk.sli.core.utils.encryption.EncryptionTool; + +/** + * Implementation of SshConnection interface based on Apache MINA SSHD library. + */ +class SshConnectionSshd implements SshConnection { + + private static final EELFLogger logger = EELFManager.getInstance().getApplicationLogger(); + + private static final long AUTH_TIMEOUT = 60000; + private static final long EXEC_TIMEOUT = 120000; + + private final String host; + private final int port; + private final String username; + private final String password; + private long timeout = EXEC_TIMEOUT; + private final String keyFile; + private SshClient sshClient; + private ClientSession clientSession; + private static final Configuration configuration = ConfigurationFactory.getConfiguration(); + + public SshConnectionSshd(String host, int port, String username, String password, String keyFile) { + this.host = host; + this.port = port; + this.username = username; + this.password = password; + this.keyFile = keyFile; + } + + public SshConnectionSshd(String host, int port, String username, String password) { + this(host, port, username, password, null); + } + + public SshConnectionSshd(String host, int port, String keyFile) { + this(host, port, null, null, keyFile); + } + + @Override + public void connect() { + sshClient = SshClient.setUpDefaultClient(); + sshClient.start(); + try { + clientSession = + sshClient.connect(EncryptionTool.getInstance().decrypt(username), host, port).verify().getSession(); + if (password != null) { + clientSession.addPasswordIdentity(EncryptionTool.getInstance().decrypt(password)); + } + if (keyFile != null) { + KeyPairProvider keyPairProvider = new FileKeyPairProvider(Paths.get(keyFile)); + KeyPair keyPair = keyPairProvider.loadKeys().iterator().next(); + clientSession.addPublicKeyIdentity(keyPair); + } + AuthFuture authFuture = clientSession.auth(); + authFuture.await(AUTH_TIMEOUT); + if (!authFuture.isSuccess()) { + throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + + "]. Authentication failed."); + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + "].", + e); + } + if (logger.isDebugEnabled()) { + logger.debug("SSH: connected to [" + toString() + "]"); + } + } + + @Override + public void connectWithRetry() { + int retryCount ; + int retryDelay ; + int retriesLeft; + + 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 { + this.connect(); + break; + } catch (RuntimeException e) { + if (retriesLeft > 1) { + logger.debug("SSH Connection failed. Waiting for change in server's state."); + waitForConnection(retryDelay); + retriesLeft--; + logger.debug("Retrying SSH connection. Attempt [" + Integer.toString(retryCount - retriesLeft + 1) + + "] out of [" + retryCount + "]"); + } else { + throw e; + } + } + } while (retriesLeft > 0); + } + + @Override + public void disconnect() { + try { + if (logger.isDebugEnabled()) { + logger.debug("SSH: disconnecting from [" + toString() + "]"); + } + clientSession.close(false); + } finally { + if (sshClient != null) { + sshClient.stop(); + } + } + } + + @Override + public void setExecTimeout(long timeout) { + this.timeout = timeout; + } + + @Override + public int execCommand(String cmd, OutputStream out, OutputStream err) { + return execCommand(cmd, out, err, false); + } + + @Override + public int execCommandWithPty(String cmd, OutputStream out) { + return execCommand(cmd, out, out, true); + } + + private int execCommand(String cmd, OutputStream out, OutputStream err, boolean usePty) { + try { + if (logger.isDebugEnabled()) { + logger.debug("SSH: executing command"); + } + ChannelExec client = clientSession.createExecChannel(cmd); + client.setUsePty(usePty); // use pseudo-tty? + client.setOut(out); + client.setErr(err); + OpenFuture openFuture = client.open(); + int exitStatus; + try { + client.waitFor(Collections.singleton(ClientChannelEvent.CLOSED), timeout); + openFuture.verify(); + Integer exitStatusI = client.getExitStatus(); + if (exitStatusI == null) { + throw new SshException("Error executing command [" + cmd + "] over SSH [" + username + "@" + host + + ":" + port + "]. Operation timed out."); + } + exitStatus = exitStatusI; + } finally { + client.close(false); + } + return exitStatus; + } catch (RuntimeException e) { + throw e; + } catch (Exception e1) { + throw new SshException( + "Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + port + "]", e1); + } + } + + private void waitForConnection(int retryDelay) { + long time = retryDelay * 1000L; + long future = System.currentTimeMillis() + time; + if (time != 0) { + while (System.currentTimeMillis() < future && time > 0) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + /* + * This is rare, but it can happen if another thread interrupts us while we are sleeping. In that + * case, the thread is resumed before the delay time has actually expired, so re-calculate the + * amount of delay time needed and reenter the sleep until we get to the future time. + */ + time = future - System.currentTimeMillis(); + } + } + } + } + + @Override + public String toString() { + String address = host; + if (username != null) { + address = username + '@' + address; + } + return address; + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshdDataAccessService.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshdDataAccessService.java new file mode 100644 index 000000000..af8cb8b03 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshdDataAccessService.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh.sshd; + +import java.sql.SQLException; +import java.util.ArrayList; +import javax.sql.rowset.CachedRowSet; +import org.onap.ccsdk.sli.adaptors.ssh.Constants; +import org.onap.ccsdk.sli.adaptors.ssh.SshConnectionDetails; +import org.onap.ccsdk.sli.adaptors.ssh.SshDataAccessException; +import org.onap.ccsdk.sli.adaptors.ssh.SshDataAccessService; +import org.onap.ccsdk.sli.core.dblib.DbLibService; + +public class SshdDataAccessService implements SshDataAccessService { + + private String schema = Constants.NETCONF_SCHEMA; + private DbLibService dbLibService; + + @Override + public void setSchema(String schema) { + this.schema = schema; + } + + public String getSchema() { + return this.schema; + } + + @Override + public void setDbLibService(DbLibService dbLibService) { + this.dbLibService = dbLibService; + } + + public DbLibService getDbLibService() { + return this.dbLibService; + } + + + @Override + public boolean retrieveConnectionDetails(String vnfType, SshConnectionDetails connectionDetails) throws SshDataAccessException { + + boolean recordFound = false; + + String queryString = "select " + Constants.USER_NAME_TABLE_FIELD_NAME + "," + Constants.PASSWORD_TABLE_FIELD_NAME + "," + Constants.PORT_NUMBER_TABLE_FIELD_NAME + " " + + "from " + Constants.DEVICE_AUTHENTICATION_TABLE_NAME + " " + + "where " + Constants.VNF_TYPE_TABLE_FIELD_NAME + " = ?"; + + ArrayList<String> argList = new ArrayList<>(); + argList.add(vnfType); + + try { + + final CachedRowSet data = dbLibService.getData(queryString, argList, schema); + if (data.first()) { + recordFound = true; + connectionDetails.setUsername(data.getString(Constants.USER_NAME_TABLE_FIELD_NAME)); + connectionDetails.setPassword(data.getString(Constants.PASSWORD_TABLE_FIELD_NAME)); + connectionDetails.setPort(data.getInt(Constants.PORT_NUMBER_TABLE_FIELD_NAME)); + } + + } catch (SQLException e) { + throw new SshDataAccessException(e); + } + + return recordFound; + } + + @Override + public String retrieveConfigFileName(String xmlID) throws SshDataAccessException { + String fileContent; + + String queryString = "select " + Constants.FILE_CONTENT_TABLE_FIELD_NAME + " " + + "from " + Constants.CONFIGFILES_TABLE_NAME + " " + + "where " + Constants.FILE_NAME_TABLE_FIELD_NAME + " = ?"; + + ArrayList<String> argList = new ArrayList<>(); + argList.add(xmlID); + + try { + + final CachedRowSet data = dbLibService.getData(queryString, argList, schema); + fileContent = data.getString(Constants.FILE_CONTENT_TABLE_FIELD_NAME); + + } catch (SQLException e) { + throw new SshDataAccessException(e); + } + + return fileContent; + } + + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 000000000..e24bbb386 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 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 + + 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========================================================= + --> + + +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> + + <bean id="sshdBean" class="org.onap.ccsdk.sli.adaptors.ssh.sshd.SshAdaptorSshd" scope="singleton"/> + <service id="sshAdaptor" interface="org.onap.ccsdk.sli.adaptors.ssh.SshAdaptor" ref="sshdBean"/> + + <reference id="dbLibServiceRef" availability="mandatory" activation="eager" interface="org.onap.ccsdk.sli.core.dblib.DbLibService" /> + <bean id="sshdDAServiceBean" class="org.onap.ccsdk.sli.adaptors.ssh.sshd.SshdDataAccessService" scope="singleton"> + <property name="dbLibService" ref="dbLibServiceRef" /> + </bean> + + <service id="sshDAService" interface="org.onap.ccsdk.sli.adaptors.ssh.SshDataAccessService" ref="sshdDAServiceBean"/> + +</blueprint> diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/ConstantsTest.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/ConstantsTest.java new file mode 100644 index 000000000..dddf33878 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/ConstantsTest.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. 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.adaptors.ssh; + +import java.lang.reflect.Constructor; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ConstantsTest { + + @Test + public void test() { + String payLoad = Constants.PAYLOAD; + assertEquals(payLoad, "payload"); + + assertEquals(Constants.NETCONF_SCHEMA, "sdnctl"); + assertEquals(Constants.SDNCTL_SCHEMA, "sdnctl" ); + assertEquals(Constants.DEVICE_AUTHENTICATION_TABLE_NAME, "DEVICE_AUTHENTICATION" ); + assertEquals(Constants.CONFIGFILES_TABLE_NAME, "CONFIGFILES" ); + assertEquals(Constants.DEVICE_INTERFACE_LOG_TABLE_NAME, "DEVICE_INTERFACE_LOG" ); + assertEquals(Constants.FILE_CONTENT_TABLE_FIELD_NAME, "FILE_CONTENT" ); + assertEquals(Constants.FILE_NAME_TABLE_FIELD_NAME, "FILE_NAME" ); + + assertEquals(Constants.VM_NAMES[0], "fe1"); + assertEquals(Constants.VM_NAMES[1], "fe2"); + assertEquals(Constants.VM_NAMES[2], "be1"); + assertEquals(Constants.VM_NAMES[3], "be2"); + assertEquals(Constants.VM_NAMES[4], "be3"); + assertEquals(Constants.VM_NAMES[5], "be4"); + assertEquals(Constants.VM_NAMES[6], "be5"); + assertEquals(Constants.VM_NAMES[7], "smp1"); + assertEquals(Constants.VM_NAMES[8], "smp2"); + + assertEquals(Constants.DG_ERROR_FIELD_NAME, "org.openecom.appc.dg.error"); + + } + @Test + public void testValidatesThatClassConstantsIsNotInstantiable() throws Exception { + Constructor<Constants> c = Constants.class.getDeclaredConstructor(); + c.setAccessible(true); + c.newInstance(); + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/SshAdaptorMock.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/SshAdaptorMock.java new file mode 100644 index 000000000..d04f22e17 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/SshAdaptorMock.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +import java.util.ArrayList; +import java.util.List; + +public class SshAdaptorMock implements SshAdaptor { + + private final List<SshConnectionMock> connectionMocks = new ArrayList<>(); + + private int returnStatus; + private String returnStdout; + private String returnStderr; + +@Override + public SshConnection getConnection(String host, int port, String username, String password) { + SshConnectionMock sshConnectionMock = new SshConnectionMock(host, port, username, password, null); + sshConnectionMock.setReturnStatus(returnStatus); + sshConnectionMock.setReturnStdout(returnStdout); + sshConnectionMock.setReturnStderr(returnStderr); + connectionMocks.add(sshConnectionMock); + return sshConnectionMock; + } + + @Override + public SshConnection getConnection(String host, int port, String keyFile) { + SshConnectionMock sshConnectionMock = new SshConnectionMock(host, port, null, null, keyFile); + sshConnectionMock.setReturnStatus(returnStatus); + sshConnectionMock.setReturnStdout(returnStdout); + sshConnectionMock.setReturnStderr(returnStderr); + connectionMocks.add(sshConnectionMock); + return sshConnectionMock; + } + + public List<SshConnectionMock> getConnectionMocks() { + return connectionMocks; + } + + public int getReturnStatus() { + return returnStatus; + } + + public void setReturnStatus(int returnStatus) { + this.returnStatus = returnStatus; + } + + public String getReturnStdout() { + return returnStdout; + } + + public void setReturnStdout(String returnStdout) { + this.returnStdout = returnStdout; + } + + public String getReturnStderr() { + return returnStderr; + } + + public void setReturnStderr(String returnStderr) { + this.returnStderr = returnStderr; + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnectionMock.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnectionMock.java new file mode 100644 index 000000000..db35ddbec --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/SshConnectionMock.java @@ -0,0 +1,169 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +public class SshConnectionMock implements SshConnection { + + private static final int DEF_SUCCESS_STATUS = 0; + + private final String host; + private final int port; + private final String username; + private final String password; + private final String keyFile; + private long timeout; + + private int returnStatus = DEF_SUCCESS_STATUS; + private String returnStdout; + private String returnStderr; + + private int connectCallCount = 0; + private int disconnectCallCount = 0; + private final List<String> executedCommands = new ArrayList<>(); + + public SshConnectionMock(String host, int port, String username, String password, String keyFile) { + this.host = host; + this.port = port; + this.username = username; + this.password = password; + this.keyFile = keyFile; + } + + + + @Override + public void connect() { + connectCallCount++; + } + + @Override + public void connectWithRetry() { + connectCallCount++; + } + + @Override + public void disconnect() { + disconnectCallCount++; + } + + @Override + public int execCommand(String cmd, OutputStream out, OutputStream err) { + return execCommand(cmd, out, err, false); + } + + @Override + public int execCommandWithPty(String cmd, OutputStream out) { + return execCommand(cmd, out, out, true); + } + + private int execCommand(String cmd, OutputStream out, OutputStream err, boolean usePty) { + executedCommands.add(cmd); + try { + if((out != null) && (returnStdout != null)) { + out.write(returnStdout.getBytes()); + } + } catch(IOException e) { + throw new RuntimeException("Error writing to stdout output stream", e); + } + try { + if((err != null) && (returnStderr != null)) { + err.write(returnStderr.getBytes()); + } + } catch(IOException e) { + throw new RuntimeException("Error writing to stderr output stream", e); + } + return returnStatus; + } + + @Override + public void setExecTimeout(long timeout) { + this.timeout = timeout; + } + + public long getExecTimeout() { + return timeout; + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getKeyFile() { + return keyFile; + } + + public int getConnectCallCount() { + return connectCallCount; + } + + public int getDisconnectCallCount() { + return disconnectCallCount; + } + + public List<String> getExecutedCommands() { + return executedCommands; + } + + public int getReturnStatus() { + return returnStatus; + } + + public void setReturnStatus(int returnStatus) { + this.returnStatus = returnStatus; + } + + public String getReturnStdout() { + return returnStdout; + } + + public void setReturnStdout(String returnStdout) { + this.returnStdout = returnStdout; + } + + public String getReturnStderr() { + return returnStderr; + } + + public void setReturnStderr(String returnStderr) { + this.returnStderr = returnStderr; + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshAdaptorMock.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshAdaptorMock.java new file mode 100644 index 000000000..53048986a --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshAdaptorMock.java @@ -0,0 +1,77 @@ +/* +* ============LICENSE_START======================================================= +* ONAP : APPC +* ================================================================================ +* Copyright 2018 TechMahindra +*================================================================================= +* 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.adaptors.ssh; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +public class TestSshAdaptorMock { + private SshAdaptorMock sshAdaptorMock; + + @Before + public void setUp() { + sshAdaptorMock = new SshAdaptorMock(); + } + + @Test + public void testGetReturnStatus() { + sshAdaptorMock.setReturnStatus(200); + assertEquals(sshAdaptorMock.getReturnStatus(), 200); + } + + @Test + public void testGetReturnStdout() { + sshAdaptorMock.setReturnStdout("success"); + assertNotNull(sshAdaptorMock.getReturnStdout()); + assertEquals(sshAdaptorMock.getReturnStdout(), "success"); + } + + @Test + public void testGetReturnStderr() { + sshAdaptorMock.setReturnStderr("error"); + assertNotNull(sshAdaptorMock.getReturnStderr()); + assertEquals(sshAdaptorMock.getReturnStderr(), "error"); + } + + @Test + public void testGetConnectionMocks() { + sshAdaptorMock.setReturnStatus(200); + sshAdaptorMock.setReturnStdout("success"); + sshAdaptorMock.setReturnStderr("error"); + sshAdaptorMock.getConnection("localhost", 8080, "myUser", "myPassword"); + assertFalse(sshAdaptorMock.getConnectionMocks().isEmpty()); + assertNotNull(sshAdaptorMock.getConnectionMocks()); + } + + @Test + public void testGetConnection() { + SshAdaptorMock sshAdaptorMock = new SshAdaptorMock(); + sshAdaptorMock.setReturnStatus(200); + sshAdaptorMock.setReturnStdout("success"); + sshAdaptorMock.setReturnStderr("error"); + sshAdaptorMock.getConnection("localhost", 8080, "keyFile"); + assertFalse(sshAdaptorMock.getConnectionMocks().isEmpty()); + } + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshConnectionDetails.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshConnectionDetails.java new file mode 100644 index 000000000..044d952f8 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshConnectionDetails.java @@ -0,0 +1,63 @@ +/* +* ============LICENSE_START======================================================= +* ONAP : APPC +* ================================================================================ +* Copyright 2018 TechMahindra +*================================================================================= +* 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.adaptors.ssh; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class TestSshConnectionDetails { + + private SshConnectionDetails sshConnectionDetails; + + @Before + public void setUp() { + sshConnectionDetails = new SshConnectionDetails(); + } + + @Test + public void testGetHost() { + sshConnectionDetails.setHost("localhost"); + assertNotNull(sshConnectionDetails.getHost()); + assertEquals(sshConnectionDetails.getHost(), "localhost"); + } + + @Test + public void testGetPort() { + sshConnectionDetails.setPort(8080); + assertEquals(sshConnectionDetails.getPort(), 8080); + } + + @Test + public void testGetUsername() { + sshConnectionDetails.setUsername("username"); + assertNotNull(sshConnectionDetails.getUsername()); + assertEquals(sshConnectionDetails.getUsername(), "username"); + } + + @Test + public void testGetPassword() { + sshConnectionDetails.setPassword("password"); + assertNotNull(sshConnectionDetails.getPassword()); + assertEquals(sshConnectionDetails.getPassword(), "password"); + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshConnectionMock.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshConnectionMock.java new file mode 100644 index 000000000..70665a555 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshConnectionMock.java @@ -0,0 +1,104 @@ +/* +* ============LICENSE_START======================================================= +* ONAP : APPC +* ================================================================================ +* Copyright 2018 TechMahindra +*================================================================================= +* 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.adaptors.ssh; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +public class TestSshConnectionMock { + + private SshConnectionMock sshConnectionMock; + @Before + public void setUp() { + sshConnectionMock=new SshConnectionMock("localhost", 8080, "myUser", "myPassword", "sampleKeyFile"); + } + + @Test + public void testGetHost() { + assertEquals("localhost", sshConnectionMock.getHost()); + } + + @Test + public void testGetPort() { + assertEquals(8080, sshConnectionMock.getPort()); + } + + @Test + public void testGetUsername() { + assertEquals("myUser", sshConnectionMock.getUsername()); + } + + @Test + public void testGetPassword() { + assertEquals("myPassword", sshConnectionMock.getPassword()); + } + + @Test + public void testKeyFile() { + assertEquals("sampleKeyFile", sshConnectionMock.getKeyFile()); + } + + @Test + public void testGetReturnStderr() { + sshConnectionMock.setReturnStderr("returnStderr"); + assertEquals("returnStderr", sshConnectionMock.getReturnStderr()); + } + @Test + public void testGetReturnStdout() { + sshConnectionMock.setReturnStdout("returnStdout"); + assertEquals("returnStdout", sshConnectionMock.getReturnStdout()); + } + @Test + public void testGetReturnStatus() { + sshConnectionMock.setReturnStatus(200); + assertEquals(200, sshConnectionMock.getReturnStatus()); + } + @Test + public void testGetExecutedCommands() { + sshConnectionMock.getExecutedCommands().add("cls"); + sshConnectionMock.getExecutedCommands().add("pwd"); + assertNotNull(sshConnectionMock.getExecutedCommands()); + assertFalse(sshConnectionMock.getExecutedCommands().isEmpty()); + } + + @Test + public void testExecTimeout() + { + sshConnectionMock.setExecTimeout(20); + assertEquals(20,sshConnectionMock.getExecTimeout()); + } + + @Test + public void testConnectCallCount() + { + assertEquals(0, sshConnectionMock.getConnectCallCount()); + } + + @Test + public void testDisconnectCallCount() + { + assertEquals(0, sshConnectionMock.getDisconnectCallCount()); + } + +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshDataAccessException.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshDataAccessException.java new file mode 100644 index 000000000..f0fbd4d3f --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshDataAccessException.java @@ -0,0 +1,64 @@ +/* +* ============LICENSE_START======================================================= +* ONAP : APPC +* ================================================================================ +* Copyright 2018 TechMahindra +*================================================================================= +* 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.adaptors.ssh; + +import org.junit.Assert; +import org.junit.Test; + +public class TestSshDataAccessException { + + @Test + public void testConstructorNoArgument() throws Exception { + SshDataAccessException sshDataAccessException = new SshDataAccessException(); + Assert.assertNull(sshDataAccessException.getCause()); + Assert.assertNull(sshDataAccessException.getLocalizedMessage()); + Assert.assertNull(sshDataAccessException.getMessage()); + } + + @Test + public void testConstructorWithMessaqge() throws Exception { + String message = "testing message"; + SshDataAccessException sshDataAccessException = new SshDataAccessException(message); + Assert.assertNull(sshDataAccessException.getCause()); + Assert.assertEquals(message, sshDataAccessException.getLocalizedMessage()); + Assert.assertEquals(message, sshDataAccessException.getMessage()); + } + + @Test + public void testConstructorWithThrowable() throws Exception { + String message = "testing message"; + Throwable throwable = new Throwable(message); + SshDataAccessException sshDataAccessException = new SshDataAccessException(throwable); + Assert.assertEquals(throwable, sshDataAccessException.getCause()); + Assert.assertTrue(sshDataAccessException.getLocalizedMessage().contains(message)); + Assert.assertTrue(sshDataAccessException.getMessage().contains(message)); + } + + @Test + public void testConstructorWithMessageAndThrowable() throws Exception { + String message = "testing message"; + String tMessage = "throwable message"; + Throwable throwable = new Throwable(tMessage); + SshDataAccessException sshDataAccessException =new SshDataAccessException(message, throwable); + Assert.assertEquals(throwable, sshDataAccessException.getCause()); + Assert.assertTrue(sshDataAccessException.getLocalizedMessage().contains(message)); + Assert.assertTrue(sshDataAccessException.getMessage().contains(message)); + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshException.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshException.java new file mode 100644 index 000000000..5abc90d38 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/TestSshException.java @@ -0,0 +1,46 @@ +/* +* ============LICENSE_START======================================================= +* ONAP : APPC +* ================================================================================ +* Copyright 2018 TechMahindra +*================================================================================= +* 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.adaptors.ssh; + +import org.junit.Assert; +import org.junit.Test; + +public class TestSshException { + + @Test + public void testConstructorWithMessaqge() throws Exception { + String message = "testing message"; + SshException sshException = new SshException(message); + Assert.assertNull(sshException.getCause()); + Assert.assertEquals(message, sshException.getLocalizedMessage()); + Assert.assertEquals(message, sshException.getMessage()); + } + + @Test + public void testConstructorWithMessageAndThrowable() throws Exception { + String message = "testing message"; + String tMessage = "throwable message"; + Throwable throwable = new Throwable(tMessage); + SshException sshException = new SshException(message, throwable); + Assert.assertEquals(throwable, sshException.getCause()); + Assert.assertTrue(sshException.getLocalizedMessage().contains(message)); + Assert.assertTrue(sshException.getMessage().contains(message)); + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorSample.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorSample.java new file mode 100644 index 000000000..e82d12fb9 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorSample.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.ssh.sshd; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import org.onap.ccsdk.sli.adaptors.ssh.SshAdaptor; +import org.onap.ccsdk.sli.adaptors.ssh.SshConnection; + +public class SshAdaptorSample { + + public static void main(String[] args) { + String host = "hostname"; + int port = 22; + String username = "user"; + String password = "secret"; + String command = "ls"; + + SshAdaptor sshAdaptor = new SshAdaptorSshd(); + SshConnection sshConnection = sshAdaptor.getConnection(host, port, username, password); + sshConnection.connect(); + try { + OutputStream stdout = new ByteArrayOutputStream(); + OutputStream stderr = new ByteArrayOutputStream(); + int status = sshConnection.execCommand(command, stdout, stderr); + if(status == 0) { + System.out.println("Command executed successfully. Output:\n" + stdout.toString()); + } else { + System.err.println("Command returned status " + status + ". Error:\n" + stderr.toString()); + } + } finally { + sshConnection.disconnect(); + } + } +} diff --git a/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorTest.java b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorTest.java new file mode 100644 index 000000000..5067debd5 --- /dev/null +++ b/adaptors/ssh-adaptor/ssh-adaptor-bundle/src/test/java/org/onap/ccsdk/sli/adaptors/ssh/sshd/SshAdaptorTest.java @@ -0,0 +1,265 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Modifications Copyright (C) 2019 Ericsson + * ============================================================================= + * 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.adaptors.ssh.sshd; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.BindException; +import java.nio.file.Paths; +import java.util.Collections; +import org.apache.sshd.common.util.OsUtils; +import org.apache.sshd.server.SshServer; +import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; +import org.apache.sshd.server.scp.ScpCommandFactory; +import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory; +import org.hamcrest.CoreMatchers; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onap.ccsdk.sli.adaptors.ssh.SshAdaptor; +import org.onap.ccsdk.sli.adaptors.ssh.SshConnection; +import org.onap.ccsdk.sli.adaptors.ssh.SshException; + +import static org.junit.Assert.assertTrue; + +@Ignore +public class SshAdaptorTest { + + private static final boolean START_SERVER = true; + private static final String SSH_HOST = "localhost"; + private static final int SSH_PORT = 2222; + private static final String SSH_USERNAME = "test"; + private static final String SSH_PASSWORD = "test"; + private static final String F_TEST_CMD = "ping -%c 4 %s"; + + private int sshPort = SSH_PORT; + private SshServer sshd; + private final SshAdaptor sshAdaptor = new SshAdaptorSshd(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testExecute() { + String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost"); + SshConnection sshConnection = connect(); + if (sshConnection == null) return; + try { + System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + int status = execCmd(sshConnection, cmd, stdout, stderr, false); + Assert.assertEquals(stdout + ". " + stderr, 0, status); + } finally { + disconnect(sshConnection); + } + } + + @Test + public void testExecuteWithPty() { + String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost"); + SshConnection sshConnection = connect(); + if (sshConnection == null) return; + try { + System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + int status = execCmd(sshConnection, cmd, stdout, null, true); + Assert.assertEquals(stdout + ". " + stdout, 0, status); + } finally { + disconnect(sshConnection); + } + } + + @Test + public void testExecuteInvalidCommand() { + String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "nosuchhost"); + SshConnection sshConnection = connect(); + if (sshConnection == null) return; + try { + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + int status = execCmd(sshConnection, cmd, stdout, stderr, false); + Assert.assertNotEquals(stdout + ". " + stderr, 0, status); + } finally { + disconnect(sshConnection); + } + } + + @Test + public void testWrongUsername() { + thrown.expect(SshException.class); + thrown.expectMessage(CoreMatchers.containsString("Authentication failed")); + disconnect(invalidConnect("WrongUsername", SSH_PASSWORD)); + } + + @Test + public void testWrongPassword() { + thrown.expect(SshException.class); + thrown.expectMessage(CoreMatchers.containsString("Authentication failed")); + disconnect(invalidConnect(SSH_USERNAME, "WrongPassword")); + } + + + + @Test + public void testInstantiateWithKeyFile() { + SshConnection connection = sshAdaptor.getConnection(null, 0, null); + assertTrue(connection instanceof SshConnection); + } + + /* + @Test + public void testConnectWithRetry() { + SshConnection connection = Mockito.spy(sshAdaptor.getConnection( + SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD)); + connection.setExecTimeout(1); + connection.connectWithRetry(); + Mockito.verify(connection).connect(); + } + + @Test + public void testToString() { + SshConnection connection = Mockito.spy(sshAdaptor.getConnection( + SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD)); + assertEquals(SSH_USERNAME + "@" + SSH_HOST, connection.toString()); + String s = null; + Whitebox.setInternalState(connection, "username", s); + assertEquals(SSH_HOST, connection.toString()); + } + */ + + @Before + public void beforeTest() throws IOException { + if (START_SERVER) { + startServer(); + } + } + + @After + public void afterTest() { + stopServer(); + } + + private SshConnection connect() { + SshConnection sshConnection = sshAdaptor.getConnection(SSH_HOST, sshPort, SshAdaptorTest.SSH_USERNAME, SshAdaptorTest.SSH_PASSWORD); + try { + /* move connect to inside try block, in case ssh connection to localhost is + * blocked by localhost ssh policy */ + sshConnection.connect(); + System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + } catch (Exception e) { + sshConnection = null; + System.out.println("SSH client connect failed. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + } + return sshConnection; + } + + private SshConnection invalidConnect(String username, String password) { + SshConnection sshConnection = sshAdaptor.getConnection(SSH_HOST, sshPort, username, password); + sshConnection.connect(); + System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + return sshConnection; + } + + private void disconnect(SshConnection sshConnection) { + if (sshConnection != null) { + sshConnection.disconnect(); + System.out.println("SSH client disconnected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + } +} + + private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) { + System.out.println("=> Running command [" + cmd + "] over SSH"); + int status; + if (usePty) { + status = sshConnection.execCommandWithPty(cmd, stdout); + } else { + status = sshConnection.execCommand(cmd, stdout, stderr); + } + System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + stdout + "], stderr is [" + stderr + "]"); + return status; + } + + private void startServer() throws IOException { + sshd = SshServer.setUpDefaultServer(); + sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory())); + sshd.setCommandFactory(new ScpCommandFactory()); + + sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get(System.getProperty("java.io.tmpdir") + "/key.ser"))); + sshd.setPasswordAuthenticator((username, password, session) -> (SSH_USERNAME.equals(username) && SSH_PASSWORD.equals(password))); + sshd.setPublickeyAuthenticator((username, key, session) -> false); + sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD\n"); + startServer0(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // ignore + } + } + + private void startServer0() throws IOException { + boolean serverStarted = false; + IOException exception = null; + while (!serverStarted && (sshPort < Integer.MAX_VALUE)) { + try { + System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + sshd.setPort(sshPort); + sshd.start(); + serverStarted = true; + } catch (BindException e) { + System.err.println("Cannot start SSH server on port [" + sshPort + "]. " + e.getMessage()); + if (exception == null) { + // store first thrown exception - will be thrown if cannot start the server + exception = e; + } + sshPort++; + } + } + if (!serverStarted && exception != null) { + throw exception; + } + System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + } + + private void stopServer() { + try { + if (sshd != null) { + sshd.stop(); + System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]"); + } + } catch (IOException e) { + System.err.println("=> IO Error stopping SSH server."); + e.printStackTrace(); + } finally { + sshd = null; + } + } +} diff --git a/core/features/ccsdk-dblib/pom.xml b/core/features/ccsdk-dblib/pom.xml index 7c022a448..313371b68 100644 --- a/core/features/ccsdk-dblib/pom.xml +++ b/core/features/ccsdk-dblib/pom.xml @@ -17,13 +17,11 @@ <name>ccsdk-sli-core :: features :: ${project.artifactId}</name> <dependencies> - <dependency> <groupId>${project.groupId}</groupId> <artifactId>dblib-provider</artifactId> <version>${project.version}</version> </dependency> - <dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> diff --git a/core/utils/provider/pom.xml b/core/utils/provider/pom.xml index ac9941aec..476448775 100644 --- a/core/utils/provider/pom.xml +++ b/core/utils/provider/pom.xml @@ -32,6 +32,16 @@ <artifactId>org.osgi.core</artifactId> <scope>provided</scope> </dependency> + <dependency> + <groupId>com.att.eelf</groupId> + <artifactId>eelf-core</artifactId> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> <!-- Testing Dependencies --> <dependency> diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/Configuration.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/Configuration.java new file mode 100644 index 000000000..1e41a5268 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/Configuration.java @@ -0,0 +1,239 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.core.utils.configuration; + +import java.util.Properties; + +/** + * This interface defines the common configuration support that is available to the application. + * <p> + * Where properties are common to all CDP components (server, coordinator, and EPM), the property symbolic values are + * defined as part of this interface. Where they are unique to each component, they must be defined within that + * component. + * </p> + */ +public interface Configuration { + + String PROPERTY_BOOTSTRAP_FILE_NAME = "org_onap_appc_bootstrap_file"; // + String DEFAULT_BOOTSTRAP_FILE_NAME = "appc.properties"; + String PROPERTY_BOOTSTRAP_FILE_PATH = "org_onap_appc_bootstrap_path"; // + String DEFAULT_BOOTSTRAP_FILE_PATH = "/opt/onap/appc/data/properties,${user.home},etc,../etc"; + String PROPERTY_RESOURCE_BUNDLES = "org.onap.appc.resources"; + String DEFAULT_RESOURCE_BUNDLES = "org/onap/appc/i18n/MessageResources"; + + /** + * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for + * {@link Boolean#valueOf(String)} are used. + * + * @param key + * The property key + * @return The value of the property expressed as a boolean, or false if it does not exist. + */ + boolean getBooleanProperty(String key); + + /** + * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for + * {@link Boolean#valueOf(String)} are used. + * + * @param key + * The property key + * @param defaultValue + * The default value to be returned if the property does not exist + * @return The value of the property expressed as a boolean, or false if it does not exist. + */ + boolean getBooleanProperty(String key, boolean defaultValue); + + /** + * Returns the indicated property value expressed as a floating point double-precision value (double). The standard + * rules for {@link Double#valueOf(String)} are used. + * + * @param key + * The property to retrieve + * @return The value of the property, or 0.0 if not found or invalid + */ + double getDoubleProperty(String key); + + /** + * Returns the indicated property value expressed as a floating point double-precision value (double). The standard + * rules for {@link Double#valueOf(String)} are used. + * + * @param key + * The property to retrieve + * @param defaultValue + * The default value to be returned if the property does not exist + * @return The value of the property, or 0.0 if not found or invalid + */ + double getDoubleProperty(String key, double defaultValue); + + /** + * Returns the property indicated expressed as an integer. The standard rules for + * {@link Integer#parseInt(String, int)} using a radix of 10 are used. + * + * @param key + * The property name to retrieve. + * @return The value of the property, or 0 if it does not exist or is invalid. + */ + int getIntegerProperty(String key); + + /** + * Returns the property indicated expressed as an integer. The standard rules for + * {@link Integer#parseInt(String, int)} using a radix of 10 are used. + * + * @param key + * The property name to retrieve. + * @param defaultValue + * The default value to be returned if the property does not exist + * @return The value of the property, or 0 if it does not exist or is invalid. + */ + int getIntegerProperty(String key, int defaultValue); + + /** + * Returns the specified property as a long integer value, if it exists, or zero if it does not. + * + * @param key + * The key of the property desired. + * @return The value of the property expressed as an integer long value, or zero if the property does not exist or + * is not a valid integer long. + */ + long getLongProperty(String key); + + /** + * Returns the specified property as a long integer value, if it exists, or the default value if it does not exist + * or is invalid. + * + * @param key + * The key of the property desired. + * @param defaultValue + * the value to be returned if the property is not valid or does not exist. + * @return The value of the property expressed as an integer long value, or the default value if the property does + * not exist or is not a valid integer long. + */ + long getLongProperty(String key, long defaultValue); + + /** + * This method can be called to retrieve a properties object that is immutable. Any attempt to modify the properties + * object returned will result in an exception. This allows a caller to view the current configuration as a set of + * properties. + * + * @return An unmodifiable properties object. + */ + Properties getProperties(); + + /** + * This method is called to obtain a property as a string value + * + * @param key + * The key of the property + * @return The string value, or null if it does not exist. + */ + String getProperty(String key); + + /** + * This method is called to obtain a property as a string value + * + * @param key + * The key of the property + * @param defaultValue + * The default value to be returned if the property does not exist + * @return The string value, or null if it does not exist. + */ + String getProperty(String key, String defaultValue); + + /** + * Returns true if the named property is defined, false otherwise. + * + * @param key + * The key of the property we are interested in + * @return True if the property exists. + */ + boolean isPropertyDefined(String key); + + /** + * Returns an indication of the validity of the boolean property. A boolean property is considered to be valid only + * if it has the value "true" or "false" (ignoring case). + * + * @param key + * The property to be checked + * @return True if the value is a boolean constant, or false if it does not exist or is not a correct string + */ + boolean isValidBoolean(String key); + + /** + * Returns an indication if the indicated property represents a valid double-precision floating point number. + * + * @param key + * The property to be examined + * @return True if the property is a valid representation of a double, or false if it does not exist or contains + * illegal characters. + */ + boolean isValidDouble(String key); + + /** + * Returns an indication if the property is a valid integer value or not. + * + * @param key + * The key of the property to check + * @return True if the value is a valid integer string, or false if it does not exist or contains illegal + * characters. + */ + boolean isValidInteger(String key); + + /** + * Determines is the specified property exists and is a valid representation of an integer long value. + * + * @param key + * The property to be checked + * @return True if the property is a valid representation of an integer long value, and false if it either does not + * exist or is not valid. + */ + boolean isValidLong(String key); + + /** + * This method allows the caller to set all properties from a provided properties object into the configuration + * property set. + * <p> + * The primary difference between this method and the factory method + * {@link org.onap.ccsdk.sli.core.utils.configuration.ConfigurationFactory#getConfiguration(Properties)} is that this method does not clear and reload the + * configuration. Rather, this method merges the provided properties object contents into the existing properties, + * replacing any same-named keys with the values from this object. + * </p> + * + * @param properties + * The properties object to copy all properties from + */ + void setProperties(Properties properties); + + /** + * This method allows a caller to insert a new property definition into the configuration object. This allows the + * application to adjust or add to the current configuration. If the property already exists, it is replaced with + * the new value. + * + * @param key + * The key of the property to be defined + * @param value + * The value of the property to be defined + */ + void setProperty(String key, String value); +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/ConfigurationFactory.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/ConfigurationFactory.java new file mode 100644 index 000000000..05c132d0f --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/ConfigurationFactory.java @@ -0,0 +1,446 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.core.utils.configuration; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.att.eelf.i18n.EELFResourceManager; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.DateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Optional; +import java.util.Properties; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; +import org.apache.commons.lang3.StringUtils; +import org.onap.ccsdk.sli.core.utils.logging.LoggingUtils; +import org.onap.ccsdk.sli.core.utils.logging.Msg; + +/** + * The configuration factory is used to obtain access to an already created and initialized + * singleton configuration object as well as to create and initialize the singleton if not already + * set up. + * <p> + * This class is responsible for the creation of the configuration object used to manage the + * configuration of the application. The configuration object implementation must implement the + * <code>Configuration</code> interface. This allows for the factory to create different + * specializations in the future if needed and not break any application code. + * </p> + * <p> + * The configuration object is basically a wrapper around a properties object. The configuration is + * therefore specified as a set of properties that are loaded and processed from different sources + * with different precedences. It is important that the configuration object always be able to + * supply default values for any configuration properties that must be supplied, and not rely on the + * user always supplying these values. This also relieves the application itself from having to + * interpret missing or invalid properties and applying defaults. By having all of the defaults in + * one place, the application code can be simpler (not having to worry about defaults or invalid + * properties), and the defaults can be changed much easier (they are all in one place and not + * distributed throughout the codebase). + * </p> + * <p> + * Since the configuration is managed as a property object, we can use a characteristic of the + * <code>Properties</code> class to our advantage. Namely, if we put a property into a + * <code>Properties</code> object that already exists, the <code>Properties</code> object replaces + * it with the new value. This does not affect any other properties that may already be defined in + * the properties object. This gives us the ability to initialize the properties with default values + * for all of the application settings, then override just those that we need to override, possibly + * from multiple sources and in increasing order of precedence. + * </p> + * <p> + * This means that properties are in effect "merged" together from multiple sources in a prescribed + * precedence order. In fact, the precedence order that this factory implements is defined as: + * </p> + * <ol> + * <li>Default values from a system resource file.</li> + * <li>User-supplied properties file, if any.</li> + * <li>Application-supplied properties, if any.</li> + * <li>Command-line properties (if any)</li> + * </ol> + * <p> + * The name and location of the properties file that is loaded can also be set, either in the + * defaults, overridden by the system command line via -D, or as a system environment variable. + * There are two properties that can be specified to define the name and path. These are: + * </p> + * <dl> + * <dt>org.onap.appc.bootstrap.file</dt> + * <dd>This property defines the name of the file that will be loaded. If not specified, the default + * value is "appc.properties". This can be specified in either (or both) the default properties or + * the command line. The command line specification will always override.</dd> + * <dt>org.onap.appc.bootstrap.path</dt> + * <dd>This is a comma-delimited (,) path of directories to be searched to locate the specified + * file. The first occurrence of the file is the one loaded, and no additional searching is + * performed. The path can be specified in either, or both, the default values and the command line + * specification. If specified on the command line, the value overrides the default values. If + * omitted, the default path is <code>$/opt/onap/appc/data/properties,${user.home},.</code></dd> + * </dl> + * + * @since Mar 18, 2014 + * @version $Id$ + */ +public final class ConfigurationFactory { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(ConfigurationFactory.class); + + /** + * This is a string constant for the comma character. It's intended to be used a common string + * delimiter. + */ + private static final String COMMA = ","; + + /** + * The default Configuration object that implements the <code>Configuration</code> interface and + * represents our system configuration settings. + */ + private static DefaultConfiguration config = null; + + /** + * The default properties resource to be loaded + */ + private static final String DEFAULT_PROPERTIES = "org/onap/appc/default.properties"; + + /** + * This collection allows for special configurations to be created and maintained, organized by + * some identification (such as an object reference to the StackBuilder to which they apply), + * and then obtained from the configuration factory when needed. + */ + private static HashMap<Object, Configuration> localConfigs = new HashMap<>(); + + /** + * The reentrant shared lock used to serialize access to the properties. + */ + private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + /** + * This is a constant array of special property names that will be copied from the configuration + * back to the System properties object if they are defined in the configuration AND they do not + * already exist in the System properties object. These are intended as a convenience for + * setting the AFT properties for the Discovery client where it may be difficult or impossible + * to set VM arguments for the container. + */ + private static final String[] specialProperties = + {"AFT_LATITUDE", "AFT_LONGITUDE", "AFT_ENVIRONMENT", "SCLD_PLATFORM"}; + + private ConfigurationFactory() {} + + /** + * This method is used to obtain the common configuration object (as well as set it up if not + * already). + * + * @return The configuration object implementation + */ + public static Configuration getConfiguration() { + + /* + * First, attempt to access the properties as a read lock holder + */ + ReadLock readLock = lock.readLock(); + readLock.lock(); + try { + + /* + * If the properties don't exist, release the read lock and acquire the write lock. Once + * we get the write lock, we need to re-check to see that the configuration needs to be + * set up (because another thread may have beat us to it). After we get a configuration + * set up, release the write lock and re-obtain the read lock to access the properties. + */ + if (config == null) { + readLock.unlock(); + WriteLock writeLock = lock.writeLock(); + writeLock.lock(); + try { + if (config == null) { + config = new DefaultConfiguration(); + initialize(null); + } + } catch (Exception e){ + logger.error("getConfiguration: " + LoggingUtils.formatException(e)); + } finally { + writeLock.unlock(); + } + readLock.lock(); + } + } finally { + readLock.unlock(); + } + return config; + } + + /** + * This method will obtain the local configuration for the specified object if it exists, or + * will create it from the current global configuration. This allows the configuration to be + * tailored for a specific process or operation, and uniquely identified by some value (such as + * the object that represents the special use of the configuration). + * + * @param owner The owner or identification of the owner of the special configuration + * @return The special configuration object, or a clone of the global configuration so that it + * can be altered if needed. + */ + public static Configuration getConfiguration(final Object owner) { + DefaultConfiguration local; + ReadLock readLock = lock.readLock(); + readLock.lock(); + try { + local = (DefaultConfiguration) localConfigs.get(owner); + if (local == null) { + readLock.unlock(); + WriteLock writeLock = lock.writeLock(); + writeLock.lock(); + local = (DefaultConfiguration) localConfigs.get(owner); + if (local == null) { + local = getClonedDefaultConfiguration(owner, local); + } + writeLock.unlock(); + } + readLock.lock(); + } finally { + readLock.unlock(); + } + return local; + } + + /** + * This method allows the caller to alter the configuration, supplying the specified + * configuration properties which override the application default values. + * <p> + * The configuration is re-constructed (if already constructed) or created new (if not already + * created) and the default properties are loaded into the configuration. + * </p> + * <p> + * The primary purpose of this method is to allow the application configuration properties to be + * reset or refreshed after the application has already been initialized. This method will lock + * the configuration for the duration while it is being re-built, and should not be called on a + * regular basis. + * </p> + * + * @param props The properties used to configure the application. + * @return Access to the configuration implementation + */ + public static Configuration getConfiguration(final Properties props) { + WriteLock writeLock = lock.writeLock(); + writeLock.lock(); + try { + config = new DefaultConfiguration(); + initialize(props); + return config; + } finally { + writeLock.unlock(); + } + } + + private static DefaultConfiguration getClonedDefaultConfiguration(Object owner, DefaultConfiguration local) { + Optional<DefaultConfiguration> global = + Optional.ofNullable((DefaultConfiguration) getConfiguration()); + try { + if (global.isPresent()) { + local = (DefaultConfiguration) global.get().clone(); + } + } catch (CloneNotSupportedException e) { + logger.error("getClonedDefaultConfiguration: " + LoggingUtils.formatException(e)); + } + localConfigs.put(owner, local); + return local; + } + + /** + * This method will clear the current configuration and then re-initialize it with the default + * values, application-specific configuration file, user-supplied properties (if any), and then + * command-line settings. + * <p> + * This method <strong><em>MUST</em></strong> be called holding the configuration lock! + * </p> + * <p> + * This method is a little special in that logging messages generated during the method must be + * cached and delayed until after the logging framework has been initialized. After that, the + * delayed logging buffer can be dumped to the log file and cleared. + * </p> + * + * @param props Application-supplied configuration values, if any + */ + private static void initialize(final Properties props) { + DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); + Date now = new Date(); + logger.info( + "------------------------------------------------------------------------------"); + + logger.info(Msg.CONFIGURATION_STARTED, format.format(now)); + + /* + * Clear any existing properties + */ + config.clear(); + logger.info(Msg.CONFIGURATION_CLEARED); + + /* + * Load the defaults (if any are present) + */ + InputStream in = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(DEFAULT_PROPERTIES); + if (in != null) { + logger.info(Msg.LOADING_DEFAULTS, DEFAULT_PROPERTIES); + try { + config.setProperties(in); + } finally { + try { + in.close(); + } catch (IOException e) { + logger.error("Cannot close inputStream: " + LoggingUtils.formatException(e)); + } + } + for (String key : config.getProperties().stringPropertyNames()) { + + if ((!StringUtils.containsIgnoreCase(key, "pass"))&&(!StringUtils.containsIgnoreCase(key, "secret"))) + logger.info(Msg.PROPERTY_VALUE, key, config.getProperty(key)); + else + logger.info(Msg.PROPERTY_VALUE, key, "XXXX"); + } + } else { + logger.info(Msg.NO_DEFAULTS_FOUND, DEFAULT_PROPERTIES); + } + + /* + * Look for application configuration property file. By default, we will look for the file + * "cdp.properties" on the user home path, then on "./etc" (relative to current path), then + * on "../etc" (relative to current path). If we do not find any property file, then we + * continue. Otherwise, we load the first property file we find and then continue. In order + * to allow default values for the filename and paths to be searched, we first attempt to + * obtain these from our configuration object (which should be primed with default values + * and/or overridden with application-specified values). We then use the values obtained + * from that to get any user supplied values on the command line. + */ + String filename = config.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME, + Configuration.DEFAULT_BOOTSTRAP_FILE_NAME); + filename = System.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME, filename); + String env = System.getenv(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME); + if (env != null && env.trim().length() > 0) { + filename = env; + } + + String path = config.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH, + Configuration.DEFAULT_BOOTSTRAP_FILE_PATH); + path = System.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH, path); + env = System.getenv(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH); + if (env != null && env.trim().length() > 0) { + path = env; + } + + logger.info(Msg.SEARCHING_CONFIGURATION_OVERRIDES, path, filename); + + String[] pathElements = path.split(COMMA); + boolean found = false; + for (String pathElement : pathElements) { + File file = new File(pathElement, filename); + if (file.exists() && file.canRead() && !file.isDirectory()) { + + logger.info(Msg.LOADING_CONFIGURATION_OVERRIDES, file.getAbsolutePath()); + Properties fileProperties = new Properties(); + BufferedInputStream stream = null; + try { + stream = new BufferedInputStream(new FileInputStream(file)); + fileProperties.load(stream); + for (String key : fileProperties.stringPropertyNames()) { + if ((!StringUtils.containsIgnoreCase(key, "pass"))&&(!StringUtils.containsIgnoreCase(key, "secret"))) + logger.debug(Msg.PROPERTY_VALUE, key, fileProperties.getProperty(key)); + else + logger.info(Msg.PROPERTY_VALUE, key, "XXXX"); + config.setProperty(key, fileProperties.getProperty(key)); + } + found = true; + break; + } catch (IOException e) { + logger.error(LoggingUtils.formatException(e)); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + logger.error("Unable to close stream: " + LoggingUtils.formatException(e)); + } + } + } + } + + if (!found) { + logger.warn(Msg.NO_OVERRIDE_PROPERTY_FILE_LOADED, filename, path); + } + + /* + * Apply any application-specified properties + */ + if (props != null) { + logger.info(Msg.LOADING_APPLICATION_OVERRIDES); + for (String key : props.stringPropertyNames()) { + if ((!StringUtils.containsIgnoreCase(key, "pass"))&&(!StringUtils.containsIgnoreCase(key, "secret"))) + logger.debug(Msg.PROPERTY_VALUE, key, props.getProperty(key)); + else + logger.info(Msg.PROPERTY_VALUE, key, "XXXX"); + config.setProperty(key, props.getProperty(key)); + } + } else { + logger.info(Msg.NO_APPLICATION_OVERRIDES); + } + + /* + * Merge in the System.properties to pick-up any command line arguments (-Dkeyword=value) + */ + logger.info(Msg.MERGING_SYSTEM_PROPERTIES); + config.setProperties(System.getProperties()); + + /* + * As a convenience, copy the "specialProperties" that are not defined in System.properties + * from the configuration back to the system properties object. + */ + for (String key : config.getProperties().stringPropertyNames()) { + for (String specialProperty : specialProperties) { + if (key.equals(specialProperty) && !System.getProperties().containsKey(key)) { + System.setProperty(key, config.getProperty(key)); + logger.info(Msg.SETTING_SPECIAL_PROPERTY, key, config.getProperty(key)); + } + } + } + + /* + * Initialize the resource manager by loading the requested bundles, if any are defined. + * Resource bundles may be specified as a comma-delimited list of names. These resource + * names are base names of resource bundles, do not include the language or country code, or + * the ".properties" extension. The actual loading of the resource bundles is done lazily + * when requested the first time. If the bundle does not exist, or cannot be loaded, it is + * ignored. + */ + String resourcesList = config.getProperty(Configuration.PROPERTY_RESOURCE_BUNDLES, + Configuration.DEFAULT_RESOURCE_BUNDLES); + String[] resources = resourcesList.split(","); + for (String resource : resources) { + logger.info(Msg.LOADING_RESOURCE_BUNDLE, resource.trim()); + EELFResourceManager.loadMessageBundle(resource.trim()); + } + } +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/DefaultConfiguration.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/DefaultConfiguration.java new file mode 100644 index 000000000..319b9f0b6 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/DefaultConfiguration.java @@ -0,0 +1,565 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.core.utils.configuration; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.security.Provider; +import java.security.Provider.Service; +import java.security.Security; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.onap.ccsdk.sli.core.utils.encryption.EncryptionTool; +import org.onap.ccsdk.sli.core.utils.logging.LoggingUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class provides the implementation of the <code>Configuration</code> interface. It is created + * by the ConfigurationFactory and initialized with the configuration values for the process. + * + * @since Mar 18, 2014 + */ +public final class DefaultConfiguration implements Configuration, Cloneable { + + private static final Logger logger = LoggerFactory.getLogger(DefaultConfiguration.class); + + /** + * The framework configuration properties. + */ + private Properties properties = new Properties(); + + /** + * Construct the configuration object. + */ + DefaultConfiguration() {} + + /** + * Clears all properties + */ + public void clear() { + properties.clear(); + } + + /** + * @see Object#clone() + */ + @Override + protected Object clone() throws CloneNotSupportedException { + DefaultConfiguration clone = (DefaultConfiguration) super.clone(); + + clone.properties = new Properties(this.properties); + clone.properties.putAll(this.properties); + + return clone; + } + + /** + * Decrypts an encrypted value, if it is encrypted, and returns the clear text. Performs no + * operation on the string if it is not encrypted. + * + * @param value The value to (optionally) be decrypted + * @return The clear text + */ + @SuppressWarnings("nls") + private static String decrypt(String value) { + if (value != null && value.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX)) { + try { + return EncryptionTool.getInstance().decrypt(value); + } catch (Exception e) { + StringBuilder out = new StringBuilder(); + for (Provider p : Security.getProviders()) { + for (Service s : p.getServices()) { + String algo = s.getAlgorithm(); + out.append(String.format( + "\n==Found Algorithm [ %s ] in provider [ %s ] and service [ %s ]", + algo, p.getName(), s.getClassName())); + } + } + logger.debug(out.toString()); + logger.warn(String.format("Could not decrypt the configuration value [%s]", value), + e); + } + } + return value; + } + + /** + * Decrypts all elements in the properties object + */ + private void decryptAllProperties() { + if (properties != null) { + for (Entry<Object, Object> e : properties.entrySet()) { + if (e.getValue() != null) { + e.setValue(decrypt(e.getValue().toString())); + } + } + } + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object obj) { + + if (obj == null) { + return false; + } + + if (this.getClass() != obj.getClass()) { + return false; + } + + DefaultConfiguration other = (DefaultConfiguration) obj; + + return (this.properties.size() == other.properties.size()) + && (this.properties.entrySet().containsAll(other.properties.entrySet())) + && (other.properties.entrySet().containsAll(this.properties.entrySet())); + + } + + /** + * This method will use the properties object to expand any variables that may be present in the + * template provided. Variables are represented by the string "${name}", where "name" is the + * name of a property defined in either the current configuration object, or system properties + * if undefined. If the value cannot be found, the variable is removed and an empty string is + * used to replace the variable. + * + * @param template The template to be expanded + * @return The expanded template where each variable is replaced with its value + */ + @SuppressWarnings("nls") + private String expandVariables(String template) { + if (template == null) { + return null; + } + + // Decrypt the template if needed + // template = decrypt(template); DH: Do not assign values to parameters, bad form! Also, + // Sonar complains + // bitterly + + StringBuilder builder = new StringBuilder(decrypt(template)); + Pattern pattern = Pattern.compile("\\$\\{([^\\}]+)\\}"); + Matcher matcher = pattern.matcher(builder); + while (matcher.find()) { + String variable = matcher.group(1); + String value = properties.getProperty(variable); + if (value == null) { + value = System.getProperty(variable); + } + if (value == null) { + value = ""; + } + builder.replace(matcher.start(), matcher.end(), value); + + matcher.reset(); + } + return builder.toString().trim(); + } + + /** + * This method is called to obtain a property expressed as a boolean value (true or false). The + * standard rules for Boolean.parseBoolean() are used. + * + * @param key The property key + * @return The value of the property expressed as a boolean, or false if it does not exist. + */ + @SuppressWarnings("nls") + @Override + public boolean getBooleanProperty(String key) { + return Boolean.valueOf(getProperty(key, "false")); + } + + /** + * This method is called to obtain a property expressed as a boolean value (true or false). The + * standard rules for Boolean.valueOf(String) are used. + * + * @param key The property key + * @param defaultValue The default value to be returned if the property does not exist + * @return The value of the property expressed as a boolean, or false if it does not exist. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getBooleanProperty(String, boolean) + */ + @Override + public boolean getBooleanProperty(String key, boolean defaultValue) { + if (isPropertyDefined(key)) { + return getBooleanProperty(key); + } + return defaultValue; + } + + /** + * Returns the indicated property value expressed as a floating point double-precision value + * (double). + * + * @param key The property to retrieve + * @return The value of the property, or 0.0 if not found + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getDoubleProperty(String) + */ + @SuppressWarnings("nls") + @Override + public double getDoubleProperty(String key) { + try { + return Double.valueOf(getProperty(key, "0.0")); + } catch (NumberFormatException e) { + return 0.0; + } + } + + /** + * This method is called to obtain a property as a string value + * + * @param key The key of the property + * @param defaultValue The default value to be returned if the property does not exist + * @return The string value, or null if it does not exist. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getDoubleProperty(String, double) + */ + @Override + public double getDoubleProperty(String key, double defaultValue) { + if (isPropertyDefined(key)) { + return getDoubleProperty(key); + } + return defaultValue; + } + + /** + * Returns the property indicated expressed as an integer. The standard rules for + * {@link Integer#parseInt(String, int)} using a radix of 10 are used. + * + * @param key The property name to retrieve. + * @return The value of the property, or 0 if it does not exist or is invalid. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getIntegerProperty(String) + */ + @SuppressWarnings("nls") + @Override + public int getIntegerProperty(String key) { + try { + return Integer.parseInt(getProperty(key, "0"), 10); + } catch (NumberFormatException e) { + return 0; + } + } + + /** + * Returns the property indicated expressed as an integer. The standard rules for + * Integer.parseInt(String, int) using a radix of 10 are used. + * + * @param key The property name to retrieve. + * @param defaultValue The default value to be returned if the property does not exist + * @return The value of the property, or 0 if it does not exist or is invalid. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getIntegerProperty(String, int) + */ + @Override + public int getIntegerProperty(String key, int defaultValue) { + if (isPropertyDefined(key)) { + return getIntegerProperty(key); + } + return defaultValue; + } + + /** + * Returns the specified property as a long integer value, if it exists, or zero if it does not. + * + * @param key The key of the property desired. + * @return The value of the property expressed as an integer long value, or zero if the property + * does not exist or is not a valid integer long. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getLongProperty(String) + */ + @SuppressWarnings("nls") + @Override + public long getLongProperty(String key) { + try { + return Long.parseLong(getProperty(key, "0"), 10); + } catch (NumberFormatException e) { + return 0; + } + } + + /** + * Returns the specified property as a long integer value, if it exists, or the default value if + * it does not exist or is invalid. + * + * @param key The key of the property desired. + * @param defaultValue the value to be returned if the property is not valid or does not exist. + * @return The value of the property expressed as an integer long value, or the default value if + * the property does not exist or is not a valid integer long. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getLongProperty(String, long) + */ + @Override + public long getLongProperty(String key, long defaultValue) { + if (isPropertyDefined(key)) { + return getLongProperty(key); + } + return defaultValue; + } + + /** + * This method can be called to retrieve a properties object that is immutable. Any attempt to + * modify the properties object returned will result in an exception. This allows a caller to + * view the current configuration as a set of properties. + * + * @return An unmodifiable properties object. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getProperties() + */ + @Override + public Properties getProperties() { + return new UnmodifiableProperties(properties); + } + + /** + * This method is called to obtain a property as a string value + * + * @param key The key of the property + * @return The string value, or null if it does not exist. + */ + @Override + public String getProperty(String key) { + String value = properties.getProperty(key); + if (value == null) { + return null; + } + return expandVariables(value.trim()); + } + + /** + * This method is called to obtain a property as a string value + * + * @param key The key of the property + * @param defaultValue The default value to be returned if the property does not exist + * @return The string value, or null if it does not exist. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#getProperty(String, + * String) + */ + @Override + public String getProperty(String key, String defaultValue) { + if (isPropertyDefined(key)) { + return getProperty(key); + } + + if (defaultValue == null) { + return null; + } + + return expandVariables(defaultValue.trim()); + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return properties == null ? 0 : properties.hashCode(); + } + + /** + * Returns true if the named property is defined, false otherwise. + * + * @param key The key of the property we are interested in + * @return True if the property exists. + */ + @Override + public boolean isPropertyDefined(String key) { + return properties.containsKey(key); + } + + /** + * Returns an indication of the validity of the boolean property. A boolean property is + * considered to be valid only if it has the value "true" or "false" (ignoring case). + * + * @param key The property to be checked + * @return True if the value is a boolean constant, or false if it does not exist or is not a + * correct string + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#isValidBoolean(String) + */ + @SuppressWarnings("nls") + @Override + public boolean isValidBoolean(String key) { + String value = getProperty(key); + if (value != null) { + value = value.toLowerCase(); + return value.matches("true|false"); + } + return false; + } + + /** + * Returns an indication if the indicated property represents a valid double-precision floating + * point number. + * + * @param key The property to be examined + * @return True if the property is a valid representation of a double, or false if it does not + * exist or contains illegal characters. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#isValidDouble(String) + */ + @Override + public boolean isValidDouble(String key) { + String value = getProperty(key); + if (value != null) { + try { + Double.valueOf(value); + return true; + } catch (NumberFormatException e) { + return false; + } + } + return false; + } + + /** + * Returns an indication if the property is a valid integer value or not. + * + * @param key The key of the property to check + * @return True if the value is a valid integer string, or false if it does not exist or + * contains illegal characters. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#isValidInteger(String) + */ + @Override + public boolean isValidInteger(String key) { + String value = getProperty(key); + if (value != null) { + try { + Integer.parseInt(value.trim(), 10); + return true; + } catch (NumberFormatException e) { + return false; + } + } + return false; + } + + /** + * Determines is the specified property exists and is a valid representation of an integer long + * value. + * + * @param key The property to be checked + * @return True if the property is a valid representation of an integer long value, and false if + * it either does not exist or is not valid. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#isValidLong(String) + */ + @Override + public boolean isValidLong(String key) { + String value = getProperty(key); + if (value != null) { + try { + Long.parseLong(value.trim(), 10); + return true; + } catch (NumberFormatException e) { + return false; + } + } + return false; + } + + /** + * This method allows an implementation to load configuration properties that may override + * default values. + * + * @param is An input stream that contains the properties to be loaded + */ + public void setProperties(InputStream is) { + try { + properties.load(is); + } catch (IOException e) { + logger.warn("setProperties with inputStream got exception", e); + } + } + + /** + * This method allows an implementation to load configuration properties that may override + * default values. + * + * @param props An optional Properties object to be merged into the configuration, replacing any + * same-named properties. + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#setProperties(Properties) + */ + @Override + public void setProperties(Properties props) { + properties.putAll(props); + decryptAllProperties(); + } + + /** + * This method allows a caller to insert a new property definition into the configuration + * object. This allows the application to adjust or add to the current configuration. If the + * property already exists, it is replaced with the new value. + * + * @param key The key of the property to be defined + * @param value The value of the property to be defined + * @see org.onap.ccsdk.sli.core.utils.configuration.Configuration#setProperty(String, + * String) + */ + @Override + public void setProperty(String key, String value) { + properties.setProperty(key, decrypt(value)); + } + + /** + * @see Object#toString() + */ + @SuppressWarnings("nls") + @Override + public String toString() { + return String.format("Configuration: %d properties, keys:[%s]", properties.size(), + properties.keySet().toString()); + } + + /** + * This is a helper method to read the manifest of the jar file that this class was loaded from. + * Note that this will only work if the code is packaged in a jar file. If it is an open + * deployment, such as under eclipse, this will not work and there is code added to detect that + * case. + * + * @return The manifest object from the jar file, or null if the code is not packaged in a jar + * file. + */ + @SuppressWarnings({"unused", "nls"}) + private Manifest getManifest() { + ProtectionDomain domain = getClass().getProtectionDomain(); + CodeSource source = domain.getCodeSource(); + URL location = source.getLocation(); + String path = location.getPath(); + int index = path.indexOf('!'); + if (index != -1) { + path = path.substring(0, index); + } + if (path.endsWith(".jar")) { + try (JarFile jar = new JarFile(location.getFile())) { + return jar.getManifest(); + } catch (IOException e) { + logger.error("getManifest: " + LoggingUtils.formatException(e)); + } + } + + return null; + } +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/UnmodifiableProperties.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/UnmodifiableProperties.java new file mode 100644 index 000000000..539b4ed7e --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/UnmodifiableProperties.java @@ -0,0 +1,354 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.core.utils.configuration; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.InvalidPropertiesFormatException; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +/** + * This utility class is used to wrap a properties object and to delegate all read operations to the property object, + * while disallowing any write or modification to the property object. + * + */ +public class UnmodifiableProperties extends Properties implements Cloneable { + + /** + * Serial number + */ + private static final long serialVersionUID = 1L; + + private static final String PROPERTY_CANNOT_BE_MODIFIED_MSG = "Property cannot be modified!"; + + /** + * The properties object which we are wrapping + */ + private Properties properties; + + /** + * Create the unmodifiable wrapper around the provided properties object + * + * @param properties + * The properties to be wrapped and protected from modification + */ + public UnmodifiableProperties(Properties properties) { + this.properties = properties; + } + + /** + * @see java.util.Hashtable#clear() + */ + @Override + public synchronized void clear() { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see java.util.Hashtable#clone() + */ + // @sonar:off + @Override + public synchronized Object clone() { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + // @sonar:on + + /** + * @see java.util.Hashtable#contains(Object) + */ + @Override + public synchronized boolean contains(Object value) { + return properties.contains(value); + } + + /** + * @see java.util.Hashtable#containsKey(Object) + */ + @Override + public synchronized boolean containsKey(Object key) { + return properties.containsKey(key); + } + + /** + * @see java.util.Hashtable#containsValue(Object) + */ + @Override + public boolean containsValue(Object value) { + return properties.containsValue(value); + } + + /** + * @see java.util.Hashtable#elements() + */ + @Override + public synchronized Enumeration<Object> elements() { + return properties.elements(); + } + + /** + * @see java.util.Hashtable#entrySet() + */ + @Override + public Set<Map.Entry<Object, Object>> entrySet() { + return Collections.unmodifiableSet(properties.entrySet()); + } + + /** + * @see java.util.Hashtable#equals(Object) + */ + @Override + public synchronized boolean equals(Object o) { + return properties.equals(o); + } + + /** + * @see java.util.Hashtable#get(Object) + */ + @Override + public synchronized Object get(Object key) { + return properties.get(key); + } + + /** + * @see Properties#getProperty(String) + */ + @Override + public String getProperty(String key) { + return properties.getProperty(key); + } + + /** + * @see Properties#getProperty(String, String) + */ + @Override + public String getProperty(String key, String defaultValue) { + return properties.getProperty(key, defaultValue); + } + + /** + * @see java.util.Hashtable#hashCode() + */ + @Override + public synchronized int hashCode() { + return properties.hashCode(); + } + + /** + * @see java.util.Hashtable#isEmpty() + */ + @Override + public synchronized boolean isEmpty() { + return properties.isEmpty(); + } + + /** + * @see java.util.Hashtable#keys() + */ + @Override + public synchronized Enumeration<Object> keys() { + return properties.keys(); + } + + /** + * @see java.util.Hashtable#keySet() + */ + @Override + public Set<Object> keySet() { + return Collections.unmodifiableSet(properties.keySet()); + } + + /** + * @see Properties#list(PrintStream) + */ + @Override + public void list(PrintStream out) { + properties.list(out); + } + + /** + * @see Properties#list(PrintWriter) + */ + @Override + public void list(PrintWriter out) { + properties.list(out); + } + + /** + * @see Properties#load(InputStream) + */ + @Override + public synchronized void load(InputStream inStream) throws IOException { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see Properties#load(Reader) + */ + @Override + public synchronized void load(Reader reader) throws IOException { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see Properties#loadFromXML(InputStream) + */ + @Override + public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see Properties#propertyNames() + */ + @Override + public Enumeration<?> propertyNames() { + return properties.propertyNames(); + } + + /** + * @see java.util.Hashtable#put(Object, Object) + */ + @Override + public synchronized Object put(Object key, Object value) { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see java.util.Hashtable#putAll(Map) + */ + @Override + public synchronized void putAll(Map<? extends Object, ? extends Object> t) { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see java.util.Hashtable#rehash() + */ + @Override + protected void rehash() { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see java.util.Hashtable#remove(Object) + */ + @Override + public synchronized Object remove(Object key) { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see Properties#save(OutputStream, String) + */ + @Override + @Deprecated + public synchronized void save(OutputStream out, String comments) { + properties.save(out, comments); + } + + /** + * @see Properties#setProperty(String, String) + */ + @Override + public synchronized Object setProperty(String key, String value) { + throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG); + } + + /** + * @see java.util.Hashtable#size() + */ + @Override + public synchronized int size() { + return properties.size(); + } + + /** + * @see Properties#store(OutputStream, String) + */ + @Override + public void store(OutputStream out, String comments) throws IOException { + properties.store(out, comments); + } + + /** + * @see Properties#store(Writer, String) + */ + @Override + public void store(Writer writer, String comments) throws IOException { + properties.store(writer, comments); + } + + /** + * @see Properties#storeToXML(OutputStream, String) + */ + @Override + public synchronized void storeToXML(OutputStream os, String comment) throws IOException { + properties.storeToXML(os, comment); + } + + /** + * @see Properties#storeToXML(OutputStream, String, String) + */ + @Override + public synchronized void storeToXML(OutputStream os, String comment, String encoding) throws IOException { + properties.storeToXML(os, comment, encoding); + } + + /** + * @see Properties#stringPropertyNames() + */ + @Override + public Set<String> stringPropertyNames() { + return properties.stringPropertyNames(); + } + + /** + * @see java.util.Hashtable#toString() + */ + @Override + public synchronized String toString() { + return properties.toString(); + } + + /** + * @see java.util.Hashtable#values() + */ + @Override + public Collection<Object> values() { + return Collections.unmodifiableCollection(properties.values()); + } +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/package.html b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/package.html new file mode 100644 index 000000000..059821d2f --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/package.html @@ -0,0 +1,173 @@ +<!-- + ============LICENSE_START======================================================= + ONAP : APPC + ================================================================================ + Copyright (C) 2017 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 + + 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========================================================= + --> + +<html> +<head> +<title>Configuration</title> +</head> + +<body> + <p style="margin-left: 30.0px;"> + CDP Configuration support is provided by a common framework to load + and manage configuration properties from multiple sources. The basic + concept is to load a set of default properties from a known resource + file located on the class path, and then override these defaults + with optional settings that can be provided by a user through either + additional property files or via the command line (as VM arguments). + The loading of defaults from a resource property file (named <strong>com/att/cdp/default.properties</strong>) + ensures that values are defined for properties the application needs + in order to operate. + </p> + <p style="margin-left: 30.0px;"> + One of these default values that can be set is the name of the + property file that allows the user to supply settings, as well as + the path where the file can be found. In general, the default name + of the property file will be "<strong>cdp.properties</strong>", + and the path that will be searched is "<strong>${user.home};etc;../etc</strong>". + However, these values can be changed through the use of the + default.properties resource file. The property that specifies the + property file name is named <strong>com.att.cdp.bootstrap.file</strong>, + while the property named <strong>com.att.cdp.bootstrap.path</strong> + specifies the search path. + </p> + <p style="margin-left: 30.0px;"> + After the default.properties are loaded, but prior to searching for + the application configuration file, the configuration factory checks + for properties <strong>com.att.cdp.bootstrap.path</strong> and <strong>com.att.cdp.bootstrap.file + </strong>in the System properties object (meaning they were set by the + command line). If these values are defined in the system properties + object, they are used. If not, these values are obtained from the + default properties just loaded. This allows the specification of + either the file name or path, or both, to be overridden during start + up by using command-line arguments. + </p> + <p style="margin-left: 30.0px;">The search path is scanned for the + first occurrence of the specified property file. The first + occurrence is loaded and scanning is stopped at that point. The + configuration factory does not load all occurrences it finds, only + the first occurrence it finds.</p> + <p style="margin-left: 30.0px;">The configuration properties are + loaded and processed according to a defined precedence order, such + that properties defined with a higher precedence override the same + property at a lower precedence. The precedence order is defined as + follows:</p> + <h2>Precedence Order</h2> + <ol> + <li>Default properties are initially loaded into the + configuration. These default properties are the lowest level + precedence, and will be overridden by any properties specified at + higher levels. These are loaded from resources that are packaged + as part of the various application components. Each component + (Server, Coordinator, EPM, or CLI) may have different default + properties. The default properties are loaded from a resource + named <strong>com/att/cdp/default.properties</strong>. The default + properties can specify the name of the application property file + to be used to configure the application, as well as the path to + search. Additionally, these properties can be supplied via the + command line to override the default settings if needed.<br /> <br /> + </li> + <li>The configuration factory allows for the application to + supply an initial properties object to initialize the + configuration. This properties object could be loaded or created + in any way necessary for the application. This is totally up to + the application to define, if it is needed. If no + application-specific property object is supplied, this step is + skipped. If a property object is supplied, it is used to replace + or set any properties that may have been defined by the defaults.<br /> + <br /> + </li> + <li>The configuration factory will then search for a bootstrap + file on a bootstrap path. The actual bootstrap file name and path + can be specified as properties on the command line, or will + default to a file name of <strong>cdp.properties</strong> and a + path of <strong>${user.home};etc;../etc</strong>. If desired, the + user can specify the exact name of the property file to be loaded + as well as the path using <strong>-Dcom.att.cdp.bootstrap.file=<filename></strong> + and <strong>-Dcom.att.cdp.bootstrap.path=<path></strong>. + These properties are set to default values by the default + properties loaded in step #1 above. The first occurrence of a + property file is the file loaded and used. Any other occurrences + are not processed.<br /> <br /> + </li> + <li>The System properties are then merged into the + configuration. This allows the highest level of precedence, + command-line VM arguments (-D<strong>name=value</strong>) to be + merged into the configuration property object. These settings + override all lower level settings of the same name, as well as + merge all system properties into the configuration object. + </li> + </ol> + <h2>Variables</h2> + <p style="margin-left: 30.0px;"> + The configuration support allows for variables to be inserted into + any property that is defined. Variables are named using the format <strong>${name}</strong>, + where the "name" is the name of a property that is defined + in the configuration, or a system property (such as <strong>user.home</strong>). + Variables can nest, such that a variable can be replaced with + another variable, which is then reevaluated to obtain the value. + This allows for indirection as well as variable substitution, if + needed. + </p> + <h2>Using the Configuration Support</h2> + <p style="margin-left: 30.0px;"> + The configuration support was designed to be easy to use. The + configuration implementation is abstracted away from the application + so that it could be changed easily in the future if needed, or if we + needed to load different implementations for different reasons. This + means that the application always accesses the configuration through + an interface, named <strong>Configuration</strong>. The + implementation of that configuration interface is obtained by a + static method on the <strong>ConfigurationFactory</strong> class. + The configuration factory will both create the configuration if not + already created on the first access, as well as return the current + configuration if already created. Additionally, the + ConfigurationFactory provides mechanisms to recreate the + configuration after the application is initialized should the need + arise to update its configuration. + </p> + <p style="margin-left: 30.0px;">An example of the code needed to + obtain access to the configuration is:</p> + <pre style="margin-left: 30.0px;">Configuration config = ConfigurationFactory.getConfiguration();</pre> + <p style="margin-left: 30.0px;">Please refer to the javadoc or the + source code in cdp-common for other ways that the configuration and + configuration factory can be used.</p> + <h2>Reloading Properties</h2> + <p style="margin-left: 30.0px;">The configuration support allows + for properties to be re-loaded and re-evaluated after the + application is running. This is designed to allow a configuration to + be refreshed should the need arise. This could allow on-demand + refresh (via a command, for example), or automatically based on + sensing a change in the configuration file.</p> + <p style="margin-left: 30.0px;"> + When the <strong>ConfigurationFactory</strong> method <strong>getConfiguration(Propert</strong><strong>ies)</strong> + is called, the current configuration is cleared and rebuilt using + the process defined above. The supplied property object is used in + step #2 of the process. While the properties are being re-built, no + access to the properties are allowed. Any attempt to access + properties while the re-build operation is in effect will block the + caller until completed. This is accomplished using read and write + shared locks. + </p> +</body> +</html> diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/LoggingConstants.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/LoggingConstants.java new file mode 100644 index 000000000..6ef270d21 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/LoggingConstants.java @@ -0,0 +1,132 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.core.utils.logging; + +import java.util.Arrays; +import java.util.List; + +/** + * Constant definition of logging + */ +public class LoggingConstants { + private LoggingConstants() { + throw new IllegalAccessError("LoggingConstants"); + } + + /** + * Constants of MDC property keys + */ + public static class MDCKeys { + private MDCKeys() { + throw new IllegalAccessError("MDCKeys"); + } + + public static final String REQUEST_ID = "RequestID"; + public static final String INSTANCE_ID = "InstanceUUID"; + public static final String SERVICE_INSTANCE_ID = "ServiceInstanceID"; + public static final String ERROR_CODE = "ErrorCode"; + public static final String ERROR_DESCRIPTION = "ErrorDescription"; + public static final String STATUS_CODE = "StatusCode"; + public static final String RESPONSE_CODE = "ResponseCode"; + public static final String RESPONSE_DESCRIPTION = "ResponseDescription"; + public static final String TARGET_ENTITY = "TargetEntity"; + public static final String TARGET_SERVICE_NAME = "TargetServiceName"; + public static final String PARTNER_NAME = "PartnerName"; + public static final String SERVER_NAME = "ServerName"; + public static final String SERVICE_NAME = "ServiceName"; + public static final String BEGIN_TIMESTAMP = "BeginTimestamp"; + public static final String END_TIMESTAMP = "EndTimestamp"; + public static final String ELAPSED_TIME = "ElapsedTime"; + public static final String MARKER = "Marker"; + public static final String METRIC_MARKER = "MetricMarker"; + public static final String MDC_STRING = "MDC"; + public static final String CUSTOM_FIELD1 = "CustomField1"; + public static final String CUSTOM_FIELD2 = "CustomField2"; + public static final String CLIENT_IP_ADDRESS = "ClientIPAddress"; + public static final String PROCESS_KEY = "ProcessKey"; + public static final String CLASS_NAME = "ClassName"; + public static final String TARGET_VIRTUAL_ENTITY = "TargetVirtualEntity"; + public static final String INVOCATION_ID = "InvocationID"; + + public static final List<String> MDC_KEYS = Arrays.asList( + BEGIN_TIMESTAMP, END_TIMESTAMP, REQUEST_ID, SERVICE_INSTANCE_ID, + ERROR_CODE, SERVER_NAME, SERVICE_NAME, PARTNER_NAME, STATUS_CODE, + RESPONSE_CODE, RESPONSE_DESCRIPTION, INSTANCE_ID, + ERROR_DESCRIPTION, MARKER, PROCESS_KEY, INVOCATION_ID + ); + } + + /** + * Constants of status code values + */ + public static class StatusCodes { + private StatusCodes() { + throw new IllegalAccessError("StatusCodes"); + } + public static final String COMPLETE = "COMPLETE"; + public static final String ERROR = "ERROR"; + } + + /** + * Constants of APPC target names + */ + public static class TargetNames { + private TargetNames() { + throw new IllegalAccessError("TargetNames"); + } + public static final String APPC = "APPC"; + public static final String AAI = "A&AI"; + public static final String DB = "DataBase"; + public static final String APPC_PROVIDER = "APPC Provider"; + public static final String APPC_OAM_PROVIDER = "APPC OAM Provider"; + public static final String STATE_MACHINE = "StateMachine"; + public static final String WORKFLOW_MANAGER = "WorkflowManager"; + public static final String REQUEST_VALIDATOR = "RequestValidator"; + public static final String LOCK_MANAGER = "LockManager"; + public static final String REQUEST_HANDLER = "RequestHandler"; + } + + /** + * Constants of targeted service names + */ + public static class TargetServiceNames { + private TargetServiceNames() { + throw new IllegalAccessError("TargetServiceNames"); + } + + /** + * Constants of AAI service names + */ + public static class AAIServiceNames { + private AAIServiceNames() { + throw new IllegalAccessError("AAIServiceNames"); + } + public static final String QUERY = "/aai/v14/network/generic-vnfs/generic-vnf"; + public static final String GET_VNF_DATA = "getVnfData"; + } + + } + +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/LoggingUtils.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/LoggingUtils.java new file mode 100644 index 000000000..d9470ddf2 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/LoggingUtils.java @@ -0,0 +1,314 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.core.utils.logging; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.att.eelf.i18n.EELFResolvableErrorEnum; +import com.att.eelf.i18n.EELFResourceManager; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.TimeZone; +import java.util.UUID; +import org.slf4j.MDC; + +import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID; +import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME; + +/** + * Logging utilities + */ +public class LoggingUtils { + + private static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger(); + private static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + private static final EELFLogger metricLogger = EELFManager.getInstance().getMetricsLogger(); + + private LoggingUtils() { + throw new IllegalAccessError("LoggingUtils"); + } + + + public static void logErrorMessage(String errorCode, String errorDescription, + String targetEntity, String targetServiceName, String additionalMessage, + String className) { + logError(errorCode, errorDescription, targetEntity, targetServiceName, additionalMessage, + className); + } + + public static void logErrorMessage(String targetEntity, String targetServiceName, + String additionalMessage, String className) { + logError("", "", targetEntity, targetServiceName, additionalMessage, className); + } + + public static void logErrorMessage(String targetServiceName, String additionalMessage, + String className) { + logError("", "", LoggingConstants.TargetNames.APPC, targetServiceName, additionalMessage, + className); + } + + private static void logError(String errorCode, String errorDescription, String targetEntity, + String targetServiceName, String additionalMessage, String className) { + populateErrorLogContext(errorCode, errorDescription, targetEntity, targetServiceName, + className); + int additionalLength = additionalMessage.length()<100 ? additionalMessage.length() : 100; + String additionalLog = additionalMessage == null ? "" : additionalMessage.replace("\n", "").substring(0, additionalLength); + errorLogger.error(additionalLog); + cleanErrorLogContext(); + } + + public static String formatException(Exception e) { + String outStr = EELFResourceManager.format(e); + outStr = outStr.replaceAll("[\\n]", ""); + return outStr; + } + + public static void logAuditMessage(Instant beginTimeStamp, Instant endTimeStamp, String code, + String responseDescription, String className) { + populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className); + auditLogger.info(EELFResourceManager.format(Msg.APPC_AUDIT_MSG, MDC.get(MDC_SERVICE_NAME), + MDC.get(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY), + MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME), MDC.get(MDC_KEY_REQUEST_ID), + MDC.get(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP), + MDC.get(LoggingConstants.MDCKeys.END_TIMESTAMP), + MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE))); + cleanAuditErrorContext(); + } + + public static String formMDCString() { + //Remove all newlines, tabs, pipes, escape all commas + StringBuilder sb = new StringBuilder(); + for (String key : LoggingConstants.MDCKeys.MDC_KEYS) { + String value = MDC.get(key); + + if (value != null) { + value = value.replaceAll("[\\n\\t\\|]", ""); + value = value.replaceAll(",", "\\\\,"); + } + else + value = ""; + + if (sb.length()==0) + sb.append(key + "=" + value); + else + sb.append("," + key + "=" + value); + } + + return sb.toString(); + } + + public static String formServerFqdnString() { + return (System.getenv("fqdn")!=null) ? System.getenv("fqdn") : "www.appc.com"; + } + + public static void auditInfo(Instant beginTimeStamp, Instant endTimeStamp, String code, + String responseDescription, String className, EELFResolvableErrorEnum resourceId, + String... arguments) { + populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className); + auditLogger.info(resourceId, arguments); + cleanAuditErrorContext(); + } + + public static void auditWarn(Instant beginTimeStamp, Instant endTimeStamp, String code, + String responseDescription, String className, EELFResolvableErrorEnum resourceId, + String... arguments) { + populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className); + auditLogger.warn(resourceId, arguments); + cleanAuditErrorContext(); + } + + public static void logMetricsMessage(Instant beginTimeStamp, Instant endTimeStamp, + String targetEntity, String targetServiceName, String statusCode, String responseCode, + String responseDescription, String className) { + populateMetricLogContext(beginTimeStamp, endTimeStamp, targetEntity, targetServiceName, + statusCode, responseCode, responseDescription, className); + metricLogger.info(EELFResourceManager.format(Msg.APPC_METRIC_MSG, MDC.get(MDC_SERVICE_NAME), + MDC.get(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY), + MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME), MDC.get(MDC_KEY_REQUEST_ID), + MDC.get(LoggingConstants.MDCKeys.TARGET_ENTITY), + MDC.get(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME), + MDC.get(LoggingConstants.MDCKeys.ELAPSED_TIME), + MDC.get(LoggingConstants.MDCKeys.STATUS_CODE))); + cleanMetricContext(); + } + + private static void populateAuditLogContext(Instant beginTimeStamp, Instant endTimeStamp, + String code, String responseDescription, String className) { + populateTimeContext(beginTimeStamp, endTimeStamp); + populateRequestContext(); + String statusCode = ("100".equals(code) || "400".equals(code)) + ? LoggingConstants.StatusCodes.COMPLETE : LoggingConstants.StatusCodes.ERROR; + populateResponseContext(statusCode, code, responseDescription); + MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : ""); + MDC.put(LoggingConstants.MDCKeys.MDC_STRING, LoggingUtils.formMDCString()); + } + + private static void cleanAuditErrorContext() { + cleanRequestContext(); + cleanTimeContext(); + cleanResponseContext(); + cleanErrorContext(); + MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME); + } + + private static void populateErrorLogContext(String errorCode, String errorDescription, + String targetEntity, String targetServiceName, String className) { + populateErrorContext(errorCode, errorDescription); + populateTargetContext(targetEntity, targetServiceName != null ? targetServiceName : ""); + MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : ""); + } + + private static void cleanErrorLogContext() { + cleanErrorContext(); + cleanTargetContext(); + MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME); + } + + private static void populateMetricLogContext(Instant beginTimeStamp, Instant endTimeStamp, + String targetEntity, String targetServiceName, String statusCode, String responseCode, + String responseDescription, String className) { + populateRequestContext(); + populateTimeContext(beginTimeStamp, endTimeStamp); + populateTargetContext(targetEntity, targetServiceName); + populateResponseContext(statusCode, responseCode, responseDescription); + MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : ""); + MDC.put(LoggingConstants.MDCKeys.MDC_STRING, LoggingUtils.formMDCString()); + } + + private static void cleanMetricContext() { + cleanRequestContext(); + cleanTimeContext(); + cleanTargetContext(); + cleanResponseContext(); + MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME); + } + + private static void populateTargetContext(String targetEntity, String targetServiceName) { + MDC.put(LoggingConstants.MDCKeys.TARGET_ENTITY, targetEntity != null ? targetEntity : ""); + MDC.put(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME, + targetServiceName != null ? targetServiceName : ""); + } + + private static void cleanTargetContext() { + MDC.remove(LoggingConstants.MDCKeys.TARGET_ENTITY); + MDC.remove(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME); + } + + private static void populateRequestContext() { + try { + UUID.fromString(MDC.get(MDC_KEY_REQUEST_ID)); + //reaching here without exception means existing RequestId is + //valid UUID as per ECOMP logging standards, no-op + } catch (Exception e) { + MDC.put(MDC_KEY_REQUEST_ID, UUID.randomUUID().toString()); + } + + try { + String partnerName = MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME); + + //ECOMP logging standards require some value for PartnerName. Default to appc if empty + if (partnerName.isEmpty()) + MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, "appc"); + } catch (Exception e) { + MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, "appc"); + } + + try { + String serviceName = MDC.get(MDC_SERVICE_NAME); + + //ECOMP logging standards require some value for ServiceName. Default to DEFAULT if empty + if (serviceName.isEmpty()) + MDC.put(MDC_SERVICE_NAME, "DEFAULT"); + } catch (Exception e) { + MDC.put(MDC_SERVICE_NAME, "DEFAULT"); + } + } + + private static void cleanRequestContext() { + MDC.remove(MDC_KEY_REQUEST_ID); + MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME); + MDC.remove(MDC_SERVICE_NAME); + } + + private static void populateTimeContext(Instant beginTimeStamp, Instant endTimeStamp) { + String beginTime = ""; + String endTime = ""; + String elapsedTime = ""; + + if (beginTimeStamp != null && endTimeStamp != null) { + elapsedTime = String.valueOf(ChronoUnit.MILLIS.between(beginTimeStamp, endTimeStamp)); + beginTime = generateTimestampStr(beginTimeStamp); + endTime = generateTimestampStr(endTimeStamp); + } + + MDC.put(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP, beginTime); + MDC.put(LoggingConstants.MDCKeys.END_TIMESTAMP, endTime); + MDC.put(LoggingConstants.MDCKeys.ELAPSED_TIME, elapsedTime); + } + + public static String generateTimestampStr(Instant timeStamp) { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); + TimeZone tz = TimeZone.getTimeZone("UTC"); + df.setTimeZone(tz); + return df.format(Date.from(timeStamp)); + } + + private static void cleanTimeContext() { + MDC.remove(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP); + MDC.remove(LoggingConstants.MDCKeys.END_TIMESTAMP); + MDC.remove(LoggingConstants.MDCKeys.ELAPSED_TIME); + } + + private static void populateResponseContext(String statusCode, String responseCode, + String responseDescription) { + MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, statusCode != null ? statusCode : ""); + MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, responseCode); + MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION, + responseDescription != null ? responseDescription : ""); + } + + private static void cleanResponseContext() { + MDC.remove(LoggingConstants.MDCKeys.STATUS_CODE); + MDC.remove(LoggingConstants.MDCKeys.RESPONSE_CODE); + MDC.remove(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION); + } + + private static void populateErrorContext(String errorCode, String errorDescription) { + String pattern = "[1-9]00"; + //Logging specs mandate errorCode of 100|200|300|400|500|600|700|800|900 + String errorValue = (errorCode!=null && errorCode.matches(pattern)) ? errorCode : "900"; + MDC.put(LoggingConstants.MDCKeys.ERROR_CODE, errorValue); + MDC.put(LoggingConstants.MDCKeys.ERROR_DESCRIPTION, errorDescription); + } + + private static void cleanErrorContext() { + MDC.remove(LoggingConstants.MDCKeys.ERROR_CODE); + MDC.remove(LoggingConstants.MDCKeys.ERROR_DESCRIPTION); + } + +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/Msg.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/Msg.java new file mode 100644 index 000000000..242676d7d --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/logging/Msg.java @@ -0,0 +1,869 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 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 + * + * 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.core.utils.logging; + +import com.att.eelf.i18n.EELFResolvableErrorEnum; +import com.att.eelf.i18n.EELFResourceManager; + +/** + * The messages issued by APPC components. + * <p> + * This message definition is shared by all APPC components. + * </p> + * + */ +@SuppressWarnings("nls") +public enum Msg implements EELFResolvableErrorEnum { + + /** + * ECOMP Application Controller (APP-C) initialization started at {0} + */ + CONFIGURATION_STARTED, + + /** + * Prior configuration has been cleared + */ + CONFIGURATION_CLEARED, + + /** + * Loading configuration properties from file "{0}" + */ + LOADING_CONFIGURATION_OVERRIDES, + + /** + * Configuration defaults loaded from resource file "{0}" + */ + LOADING_DEFAULTS, + + /** + * No default property resource "{0}" was found! + */ + NO_DEFAULTS_FOUND, + + /** + * Property "{0}" ="{1}" + */ + PROPERTY_VALUE, + + /** + * No configuration file named [{0}] was found on the configuration search path [{1}]. \ If a configuration file + * should have been loaded, check the file name and search path specified. CDP will proceed using the \ default + * values and command-line overrides (if any). + */ + NO_OVERRIDE_PROPERTY_FILE_LOADED, + + /** + * Searching path "{0}" for configuration settings "{1}" + */ + SEARCHING_CONFIGURATION_OVERRIDES, + + /** + * Loading application-specific override properties + */ + LOADING_APPLICATION_OVERRIDES, + + /** + * No application-specific override properties were provided! + */ + NO_APPLICATION_OVERRIDES, + + /** + * Merging system properties into configuration + */ + MERGING_SYSTEM_PROPERTIES, + + /** + * Setting property "{0}={1}" in system properties + */ + SETTING_SPECIAL_PROPERTY, + + /** + * Loading resource bundle "{0}" + */ + LOADING_RESOURCE_BUNDLE, + + /** + * Logging has already been initialized, check the container logging definitions to ensure they represent your + * desired logging configuration. + */ + LOGGING_ALREADY_INITIALIZED, + + /** + * Searching path "{0}" for log configuration file "{1}" + */ + SEARCHING_LOG_CONFIGURATION, + + /** + * Loading default logging configuration from system resource file "{0}" + */ + LOADING_DEFAULT_LOG_CONFIGURATION, + + /** + * No log configuration could be found or defaulted! + */ + NO_LOG_CONFIGURATION, + + /** + * An unsupported logging framework is bound to SLF4J. Only Logback or Log4J are supported. + */ + UNSUPPORTED_LOGGING_FRAMEWORK, + + /** + * Loading logging configuration from file "{0}" + */ + LOADING_LOG_CONFIGURATION, + + /** + * Provider {0} cannot be found or cannot be resolved to a valid provider. + */ + UNKNOWN_PROVIDER, + + /** + * Server name "{0}" with id "{1}" in tenant "{2}" and region "{3}" did not change state within the alloted time. + * Current state is "{4}" and the desired state(s) are "{5}" + */ + SERVER_STATE_CHANGE_TIMEOUT, + + /** + * Server name "{0}" with id "{1}" in tenant "{2}" has a state of deleted and cannot be {3}. + */ + SERVER_DELETED, + + /** + * Server name "{0}" with id "{1}" in tenant "{2}" has an unknown state of "{3}". + */ + UNKNOWN_SERVER_STATE, + + /** + * {0} component {1} is being initialized... + */ + COMPONENT_INITIALIZING, + + /** + * {0} component {1} has completed initialization + */ + COMPONENT_INITIALIZED, + + /** + * {0} component {1} is terminating... + */ + COMPONENT_TERMINATING, + + /** + * {0} component {1} has terminated + */ + COMPONENT_TERMINATED, + + /** + * Operation {0} is not supported or implemented at this time. + */ + IAAS_ADAPTER_UNSUPPORTED_OPERATION, + + /** + * Operation {0} called. Input document:\n{1} + */ + IAAS_ADAPTER_RPC_CALLED, + + /** + * Unable to locate the {0} service in the OSGi container + */ + NO_SERVICE_FOUND, + + /** + * Dump of context parameters for module {0}, RPC {1}, and version {2} + */ + CONTEXT_PARAMETERS_DISPLAY, + + /** + * Response properties from execution of module '{0}', RPC '{1}', and version '{2}' are: + */ + RESPONSE_PARAMETERS_DISPLAY, + + /** + * Service {0}:{1} was provided a null (empty) or invalid argument, '{2}' = '{3}' + */ + NULL_OR_INVALID_ARGUMENT, + + /** + * Service {0}:{1} is processing service '{2}' with request id '{3}' + */ + PROCESSING_REQUEST, + + /** + * Service {0}:{1} received request for service '{2}' but that service is invalid or unknown. + */ + INVALID_SERVICE_REQUEST, + + /** + * {0} registering service {1} using class {2} + */ + REGISTERING_SERVICE, + + /** + * {0} unregistering service {1} + */ + UNREGISTERING_SERVICE, + + /** + * {0} IAAS Adapter initializing provider {1} as {2} + */ + LOADING_PROVIDER_DEFINITIONS, + + /** + * {0} IAAS Adapter restart of server requested + */ + RESTARTING_SERVER, + + /** + * {0} IAAS Adapter rebuild of server requested + */ + REBUILDING_SERVER, + + /** + * {0} IAAS Adapter migrate of server requested + */ + MIGRATING_SERVER, + + /** + * {0} IAAS Adapter evacuate of server requested + */ + EVACUATING_SERVER, + + /** + * {0} IAAS Adapter create snapshot of server requested + */ + SNAPSHOTING_SERVER, + + /** + * {0} IAAS Adapter look for server requested + */ + LOOKING_SERVER_UP, + + /** + * {0} IAAS Adapter cannot perform requested service, VM url '{1}' is invalid + */ + INVALID_SELF_LINK_URL, + + /** + * Located server '{0}' on tenant '{1}' and in state '{2}' + */ + SERVER_FOUND, + + /** + * No server found in provider with self-link URL [{0}] + */ + SERVER_NOT_FOUND, + + /** + * Exception {0} was caught attempting {1} of server [{2}] on tenant [{3}] + */ + SERVER_OPERATION_EXCEPTION, + + /** + * One or more properties for [{0}] are missing, null, or empty. They are: + */ + MISSING_REQUIRED_PROPERTIES, + + /** + * The server [{0}] (id={1}) in tenant {2} is in error state, {3} is not allowed + */ + SERVER_ERROR_STATE, + + /** + * The image {0} could not be located for {1} + */ + IMAGE_NOT_FOUND, + + /** + * Time out waiting for {0} with name {1} (and id {2}) to reach one of {3} states, current state is {4} + */ + STATE_CHANGE_TIMEOUT, + + /** + * Exception {0} waiting for {1} with name {2} (and id {3}) to reach one of {4} states, current state is {5} + * cause={6} + */ + STATE_CHANGE_EXCEPTION, + + /** + * Server {0} is being stopped... + */ + STOP_SERVER, + + /** + * Server {0} is being started... + */ + START_SERVER, + + /** + * Server {0} is being resumed... + */ + RESUME_SERVER, + + /** + * Server {0} is being unpaused... + */ + UNPAUSE_SERVER, + + /** + * Server {0} is being rebuilt... + */ + REBUILD_SERVER, + + /** + * Connection to provider {0} at identity {1} using tenant name {2} (id {3}) failed, reason={4}, retrying in {5} + * seconds, attempt {6} of {7}. + */ + CONNECTION_FAILED_RETRY, + + /** + * Connection to provider {0} at service {1} failed after all retry attempts. + */ + CONNECTION_FAILED, + + /** + * {0} IAAS Adapter stop server requested + */ + STOPPING_SERVER, + + /** + * {0} IAAS Adapter start server requested + */ + STARTING_SERVER, + + /** + * Server {0} (id {1}) failed to rebuild, reason {2} + */ + REBUILD_SERVER_FAILED, + + /** + * Application {0} graph {1} response did not set the {2} parameter. This parameter is required for synchronization + * with the controller. Absence of this parameter is assumed to be a failure. Please correct the DG. + */ + PARAMETER_IS_MISSING, + + /** + * Application {0} graph {1} did not set parameter {2} to a valid numeric value ({3}). Please correct the DG. + */ + PARAMETER_NOT_NUMERIC, + + /** + * Application {0} graph {1} completed with failure: error code = {2}, message = {3} + */ + DG_FAILED_RESPONSE, + + /** + * Application {0} received exception {1} attempting to call graph {2}, exception message = {3} + */ + EXCEPTION_CALLING_DG, + + /** + * Application {0} was unable to locate graph {1} + */ + GRAPH_NOT_FOUND, + + /** + * Application {0} graph {1} responded with {3} properties + */ + DEBUG_GRAPH_RESPONSE_HEADER, + + /** + * {0}:{1} - {2} = {3} + */ + DEBUG_GRAPH_RESPONSE_DETAIL, + + /** + * Application {0} request {1} was supplied a property '{2}' with the value '{3}' that does not meet the required + * form(s): + */ + INVALID_REQUIRED_PROPERTY, + + /** + * Server {0} (id {1}) failed to migrate during {2} phase, reason {3} + */ + MIGRATE_SERVER_FAILED, + + /** + * Server {0} (id {1}) failed to evacuate, reason {2} + */ + EVACUATE_SERVER_FAILED, + + /** + * Server {0} evacuate from host {1} to host {2} failed during the rebuild on host {2}, reason {3} + */ + EVACUATE_SERVER_REBUILD_FAILED, + + /** + * APP-C instance is too busy + */ + APPC_TOO_BUSY, + + /** + * Concurrent access to server "{0}" + */ + VF_SERVER_BUSY, + + /** + * Server "{0}" does not support command "{1}" in the current state "{2}" + */ + VF_ILLEGAL_COMMAND, + + /** + * Server "{0}" cannot handle command "{1}" because of its doubtful state + */ + VF_UNDEFINED_STATE, + + /** + * No resource found with ID "{0}" in A&AI system + */ + APPC_NO_RESOURCE_FOUND, + + /** + * The request "{0}" for server "{1}" has exceeded its TTL limit of "{3}" seconds + */ + APPC_EXPIRED_REQUEST, + + /** + * Workflow for vnfType = "{0}" and command = "{1}" not found. + */ + APPC_WORKFLOW_NOT_FOUND, + + /** + * Null vnfId and command provided + */ + APPC_INVALID_INPUT, + + /** + * Operation '{0}' for VNF type '{1}' from Source '{2}' with RequestID '{3}' was started at '{4}' and ended at '{5}' + * with status code '{6}' + */ + APPC_AUDIT_MSG, + + /** + * APP-C is unable to communicate with A&AI + */ + AAI_CONNECTION_FAILED, + + /** + * APP-C is unable to update COMPONENT_ID {0} to {1} for reason {2} + */ + AAI_UPDATE_FAILED, + + /** + * APP-C is unable to retrieve VF/VFC {0} data for Transaction ID{1}as a result of A&AI communication failure or its + * internal error. + */ + AAI_GET_DATA_FAILED, + + /** + * A&AI at identity {0} using VNF_ID {1} failed, reason={2}, retrying in {3} seconds, attempt {4} of {5} + */ + AAI_CONNECTION_FAILED_RETRY, + + /** + * APP-C is unable to delete COMPONENT_ID {0} for reason {1} + */ + AAI_DELETE_FAILED, + + /** + * APP-C is unable to query AAI for VNF_ID {0} + */ + AAI_QUERY_FAILED, + + /** + * VNF {0} is configured + */ + VNF_CONFIGURED, + + /** + * VNF {0} is being configured + */ + VNF_CONFIGURATION_STARTED, + + /** + * VNF {0} configuration failed for reason {1} + */ + VNF_CONFIGURATION_FAILED, + + /** + * VNF {0} is being tested + */ + VNF_TEST_STARTED, + + /** + * VNF {0} was tested + */ + VNF_TESTED, + + /** + * VNF {0} test failed for reason {1} + */ + VNF_TEST_FAILED, + + /** + * VNF {0} test failed for reason {1} + */ + VNF_NOT_FOUND, + + /** + * VNF {0} Healthcheck operation failed for reason {1} + */ + VNF_HEALTHCECK_FAILED, + + /** + * VM {0} Healthcheck operation failed for reason {1} + */ + VM_HEALTHCECK_FAILED, + + /** + * Server {0} (id {1}) failed to stop during {2} phase, reason {3} + */ + STOP_SERVER_FAILED, + + /** + * Server {0} (id {1}) failed to terminate during {2} phase, reason {3} + */ + TERMINATE_SERVER_FAILED, + + /** + * {0} IAAS Adapter terminate server requested + */ + TERMINATING_SERVER, + + /** + * Server {0} is being terminated... + */ + TERMINATE_SERVER, + + /** + * Migrate {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}... + */ + MIGRATE_COMPLETE, + + /** + * Restart {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}... + */ + RESTART_COMPLETE, + + /** + * Rebuild {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}... + */ + REBUILD_COMPLETE, + + /** + * Located stack '{0}' on tenant '{1}' and in state '{2}' + */ + STACK_FOUND, + + /** + * {0} IAAS Adapter terminate stack requested + */ + + TERMINATING_STACK, + + /** + * stack {0} is being terminated... + */ + TERMINATE_STACK, + /** + * No stack found in provider with self-link URL [{0}] + */ + + STACK_NOT_FOUND, + + /** + * Exception {0} was caught attempting {1} of stack [{2}] on tenant [{3}] + */ + STACK_OPERATION_EXCEPTION, + + /** + * Stack {0} (id {1}) failed to terminate during {2} phase, reason {3} + */ + + TERMINATE_STACK_FAILED, + + /** + * Exception {0} was caught attempting to close provider context for {1}. + */ + + CLOSE_CONTEXT_FAILED, + + /** + * {0} IAAS Adapter snapshoting stack + */ + SNAPSHOTING_STACK, + + /** + * Stack {0} snapshoted, snapshot ID = [{1}]. + */ + STACK_SNAPSHOTED, + + /** + * {0} IAAS Adapter restoring stack + */ + RESTORING_STACK, + + /** + * Stack {0} is restored to snapshot {1}. + */ + STACK_RESTORED, + + /** + * {0} IAAS Adapter checking server + */ + CHECKING_SERVER, + + /** + * Parameter {0} is missing in svc request of {1}. + */ + MISSING_PARAMETER_IN_REQUEST, + + /** + * Cannot establish connection to server {0} port {1} with user {2}. + */ + CANNOT_ESTABLISH_CONNECTION, + + /** + * Operation '{0}' for VNF type '{1}' from Source '{2}' with RequestID '{3}' on '{4}' with action '{5}' + * ended in {6}ms with result '{7}' + */ + APPC_METRIC_MSG, + + /** + * Parsing failied for{0} + */ + INPUT_PAYLOAD_PARSING_FAILED, + + /** + * Error occurred for due to {0} + */ + APPC_EXCEPTION, + + /** + * SSH Data Exception occurred due to {0} + */ + SSH_DATA_EXCEPTION, + + /** + * Json processing exception occurred due to {0} + */ + JSON_PROCESSING_EXCEPTION, + + /** + * Operation {0} succeed for {1} + */ + SUCCESS_EVENT_MESSAGE, + + /** + * Dependency model not found for VNF type {0} due to {1} + */ + DEPENDENCY_MODEL_NOT_FOUND, + + /** + * Invalid Dependency model for VNF Type {0} due to {1} + */ + INVALID_DEPENDENCY_MODEL, + + /** + * Failed to retrieve VNFC DG + */ + FAILURE_RETRIEVE_VNFC_DG, + + /** + * Network check for Server {0} failed for Port {1} + * + */ + SERVER_NETWORK_ERROR, + + /** + * Hypervisor check for Server {0} failed. Status is DOWN or UNKNOWN + * + */ + HYPERVISOR_DOWN_ERROR, + + /** + * Unable to determine Hypervisor status for Server {0}. failed. + * + */ + HYPERVISOR_STATUS_UKNOWN, + + /** + * Hypervisor Network check for Server {0} failed. Not reachable by APPC + * + */ + HYPERVISOR_NETWORK_ERROR, + + /** + * Restart application operation failed on server : {0}, reason {1} + */ + APPLICATION_RESTART_FAILED, + + /** + * Start application operation failed on server : {0}, reason {1} + */ + APPLICATION_START_FAILED, + + /** + * Start application operation failed on server : {0}, reason {1} + */ + APPLICATION_STOP_FAILED, + + /** + * Application on server {0} is being restarted... + */ + RESTART_APPLICATION, + + /** + * Application on server {0} is being started... + */ + START_APPLICATION, + + /** + * Application on server {0} is being started... + */ + STOP_APPLICATION, + + /** + * APPC LCM operations are disabled + */ + LCM_OPERATIONS_DISABLED, + + /** + * Application {0} received exception {1} while attempting to execute oam operation {2}, exception message = {3}|\ + */ + OAM_OPERATION_EXCEPTION, + + /** + * Application {0} is {1} + */ + OAM_OPERATION_ENTERING_MAINTENANCE_MODE, + + /** + * Application {0} is in {1} + */ + OAM_OPERATION_MAINTENANCE_MODE, + + /** + * Application {0} is {1} + */ + OAM_OPERATION_STARTING, + + /** + * Application {0} is {1} + */ + OAM_OPERATION_STARTED, + + /** + * Application {0} is {1} + */ + OAM_OPERATION_STOPPING, + + /** + * Application {0} is {1} + */ + OAM_OPERATION_STOPPED, + /** + * A {1} API is not allowed when {0} is in the {2} state + */ + INVALID_STATE_TRANSITION, + + /** + * Application {0} was unable to find the Request Handler service + */ + REQUEST_HANDLER_UNAVAILABLE, + + /** + * Application {0} is {1} + */ + OAM_OPERATION_RESTARTING, + + /** + * Application {0} is {1} for restart + */ + OAM_OPERATION_RESTARTED, + + /** + * {0} + */ + OAM_OPERATION_INVALID_INPUT, + + ATTACHINGVOLUME_SERVER, + + DETTACHINGVOLUME_SERVER, + + REBOOT_SERVER, + /** + * {0} IAAS Adapter reboot of server requested + */ + /** + * Unsupported identity service version, unable to retrieve ServiceCatalog + * for identity service {0} + */ + IAAS_UNSUPPORTED_IDENTITY_SERVICE, + + /** + * Sftp data transfer failed on connection to host {0} with user {1} for {2} operation, reason : {3} + */ + SFTP_TRANSFER_FAILED, + /** + * Ssh session with host {0} has timed out during command {1} execution + */ + SSH_CONNECTION_TIMEOUT, + /** + * Exception {0} was caught while posting action {1} to service {2} + */ + POST_OPERATION_EXCEPTION, + /** + *Connecting to image service {0}failed + */ + IMAGE_SERVICE_FAILED, + /** + * Time out waiting for volume {0} with device {1} (and server {2}) after retry one of {3} times, retry interval is {4} + */ + VOLUME_ATTACH_TIMEOUT, + /** + * Time out waiting for volume {0} (from server {1}) after retry one of {2} times, retry interval is {3} + */ + VOLUME_DETACH_TIMEOUT, + /** + * MSO throwing error from openstack{0} + */ + MSO_EXCEPTION, + /** + * Server [{0}], ID [{1}], is in state [{2}] but is expected to be in one of [{3}] + */ + OS_INVALID_SERVER_STATE, + /** + * Could not configure existing ssh session, reason: {0} + */ + SSH_SESSION_CONFIG_ERROR + ; + /* + * Static initializer to ensure the resource bundles for this class are loaded... + */ + static { + EELFResourceManager.loadMessageBundle("org/onap/appc/i18n/MessageResources"); + } +} |