diff options
author | Jessica Wagantall <jwagantall@linuxfoundation.org> | 2020-12-01 11:33:35 -0800 |
---|---|---|
committer | Jessica Wagantall <jwagantall@linuxfoundation.org> | 2020-12-01 11:33:35 -0800 |
commit | 96a9aafdff7813324bc8a8ba1e743683e251dde6 (patch) | |
tree | 644c6837ab58ed21fb05f4bf988dc392875b9f8d /plugins/sshapi-call-node | |
parent | a0e97e71a49a8b54fddf8fb004b32f202f114011 (diff) |
Migrate files from sli-plugins
Migrate sli-plugins repo into new
directory "plugins".
Signed-off-by: Jessica Wagantall <jwagantall@linuxfoundation.org>
Diffstat (limited to 'plugins/sshapi-call-node')
29 files changed, 3103 insertions, 0 deletions
diff --git a/plugins/sshapi-call-node/.gitignore b/plugins/sshapi-call-node/.gitignore new file mode 100755 index 000000000..3c30c3505 --- /dev/null +++ b/plugins/sshapi-call-node/.gitignore @@ -0,0 +1,35 @@ +#####standard .git ignore entries##### + +## IDE Specific Files ## +org.eclipse.core.resources.prefs +.classpath +.project +.settings +.idea +.externalToolBuilders +maven-eclipse.xml +workspace + +## Compilation Files ## +*.class +**/target +target +target-ide +MANIFEST.MF + +## Misc Ignores (OS specific etc) ## +bin/ +dist +*~ +*.ipr +*.iml +*.iws +classes +out/ +.DS_STORE +.metadata +*.log + +## Folders which contain auto generated source code ## +yang-gen-config +yang-gen-sal diff --git a/plugins/sshapi-call-node/installer/pom.xml b/plugins/sshapi-call-node/installer/pom.xml new file mode 100755 index 000000000..de7509dbc --- /dev/null +++ b/plugins/sshapi-call-node/installer/pom.xml @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.1.0</version> + </parent> + + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>sshapi-call-node-installer</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-plugins :: sshapi-call-node :: ${project.artifactId}</name> + + <properties> + <application.name>ccsdk-sshapi-call-node</application.name> + <features.boot>${application.name}</features.boot> + <features.repositories>mvn:org.onap.ccsdk.sli.plugins/${features.boot}/${project.version}/xml/features</features.repositories> + <include.transitive.dependencies>false</include.transitive.dependencies> + </properties> + + <dependencies> + + <dependency> + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>sshapi-call-node-provider</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>maven-repo-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>stage/${application.name}-${project.version}</finalName> + <descriptors> + <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>true</appendAssemblyId> + </configuration> + </execution> + <execution> + <id>installer-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>${application.name}-${project.version}-installer</finalName> + <descriptors> + <descriptor>src/assembly/assemble_installer_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <goals> + <goal>copy-dependencies</goal> + </goals> + <phase>prepare-package</phase> + <configuration> + <transitive>false</transitive> + <outputDirectory>${project.build.directory}/assembly/system</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <useRepositoryLayout>true</useRepositoryLayout> + <addParentPoms>false</addParentPoms> + <copyPom>false</copyPom> + <includeGroupIds>org.onap.ccsdk.sli.plugins</includeGroupIds> + <scope>provided</scope> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>copy-version</id> + <goals> + <goal>copy-resources</goal> + </goals><!-- here the phase you need --> + <phase>validate</phase> + <configuration> + <outputDirectory>${basedir}/target/stage</outputDirectory> + <resources> + <resource> + <directory>src/main/resources/scripts</directory> + <includes> + <include>install-feature.sh</include> + </includes> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + + </executions> + </plugin> + + </plugins> + </build> +</project> diff --git a/plugins/sshapi-call-node/installer/src/assembly/assemble_installer_zip.xml b/plugins/sshapi-call-node/installer/src/assembly/assemble_installer_zip.xml new file mode 100644 index 000000000..b2e792123 --- /dev/null +++ b/plugins/sshapi-call-node/installer/src/assembly/assemble_installer_zip.xml @@ -0,0 +1,59 @@ +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + Copyright (C) 2018 Samsung Electronics. All rights + reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>installer_zip</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>755</fileMode> + <includes> + <include>*.sh</include> + </includes> + </fileSet> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>644</fileMode> + <excludes> + <exclude>*.sh</exclude> + </excludes> + </fileSet> + </fileSets> + + + +</assembly> diff --git a/plugins/sshapi-call-node/installer/src/assembly/assemble_mvnrepo_zip.xml b/plugins/sshapi-call-node/installer/src/assembly/assemble_mvnrepo_zip.xml new file mode 100644 index 000000000..2a6344697 --- /dev/null +++ b/plugins/sshapi-call-node/installer/src/assembly/assemble_mvnrepo_zip.xml @@ -0,0 +1,49 @@ +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + Copyright (C) 2018 Samsung Electronics. All rights + reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>repo</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/assembly/</directory> + <outputDirectory>.</outputDirectory> + <excludes> + </excludes> + </fileSet> + </fileSets> + + + +</assembly> diff --git a/plugins/sshapi-call-node/installer/src/main/resources/scripts/install-feature.sh b/plugins/sshapi-call-node/installer/src/main/resources/scripts/install-feature.sh new file mode 100644 index 000000000..8e516a247 --- /dev/null +++ b/plugins/sshapi-call-node/installer/src/main/resources/scripts/install-feature.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +### +# ============LICENSE_START======================================================= +# openECOMP : SDN-C +# ================================================================================ +# Copyright (C) 2018 Samsung Electronics. All rights +# reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +ODL_HOME=${ODL_HOME:-/opt/opendaylight/current} +ODL_KARAF_CLIENT=${ODL_KARAF_CLIENT:-${ODL_HOME}/bin/client} +INSTALLERDIR=$(dirname $0) + +REPOZIP=${INSTALLERDIR}/${features.boot}-${project.version}.zip + +if [ -f ${REPOZIP} ] +then + unzip -nd ${ODL_HOME} ${REPOZIP} +else + echo "ERROR : repo zip ($REPOZIP) not found" + exit 1 +fi + +${ODL_KARAF_CLIENT} feature:repo-add ${features.repositories} +${ODL_KARAF_CLIENT} feature:install ${features.boot} diff --git a/plugins/sshapi-call-node/pom.xml b/plugins/sshapi-call-node/pom.xml new file mode 100755 index 000000000..a9dc52e4b --- /dev/null +++ b/plugins/sshapi-call-node/pom.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.1.0</version> + </parent> + + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>sshapi-call-node</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-plugins :: sshapi-call-node</name> + <description>This is an implementation of DG Execute Node that makes a call to an external REST API</description> + + <modules> + <module>provider</module> + <module>installer</module> + </modules> +</project> diff --git a/plugins/sshapi-call-node/provider/ReadMe.md b/plugins/sshapi-call-node/provider/ReadMe.md new file mode 100644 index 000000000..beaadcda8 --- /dev/null +++ b/plugins/sshapi-call-node/provider/ReadMe.md @@ -0,0 +1,32 @@ +SSHApi-Call-Node Plugin: + +Parameters List that managed in from Directed Graphs: + +Input: +Url -> Mandatory -> url to make the SSH connection request to. +Port -> Mandatory -> port to make the SSH connection request to. +AuthType -> Optional -> Type of authentiation to be used BASIC or sshKey based -> true or false +User -> Optional -> user name to use for ssh basic authentication -> sdnc_ws +Password -> Optional -> unencrypted password to use for ssh basic authentication -> plain_password +SshKey -> Optional -> Consumer SSH key to use for ssh authentication -> plain_key +ExecTimeout -> Optional -> SSH command execution timeout -> plain_key +Retry -> Optional -> Make ssh connection with default retry policy -> plain_key +Cmd -> Mandatory -> ssh command to be executed on the server. -> get post put delete patch +EnvParameters -> Optional -> A JSON dictionary which should list key value pairs to be passed to the command execution. These values would correspond to instance specific parameters that a command may need to execute an action. +FileParameters -> Optional -> A JSON dictionary where keys are filenames and values are contents of files. The SSH Server will utilize this feature to generate files with keys as filenames and values as content. This attribute can be used to generate files that a command may require as part of execution. +ConvertResponse -> Optional -> whether the response should be converted to properties -> true or false +ResponseType -> Optional -> If we know the response is to be in a specific format (supported are JSON, XML and NONE) +ResponsePrefix -> Optional -> location the response will be written to in context memory +listName[i] -> Optional -> Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details + +Output: +"sshApi.call.node.status" -> SSH Exit status code is set in here. +"sshApi.call.node.stdout" -> SSH command execution result is put in here. +"sshApi.call.node.stderr" -> SSH execution failure message is put in here. + + + +API methods that are exposed: +1) execCommand +2) execWithStatusCheck: Throws exception if the exit status is not successful. +3) execCommandWithPty
\ No newline at end of file diff --git a/plugins/sshapi-call-node/provider/pom.xml b/plugins/sshapi-call-node/provider/pom.xml new file mode 100755 index 000000000..49bceb122 --- /dev/null +++ b/plugins/sshapi-call-node/provider/pom.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.1.0</version> + </parent> + + <groupId>org.onap.ccsdk.sli.plugins</groupId> + <artifactId>sshapi-call-node-provider</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>ccsdk-sli-plugins :: sshapi-call-node :: ${project.artifactId}</name> + + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-core-artifacts</artifactId> + <version>${ccsdk.sli.core.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-common</artifactId> + <scope>provided</scope> + </dependency> + <!-- ILLEGAL DEPENDENCY : creates circular dependency between CCSDK and APPC --> + <dependency> + <groupId>org.onap.appc</groupId> + <artifactId>appc-ssh-adapter-api</artifactId> + <version>1.3.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + </dependency> + <dependency> + <groupId>org.codehaus.jettison</groupId> + <artifactId>jettison</artifactId> + </dependency> + <dependency> + <groupId>com.att.eelf</groupId> + <artifactId>eelf-core</artifactId> + </dependency> + </dependencies> +</project> diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java new file mode 100644 index 000000000..146188fb9 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/SshApiCallNode.java @@ -0,0 +1,283 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ============================================================================= + * Copyright (C) 2018 Samsung Electronics. All rights + reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +import org.onap.appc.adapter.ssh.SshAdapter; +import org.onap.appc.adapter.ssh.SshConnection; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +import org.onap.ccsdk.sli.plugins.sshapicall.model.AuthType; +import org.onap.ccsdk.sli.plugins.sshapicall.model.Parameters; +import org.onap.ccsdk.sli.plugins.sshapicall.model.ParseParam; + + +public class SshApiCallNode implements SvcLogicJavaPlugin { + + private static final EELFLogger logger = EELFManager.getInstance().getApplicationLogger(); + + /** + * Output parameter - SSH command execution status. + */ + private String PARAM_OUT_status = "sshApi.call.node.status"; + + /** + * Output parameter - content of SSH command stdout. + */ + private String PARAM_OUT_stdout = "sshApi.call.node.stdout"; + + /** + * Output parameter - content of SSH command stderr. + */ + private String PARAM_OUT_stderr = "sshApi.call.node.stderr"; + + /** + * Testing parameter - content of mocked SSH. + */ + private boolean PARAM_TEST_MODE = false; + private String PARAM_OUT_MESSAGE = "TestOut"; + + + /** + * Default success status. + */ + private int DEF_SUCCESS_STATUS = 0; + + + + private SshAdapter sshAdapter; + + /** + * Used for jUnit test and testing interface + */ + public SshApiCallNode(boolean mode) { + PARAM_TEST_MODE = mode; + } + + public SshApiCallNode() { + PARAM_TEST_MODE = false; + } + + public void setSshAdapter(SshAdapter sshAdapter) { + this.sshAdapter = sshAdapter; + } + + /** + * Allows Directed Graphs the ability to interact with SSH APIs. + * @param params HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>Url</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr> + * <tr><td>Port</td><td>Mandatory</td><td>port to make the SSH connection request to.</td></tr> + * <tr><td>User</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr> + * <tr><td>Password</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr> + * <tr><td>SshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr> + * <tr><td>ExecTimeout</td><td>Optional</td><td>SSH command execution timeout</td><td>plain_key</td></tr> + * <tr><td>Retry</td><td>Optional</td><td>Make ssh connection with default retry policy</td><td>plain_key</td></tr> + * <tr><td>Cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr> + * <tr><td>ResponsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td></tr> + * <tr><td>ResponseType</td><td>Optional</td><td>If we know the response is to be in a specific format (supported are JSON, XML and NONE) </td></tr> + * <tr><td>listName[i]</td><td>Optional</td><td>Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details<td></td></tr> + * <tr><td>ConvertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr> + * <tr><td>AuthType</td><td>Optional</td><td>Type of authentiation to be used BASIC or sshKey based</td><td>true or false</td></tr> + * <tr><td>EnvParameters</td><td>Optional</td><td>A JSON dictionary which should list key value pairs to be passed to the command execution. + * These values would correspond to instance specific parameters that a command may need to execute an action.</td></tr> + * <tr><td>FileParameters</td><td>Optional</td><td>A JSON dictionary where keys are filenames and values are contents of files. + * The SSH Server will utilize this feature to generate files with keys as filenames and values as content. + * This attribute can be used to generate files that a command may require as part of execution.</td></tr> + * </tbody> + * </table> + * Exec remote command over SSH. Return command execution status. + * Command output is written to out or err stream. + * + * @param ctx Reference to context memory + */ + + public void execCommand(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException { + execSshCommand(params, ctx, false); + } + + private void execSshCommand(Map<String, String> params, SvcLogicContext ctx, boolean withPty) throws SvcLogicException { + ParseParam parser = new ParseParam(); + Parameters p = parser.getParameters(params); + logger.debug("=> Connecting to SSH server..."); + SshConnection sshConnection = null; + int status = -1; + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + String stdoutRes = ""; + String stderrRes = ""; + try { + if (!PARAM_TEST_MODE) { + sshConnection = getSshConnection(p); + sshConnection.connect(); + logger.debug("=> Connected to SSH server..."); + logger.debug("=> Running SSH command..."); + sshConnection.setExecTimeout(p.sshExecTimeout); + if (withPty) { + status = sshConnection.execCommandWithPty(parser.makeCommand(params), stdout); + stderr = stdout; + } + else + status = sshConnection.execCommand(parser.makeCommand(params), stdout, stderr); + stdoutRes = stdout.toString(); + stderrRes = stderr.toString(); + + } else { + if (("true").equalsIgnoreCase(params.get("TestFail"))) + status = 202; + else + status = DEF_SUCCESS_STATUS; + stdoutRes = params.get(PARAM_OUT_MESSAGE); + } + logger.debug("=> executed SSH command"); + + if(status == DEF_SUCCESS_STATUS) { + parser.parseOutput(ctx, stdoutRes); + } + ctx.setAttribute(PARAM_OUT_status, String.format("%01d", status)); + ctx.setAttribute(PARAM_OUT_stdout, stdoutRes); + ctx.setAttribute(PARAM_OUT_stderr, stderrRes); + } catch (Exception e){ + throw new SvcLogicException("Exception in SSH adaptor : " + e.getMessage()); + } finally { + if (sshConnection != null) + sshConnection.disconnect(); + } + } + + private SshConnection getSshConnection(Parameters p) throws SvcLogicException { + if (p.authtype == AuthType.BASIC) + return sshAdapter.getConnection(p.sshapiUrl, p.sshapiPort, p.sshapiUser, p.sshapiPassword); + // This is not supported yet in the API, patch has already been added to APPC + else if (p.authtype == AuthType.KEY){ + throw new SvcLogicException("SSH Key based Auth method not supported"); + } + else if (p.authtype == AuthType.NONE){ + throw new SvcLogicException("SSH Auth type required, BASIC auth in support"); + } + else if (p.authtype == AuthType.UNSPECIFIED){ + if (p.sshapiUser != null && p.sshapiPassword != null) + return sshAdapter.getConnection(p.sshapiUrl, p.sshapiPort, p.sshapiUser, p.sshapiPassword); + else if (p.sshKey != null) + throw new SvcLogicException("SSH Key based Auth method not supported"); + } + throw new SvcLogicException("SSH Auth type required, BASIC auth in support"); + } + + + /** + * Allows Directed Graphs the ability to interact with SSH APIs. + * @param params HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>Url</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr> + * <tr><td>Port</td><td>Mandatory</td><td>port to make the SSH connection request to.</td></tr> + * <tr><td>User</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr> + * <tr><td>Password</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr> + * <tr><td>SshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr> + * <tr><td>ExecTimeout</td><td>Optional</td><td>SSH command execution timeout</td><td>plain_key</td></tr> + * <tr><td>Retry</td><td>Optional</td><td>Make ssh connection with default retry policy</td><td>plain_key</td></tr> + * <tr><td>Cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr> + * <tr><td>ResponsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td></tr> + * <tr><td>ResponseType</td><td>Optional</td><td>If we know the response is to be in a specific format (supported are JSON, XML and NONE) </td></tr> + * <tr><td>listName[i]</td><td>Optional</td><td>Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details<td></td></tr> + * <tr><td>ConvertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr> + * <tr><td>AuthType</td><td>Optional</td><td>Type of authentiation to be used BASIC or sshKey based</td><td>true or false</td></tr> + * <tr><td>EnvParameters</td><td>Optional</td><td>A JSON dictionary which should list key value pairs to be passed to the command execution. + * These values would correspond to instance specific parameters that a command may need to execute an action.</td></tr> + * <tr><td>FileParameters</td><td>Optional</td><td>A JSON dictionary where keys are filenames and values are contents of files. + * The SSH Server will utilize this feature to generate files with keys as filenames and values as content. + * This attribute can be used to generate files that a command may require as part of execution.</td></tr> + * </tbody> + * </table> + * Exec remote command over SSH. Return command execution status. + * Command output is written to out or err stream. + * + * @param ctx Reference to context memory + */ + + public void execWithStatusCheck(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException { + execCommand(params, ctx); + parseResponse(ctx); + } + + private void parseResponse (SvcLogicContext ctx) throws SvcLogicException { + int status = Integer.parseInt(ctx.getAttribute(PARAM_OUT_status)); + if(status != DEF_SUCCESS_STATUS) { + StringBuilder errmsg = new StringBuilder(); + errmsg.append("SSH command returned error status [").append(status).append(']'); + String stderr = ctx.getAttribute(PARAM_OUT_stderr); + if((stderr != null) && !stderr.isEmpty()) { + errmsg.append(". Error: [").append(stderr).append(']'); + } + throw new SvcLogicException(errmsg.toString()); + } + } + + /** + * Allows Directed Graphs the ability to interact with SSH APIs. + * @param params HashMap<String,String> of parameters passed by the DG to this function + * <table border="1"> + * <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead> + * <tbody> + * <tr><td>Url</td><td>Mandatory</td><td>url to make the SSH connection request to.</td></tr> + * <tr><td>Port</td><td>Mandatory</td><td>port to make the SSH connection request to.</td></tr> + * <tr><td>User</td><td>Optional</td><td>user name to use for ssh basic authentication</td><td>sdnc_ws</td></tr> + * <tr><td>Password</td><td>Optional</td><td>unencrypted password to use for ssh basic authentication</td><td>plain_password</td></tr> + * <tr><td>SshKey</td><td>Optional</td><td>Consumer SSH key to use for ssh authentication</td><td>plain_key</td></tr> + * <tr><td>ExecTimeout</td><td>Optional</td><td>SSH command execution timeout</td><td>plain_key</td></tr> + * <tr><td>Retry</td><td>Optional</td><td>Make ssh connection with default retry policy</td><td>plain_key</td></tr> + * <tr><td>Cmd</td><td>Mandatory</td><td>ssh command to be executed on the server.</td><td>get post put delete patch</td></tr> + * <tr><td>ResponsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td></tr> + * <tr><td>ResponseType</td><td>Optional</td><td>If we know the response is to be in a specific format (supported are JSON, XML and NONE) </td></tr> + * <tr><td>listName[i]</td><td>Optional</td><td>Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details<td></td></tr> + * <tr><td>ConvertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr> + * <tr><td>AuthType</td><td>Optional</td><td>Type of authentiation to be used BASIC or sshKey based</td><td>true or false</td></tr> + * <tr><td>EnvParameters</td><td>Optional</td><td>A JSON dictionary which should list key value pairs to be passed to the command execution. + * These values would correspond to instance specific parameters that a command may need to execute an action.</td></tr> + * <tr><td>FileParameters</td><td>Optional</td><td>A JSON dictionary where keys are filenames and values are contents of files. + * The SSH Server will utilize this feature to generate files with keys as filenames and values as content. + * This attribute can be used to generate files that a command may require as part of execution.</td></tr> + * </tbody> + * </table> + * Exec remote command over SSH. Return command execution status. + * Command output is written to out or err stream. + * + * @param ctx Reference to context memory + */ + public void execCommandWithPty(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException { + execSshCommand(params, ctx, true); + } +} diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/AuthType.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/AuthType.java new file mode 100644 index 000000000..806c80890 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/AuthType.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall.model; + +public enum AuthType { + NONE, BASIC, KEY, UNSPECIFIED; + + public static AuthType fromString(String s) { + if ("basic".equalsIgnoreCase(s)) + return BASIC; + if ("key".equalsIgnoreCase(s)) + return KEY; + if ("unspecified".equalsIgnoreCase(s)) + return UNSPECIFIED; + if ("none".equalsIgnoreCase(s)) + return NONE; + throw new IllegalArgumentException("Invalid value for format: " + s); + } +} diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Format.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Format.java new file mode 100644 index 000000000..43c3c38d6 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Format.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall.model; + +public enum Format { + JSON, XML, NONE; + + public static Format fromString(String s) { + if ("json".equalsIgnoreCase(s)) + return JSON; + if ("xml".equalsIgnoreCase(s)) + return XML; + if ("none".equalsIgnoreCase(s)) + return NONE; + throw new IllegalArgumentException("Invalid value for format: " + s); + } +} diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java new file mode 100644 index 000000000..3d48a790f --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/JsonParser.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall.model; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class JsonParser { + + private static final Logger log = LoggerFactory.getLogger(JsonParser.class); + + private JsonParser() { + // Preventing instantiation of the same. + } + + @SuppressWarnings("unchecked") + public static Map<String, String> convertToProperties(String s) + throws JSONException { + + checkNotNull(s, "Input should not be null."); + + JSONObject json = new JSONObject(s); + Map<String, Object> wm = new HashMap<>(); + Iterator<String> ii = json.keys(); + while (ii.hasNext()) { + String key1 = ii.next(); + wm.put(key1, json.get(key1)); + } + + Map<String, String> mm = new HashMap<>(); + + while (!wm.isEmpty()) + for (String key : new ArrayList<>(wm.keySet())) { + Object o = wm.get(key); + wm.remove(key); + + if (o instanceof Boolean || o instanceof Number || o instanceof String) { + mm.put(key, o.toString()); + + log.info("Added property: {} : {}", key, o.toString()); + } else if (o instanceof JSONObject) { + JSONObject jo = (JSONObject) o; + Iterator<String> i = jo.keys(); + while (i.hasNext()) { + String key1 = i.next(); + wm.put(key + "." + key1, jo.get(key1)); + } + } else if (o instanceof JSONArray) { + JSONArray ja = (JSONArray) o; + mm.put(key + "_length", String.valueOf(ja.length())); + + log.info("Added property: {}_length: {}", key, String.valueOf(ja.length())); + + for (int i = 0; i < ja.length(); i++) + wm.put(key + '[' + i + ']', ja.get(i)); + } + } + return mm; + } +} diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Parameters.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Parameters.java new file mode 100644 index 000000000..fa2371e88 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/Parameters.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall.model; + +import java.util.Set; + +public class Parameters { + public String sshapiUrl; + public int sshapiPort; + public String sshapiUser; + public String sshapiPassword; + public String sshKey; + public long sshExecTimeout; + public String sshFileParameters; + public String sshEnvParameters; + public boolean sshWithRetry; + public String cmd; + public String responsePrefix; + public Format responseType; + + public Set<String> listNameList; + public boolean convertResponse; + public AuthType authtype; +} diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java new file mode 100644 index 000000000..35c1087d8 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/ParseParam.java @@ -0,0 +1,275 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Modifications Copyright © 2018 IBM + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall.model; + +import com.google.common.base.Strings; +import org.json.JSONException; +import org.json.JSONObject; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +public class ParseParam { + private static final Logger log = LoggerFactory.getLogger(ParseParam.class); + /** + * Default SSH command timeout + */ + private long dEF_timeout = 12000; + /** + * Default SSH connection port. + */ + private int dEF_port = 22; + /** + * Default SSH command timeout + */ + private final String FILE_PARAMETERS_OPT_KEY = "FileParameters"; + public final String SSH_ResponsePrefix = "ResponsePrefix"; + /** + * Default SSH connection port. + */ + private final String ENV_PARAMETERS_OPT_KEY = "EnvParameters"; + private Parameters p = new Parameters(); + + public Parameters getParameters(Map<String, String> paramMap) throws SvcLogicException { + p.sshapiUrl = parseParam(paramMap, "Url", true, null); + p.sshapiPort = Integer.parseInt(parseParam(paramMap, "Port", true, Integer.toString(dEF_port))); + p.sshapiUser = parseParam(paramMap, "User", false, null); + p.sshapiPassword = parseParam(paramMap, "Password", false, null); + p.sshKey = parseParam(paramMap, "SshKey", false, null); + p.sshExecTimeout = Long.parseLong(parseParam(paramMap, "ExecTimeout", false, Long.toString(dEF_timeout))); + p.sshWithRetry = Boolean.valueOf(parseParam(paramMap, "Retry", false, "false")); + p.cmd = parseParam(paramMap, "Cmd", true, null); + p.responsePrefix = parseParam(paramMap, SSH_ResponsePrefix, false, null); + p.responseType = Format.fromString(parseParam(paramMap, "ResponseType", false, "none")); + p.listNameList = getListNameList(paramMap); + p.convertResponse = Boolean.valueOf(parseParam(paramMap, "ConvertResponse", false, "true")); + p.authtype = AuthType.fromString(parseParam(paramMap, "AuthType", false, "unspecified")); + + return p; + } + + public String getStringParameters(Map<String, String> paramMap, String paramName) throws SvcLogicException { + return parseParam(paramMap, SSH_ResponsePrefix, false, null); + } + + public void parseOutput (SvcLogicContext ctx, String outMessage) throws SvcLogicException { + if (p.convertResponse) { + if (p.responseType == Format.NONE) { + classifyOutput(ctx, outMessage); + } else if (p.responseType == Format.JSON) { + classifyOutput(ctx, outMessage); + } else if (p.responseType == Format.XML) { + classifyOutput(ctx, outMessage, p.listNameList); + } + } + } + + private void classifyOutput(SvcLogicContext ctx, String outMessage, Set<String> listNameList) throws SvcLogicException { + Map<String, String> mm = XmlParser.convertToProperties(outMessage, p.listNameList); + toCtx (ctx, mm); + } + + private void toCtx (SvcLogicContext ctx, Map<String, String> mm) { + if (mm != null) { + for (Map.Entry<String, String> entry : mm.entrySet()) { + if (p.responsePrefix != null) { + ctx.setAttribute(p.responsePrefix + "." + entry.getKey(), entry.getValue()); + log.info("+++ " + p.responsePrefix + "." + entry.getKey() + ": [" + entry.getValue() + "]"); + } else { + ctx.setAttribute(entry.getKey(), entry.getValue()); + log.info("+++ " + entry.getKey() + ": [" + entry.getValue() + "]"); + } + } + } + } + + private void classifyOutput(SvcLogicContext ctx, String outMessage) throws SvcLogicException { + try { + Map<String, String> mm = JsonParser.convertToProperties(outMessage); + toCtx (ctx, mm); + } catch (org.codehaus.jettison.json.JSONException e) { + log.info("Output not in JSON format"); + putToProperties(ctx, p.responsePrefix); + } catch (Exception e) { + throw new SvcLogicException("error parsing response file"); + } + } + + private void putToProperties(SvcLogicContext ctx, String outMessage) throws SvcLogicException { + + try { + Properties prop = new Properties(); + prop.load(new ByteArrayInputStream(outMessage.getBytes(StandardCharsets.UTF_8))); + for (Object key : prop.keySet()) { + String name = (String) key; + String value = prop.getProperty(name); + if (value != null && value.trim().length() > 0) { + if (p.responsePrefix != null) { + ctx.setAttribute(p.responsePrefix + "." + name, value.trim()); + log.info("+++ " + p.responsePrefix + "." + name + ": [" + value + "]"); + } else { + ctx.setAttribute(name, value.trim()); + log.info("+++ " + name + ": [" + value + "]"); + } + } + } + } catch (Exception e) { + throw new SvcLogicException( "Error parsing response file."); + } + } + + public String makeCommand (Map<String, String> params) { + JSONObject jsonPayload = new JSONObject(); + final String[] optionalTestParams = {ENV_PARAMETERS_OPT_KEY, FILE_PARAMETERS_OPT_KEY}; + parseParam(params, optionalTestParams, jsonPayload); + JSONObject envParams = (JSONObject) jsonPayload.remove(ENV_PARAMETERS_OPT_KEY); + JSONObject fileParams = (JSONObject) jsonPayload.remove(FILE_PARAMETERS_OPT_KEY); + + StringBuilder constructedCommand = new StringBuilder(); + constructedCommand.append(parseFileParam(fileParams)).append(p.cmd).append(" ").append(parseEnvParam(envParams)); + + return constructedCommand.toString(); + } + + private String parseEnvParam(JSONObject envParams) { + StringBuilder envParamBuilder = new StringBuilder(); + if (envParams != null) { + for (Object key : envParams.keySet()) { + if (envParamBuilder.length() > 0) { + envParamBuilder.append(", "); + } + envParamBuilder.append(key + "=" + envParams.get((String) key)); + } + } + return envParamBuilder.toString(); + } + + private String parseFileParam(JSONObject fileParams) { + StringBuilder fileParamBuilder = new StringBuilder(); + if (fileParams != null) { + for (Object key : fileParams.keySet()) { + fileParamBuilder.append("echo -e \"" + fileParams.get((String) key) + "\" > /srv/salt/" + key).append("; "); + } + } + return fileParamBuilder.toString(); + } + + private void parseParam(Map<String, String> params, String[] optionalTestParams, JSONObject jsonPayload) + throws JSONException { + + Set<String> optionalParamsSet = new HashSet<>(); + Collections.addAll(optionalParamsSet, optionalTestParams); + + //@formatter:off + params.entrySet() + .stream() + .filter(entry -> optionalParamsSet.contains(entry.getKey())) + .filter(entry -> !Strings.isNullOrEmpty(entry.getValue())) + .forEach(entry -> parseParam(entry, jsonPayload)); + //@formatter:on + } + + private void parseParam(Map.Entry<String, String> params, JSONObject jsonPayload) + throws JSONException { + String key = params.getKey(); + String payload = params.getValue(); + + switch (key) { + case ENV_PARAMETERS_OPT_KEY: + JSONObject paramsJson = new JSONObject(payload); + jsonPayload.put(key, paramsJson); + break; + + case FILE_PARAMETERS_OPT_KEY: + jsonPayload.put(key, getFilePayload(payload)); + break; + + default: + break; + } + } + + /** + * Return payload with escaped newlines + */ + private JSONObject getFilePayload(String payload) { + String formattedPayload = payload.replace("\n", "\\n").replace("\r", "\\r"); + return new JSONObject(formattedPayload); + } + + private Set<String> getListNameList(Map<String, String> paramMap) { + Set<String> ll = new HashSet<>(); + for (Map.Entry<String,String> entry : paramMap.entrySet()) + if (entry.getKey().startsWith("listName")) + ll.add(entry.getValue()); + return ll; + } + + private String parseParam(Map<String, String> paramMap, String name, boolean required, String def) + throws SvcLogicException { + String s = paramMap.get(name); + + if (s == null || s.trim().length() == 0) { + if (!required) + return def; + throw new SvcLogicException("Parameter " + name + " is required in sshapiCallNode"); + } + + s = s.trim(); + StringBuilder value = new StringBuilder(); + int i = 0; + int i1 = s.indexOf('%'); + while (i1 >= 0) { + int i2 = s.indexOf('%', i1 + 1); + if (i2 < 0) + break; + + String varName = s.substring(i1 + 1, i2); + String varValue = System.getenv(varName); + if (varValue == null) + varValue = "%" + varName + "%"; + + value.append(s.substring(i, i1)); + value.append(varValue); + + i = i2 + 1; + i1 = s.indexOf('%', i); + } + value.append(s.substring(i)); + + log.info("Parameter {}: [{}]", name, value); + return value.toString(); + } +} diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/XmlJsonUtil.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/XmlJsonUtil.java new file mode 100644 index 000000000..d68fbc6ac --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/XmlJsonUtil.java @@ -0,0 +1,389 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class XmlJsonUtil { + + private static final Logger log = LoggerFactory.getLogger(XmlJsonUtil.class); + + private XmlJsonUtil() { + // Preventing instantiation of the same. + } + + public static String getXml(Map<String, String> varmap, String var) { + boolean escape = true; + if (var.startsWith("'")) { + var = var.substring(1); + escape = false; + } + + Object o = createStructure(varmap, var); + return generateXml(o, 0, escape); + } + + public static String getJson(Map<String, String> varmap, String var) { + boolean escape = true; + if (var.startsWith("'")) { + var = var.substring(1); + escape = false; + } + + boolean quotes = true; + if (var.startsWith("\"")) { + var = var.substring(1); + quotes = false; + } + + Object o = createStructure(varmap, var); + return generateJson(o, escape, quotes); + } + + private static Object createStructure(Map<String, String> flatmap, String var) { + if (flatmap.containsKey(var)) { + if (var.endsWith("_length") || var.endsWith("].key")) + return null; + return flatmap.get(var); + } + + Map<String, Object> mm = new HashMap<>(); + for (String k : flatmap.keySet()) + if (k.startsWith(var + ".")) { + int i1 = k.indexOf('.', var.length() + 1); + int i2 = k.indexOf('[', var.length() + 1); + int i3 = k.length(); + if (i1 > 0 && i1 < i3) + i3 = i1; + if (i2 > 0 && i2 < i3) + i3 = i2; + String k1 = k.substring(var.length() + 1, i3); + String var1 = k.substring(0, i3); + if (!mm.containsKey(k1)) { + Object str = createStructure(flatmap, var1); + if (str != null && (!(str instanceof String) || ((String) str).trim().length() > 0)) + mm.put(k1, str); + } + } + if (!mm.isEmpty()) + return mm; + + boolean arrayFound = false; + for (String k : flatmap.keySet()) + if (k.startsWith(var + "[")) { + arrayFound = true; + break; + } + + if (arrayFound) { + List<Object> ll = new ArrayList<>(); + + int length = Integer.MAX_VALUE; + String lengthStr = flatmap.get(var + "_length"); + if (lengthStr != null) { + try { + length = Integer.parseInt(lengthStr); + } catch (Exception e) { + log.warn("Invalid number for {}_length:{}", var, lengthStr, e); + } + } + + for (int i = 0; i < length; i++) { + Object v = createStructure(flatmap, var + '[' + i + ']'); + if (v == null) + break; + ll.add(v); + } + + if (!ll.isEmpty()) + return ll; + } + + return null; + } + + @SuppressWarnings("unchecked") + private static String generateXml(Object o, int indent, boolean escape) { + if (o == null) + return null; + + if (o instanceof String) + return escape ? escapeXml((String) o) : (String) o;; + + if (o instanceof Map) { + StringBuilder ss = new StringBuilder(); + Map<String, Object> mm = (Map<String, Object>) o; + for (Map.Entry<String, Object> entry: mm.entrySet()) { + Object v = entry.getValue(); + String key = entry.getKey(); + if (v instanceof String) { + String s = escape ? escapeXml((String) v) : (String) v; + ss.append(pad(indent)).append('<').append(key).append('>'); + ss.append(s); + ss.append("</").append(key).append('>').append('\n'); + } else if (v instanceof Map) { + ss.append(pad(indent)).append('<').append(key).append('>').append('\n'); + ss.append(generateXml(v, indent + 1, escape)); + ss.append(pad(indent)).append("</").append(key).append('>').append('\n'); + } else if (v instanceof List) { + List<Object> ll = (List<Object>) v; + for (Object o1 : ll) { + ss.append(pad(indent)).append('<').append(key).append('>').append('\n'); + ss.append(generateXml(o1, indent + 1, escape)); + ss.append(pad(indent)).append("</").append(key).append('>').append('\n'); + } + } + } + return ss.toString(); + } + + return null; + } + + private static String generateJson(Object o, boolean escape, boolean quotes) { + if (o == null) + return null; + + StringBuilder ss = new StringBuilder(); + generateJson(ss, o, 0, false, escape, quotes); + return ss.toString(); + } + + @SuppressWarnings("unchecked") + private static void generateJson(StringBuilder ss, Object o, int indent, boolean padFirst, boolean escape, boolean quotes) { + if (o instanceof String) { + String s = escape ? escapeJson((String) o) : (String) o; + if (padFirst) + ss.append(pad(indent)); + if (quotes) { + ss.append('"').append(s).append('"'); + } else { + ss.append(s); + } + return; + } + + if (o instanceof Map) { + Map<String, Object> mm = (Map<String, Object>) o; + + if (padFirst) + ss.append(pad(indent)); + ss.append("{\n"); + + boolean first = true; + for (Map.Entry<String, Object> entry : mm.entrySet()) { + if (!first) + ss.append(",\n"); + first = false; + Object v = entry.getValue(); + String key = entry.getKey(); + ss.append(pad(indent + 1)).append('"').append(key).append("\": "); + generateJson(ss, v, indent + 1, false, escape, true); + } + + ss.append("\n"); + ss.append(pad(indent)).append('}'); + + return; + } + + if (o instanceof List) { + List<Object> ll = (List<Object>) o; + + if (padFirst) + ss.append(pad(indent)); + ss.append("[\n"); + + boolean first = true; + for (Object o1 : ll) { + if (!first) + ss.append(",\n"); + first = false; + + generateJson(ss, o1, indent + 1, true, escape, quotes); + } + + ss.append("\n"); + ss.append(pad(indent)).append(']'); + } + } + + public static String removeLastCommaJson(String s) { + StringBuilder sb = new StringBuilder(); + int k = 0; + int start = 0; + while (k < s.length()) { + int i11 = s.indexOf('}', k); + int i12 = s.indexOf(']', k); + int i1 = -1; + if (i11 < 0) + i1 = i12; + else if (i12 < 0) + i1 = i11; + else + i1 = i11 < i12 ? i11 : i12; + if (i1 < 0) + break; + + int i2 = s.lastIndexOf(',', i1); + if (i2 < 0) { + k = i1 + 1; + continue; + } + + String between = s.substring(i2 + 1, i1); + if (between.trim().length() > 0) { + k = i1 + 1; + continue; + } + + sb.append(s.substring(start, i2)); + start = i2 + 1; + k = i1 + 1; + } + + sb.append(s.substring(start, s.length())); + + return sb.toString(); + } + + public static String removeEmptyStructJson(String s) { + int k = 0; + while (k < s.length()) { + boolean curly = true; + int i11 = s.indexOf('{', k); + int i12 = s.indexOf('[', k); + int i1 = -1; + if (i11 < 0) { + i1 = i12; + curly = false; + } else if (i12 < 0) + i1 = i11; + else + if (i11 < i12) + i1 = i11; + else { + i1 = i12; + curly = false; + } + + if (i1 >= 0) { + int i2 = curly ? s.indexOf('}', i1) : s.indexOf(']', i1); + if (i2 > 0) { + String value = s.substring(i1 + 1, i2); + if (value.trim().length() == 0) { + int i4 = s.lastIndexOf('\n', i1); + if (i4 < 0) + i4 = 0; + int i5 = s.indexOf('\n', i2); + if (i5 < 0) + i5 = s.length(); + + s = s.substring(0, i4) + s.substring(i5); + k = 0; + } else + k = i1 + 1; + } else + break; + } else + break; + } + + return s; + } + + public static String removeEmptyStructXml(String s) { + int k = 0; + while (k < s.length()) { + int i1 = s.indexOf('<', k); + if (i1 < 0 || i1 == s.length() - 1) + break; + + char c1 = s.charAt(i1 + 1); + if (c1 == '?' || c1 == '!') { + k = i1 + 2; + continue; + } + + int i2 = s.indexOf('>', i1); + if (i2 < 0) { + k = i1 + 1; + continue; + } + + String closingTag = "</" + s.substring(i1 + 1, i2 + 1); + int i3 = s.indexOf(closingTag, i2 + 1); + if (i3 < 0) { + k = i2 + 1; + continue; + } + + String value = s.substring(i2 + 1, i3); + if (value.trim().length() > 0) { + k = i2 + 1; + continue; + } + + int i4 = s.lastIndexOf('\n', i1); + if (i4 < 0) + i4 = 0; + int i5 = s.indexOf('\n', i3); + if (i5 < 0) + i5 = s.length(); + + s = s.substring(0, i4) + s.substring(i5); + k = 0; + } + + return s; + } + + private static String escapeXml(String v) { + String s = v.replaceAll("&", "&"); + s = s.replaceAll("<", "<"); + s = s.replaceAll("'", "'"); + s = s.replaceAll("\"", """); + s = s.replaceAll(">", ">"); + return s; + } + + private static String escapeJson(String v) { + String s = v.replaceAll("\\\\", "\\\\\\\\"); + s = s.replaceAll("\"", "\\\\\""); + return s; + } + + private static String pad(int n) { + StringBuilder s = new StringBuilder(); + for (int i = 0; i < n; i++) + s.append(Character.toString('\t')); + return s.toString(); + } +} diff --git a/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/XmlParser.java b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/XmlParser.java new file mode 100644 index 000000000..6ea770ad9 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/java/org/onap/ccsdk/sli/plugins/sshapicall/model/XmlParser.java @@ -0,0 +1,176 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * + * Modifications Copyright © 2018 IBM. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.plugins.sshapicall.model; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +public final class XmlParser { + + private static final Logger log = LoggerFactory.getLogger(XmlParser.class); + + private XmlParser() { + // Preventing instantiation of the same. + } + + public static Map<String, String> convertToProperties(String s, Set<String> listNameList) + throws SvcLogicException { + + checkNotNull(s, "Input should not be null."); + + Handler handler = new Handler(listNameList); + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser = factory.newSAXParser(); + InputStream in = new ByteArrayInputStream(s.getBytes()); + saxParser.parse(in, handler); + } catch (ParserConfigurationException | IOException | SAXException | NumberFormatException e) { + throw new SvcLogicException("Unable to convert XML to properties" + e.getLocalizedMessage(), e); + } + return handler.getProperties(); + } + + private static class Handler extends DefaultHandler { + + private Set<String> listNameList; + + private Map<String, String> properties = new HashMap<>(); + + StringBuilder currentName = new StringBuilder(); + StringBuilder currentValue = new StringBuilder(); + + public Handler(Set<String> listNameList) { + super(); + this.listNameList = listNameList; + if (this.listNameList == null) + this.listNameList = new HashSet<>(); + } + + public Map<String, String> getProperties() { + return properties; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + super.startElement(uri, localName, qName, attributes); + + String name = localName; + if (name == null || name.trim().length() == 0) + name = qName; + int i2 = name.indexOf(':'); + if (i2 >= 0) + name = name.substring(i2 + 1); + + if (currentName.length() > 0) + currentName.append(Character.toString('.')); + currentName.append(name); + + String listName = removeIndexes(currentName.toString()); + + if (listNameList.contains(listName)) { + String n = currentName.toString() + "_length"; + int len = getInt(properties, n); + properties.put(n, String.valueOf(len + 1)); + currentName.append("[").append(len).append("]"); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + super.endElement(uri, localName, qName); + + String name = localName; + if (name == null || name.trim().length() == 0) + name = qName; + int i2 = name.indexOf(':'); + if (i2 >= 0) + name = name.substring(i2 + 1); + + String s = currentValue.toString().trim(); + if (s.length() > 0) { + properties.put(currentName.toString(), s); + + log.info("Added property: {} : {}", currentName, s); + currentValue = new StringBuilder(); + } + + int i1 = currentName.lastIndexOf("." + name); + if (i1 <= 0) + currentName = new StringBuilder(); + else + currentName = new StringBuilder(currentName.substring(0, i1)); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + super.characters(ch, start, length); + + String value = new String(ch, start, length); + currentValue.append(value); + } + + private static int getInt(Map<String, String> mm, String name) { + String s = mm.get(name); + if (s == null) + return 0; + return Integer.parseInt(s); + } + + private String removeIndexes(String currentName) { + StringBuilder b = new StringBuilder(); + boolean add = true; + for (int i = 0; i < currentName.length(); i++) { + char c = currentName.charAt(i); + if (c == '[') + add = false; + else if (c == ']') + add = true; + else if (add) + b.append(Character.toString(c)); + } + return b.toString(); + } + } +} diff --git a/plugins/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml b/plugins/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml new file mode 100644 index 000000000..50c9b2aa3 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-context.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd"> + + <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> + <property name="locations"> + <list> + <value>file:${SDNC_CONFIG_DIR}/ueb.properties</value> + <value>file:${SDNC_CONFIG_DIR}/dme2.properties</value> + </list> + </property> + <property name="ignoreResourceNotFound" value="true" /> + <property name="ignoreUnresolvablePlaceholders" value="true" /> + </bean> + + <!-- context:property-placeholder location="file:${SDNC_CONFIG_DIR}/ueb.properties" /--> + + <bean id="sshapiCallNode" class="org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode"> + <property name="uebServers" value="${servers}" /> + </bean> + +</beans> diff --git a/plugins/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml b/plugins/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml new file mode 100644 index 000000000..25631d6af --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/resources/META-INF/spring/sshapi-call-node-osgi-context.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<beans:beans xmlns="http://www.springframework.org/schema/osgi" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" + xsi:schemaLocation="http://www.springframework.org/schema/osgi + http://www.springframework.org/schema/osgi/spring-osgi.xsd + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd"> + + <service ref="sshapiCallNode" interface="org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode" /> + +</beans:beans> diff --git a/plugins/sshapi-call-node/provider/src/main/resources/OSGI-INF/blueprint/sshapi-call-node-blueprint.xml b/plugins/sshapi-call-node/provider/src/main/resources/OSGI-INF/blueprint/sshapi-call-node-blueprint.xml new file mode 100755 index 000000000..7a5424329 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/resources/OSGI-INF/blueprint/sshapi-call-node-blueprint.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" + odl:use-default-for-reference-types="true"> + + <bean id="sshapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode" /> + + + + <service ref="sshapiCallNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode</value> + </interfaces> + </service> + +</blueprint>
\ No newline at end of file diff --git a/plugins/sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml b/plugins/sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml new file mode 100755 index 000000000..7a5424329 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/main/resources/org/opendaylight/blueprint/sshapi-call-node-blueprint.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" + odl:use-default-for-reference-types="true"> + + <bean id="sshapiCallNodeProvider" class="org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode" /> + + + + <service ref="sshapiCallNodeProvider"> + <interfaces> + <value>org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode</value> + </interfaces> + </service> + +</blueprint>
\ No newline at end of file diff --git a/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestJsonParser.java b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestJsonParser.java new file mode 100644 index 000000000..78f20e327 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestJsonParser.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package jtest.org.onap.ccsdk.sli.plugins.restapicall; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.codehaus.jettison.json.JSONException; +import org.junit.Test; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.sshapicall.model.JsonParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestJsonParser { + + private static final Logger log = LoggerFactory.getLogger(TestJsonParser.class); + + @Test + public void test() throws SvcLogicException, IOException { + BufferedReader in = new BufferedReader( + new InputStreamReader(ClassLoader.getSystemResourceAsStream("test.json")) + ); + StringBuilder b = new StringBuilder(); + String line; + while ((line = in.readLine()) != null) + b.append(line).append('\n'); + Map<String, String> mm = null; + try { + mm = JsonParser.convertToProperties(b.toString()); + } catch (JSONException e){ + throw new SvcLogicException(e.getMessage()); + } + + logProperties(mm); + + in.close(); + } + + @Test(expected = NullPointerException.class) + public void testNullString() throws SvcLogicException { + Map<String, String> mm = null; + try { + mm = JsonParser.convertToProperties(null); + } catch (JSONException e){ + throw new SvcLogicException(e.getMessage()); + } + } + + private void logProperties(Map<String, String> mm) { + List<String> ll = new ArrayList<>(); + for (Object o : mm.keySet()) + ll.add((String) o); + Collections.sort(ll); + log.info("Properties:"); + for (String name : ll) + log.info("--- {}: {}", name, mm.get(name)); + } +} diff --git a/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestSshApiCallNode.java b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestSshApiCallNode.java new file mode 100644 index 000000000..c0bcdb82a --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestSshApiCallNode.java @@ -0,0 +1,330 @@ +package jtest.org.onap.ccsdk.sli.plugins.restapicall; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.sshapicall.SshApiCallNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class TestSshApiCallNode { + + private static final Logger log = LoggerFactory.getLogger(TestSshApiCallNode.class); + + private SshApiCallNode adapter; + private String TestId; + private boolean testMode = true; + private Map<String, String> params; + private SvcLogicContext svcContext; + + + @Before + public void setup() throws IllegalArgumentException { + testMode = true; + svcContext = new SvcLogicContext(); + adapter = new SshApiCallNode(); + + params = new HashMap<>(); + params.put("AgentUrl", "https://192.168.1.1"); + params.put("User", "test"); + params.put("Password", "test"); + } + + @After + public void tearDown() { + testMode = false; + adapter = null; + params = null; + svcContext = null; + } + + @Test(expected = SvcLogicException.class) + public void testExecCommand_noUrlFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("HostName", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Test", "fail"); + adapter.execCommand(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandPty_noUrlFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("HostName", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Test", "fail"); + adapter.execCommandWithPty(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_noUrlFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("HostName", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Test", "fail"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommand_noPortFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Test", "fail"); + adapter.execCommand(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandPty_noPortFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Test", "fail"); + adapter.execCommandWithPty(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_noPortFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Test", "fail"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommand_noCmdFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + adapter.execCommand(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandPty_noCmdFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + adapter.execCommandWithPty(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_noCmdFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_noSSHBasicFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("AuthType", "basic"); + params.put("Cmd", "test"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_noSSHKeyFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("AuthType", "key"); + params.put("Cmd", "test"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_noSSHNoneFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("AuthType", "none"); + params.put("Cmd", "test"); + params.put("ResponseType", "xml"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_noSSHFailed() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("ResponseType", "json"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = IllegalArgumentException.class) + public void testExecCommandResponse_noSSHInvalidParam() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("ResponseType", "txt"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = IllegalArgumentException.class) + public void testExecCommandResponse_noSSHInvalidAuthParam() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("AuthType", "spring"); + params.put("ResponseType", "json"); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test + public void testExecCommandResponse_validJSON() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("AuthType", "basic"); + params.put("ResponseType", "json"); + params.put("TestOut", "{\"equipment-data\":\"boo\"}"); + params.put("TestFail", "false"); + adapter = new SshApiCallNode(true); + adapter.execWithStatusCheck(params, svcContext); + assertEquals("boo", svcContext.getAttribute("equipment-data")); + } + + @Test + public void testExecCommandResponse_validXML() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("AuthType", "basic"); + params.put("ResponseType", "xml"); + params.put("TestOut", "<modelVersion>4.0.0</modelVersion>"); + params.put("TestFail", "false"); + adapter = new SshApiCallNode(true); + adapter.execWithStatusCheck(params, svcContext); + assertEquals("4.0.0", svcContext.getAttribute("modelVersion")); + } + + @Test + public void testExecCommandResponse_validJSONPrefix() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("AuthType", "basic"); + params.put("ResponseType", "json"); + params.put("TestOut", "{\"equipment-data\":\"boo\"}"); + params.put("ResponsePrefix", "test"); + params.put("TestFail", "false"); + adapter = new SshApiCallNode(true); + adapter.execWithStatusCheck(params, svcContext); + assertEquals("boo", svcContext.getAttribute("test.equipment-data")); + } + + @Test + public void testExecCommandResponse_validXMLPrefix() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("AuthType", "basic"); + params.put("ResponseType", "xml"); + params.put("TestOut", "<modelVersion>4.0.0</modelVersion>"); + params.put("ResponsePrefix", "test"); + params.put("TestFail", "false"); + adapter = new SshApiCallNode(true); + adapter.execWithStatusCheck(params, svcContext); + assertEquals("4.0.0", svcContext.getAttribute("test.modelVersion")); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_validXMLFail() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + + params.put("Url", "test"); + params.put("Port", "10"); + params.put("User", "test"); + params.put("Password", "test"); + params.put("Cmd", "test"); + params.put("AuthType", "basic"); + params.put("ResponseType", "xml"); + params.put("TestOut", "<modelVersion>4.0.0</modelVersion>"); + params.put("TestFail", "true"); + params.put("ResponsePrefix", "test"); + adapter = new SshApiCallNode(true); + adapter.execWithStatusCheck(params, svcContext); + } + + @Test(expected = SvcLogicException.class) + public void testExecCommandResponse_validXMLPrefixKey() throws SvcLogicException, + IllegalStateException, IllegalArgumentException { + params = new HashMap<>(); + params.put("Url", "test"); + params.put("Port", "10"); + params.put("SshKey", "test"); + params.put("Cmd", "test"); + params.put("ResponseType", "xml"); + params.put("TestOut", "<modelVersion>4.0.0</modelVersion>"); + params.put("ResponsePrefix", "test"); + adapter.execWithStatusCheck(params, svcContext); + assertEquals("4.0.0", svcContext.getAttribute("test.modelVersion")); + } +} diff --git a/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestXmlJsonUtil.java b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestXmlJsonUtil.java new file mode 100644 index 000000000..33e0f24dd --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestXmlJsonUtil.java @@ -0,0 +1,264 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package jtest.org.onap.ccsdk.sli.plugins.restapicall; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.onap.ccsdk.sli.plugins.sshapicall.model.XmlJsonUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class TestXmlJsonUtil { + + private static final Logger log = LoggerFactory.getLogger(TestXmlJsonUtil.class); + + @Test + public void test() { + Map<String, String> mm = new HashMap<>(); + mm.put("service-data.vnf-config-parameters-list.vnf-config-parameters[0].vnf-type", "N-SBG"); + mm.put("service-data.service-information.service-instance-id", "someinstance001"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].dns-server-ip-address", "10.11.12.13"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].escf-domain-name", "hclab.atttest.com"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].snmp-target-v3_length", "2"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].snmp-target-v3[0].snmp-target-v3-id", "1"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].snmp-target-v3[0].snmp-target-ip-address", "127.0.0.1"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].snmp-target-v3[0].snmp-security-level", "NO_AUTH_NO_PRIV"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].snmp-target-v3[1].snmp-target-v3-id", "2"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].snmp-target-v3[1].snmp-target-ip-address", "192.168.1.8"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].snmp-target-v3[1].snmp-security-level", "NO_AUTH_NO_PRIV"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].dns-ip-address-1", "2001:1890:1001:2224::1"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].dns-ip-address-2", "2001:1890:1001:2424::1"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].diameter-rf-realm-name", "uvp.els-an.att.net"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].diameter-rf-peer-ip-address", "192.168.1.66"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].bgf-controller-ip-address", "192.168.1.186"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].bgf-control-link-name", "mg3/69@192.168.1.226"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].rf-interface-nexthop-ip-address", "10.111.108.150"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].rf-mated-pair-ip-address", "10.111.108.146"); + + mm.put("service-data.vnf-config-parameters-list.vnf-config-parameters[0].access-net-pcscf_length", "4"); + + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[0].network-name", "UvpbUgnAccess1"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[0].sip-pa-termination-ip-address", "10.111.108.146"); + + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[1].network-name", "MIS"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[1].proactive-transcoding-profile", + "trinity-transcodingProfile"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[1].next-hop-ip-address", "10.111.108.158"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[1].subnet-mask-length", "10.111.108.154"); + + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[2].network-name", "AVPN1"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[2].proactive-transcoding-profile", + "trinity-transcodingProfile"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[2].next-hop-ip-address", "10.111.108.166"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[2].subnet-mask-length", "10.111.108.162"); + + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[3].network-name", "AVPN1"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[3].proactive-transcoding-profile", + "trinity-transcodingProfile"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[3].next-hop-ip-address", "10.129.108.166"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].access-net-pcscf[3].subnet-mask-length", "10.129.108.162"); + + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].core-net-pcscf_length", "1"); + + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].core-net-pcscf[0].network-name", "Core"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].core-net-pcscf[0].next-hop-ip-address", "10.111.108.142"); + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].core-net-pcscf[0].sip-pa-termination-ip-address", "10.111.108.138"); + + mm.put("service-data.vnf-config-parameters-list." + + "vnf-config-parameters[0].mated-pair-fully-qualified-domain-name", + "mt1nj01sbg01pyl-mt1nj01sbg02pyl.ar1ga.uvp.els-an.att.net"); + + mm.put("service-data.appc-request-header.svc-request-id", "SOMESERVICEREQUEST123451000"); + mm.put("service-data.vnf-config-information.vnf-host-ip-address", "192.168.13.151"); + mm.put("service-data.vnf-config-information.vendor", "Netconf"); + + mm.put("service-data.vnf-config-information.escape-test", + "blah blah \"xxx&nnn<>\\'\"there>blah<&''\"\"123\\\\\\'''blah blah &"); + + String ss = XmlJsonUtil.getXml(mm, "service-data.vnf-config-parameters-list"); + log.info(ss); + + ss = XmlJsonUtil.getXml(mm, "service-data.vnf-config-information"); + log.info(ss); + + ss = XmlJsonUtil.getJson(mm, "service-data.vnf-config-parameters-list.vnf-config-parameters"); + log.info(ss); + + ss = XmlJsonUtil.getJson(mm, "service-data.vnf-config-information"); + log.info(ss); + + ss = XmlJsonUtil.getJson(mm, "service-data.vnf-config-information.vnf-host-ip-address"); + log.info(ss); + + ss = XmlJsonUtil.getJson(mm, "\"service-data.vnf-config-information.vnf-host-ip-address"); + log.info(ss); + } + + @Test + public void testRemoveEmptyStructXml() { + String xmlin = "" + + "<T1>\n" + + " <T2>\n" + + " <T3>\n" + + " <T4></T4>\n" + + " <T5> </T5>\n" + + " <T6>\n" + + " </T6>\n" + + " </T3>\n" + + " <T7>blah</T7>\n" + + " </T2>\n" + + " <T8>\n" + + " <T9>\n" + + " <T10></T10>\n" + + " <T11> </T11>\n" + + " <T12>\n" + + " </T12>\n" + + " </T9>\n" + + " <T13>\n" + + " <T14></T14>\n" + + " <T15> </T15>\n" + + " <T16>\n" + + " <T17></T17>\n" + + " </T16>\n" + + " </T13>\n" + + " <T17>\n" + + " </T17>\n" + + " </T8>\n" + + " <T18>blah blah</T18>\n" + + "</T1>\n"; + + String xmloutexpected = "" + + "<T1>\n" + + " <T2>\n" + + " <T7>blah</T7>\n" + + " </T2>\n" + + " <T18>blah blah</T18>\n" + + "</T1>\n"; + + String xmlout = XmlJsonUtil.removeEmptyStructXml(xmlin); + log.info(xmlout); + + Assert.assertEquals(xmloutexpected, xmlout); + } + + @Test + public void testRemoveEmptyStructJson() { + String xmlin = "{\r\n" + + " \"T1\":{\r\n" + + " \"T2\":{\r\n" + + " \"T3\":[\r\n" + + " \r\n" + + " ],\r\n" + + " \"T4\":{\r\n" + + " \"T12\":[\r\n" + + " \r\n" + + " ],\r\n" + + " \"T13\":[ ],\r\n" + + " \"T14\":{\r\n" + + " \"T15\":{\r\n" + + " \r\n" + + " },\r\n" + + " \"T16\":{\r\n" + + " \r\n" + + " }\r\n" + + " }\r\n" + + " },\r\n" + + " \"T5\":{\r\n" + + " \"T6\":[\r\n" + + " \r\n" + + " ],\r\n" + + " \"T7\":[\r\n" + + " \"T8\":{\r\n" + + " \r\n" + + " },\r\n" + + " \"T9\":{ },\r\n" + + " \"T10\":\"blah\",\r\n" + + " \"T11\":[\r\n" + + " \r\n" + + " ]\r\n" + + " ]\r\n" + + " }\r\n" + + " }\r\n" + + " }\r\n" + + "}\r\n" + + ""; + + String xmloutexpected = "{\r\n" + + " \"T1\":{\r\n" + + " \"T2\":{\r\n" + + " \"T5\":{\r\n" + + " \"T7\":[\r\n" + + " \"T10\":\"blah\",\r\n" + + " ]\r\n" + + " }\r\n" + + " }\r\n" + + " }\r\n" + + "}\r\n" + + ""; + + String xmlout = XmlJsonUtil.removeEmptyStructJson(xmlin); + log.info(xmlout); + + Assert.assertEquals(xmloutexpected, xmlout); + } +} diff --git a/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestXmlParser.java b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestXmlParser.java new file mode 100644 index 000000000..ba0ae41de --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/java/jtest/org/onap/ccsdk/sli/plugins/restapicall/TestXmlParser.java @@ -0,0 +1,123 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package jtest.org.onap.ccsdk.sli.plugins.restapicall; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.plugins.sshapicall.model.XmlParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TestXmlParser { + + private static final Logger log = LoggerFactory.getLogger(TestXmlParser.class); + + @Test + public void test() throws Exception { + BufferedReader in = new BufferedReader( + new InputStreamReader(ClassLoader.getSystemResourceAsStream("test3.xml")) + ); + StringBuilder b = new StringBuilder(); + String line; + while ((line = in.readLine()) != null) + b.append(line).append('\n'); + + Set<String> listNameList = new HashSet<String>(); + listNameList.add("project.dependencies.dependency"); + listNameList.add("project.build.plugins.plugin"); + listNameList.add("project.build.plugins.plugin.executions.execution"); + listNameList.add("project.build.pluginManagement.plugins.plugin"); + listNameList.add("project.build.pluginManagement." + + "plugins.plugin.configuration.lifecycleMappingMetadata.pluginExecutions.pluginExecution"); + + Map<String, String> mm = XmlParser.convertToProperties(b.toString(), listNameList); + logProperties(mm); + in.close(); + } + + @Test + public void testValidLength() throws Exception { + BufferedReader in = new BufferedReader( + new InputStreamReader(ClassLoader.getSystemResourceAsStream("test3.xml")) + ); + StringBuilder b = new StringBuilder(); + String line; + while ((line = in.readLine()) != null) + b.append(line).append('\n'); + + Set<String> listNameList = new HashSet<String>(); + listNameList.add("ApplyGroupResponse.ApplyGroupResponseData.VrfDetails.VrfImport"); + listNameList.add("ApplyGroupResponse.ApplyGroupResponseData.VrfDetails.VrfExport"); + + Map<String, String> mm = XmlParser.convertToProperties(b.toString(), listNameList); + + assertThat(mm.get("ApplyGroupResponse.ApplyGroupResponseData.VrfDetails.VrfExport[5]"), is("SET_RESET_LP")); + assertThat(mm.get("ApplyGroupResponse.ApplyGroupResponseData.VrfDetails.VrfImport[0]"), is("SET_BVOIP_IN")); + + logProperties(mm); + in.close(); + } + + @Test(expected = SvcLogicException.class) + public void testInvalidLength() throws Exception { + BufferedReader in = new BufferedReader( + new InputStreamReader(ClassLoader.getSystemResourceAsStream("invalidlength.xml")) + ); + StringBuilder b = new StringBuilder(); + String line; + while ((line = in.readLine()) != null) + b.append(line).append('\n'); + + Set<String> listNameList = new HashSet<String>(); + listNameList.add("ApplyGroupResponse.ApplyGroupResponseData.VrfDetails.VrfImport"); + listNameList.add("ApplyGroupResponse.ApplyGroupResponseData.VrfDetails.VrfExport"); + + Map<String, String> mm = XmlParser.convertToProperties(b.toString(), listNameList); + logProperties(mm); + in.close(); + } + + private void logProperties(Map<String, String> mm) { + List<String> ll = new ArrayList<>(); + for (Object o : mm.keySet()) + ll.add((String) o); + Collections.sort(ll); + + log.info("Properties:"); + for (String name : ll) + log.info("--- " + name + ": " + mm.get(name)); + } +} diff --git a/plugins/sshapi-call-node/provider/src/test/resources/invalidlength.xml b/plugins/sshapi-call-node/provider/src/test/resources/invalidlength.xml new file mode 100644 index 000000000..b71f6391f --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/resources/invalidlength.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + Copyright (C) 2018 Samsung Electronics. All rights + reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<ApplyGroupResponse xmlns="http://onap.org/vpn/schema/v1" + xmlns:ns2="http://onap.org/prov/vpn/schema/v2"> + <ApplyGroupResponseData> + <ServiceInstanceId>ICOREPVC-81114561</ServiceInstanceId> + <VrfDetails> + <End2EndVpnKey>VPNL811182</End2EndVpnKey> + <VpnId>811182</VpnId> + <VrfName>21302:811182</VrfName> + <VrfImport>SET_BVOIP_IN</VrfImport> + <VrfImport>SET6_BVOIP_IN</VrfImport> + <VrfExport_length>a</VrfExport_length> + <VrfExport>SET6_DSU</VrfExport> + <VrfExport>SET_DSU</VrfExport> + <VrfExport>SET6_MANAGED</VrfExport> + <VrfExport>SET_MANAGED</VrfExport> + <VrfExport>SET_LOVRF_COMMUNITY</VrfExport> + <VrfExport>SET_RESET_LP</VrfExport> + <ApplyGroup> + <ns2:ApplyGroup>AG_MAX_MCASTROUTES</ns2:ApplyGroup> + </ApplyGroup> + </VrfDetails> + </ApplyGroupResponseData> + <response-code>200</response-code> + <response-message>Success</response-message> + <ack-final-indicator>Y</ack-final-indicator> +</ApplyGroupResponse> + diff --git a/plugins/sshapi-call-node/provider/src/test/resources/test-template.json b/plugins/sshapi-call-node/provider/src/test/resources/test-template.json new file mode 100644 index 000000000..cd5e74699 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/resources/test-template.json @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +{ + "sdn-circuit-request": [ + ${repeat:tmp.sdn-circuit-req-row_length: + { + "request-id": ${tmp.sdn-circuit-req-row[${1}].request-id}, + "source-uid": ${tmp.sdn-circuit-req-row[${1}].source-uid}, + "action": ${tmp.sdn-circuit-req-row[${1}].action}, + "request-timestamp": ${tmp.sdn-circuit-req-row[${1}].request-timestamp}, + "update-timestamp": ${tmp.sdn-circuit-req-row[${1}].update-timestamp}, + "request-status": ${tmp.sdn-circuit-req-row[${1}].request-status}, + "processing-status": ${tmp.sdn-circuit-req-row[${1}].processing-status}, + "reason-code": ${tmp.sdn-circuit-req-row[${1}].reason-code}, + "reason-message": ${tmp.sdn-circuit-req-row[${1}].reason-message}, + "customer-code": ${tmp.sdn-circuit-req-row[${1}].customer-code}, + "bundle-id": ${tmp.sdn-circuit-req-row[${1}].bundle-id}, + "router-name-1": ${tmp.sdn-circuit-req-row[${1}].router-name-1}, + "tail-clfi-1": ${tmp.sdn-circuit-req-row[${1}].tail-clfi-1}, + "srg-1": ${tmp.sdn-circuit-req-row[${1}].srg-1}, + "router-name-2": ${tmp.sdn-circuit-req-row[${1}].router-name-2}, + "tail-clfi-2": ${tmp.sdn-circuit-req-row[${1}].tail-clfi-2}, + "srg-2": ${tmp.sdn-circuit-req-row[${1}].srg-2}, + "facility-speed": ${tmp.sdn-circuit-req-row[${1}].facility-speed}, + "facility-speed-units": ${tmp.sdn-circuit-req-row[${1}].facility-speed-units}, + "facility-type": ${tmp.sdn-circuit-req-row[${1}].facility-type}, + "service-clfi": ${tmp.sdn-circuit-req-row[${1}].service-clfi}, + "clci": ${tmp.sdn-circuit-req-row[${1}].clci}, + "wavelength-purpose": ${tmp.sdn-circuit-req-row[${1}].wavelength-purpose}, + "activate-setting": ${tmp.sdn-circuit-req-row[${1}].activate-setting}, + "apply-date": ${tmp.sdn-circuit-req-row[${1}].apply-date}, + "run-id": ${tmp.sdn-circuit-req-row[${1}].run-id}, + "hostname": ${tmp.sdn-circuit-req-row[${1}].hostname}, + "algo-request-reason": ${tmp.sdn-circuit-req-row[${1}].algo-request-reason} + }, + } + ] +} diff --git a/plugins/sshapi-call-node/provider/src/test/resources/test.json b/plugins/sshapi-call-node/provider/src/test/resources/test.json new file mode 100644 index 000000000..e272d457a --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/resources/test.json @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +{ + "equipment-data": [ + { + "server-count": "4", + "max-server-speed": "1600000", + "number-primary-servers": "2", + "equipment-id": "Server1", + "server-model": "Unknown", + "server-id": "Server1", + "test-node" : { + "test-inner-node" : "Test-Value" + } + } + ], + "resource-state": { + "threshold-value": "1600000", + "last-added": "1605000", + "used": "1605000", + "limit-value": "1920000" + }, + "resource-rule": { + "endpoint-position": "VCE-Cust", + "soft-limit-expression": "0.6 * max-server-speed * number-primary-servers", + "resource-name": "Bandwidth", + "service-model": "DUMMY", + "hard-limit-expression": "max-server-speed * number-primary-servers", + "equipment-level": "Server" + }, + "message": "The provisioned access bandwidth is at or exceeds 50% of the total server capacity." +} diff --git a/plugins/sshapi-call-node/provider/src/test/resources/test.xml b/plugins/sshapi-call-node/provider/src/test/resources/test.xml new file mode 100644 index 000000000..7645f1992 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/resources/test.xml @@ -0,0 +1,184 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights + reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<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.sli.plugins</groupId> + <artifactId>sshapi-call-node</artifactId> + <version>6.0.0-SNAPSHOT</version> + </parent> + <artifactId>sshapi-call-node-provider</artifactId> + <packaging>bundle</packaging> + <name>SSHAPI Call Node - Provider</name> + <url>http://maven.apache.org</url> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <version>3.1.4.RELEASE</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli</groupId> + <artifactId>sli-common</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli</groupId> + <artifactId>sli-provider</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-beans</artifactId> + <version>3.1.4.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + <version>3.1.4.RELEASE</version> + </dependency> + <dependency> + <groupId>xerces</groupId> + <artifactId>xerces</artifactId> + <version>2.4.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-client</artifactId> + <version>1.17</version> + </dependency> + <dependency> + <groupId>com.sun.jersey.contribs.jersey-oauth</groupId> + <artifactId>oauth-signature</artifactId> + <version>1.17</version> + </dependency> + <dependency> + <groupId>com.sun.jersey.contribs.jersey-oauth</groupId> + <artifactId>oauth-client</artifactId> + <version>1.17</version> + </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>com.brocade.developer</groupId> + <artifactId>providermodule-plugin</artifactId> + <configuration> + <packageId>org.onap.ccsdk.sli.plugins</packageId> + <appName>sshapi-call-node</appName> + </configuration> + <executions> + <execution> + <phase>process-sources</phase> + <goals> + <goal>process</goal> + </goals> + </execution> + </executions> + </plugin> + + + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName>org.onap.ccsdk.sli.plugins.sshapicall</Bundle-SymbolicName> + <Export-Package>org.onap.ccsdk.sli.plugins.sshapicall</Export-Package> + <Import-Package>*</Import-Package> + </instructions> + + <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation> + + </configuration> + + </plugin> + + + </plugins> + <pluginManagement> + <plugins> + <!--This plugin's configuration is used to store Eclipse m2e settings + only. It has no influence on the Maven build itself. --> + <plugin> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId> + com.brocade.developer + </groupId> + <artifactId> + providermodule-plugin + </artifactId> + <versionRange> + [1.2.0.100-SNAPSHOT,) + </versionRange> + <goals> + <goal>process</goal> + </goals> + </pluginExecutionFilter> + <action> + <ignore /> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> +</project> diff --git a/plugins/sshapi-call-node/provider/src/test/resources/test3.xml b/plugins/sshapi-call-node/provider/src/test/resources/test3.xml new file mode 100644 index 000000000..52a7a7d98 --- /dev/null +++ b/plugins/sshapi-call-node/provider/src/test/resources/test3.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + Copyright (C) 2018 Samsung Electronics. All rights + reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<ApplyGroupResponse xmlns="http://onap.org/vpn/schema/v1" + xmlns:ns2="http://onap.org/prov/vpn/schema/v2"> + <ApplyGroupResponseData> + <ServiceInstanceId>ICOREPVC-81114561</ServiceInstanceId> + <VrfDetails> + <End2EndVpnKey>VPNL811182</End2EndVpnKey> + <VpnId>811182</VpnId> + <VrfName>21302:811182</VrfName> + <VrfImport>SET_BVOIP_IN</VrfImport> + <VrfImport>SET6_BVOIP_IN</VrfImport> + <VrfExport>SET6_DSU</VrfExport> + <VrfExport>SET_DSU</VrfExport> + <VrfExport>SET6_MANAGED</VrfExport> + <VrfExport>SET_MANAGED</VrfExport> + <VrfExport>SET_LOVRF_COMMUNITY</VrfExport> + <VrfExport>SET_RESET_LP</VrfExport> + <ApplyGroup> + <ns2:ApplyGroup>AG_MAX_MCASTROUTES</ns2:ApplyGroup> + </ApplyGroup> + </VrfDetails> + <RoutingApplyGroups> + <RoutingProtocol>BGP4_PROTOCOL</RoutingProtocol> + <Family>v4</Family> + <PeerGroupName>gp_21302:811182</PeerGroupName> + <ApplyGroupPeer> + <ns2:ApplyGroup>AG_L3VPN_EBGP</ns2:ApplyGroup> + </ApplyGroupPeer> + <ApplyGroupPeer> + <ns2:ApplyGroup>AG_MAX_PREFIX</ns2:ApplyGroup> + </ApplyGroupPeer> + <ApplyGroupNeighbour> + <ns2:ApplyGroup>AG_BGP_UNMANAGED</ns2:ApplyGroup> + </ApplyGroupNeighbour> + <ApplyGroupNeighbour> + <ns2:ApplyGroup>AG_BFD_BGP_3000</ns2:ApplyGroup> + </ApplyGroupNeighbour> + </RoutingApplyGroups> + <RoutingApplyGroups> + <RoutingProtocol>BGP4_PROTOCOL</RoutingProtocol> + <Family>v6</Family> + <PeerGroupName>gp6_21302:811182</PeerGroupName> + <ApplyGroupPeer> + <ns2:ApplyGroup>AG6_L3VPN_EBGP</ns2:ApplyGroup> + </ApplyGroupPeer> + <ApplyGroupPeer> + <ns2:ApplyGroup>AG6_MAX_PREFIX</ns2:ApplyGroup> + </ApplyGroupPeer> + <ApplyGroupNeighbour> + <ns2:ApplyGroup>AG6_BGP_UNMANAGED</ns2:ApplyGroup> + </ApplyGroupNeighbour> + <ApplyGroupNeighbour> + <ns2:ApplyGroup>AG6_BFD_BGP_3000</ns2:ApplyGroup> + </ApplyGroupNeighbour> + </RoutingApplyGroups> + </ApplyGroupResponseData> + <response-code>200</response-code> + <response-message>Success</response-message> + <ack-final-indicator>Y</ack-final-indicator> +</ApplyGroupResponse> + |