diff options
Diffstat (limited to 'adaptors/netbox-client')
22 files changed, 1608 insertions, 0 deletions
diff --git a/adaptors/netbox-client/installer/pom.xml b/adaptors/netbox-client/installer/pom.xml new file mode 100755 index 000000000..44fa16490 --- /dev/null +++ b/adaptors/netbox-client/installer/pom.xml @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2018 AT&T, Bell Canada + + 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. + --> + +<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> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>netbox-client-installer</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-adaptors :: netbox-client :: ${project.artifactId}</name> + + <properties> + <application.name>ccsdk-netbox-client</application.name> + <features.boot>${application.name}</features.boot> + <features.repositories>mvn:org.onap.ccsdk.sli.adaptors/${features.boot}/${project.version}/xml/features</features.repositories> + <include.transitive.dependencies>false</include.transitive.dependencies> + </properties> + + <dependencies> + + + + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>netbox-client-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.adaptors</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/adaptors/netbox-client/installer/src/assembly/assemble_installer_zip.xml b/adaptors/netbox-client/installer/src/assembly/assemble_installer_zip.xml new file mode 100644 index 000000000..ea3bef72e --- /dev/null +++ b/adaptors/netbox-client/installer/src/assembly/assemble_installer_zip.xml @@ -0,0 +1,53 @@ +<!-- + Copyright (C) 2018 AT&T, Bell Canada + + 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. + --> + +<!-- 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/adaptors/netbox-client/installer/src/assembly/assemble_mvnrepo_zip.xml b/adaptors/netbox-client/installer/src/assembly/assemble_mvnrepo_zip.xml new file mode 100644 index 000000000..b905cfe3f --- /dev/null +++ b/adaptors/netbox-client/installer/src/assembly/assemble_mvnrepo_zip.xml @@ -0,0 +1,43 @@ +<!-- + Copyright (C) 2018 AT&T, Bell Canada + + 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. + --> + +<!-- 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/adaptors/netbox-client/installer/src/main/resources/scripts/install-feature.sh b/adaptors/netbox-client/installer/src/main/resources/scripts/install-feature.sh new file mode 100644 index 000000000..b48869120 --- /dev/null +++ b/adaptors/netbox-client/installer/src/main/resources/scripts/install-feature.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# +# Copyright (C) 2018 AT&T, Bell Canada +# +# 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. +# + +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/adaptors/netbox-client/pom.xml b/adaptors/netbox-client/pom.xml new file mode 100644 index 000000000..6c9dbe85c --- /dev/null +++ b/adaptors/netbox-client/pom.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2018 AT&T, Bell Canada + + 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. + --> + +<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> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>netbox-client</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-adaptors :: netbox-client</name> + <description>The SDNC Adaptors for netbox IPAM as an OSGi service</description> + + <modules> + <module>provider</module> + <module>installer</module> + </modules> +</project> diff --git a/adaptors/netbox-client/provider/pom.xml b/adaptors/netbox-client/provider/pom.xml new file mode 100644 index 000000000..2242a157b --- /dev/null +++ b/adaptors/netbox-client/provider/pom.xml @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2018 AT&T, Bell Canada + + 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. + --> + +<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> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>netbox-client-provider</artifactId> + <version>1.1.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>ccsdk-sli-adaptors :: netbox-client :: ${project.artifactId}</name> + + <properties> + <ccsdk.sli.adaptors.version>${project.version}</ccsdk.sli.adaptors.version> + </properties> + + <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>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>${gson.version}</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <version>${apache.httpcomponents.core.version}</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>${apache.httpcomponents.client.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-common</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sliPluginUtils-provider</artifactId> + <version>${ccsdk.sli.core.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + + <!--Testing--> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <!-- Requires mockito v2 --> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>2.2.11</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.github.tomakehurst</groupId> + <artifactId>wiremock</artifactId> + <version>2.23.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Export-Package> + org.onap.ccsdk.sli.adaptors.netbox.api, + org.onap.ccsdk.sli.adaptors.netbox.ipam, + org.onap.ccsdk.sli.adaptors.netbox.model + </Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/IpamException.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/IpamException.java new file mode 100644 index 000000000..869a57cef --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/IpamException.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.api; + +public class IpamException extends Exception { + + public IpamException(final String message) { + super(message); + } + + public IpamException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java new file mode 100644 index 000000000..f770d1543 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.api; + +import java.util.Map; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource.QueryStatus; + +/** + * This client is meant to interact both with the IPAM system, and the SDNC DB, in order to provide, at any time, + * an up to date status of the assigned resources. + */ +public interface NetboxClient extends SvcLogicJavaPlugin { + + /** + * Assign next available IP in prefix and store it in the SDNC database, table IPAM_IP_ASSIGNEMENT. + * + * @param parameters 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></thead> + * <tbody> + * <tr><td>service_instance_id</td><td>Mandatory</td><td>The service instance ID uniquely identifying the service.</td></tr> + * <tr><td>vf_module_id</td><td>Mandatory</td><td>The VF module ID uniquely identifying the VF.</td></tr> + * <tr><td>prefix_id</td><td>Mandatory</td><td>The prefix from which to get next available IP.</td></tr> + * </tbody> + * </table> + */ + QueryStatus assignIpAddress(Map<String, String> parameters, SvcLogicContext ctx); + + /** + * Release the IP and update the entry in the SDNC database, table IPAM_IP_ASSIGNEMENT. + * + * @param parameters 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></thead> + * <tbody> + * <tr><td>service_instance_id</td><td>Mandatory</td><td>The service instance ID uniquely identifying the service.</td></tr> + * <tr><td>vf_module_id</td><td>Mandatory</td><td>The VF module ID uniquely identifying the VF.</td></tr> + * <tr><td>ip_address_id</td><td>Mandatory</td><td>The IP to release.</td></tr> + * </tbody> + * </table> + */ + QueryStatus unassignIpAddress(Map<String, String> parameters, SvcLogicContext ctx); +} + diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java new file mode 100644 index 000000000..bfb5ee530 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.impl; + +import com.google.common.collect.Lists; +import com.google.gson.JsonSyntaxException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Map; +import java.util.Properties; + +import javax.sql.rowset.CachedRowSet; +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; +import org.onap.ccsdk.sli.adaptors.netbox.api.NetboxClient; +import org.onap.ccsdk.sli.adaptors.netbox.model.IPAddress; +import org.onap.ccsdk.sli.adaptors.netbox.model.IPStatus; +import org.onap.ccsdk.sli.adaptors.netbox.property.NetboxProperties; +import org.onap.ccsdk.sli.core.dblib.DBResourceManager; +import org.onap.ccsdk.sli.core.dblib.DbLibService; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource.QueryStatus; +import org.onap.ccsdk.sli.core.slipluginutils.SliPluginUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetboxClientImpl implements NetboxClient { + + private static final Logger LOG = LoggerFactory.getLogger(NetboxClientImpl.class); + + // Netbox URI + + private static final String NEXT_AVAILABLE_IP_IN_PREFIX_PATH = "/api/ipam/prefixes/%s/available-ips/"; + private static final String IP_ADDRESS_PATH = "/api/ipam/ip-addresses/%s/"; + + // Netbox Payload + + private static final String ASSIGN_IP_ADDRESS_PAYLOAD = "{\n" + + " \"custom_fields\": {\n" + + " \"external-key\": \"%s\",\n" + + " \"resource-name\": \"%s\"\n" + + " }\n" + + "}"; + + // Service Logic Context input variables and exception + + private static final String SERVICE_INSTANCE_ID_PROP = "service_instance_id"; + private static final String VF_MODULE_ID_PROP = "vf_module_id"; + private static final String EXTERNAL_KEY_PROP = "external_key"; + private static final String SQL_EXCEPTION_MESSAGE = "Caught SQL exception"; + + // SQL statement + + private static final String ASSIGN_IP_SQL_STATEMENT = + "INSERT INTO IPAM_IP_ASSIGNEMENT (service_instance_id, vf_module_id, prefix_id, ip_address_id, ip_address, ip_status, ip_response_json, external_key, ip_address_type) \n" + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + private static final String UNASSIGN_IP_SQL_STATEMENT = + "UPDATE IPAM_IP_ASSIGNEMENT SET ip_status = ? WHERE service_instance_id = ? AND external_key = ?"; + private static final String GET_IP_ADDRESS_ID_SQL_STATEMENT = + "SELECT ip_address_id FROM IPAM_IP_ASSIGNEMENT WHERE service_instance_id = ? AND external_key = ?"; + + private final NetboxHttpClient client; + private final DbLibService dbLibService; + + public NetboxClientImpl() { + this(null, null); + } + + public NetboxClientImpl(final NetboxHttpClient client, final DbLibService dbLibService) { + if (client == null) { + this.client = new NetboxHttpClient(new NetboxProperties()); + } else { + this.client = client; + } + + if (dbLibService == null) { + Properties dblibProps = System.getProperties(); + + String cfgDir = dblibProps.getProperty("sdnc.config.dir", System.getenv("SDNC_CONFIG_DIR")); + + if ((cfgDir == null) || (cfgDir.length() == 0)) { + cfgDir = "/opt/sdnc/data/properties"; + } + + File dblibPropFile = new File(cfgDir + "/dblib.properties"); + if (dblibPropFile.exists()) { + try { + LOG.debug("Loading dblib properties from {}", dblibPropFile.getAbsolutePath()); + dblibProps = new Properties(); + dblibProps.load(new FileInputStream(dblibPropFile)); + } catch (Exception e) { + LOG.warn("Could not load properties file {}", dblibPropFile.getAbsolutePath(), e); + + dblibProps = System.getProperties(); + } + } + + DbLibService dbSvc = null; + try { + dbSvc = new DBResourceManager(dblibProps); + } catch (Exception e) { + LOG.error("Caught exception trying to create dblib service", e); + } + + try { + dbSvc = new DBResourceManager(dblibProps); + } catch (Exception e) { + LOG.error("Caught exception trying to create dblib service", e); + } + this.dbLibService = dbSvc; + + } else { + this.dbLibService = dbLibService; + } + } + + @Override + public QueryStatus assignIpAddress(final Map<String, String> parameters, final SvcLogicContext ctx) { + + try { + SliPluginUtils + .checkParameters(parameters, + new String[]{SERVICE_INSTANCE_ID_PROP, VF_MODULE_ID_PROP, "prefix_id", "resource_name", + EXTERNAL_KEY_PROP}, LOG); + } catch (SvcLogicException e) { + return QueryStatus.FAILURE; + } + + final String serviceInstanceId = parameters.get(SERVICE_INSTANCE_ID_PROP); + final String vfModuleId = parameters.get(VF_MODULE_ID_PROP); + final String prefixId = parameters.get("prefix_id"); + final String resourceName = parameters.get("resource_name"); + final String externalKey = parameters.get(EXTERNAL_KEY_PROP); + + HttpResponse httpResp; + try { + httpResp = client + .post(String.format(NEXT_AVAILABLE_IP_IN_PREFIX_PATH, prefixId), + String.format(ASSIGN_IP_ADDRESS_PAYLOAD, externalKey, resourceName)); + } catch (IOException e) { + LOG.error("Fail to assign IP for Prefix(id={}). {}", prefixId, e.getMessage(), e.getCause()); + return QueryStatus.FAILURE; + } + + String ipamRespJson; + try { + ipamRespJson = EntityUtils.toString(httpResp.getEntity(), "UTF-8"); + } catch (IOException e) { + LOG.error("Fail to parse IPAM response for assign in Prefix(id={}). Response={}", prefixId, + httpResp.getEntity(), e); + return QueryStatus.FAILURE; + } + + if (httpResp.getStatusLine().getStatusCode() != 201) { + LOG.error("Fail to assign IP for Prefix(id={}). HTTP code 201!={}. Response={}", prefixId, + httpResp.getStatusLine().getStatusCode(), ipamRespJson); + return QueryStatus.FAILURE; + } + + IPAddress ipAddress; + try { + ipAddress = IPAddress.fromJson(ipamRespJson); + } catch (JsonSyntaxException e) { + LOG.error("Fail to parse IPAM JSON reponse to IPAddress POJO. IPAM JSON Response={}", ipamRespJson, e); + return QueryStatus.FAILURE; + } + + ArrayList<String> args = Lists.newArrayList( + serviceInstanceId, + vfModuleId, + String.valueOf(prefixId), + String.valueOf(ipAddress.getId()), + ipAddress.getAddress(), + IPStatus.ASSIGNED.name(), + ipamRespJson, + externalKey, + resourceName); + + try { + dbLibService.writeData(ASSIGN_IP_SQL_STATEMENT, args, null); + } catch (SQLException e) { + LOG.error(SQL_EXCEPTION_MESSAGE, e); + return QueryStatus.FAILURE; + } + + ctx.setAttribute("self_serve_netbox_ip_assignement.ip-address", ipAddress.getAddress()); + + return QueryStatus.SUCCESS; + } + + @Override + public QueryStatus unassignIpAddress(final Map<String, String> parameters, final SvcLogicContext ctx) { + try { + SliPluginUtils + .checkParameters(parameters, new String[]{SERVICE_INSTANCE_ID_PROP, EXTERNAL_KEY_PROP}, + LOG); + } catch (SvcLogicException e) { + return QueryStatus.FAILURE; + } + + final String serviceInstanceId = parameters.get(SERVICE_INSTANCE_ID_PROP); + final String externalKey = parameters.get(EXTERNAL_KEY_PROP); + + String ipAddressId; + ArrayList<String> args = Lists.newArrayList( + serviceInstanceId, + externalKey); + try (CachedRowSet row = dbLibService.getData(GET_IP_ADDRESS_ID_SQL_STATEMENT, args, null)) { + if (row.next()) { + ipAddressId = row.getString("ip_address_id"); + } else { + throw new SQLException("Data not found."); + } + } catch (SQLException e) { + LOG.error(SQL_EXCEPTION_MESSAGE, e); + return QueryStatus.FAILURE; + } + + HttpResponse httpResp; + try { + httpResp = client.delete(String.format(IP_ADDRESS_PATH, ipAddressId)); + } catch (IOException e) { + LOG.error("Fail to unassign IP for IPAddress(id= " + ipAddressId + "). " + e.getMessage(), + e.getCause()); + return QueryStatus.FAILURE; + } + + if (httpResp.getStatusLine().getStatusCode() - 200 >= 100) { + LOG.error("Fail to unassign IP for IPAddress(id={}). HTTP code={}.", ipAddressId, + httpResp.getStatusLine().getStatusCode()); + return QueryStatus.FAILURE; + } + + args.clear(); + args = Lists.newArrayList( + IPStatus.DELETED.name(), + serviceInstanceId, + externalKey); + + try { + dbLibService.writeData(UNASSIGN_IP_SQL_STATEMENT, args, null); + } catch (SQLException e) { + LOG.error(SQL_EXCEPTION_MESSAGE, e); + return QueryStatus.FAILURE; + } + + return QueryStatus.SUCCESS; + } +} diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClient.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClient.java new file mode 100644 index 000000000..505c5a77e --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClient.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.impl; + +import static org.apache.http.HttpHeaders.ACCEPT; +import static org.apache.http.HttpHeaders.AUTHORIZATION; +import static org.apache.http.HttpHeaders.CONTENT_TYPE; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.SSLContext; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.ssl.TrustStrategy; +import org.onap.ccsdk.sli.adaptors.netbox.property.NetboxProperties; + +public class NetboxHttpClient implements AutoCloseable { + + private static final String APPLICATION_JSON = "application/json"; + + private final CloseableHttpClient client; + private final String url; + private final String token; + + // Used by the blueprint container + public NetboxHttpClient(NetboxProperties properties) { + this(properties.getHost(), properties.getApiKey()); + } + + NetboxHttpClient(final String url, final String token) { + this.url = url; + this.token = token; + + final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true; + final SSLContext sslContext; + try { + sslContext = SSLContexts.custom() + .loadTrustMaterial(null, acceptingTrustStrategy).build(); + } catch (final NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { + throw new IllegalStateException("Can't create http client", e); + } + client = HttpClientBuilder.create() + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .setSSLContext(sslContext) + .build(); + } + + @Override + public void close() throws IOException { + client.close(); + } + + HttpResponse post(final String uri, final String requestBody) throws IOException { + final HttpPost request = new HttpPost(url + uri); + setHeaders(request); + request.setEntity(new StringEntity(requestBody, Charset.forName("UTF-8"))); + return client.execute(request); + } + + HttpResponse delete(final String uri) throws IOException { + final HttpDelete request = new HttpDelete(url + uri); + setHeaders(request); + return client.execute(request); + } + + private void setHeaders(final HttpRequestBase request) { + request.addHeader(ACCEPT, APPLICATION_JSON); + request.addHeader(CONTENT_TYPE, APPLICATION_JSON); + request.addHeader(AUTHORIZATION, "Token " + token); + } +}
\ No newline at end of file diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPAddress.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPAddress.java new file mode 100644 index 000000000..4c2880bc4 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPAddress.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.model; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.util.Objects; + +public class IPAddress extends Identifiable { + + private static final Gson gson = new GsonBuilder().create(); + + private String address; + + public void setAddress(String address) { + this.address = address; + } + + public String getAddress() { + return address; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IPAddress ipAddress = (IPAddress) o; + return Objects.equals(address, ipAddress.address); + } + + @Override + public int hashCode() { + return Objects.hash(address); + } + + public static IPAddress fromJson(final String json) { + return gson.fromJson(json, IPAddress.class); + } +} diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java new file mode 100644 index 000000000..f3a74387a --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java @@ -0,0 +1,5 @@ +package org.onap.ccsdk.sli.adaptors.netbox.model; + +public enum IPStatus { + ASSIGNED, DELETED +} diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Identifiable.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Identifiable.java new file mode 100644 index 000000000..501088d78 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Identifiable.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.model; + +public abstract class Identifiable { + + private Integer id; + + public Integer getId() { + return id; + } + + public void setId(final Integer id) { + this.id = id; + } +} diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Prefix.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Prefix.java new file mode 100644 index 000000000..b20be91db --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Prefix.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.model; + +public class Prefix extends Identifiable { + +} diff --git a/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxProperties.java b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxProperties.java new file mode 100644 index 000000000..9b4751e64 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxProperties.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.property; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Properties; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetboxProperties { + + private static final Logger LOG = LoggerFactory.getLogger(NetboxProperties.class); + + private static final String NETBOX_PROPERTY_FILE_NAME = "netbox.properties"; + private static final String DEFAULT_PROPERTIES_DIR = "/opt/onap/ccsdk/data/properties"; + private static final String PROPERTIES_DIR_KEY = "SDNC_CONFIG_DIR"; + + private static final String NETBOX_URL_PROP = "org.onap.ccsdk.sli.adaptors.netbox.url"; + private static final String NETBOX_API_KEY_PROP = "org.onap.ccsdk.sli.adaptors.netbox.apikey"; + + private Properties properties; + + public NetboxProperties() { + loadProps(); + } + + public String getHost() { + return properties.getProperty(NETBOX_URL_PROP); + } + + public String getApiKey() { + return properties.getProperty(NETBOX_API_KEY_PROP); + } + + private void loadProps() { + properties = new Properties(); + // Try to load config from dir + final String ccsdkConfigDir = + System.getProperty(PROPERTIES_DIR_KEY, DEFAULT_PROPERTIES_DIR) + "/" + NETBOX_PROPERTY_FILE_NAME; + try (FileInputStream in = new FileInputStream(ccsdkConfigDir)) { + properties.load(in); + LOG.info("Loaded {} properties from file {}", properties.size(), ccsdkConfigDir); + } catch (Exception e) { + try { + // Try to load config from jar via OSGi + final Bundle bundle = FrameworkUtil.getBundle(NetboxProperties.class); + final BundleContext ctx = bundle.getBundleContext(); + final URL url = ctx.getBundle().getResource(NETBOX_PROPERTY_FILE_NAME); + InputStream inputStream = url.openStream(); + properties.load(inputStream); + LOG.info("Loaded {} properties from file {}", properties.size(), NETBOX_PROPERTY_FILE_NAME); + } catch (NoClassDefFoundError e1) { + // Try to load config from jar via class loader + try (InputStream inputStream = NetboxProperties.class.getResourceAsStream("/"+NETBOX_PROPERTY_FILE_NAME)) { + properties.load(inputStream); + } catch (Exception e2) { + LOG.error("Failed to load properties for file: {} " + NETBOX_PROPERTY_FILE_NAME, e1); + } + ; + LOG.info("Loaded {} properties from file {}", properties.size(), NETBOX_PROPERTY_FILE_NAME); + + } catch (IOException e1) { + LOG.error("Failed to load properties for file: {} " + NETBOX_PROPERTY_FILE_NAME, e1); + } + } + } +} diff --git a/adaptors/netbox-client/provider/src/main/resources/OSGI-INF/blueprint/netbox-client.xml b/adaptors/netbox-client/provider/src/main/resources/OSGI-INF/blueprint/netbox-client.xml new file mode 100644 index 000000000..b667dcba5 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/resources/OSGI-INF/blueprint/netbox-client.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2018 AT&T, Bell Canada + + 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. + --> +<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"> + + <reference id="dbLibService" + interface="org.onap.ccsdk.sli.core.dblib.DbLibService"/> + + <bean id="netboxProperty" class="org.onap.ccsdk.sli.adaptors.netbox.property.NetboxProperties"/> + <bean id="httpClient" class="org.onap.ccsdk.sli.adaptors.netbox.impl.NetboxHttpClient" destroy-method="close"> + <argument ref="netboxProperty"/> + </bean> + + <bean id="netboxClient" class="org.onap.ccsdk.sli.adaptors.netbox.impl.NetboxClientImpl"> + <argument ref="httpClient"/> + <argument ref="dbLibService"/> + </bean> + + <service ref="netboxClient" + interface="org.onap.ccsdk.sli.adaptors.netbox.api.NetboxClient" + odl:type="default"/> + +</blueprint> diff --git a/adaptors/netbox-client/provider/src/main/resources/netbox.properties b/adaptors/netbox-client/provider/src/main/resources/netbox.properties new file mode 100644 index 000000000..4346d1774 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/resources/netbox.properties @@ -0,0 +1,19 @@ +# +# Copyright (C) 2019 Bell Canada. +# +# 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. +# + +# Configuration file for Netbox client +org.onap.ccsdk.sli.adaptors.netbox.url=http://netbox-nginx:8080 +org.onap.ccsdk.sli.adaptors.netbox.apikey=onceuponatimeiplayedwithnetbox20180814
\ No newline at end of file diff --git a/adaptors/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml b/adaptors/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml new file mode 100644 index 000000000..b667dcba5 --- /dev/null +++ b/adaptors/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2018 AT&T, Bell Canada + + 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. + --> +<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"> + + <reference id="dbLibService" + interface="org.onap.ccsdk.sli.core.dblib.DbLibService"/> + + <bean id="netboxProperty" class="org.onap.ccsdk.sli.adaptors.netbox.property.NetboxProperties"/> + <bean id="httpClient" class="org.onap.ccsdk.sli.adaptors.netbox.impl.NetboxHttpClient" destroy-method="close"> + <argument ref="netboxProperty"/> + </bean> + + <bean id="netboxClient" class="org.onap.ccsdk.sli.adaptors.netbox.impl.NetboxClientImpl"> + <argument ref="httpClient"/> + <argument ref="dbLibService"/> + </bean> + + <service ref="netboxClient" + interface="org.onap.ccsdk.sli.adaptors.netbox.api.NetboxClient" + odl:type="default"/> + +</blueprint> diff --git a/adaptors/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java b/adaptors/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java new file mode 100644 index 000000000..624a1906e --- /dev/null +++ b/adaptors/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.created; +import static com.github.tomakehurst.wiremock.client.WireMock.delete; +import static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.givenThat; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.serverError; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.apache.http.HttpHeaders.ACCEPT; +import static org.apache.http.HttpHeaders.AUTHORIZATION; +import static org.apache.http.HttpHeaders.CONTENT_TYPE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableMap; +import com.google.common.io.Resources; +import java.io.IOException; +import java.net.URL; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.sql.rowset.CachedRowSet; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.ccsdk.sli.core.dblib.DbLibService; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource.QueryStatus; +import org.slf4j.LoggerFactory; + +@RunWith(MockitoJUnitRunner.class) +public class NetboxClientImplTest { + + private static final String APPLICATION_JSON = "application/json"; + + @Rule + public WireMockRule wm = new WireMockRule(wireMockConfig().dynamicPort()); + @Mock + private DbLibService dbLib; + @Mock + private SvcLogicContext svcLogicContext; + @Mock + private Appender<ILoggingEvent> appender; + @Captor + private ArgumentCaptor<ILoggingEvent> captor; + + + private String token = "token"; + private String serviceInstanceId = UUID.randomUUID().toString(); + private String vfModuleId = UUID.randomUUID().toString(); + + private Map<String, String> params = ImmutableMap + .of("service_instance_id", serviceInstanceId, + "vf_module_id", vfModuleId, + "prefix_id", "3", + "external_key", "3", + "resource_name", "3" + ); + + private NetboxHttpClient httpClient; + private NetboxClientImpl netboxClient; + + @Mock + private NetboxHttpClient httpClientMock; + @Mock + private NetboxClientImpl netboxClientMock; + + + @Before + public void setup() { + ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory + .getLogger(NetboxClientImpl.class); + logger.addAppender(appender); + + String baseUrl = "http://localhost:" + wm.port(); + + httpClient = new NetboxHttpClient(baseUrl, token); + + netboxClient = new NetboxClientImpl(httpClient, dbLib); + + netboxClientMock = new NetboxClientImpl(httpClientMock, dbLib); + + wm.addMockServiceRequestListener( + (request, response) -> { + System.out.println("Request URL :" + request.getAbsoluteUrl()); + System.out.println("Request body :" + request.getBodyAsString()); + System.out.println("Response status :" + response.getStatus()); + System.out.println("Response body :" + response.getBodyAsString()); + }); + } + + @After + public void tearDown() throws IOException { + httpClient.close(); + } + + @Test + public void unassignIpAddressTestNoParams() { + QueryStatus status = netboxClient.unassignIpAddress(ImmutableMap.of(), svcLogicContext); + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry( + "This method requires the parameters [service_instance_id,external_key], but no parameters were passed in."); + } + + @Test + public void unassignIpAddressFailedRequest() throws IOException, SQLException { + doThrow(new IOException("Failed request")).when(httpClientMock).delete(anyString()); + + CachedRowSet crs = mock(CachedRowSet.class); + doReturn("3").when(crs).getString(eq("ip_address_id")); + doReturn(true).when(crs).next(); + doReturn(crs).when(dbLib).getData(anyString(), any(ArrayList.class), eq(null)); + + QueryStatus status = netboxClientMock + .unassignIpAddress(params, svcLogicContext); + + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Fail to unassign IP for IPAddress(id= 3). Failed request"); + } + + @Test + public void unassignIpAddressServerError() throws SQLException { + + String expectedUrl = "/api/ipam/ip-addresses/3/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(serverError())); + + CachedRowSet crs = mock(CachedRowSet.class); + doReturn("3").when(crs).getString(eq("ip_address_id")); + doReturn(true).when(crs).next(); + doReturn(crs).when(dbLib).getData(anyString(), any(ArrayList.class), eq(null)); + + QueryStatus status = netboxClient.unassignIpAddress(params, svcLogicContext); + + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Fail to unassign IP for IPAddress(id=3). HTTP code=500."); + } + + @Test + public void unassignIpAddressFailSQL() throws IOException, SQLException { + + String response = "{}"; + + String expectedUrl = "/api/ipam/ip-addresses/3/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + CachedRowSet crs = mock(CachedRowSet.class); + doReturn(true).when(crs).next(); + doReturn("3").when(crs).getString(eq("ip_address_id")); + doReturn(crs).when(dbLib).getData(anyString(), any(ArrayList.class), eq(null)); + + doThrow(new SQLException("Failed")).when(dbLib).writeData(anyString(), any(ArrayList.class), eq(null)); + + QueryStatus status = netboxClient.unassignIpAddress(params, svcLogicContext); + + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Caught SQL exception"); + } + + @Test + public void unassignIpAddressSuccess() throws IOException, SQLException { + String response = "{}"; + + String expectedUrl = "/api/ipam/ip-addresses/3/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + CachedRowSet crs = mock(CachedRowSet.class); + doReturn("3").when(crs).getString(eq("ip_address_id")); + doReturn(true).when(crs).next(); + doReturn(crs).when(dbLib).getData(anyString(), any(ArrayList.class), eq(null)); + + QueryStatus status = netboxClient.unassignIpAddress(params, svcLogicContext); + + verify(deleteRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON)) + .withHeader(AUTHORIZATION, equalTo("Token " + token))); + + Mockito.verify(dbLib).writeData(anyString(), any(ArrayList.class), eq(null)); + Assert.assertEquals(QueryStatus.SUCCESS, status); + } + + + @Test + public void nextAvailableIpInPrefixTestNoId() { + QueryStatus status = netboxClient.assignIpAddress(ImmutableMap.of(), svcLogicContext); + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry( + "This method requires the parameters [service_instance_id,vf_module_id,prefix_id,resource_name,external_key], but no parameters were passed in."); + } + + @Test + public void nextAvailableIpInPrefixFailedRequest() throws IOException { + doThrow(new IOException("Failed request")).when(httpClientMock).post(anyString(), anyString()); + QueryStatus status = netboxClientMock.assignIpAddress(params, svcLogicContext); + + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Fail to assign IP for Prefix(id=3). Failed request"); + } + + @Test + public void nextAvailableIpInPrefixBadRespPayload() throws IOException { + URL url = Resources.getResource("badResponse.json"); + String response = Resources.toString(url, Charsets.UTF_8); + + String expectedUrl = "/api/ipam/prefixes/3/available-ips/"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + QueryStatus status = netboxClient.assignIpAddress(params, svcLogicContext); + + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Fail to parse IPAM JSON reponse to IPAddress POJO. IPAM JSON Response={\n" + + " \"id\": 8\n" + + " \"address\": \"192.168.20.7/32\"\n" + + "}"); + } + + @Test + public void nextAvailableIpInPrefixFailSQL() throws IOException, SQLException { + URL url = Resources.getResource("nextAvailableIpResponse.json"); + String response = Resources.toString(url, Charsets.UTF_8); + + String expectedUrl = "/api/ipam/prefixes/3/available-ips/"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + doThrow(new SQLException("Failed")).when(dbLib).writeData(anyString(), any(ArrayList.class), eq(null)); + + QueryStatus status = netboxClient.assignIpAddress(params, svcLogicContext); + + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Caught SQL exception"); + } + + @Test + public void nextAvailableIpInPrefixError500() throws IOException { + URL url = Resources.getResource("nextAvailableIpResponse.json"); + String response = Resources.toString(url, Charsets.UTF_8); + + String expectedUrl = "/api/ipam/prefixes/3/available-ips/"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(serverError().withBody(response))); + + QueryStatus status = netboxClient.assignIpAddress(params, svcLogicContext); + + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Fail to assign IP for Prefix(id=3). HTTP code 201!=500."); + } + + @Test + public void nextAvailableIpInPrefixSuccess() throws IOException, SQLException { + URL url = Resources.getResource("nextAvailableIpResponse.json"); + String response = Resources.toString(url, Charsets.UTF_8); + + String expectedUrl = "/api/ipam/prefixes/3/available-ips/"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + QueryStatus status = netboxClient.assignIpAddress(params, svcLogicContext); + + verify(postRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON)) + .withHeader(AUTHORIZATION, equalTo("Token " + token))); + + Mockito.verify(dbLib).writeData(anyString(), any(ArrayList.class), eq(null)); + Assert.assertEquals(QueryStatus.SUCCESS, status); + } + + private void verifyLogEntry(String message) { + Mockito.verify(appender, times(1)).doAppend(captor.capture()); + List<ILoggingEvent> allValues = captor.getAllValues(); + for (ILoggingEvent loggingEvent : allValues) { + Assert.assertTrue(loggingEvent.getFormattedMessage().contains(message)); + } + } + +}
\ No newline at end of file diff --git a/adaptors/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java b/adaptors/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java new file mode 100644 index 000000000..8634742ae --- /dev/null +++ b/adaptors/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * 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. + */ +package org.onap.ccsdk.sli.adaptors.netbox.impl; + +import static com.github.tomakehurst.wiremock.client.WireMock.delete; +import static com.github.tomakehurst.wiremock.client.WireMock.deleteRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.givenThat; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.apache.http.HttpHeaders.ACCEPT; +import static org.apache.http.HttpHeaders.CONTENT_TYPE; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import java.io.IOException; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class NetboxHttpClientTest { + + private static final String APPLICATION_JSON = "application/json"; + + @Rule + public WireMockRule wm = new WireMockRule(wireMockConfig().dynamicPort()); + + private NetboxHttpClient httpClient; + + @Before + public void setup() { + String baseUrl = "http://localhost:" + wm.port(); + String token = "token"; + + httpClient = new NetboxHttpClient(baseUrl, token); + + wm.addMockServiceRequestListener( + (request, response) -> { + System.out.println("Request URL :" + request.getAbsoluteUrl()); + System.out.println("Request body :" + request.getBodyAsString()); + System.out.println("Response status :" + response.getStatus()); + System.out.println("Response body :" + response.getBodyAsString()); + }); + } + + @After + public void tearDown() throws IOException { + httpClient.close(); + } + + @Test + public void postTest() throws IOException { + String expectedUrl = "/testPost"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(ok())); + + httpClient.post(expectedUrl, ""); + + verify(postRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON))); + } + + @Test + public void deleteTest() throws IOException { + String expectedUrl = "/testDelete"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(ok())); + httpClient.delete(expectedUrl); + verify(deleteRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON))); + } +} diff --git a/adaptors/netbox-client/provider/src/test/resources/badResponse.json b/adaptors/netbox-client/provider/src/test/resources/badResponse.json new file mode 100644 index 000000000..713109fd9 --- /dev/null +++ b/adaptors/netbox-client/provider/src/test/resources/badResponse.json @@ -0,0 +1,4 @@ +{ + "id": 8 + "address": "192.168.20.7/32" +}
\ No newline at end of file diff --git a/adaptors/netbox-client/provider/src/test/resources/nextAvailableIpResponse.json b/adaptors/netbox-client/provider/src/test/resources/nextAvailableIpResponse.json new file mode 100644 index 000000000..dec1245e9 --- /dev/null +++ b/adaptors/netbox-client/provider/src/test/resources/nextAvailableIpResponse.json @@ -0,0 +1,13 @@ +{ + "id": 8, + "address": "192.168.20.7/32", + "vrf": null, + "tenant": 1, + "status": 1, + "role": null, + "interface": null, + "description": "", + "nat_inside": null, + "created": "2018-08-15", + "last_updated": "2018-08-15T15:51:26.634903Z" +}
\ No newline at end of file |