From eae6b96f6529e4a9f350809a5def4d82a904501b Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Wed, 15 Aug 2018 14:30:43 -0400 Subject: Added netbox client to assign/unassign ip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ied317c7f251936ced116b6a3ea81789c82095df6 Issue-ID: CCSDK-462 Signed-off-by: Alexis de Talhouët --- .../adaptors/netbox/impl/NetboxClientImplTest.java | 185 +++++++++++++++++++++ .../adaptors/netbox/impl/NetboxHttpClientTest.java | 127 ++++++++++++++ .../netbox/property/NetboxPropertiesTest.java | 67 ++++++++ 3 files changed, 379 insertions(+) create mode 100644 netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java create mode 100644 netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java create mode 100644 netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java (limited to 'netbox-client/provider/src/test/java/org') diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java new file mode 100644 index 000000000..19b178c9a --- /dev/null +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java @@ -0,0 +1,185 @@ +/* + * 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.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.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.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +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.runners.MockitoJUnitRunner; +import org.onap.ccsdk.sli.adaptors.netbox.api.IpamException; +import org.onap.ccsdk.sli.adaptors.netbox.model.IPAddress; +import org.onap.ccsdk.sli.adaptors.netbox.model.Prefix; +import org.onap.ccsdk.sli.adaptors.netbox.model.Status.Values; + +@RunWith(MockitoJUnitRunner.class) +public class NetboxClientImplTest { + + private static final String APPLICATION_JSON = "application/json"; + + @Rule + public WireMockRule wm = new WireMockRule(wireMockConfig().dynamicPort()); + + private String token = "token"; + + private NetboxHttpClient httpClient; + private NetboxClientImpl netboxClient; + + @Before + public void setup() { + String baseUrl = "http://localhost:" + wm.port(); + + httpClient = new NetboxHttpClient(baseUrl, token); + httpClient.init(); + + netboxClient = new NetboxClientImpl(httpClient); + + 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 nextAvailableIpInPrefixTestNoId() { + Prefix prefix = mock(Prefix.class); + doReturn(null).when(prefix).getId(); + try { + netboxClient.assign(prefix); + } catch (IpamException e) { + Assert.assertEquals("Id must be set", e.getMessage()); + return; + } + Assert.fail(); + } + + @Test + public void nextAvailableIpInPrefixTest() throws IOException, IpamException { + Integer id = 3; + Prefix prefix = mock(Prefix.class); + doReturn(id).when(prefix).getId(); + + URL url = Resources.getResource("nextAvailableIpResponse.json"); + String response = Resources.toString(url, Charsets.UTF_8); + + String expectedUrl = "/api/ipam/prefixes/" + id + "/available-ips/"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + netboxClient.assign(prefix); + + verify(postRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON)) + .withHeader(AUTHORIZATION, equalTo("Token " + token))); + } + + @Test + public void deleteIpTestError500() { + Integer id = 3; + IPAddress ipAddress = mock(IPAddress.class); + doReturn(id).when(ipAddress).getId(); + + String expectedUrl = "/api/ipam/ip-addresses/" + id + "/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(serverError())); + try { + netboxClient.unassign(ipAddress); + } catch (IpamException e) { + Assert.assertEquals(IllegalStateException.class, e.getCause().getClass()); + Assert.assertTrue(e.getMessage().contains( + "Fail to unassign IP for IPAddress(id= 3). java.lang.IllegalStateException: Netbox request failed with status: HTTP/1.1 500 Server Error")); + return; + } + Assert.fail(); + } + + @Test + public void deleteIpTest() throws IpamException { + Integer id = 3; + IPAddress ipAddress = mock(IPAddress.class); + doReturn(id).when(ipAddress).getId(); + + String expectedUrl = "/api/ipam/ip-addresses/" + id + "/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(ok())); + netboxClient.unassign(ipAddress); + verify(deleteRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON)) + .withHeader(AUTHORIZATION, equalTo("Token " + token))); + } + + + @Test + public void getIpAddressTest() throws IOException { + StatusLine statusLine = mock(StatusLine.class); + doReturn(201).when(statusLine).getStatusCode(); + + URL url = Resources.getResource("nextAvailableIpResponse.json"); + String response = Resources.toString(url, Charsets.UTF_8); + InputStream stream = new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8)); + + HttpEntity entity = mock(HttpEntity.class); + doReturn(stream).when(entity).getContent(); + + HttpResponse httpResponse = mock(HttpResponse.class); + doReturn(statusLine).when(httpResponse).getStatusLine(); + doReturn(entity).when(httpResponse).getEntity(); + + IPAddress ipAddress = netboxClient.getIpAddress(httpResponse); + + Assert.assertEquals("192.168.20.7/32", ipAddress.getAddress()); + Assert.assertEquals(Integer.valueOf(8), ipAddress.getId()); + Assert.assertEquals(Values.ACTIVE, ipAddress.getStatus()); + } +} \ No newline at end of file diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java new file mode 100644 index 000000000..ee2861c0a --- /dev/null +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java @@ -0,0 +1,127 @@ +/* + * 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.aResponse; +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.http.Fault; +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import java.io.IOException; +import java.util.concurrent.CompletionException; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.onap.ccsdk.sli.adaptors.netbox.api.IpamException; + +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); + httpClient.init(); + + 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() { + String expectedUrl = "/testPost"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(ok())); + + httpClient.post(expectedUrl, "").toCompletableFuture().join(); + + verify(postRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON))); + } + + @Test + public void postTestException() { + String expectedUrl = "/testPost"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); + + try { + httpClient.post(expectedUrl, "").toCompletableFuture().join(); + } catch (CompletionException e) { + Assert.assertEquals(IpamException.class, e.getCause().getClass()); + Assert.assertEquals("Netbox request failed", e.getCause().getMessage()); + return; + } + Assert.fail(); + } + + @Test + public void deleteTest() { + String expectedUrl = "/testDelete"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(ok())); + + httpClient.delete(expectedUrl).toCompletableFuture().join(); + + verify(deleteRequestedFor(urlEqualTo(expectedUrl)) + .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) + .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON))); + } + + @Test + public void deleteTestException() { + String expectedUrl = "/testDelete"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); + + try { + httpClient.delete(expectedUrl).toCompletableFuture().join(); + } catch (CompletionException e) { + Assert.assertEquals(IpamException.class, e.getCause().getClass()); + Assert.assertEquals("Netbox request failed", e.getCause().getMessage()); + return; + } + Assert.fail(); + } +} diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java new file mode 100644 index 000000000..d9916707f --- /dev/null +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java @@ -0,0 +1,67 @@ +/* + * 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 static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import java.util.List; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.slf4j.LoggerFactory; + +@RunWith(MockitoJUnitRunner.class) +public class NetboxPropertiesTest { + + private NetboxProperties props; + + @Mock + private Appender appender; + @Captor + private ArgumentCaptor captor; + + @Before + public void setup() { + ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory + .getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + logger.addAppender(appender); + } + + @Test + public void testMissingFile() { + props = new NetboxProperties(); + + verifyLogEntry( + "Missing configuration properties resource for Netbox: netbox.properties"); + } + + + private void verifyLogEntry(String message) { + verify(appender, times(1)).doAppend(captor.capture()); + List allValues = captor.getAllValues(); + for (ILoggingEvent loggingEvent : allValues) { + Assert.assertTrue(loggingEvent.getFormattedMessage().contains(message)); + } + } +} \ No newline at end of file -- cgit 1.2.3-korg From e864171d3d4f378a150466161f7162070368e554 Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Mon, 20 Aug 2018 15:27:59 -0400 Subject: Add DB update support for IPAM interaction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For assign and unassign scenario, we need to interact with the SDNC DB in order to cache the IP Address information used for a given ServiceInstance / VfModule. Change-Id: Id349338216d12d2dc9efd76cd672b5cc9fdc6192 Issue-ID: CCSDK-462 Signed-off-by: Alexis de Talhouët --- .../sli/adaptors/netbox/api/NetboxClient.java | 23 +++++++--- .../sli/adaptors/netbox/impl/NetboxClientImpl.java | 52 ++++++++++++++++++---- .../org/opendaylight/blueprint/netbox-client.xml | 4 ++ .../adaptors/netbox/impl/NetboxClientImplTest.java | 34 ++++++++++---- 4 files changed, 90 insertions(+), 23 deletions(-) (limited to 'netbox-client/provider/src/test/java/org') diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java index 57d727add..e11fe8bcc 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java @@ -15,26 +15,37 @@ */ package org.onap.ccsdk.sli.adaptors.netbox.api; +import java.sql.SQLException; import org.onap.ccsdk.sli.adaptors.netbox.model.IPAddress; import org.onap.ccsdk.sli.adaptors.netbox.model.Prefix; +/** + * 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 { /** - * Assign next available IP in prefix. + * Assign next available IP in prefix and store it in the SDNC database, table IPAM_IP_ASSIGNEMENT. * * @param prefix The prefix from which to get next available IP. + * @param serviceInstanceId The service instance ID uniquely identifying the service. + * @param vfModuleId The VF module ID uniquely identifying the VF. * @return The IPAddress - * @throws IpamException If something goes wrong. + * @throws IpamException If something goes wrong while communicating with the IPAM system. + * @throws SQLException If something goes wrong while communicating with the SDNC DB. */ - IPAddress assign(Prefix prefix) throws IpamException; + IPAddress assign(Prefix prefix, String serviceInstanceId, String vfModuleId) throws IpamException, SQLException; /** - * Free the IP. + * Release the IP and remove the entry in the SDNC database, table IPAM_IP_ASSIGNEMENT. * * @param ip The IP to release. - * @throws IpamException If something goes wrong. + * @param serviceInstanceId The service instance ID uniquely identifying the service. + * @param vfModuleId The VF module ID uniquely identifying the VF. + * @throws IpamException If something goes wrong while communicating with the IPAM system. + * @throws SQLException If something goes wrong while communicating with the SDNC DB. */ - void unassign(IPAddress ip) throws IpamException; + void unassign(IPAddress ip, String serviceInstanceId, String vfModuleId) throws IpamException, SQLException; } diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java index 0520ad5e5..036ff44d4 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java @@ -16,12 +16,15 @@ package org.onap.ccsdk.sli.adaptors.netbox.impl; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSerializer; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.sql.SQLException; +import java.util.ArrayList; import java.util.concurrent.CompletionException; import org.apache.http.HttpResponse; import org.onap.ccsdk.sli.adaptors.netbox.api.IpamException; @@ -29,19 +32,29 @@ 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.Prefix; import org.onap.ccsdk.sli.adaptors.netbox.model.Status; +import org.onap.ccsdk.sli.core.dblib.DbLibService; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; -public class NetboxClientImpl implements NetboxClient { +public class NetboxClientImpl implements NetboxClient, SvcLogicJavaPlugin { 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/"; private static final String EMPTY_STRING = ""; private static final String ID_MISSING_MSG = "Id must be set"; + 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_adress, ip_status) \n" + + "VALUES (?, ?, ?, ?, ?, ?)"; + private static final String UNASSIGN_IP_SQL_STATEMENT = + "DELETE FROM IPAM_IP_ASSIGNEMENT WHERE service_instance_id = ? AND vf_module_id = ? AND ip_address_id = ?"; + private final NetboxHttpClient client; private final Gson gson; + private final DbLibService dbLibService; - public NetboxClientImpl(final NetboxHttpClient client) { + public NetboxClientImpl(final NetboxHttpClient client, final DbLibService dbLibService) { this.client = client; + this.dbLibService = dbLibService; final JsonSerializer vlanStatusDeserializer = (val, type, context) -> val.toJson(); gson = new GsonBuilder() .registerTypeAdapter(Status.class, vlanStatusDeserializer) @@ -49,31 +62,54 @@ public class NetboxClientImpl implements NetboxClient { } @Override - public IPAddress assign(final Prefix prefix) throws IpamException { + public IPAddress assign(final Prefix prefix, final String serviceInstanceId, final String vfModuleId) + throws IpamException, SQLException { + checkArgument(prefix.getId() != null); try { - return client.post(String.format(NEXT_AVAILABLE_IP_IN_PREFIX_PATH, prefix.getId()), EMPTY_STRING) + IPAddress ipAddress = client + .post(String.format(NEXT_AVAILABLE_IP_IN_PREFIX_PATH, prefix.getId()), EMPTY_STRING) .thenApply(this::getIpAddress) .toCompletableFuture() .join(); + + ArrayList args = Lists.newArrayList(serviceInstanceId, + vfModuleId, + String.valueOf(prefix.getId()), + String.valueOf(ipAddress.getId()), + ipAddress.getAddress(), + ipAddress.getStatus().getLabel()); + dbLibService.writeData(ASSIGN_IP_SQL_STATEMENT, args, null); + + return ipAddress; } catch (CompletionException e) { - // Unwrap the ComplettionException and wrap in IpamException + // Unwrap the CompletionException and wrap in IpamException throw new IpamException("Fail to assign IP for Prefix(id= " + prefix.getId() + "). " + e.getMessage(), e.getCause()); } } @Override - public void unassign(final IPAddress ipAddress) throws IpamException { + public void unassign(final IPAddress ipAddress, final String serviceInstanceId, final String vfModuleId) + throws IpamException, SQLException { + checkArgument(ipAddress.getId() != null); try { client.delete(String.format(IP_ADDRESS_PATH, ipAddress.getId())) .thenAccept(this::checkResult) .toCompletableFuture() .join(); + + ArrayList args = Lists.newArrayList( + serviceInstanceId, + vfModuleId, + String.valueOf(ipAddress.getId())); + dbLibService.writeData(UNASSIGN_IP_SQL_STATEMENT, args, null); + } catch (CompletionException e) { - // Unwrap the ComplettionException and wrap in IpamException - throw new IpamException("Fail to unassign IP for IPAddress(id= " + ipAddress.getId() + "). " + e.getMessage(), + // Unwrap the CompletionException and wrap in IpamException + throw new IpamException( + "Fail to unassign IP for IPAddress(id= " + ipAddress.getId() + "). " + e.getMessage(), e.getCause()); } } diff --git a/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml b/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml index cf8a1af4d..950fd97b0 100644 --- a/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml +++ b/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml @@ -17,6 +17,9 @@ + + @@ -25,6 +28,7 @@ + { @@ -93,11 +107,11 @@ public class NetboxClientImplTest { } @Test - public void nextAvailableIpInPrefixTestNoId() { + public void nextAvailableIpInPrefixTestNoId() throws SQLException { Prefix prefix = mock(Prefix.class); doReturn(null).when(prefix).getId(); try { - netboxClient.assign(prefix); + netboxClient.assign(prefix, serviceInstanceId, vfModuleId); } catch (IpamException e) { Assert.assertEquals("Id must be set", e.getMessage()); return; @@ -106,7 +120,7 @@ public class NetboxClientImplTest { } @Test - public void nextAvailableIpInPrefixTest() throws IOException, IpamException { + public void nextAvailableIpInPrefixTest() throws IOException, IpamException, SQLException { Integer id = 3; Prefix prefix = mock(Prefix.class); doReturn(id).when(prefix).getId(); @@ -117,16 +131,17 @@ public class NetboxClientImplTest { String expectedUrl = "/api/ipam/prefixes/" + id + "/available-ips/"; givenThat(post(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); - netboxClient.assign(prefix); + netboxClient.assign(prefix, serviceInstanceId, vfModuleId); 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))); } @Test - public void deleteIpTestError500() { + public void deleteIpTestError500() throws SQLException { Integer id = 3; IPAddress ipAddress = mock(IPAddress.class); doReturn(id).when(ipAddress).getId(); @@ -134,7 +149,7 @@ public class NetboxClientImplTest { String expectedUrl = "/api/ipam/ip-addresses/" + id + "/"; givenThat(delete(urlEqualTo(expectedUrl)).willReturn(serverError())); try { - netboxClient.unassign(ipAddress); + netboxClient.unassign(ipAddress, serviceInstanceId, vfModuleId); } catch (IpamException e) { Assert.assertEquals(IllegalStateException.class, e.getCause().getClass()); Assert.assertTrue(e.getMessage().contains( @@ -145,18 +160,19 @@ public class NetboxClientImplTest { } @Test - public void deleteIpTest() throws IpamException { + public void deleteIpTest() throws IpamException, SQLException { Integer id = 3; IPAddress ipAddress = mock(IPAddress.class); doReturn(id).when(ipAddress).getId(); String expectedUrl = "/api/ipam/ip-addresses/" + id + "/"; givenThat(delete(urlEqualTo(expectedUrl)).willReturn(ok())); - netboxClient.unassign(ipAddress); + netboxClient.unassign(ipAddress, serviceInstanceId, vfModuleId); 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))); } -- cgit 1.2.3-korg From 00ea51d999daaa26ea62b6fd0a3a1c911bc26cba Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Fri, 24 Aug 2018 08:37:11 -0400 Subject: Add SvcLogicContext interaction with netbox-client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And return proper QueryStatus as exepected by the DG. Change-Id: I6af3971a2c6a8b6eda949f7b63cd30fe361dfbc4 Issue-ID: CCSDK-462 Signed-off-by: Alexis de Talhouët --- netbox-client/provider/pom.xml | 11 +- .../sli/adaptors/netbox/api/NetboxClient.java | 44 ++-- .../sli/adaptors/netbox/impl/NetboxClientImpl.java | 194 ++++++++++------- .../sli/adaptors/netbox/impl/NetboxHttpClient.java | 87 ++------ .../ccsdk/sli/adaptors/netbox/model/IPAddress.java | 22 +- .../ccsdk/sli/adaptors/netbox/model/IPStatus.java | 5 + .../ccsdk/sli/adaptors/netbox/model/Status.java | 77 ------- .../org/opendaylight/blueprint/netbox-client.xml | 3 +- .../adaptors/netbox/impl/NetboxClientImplTest.java | 237 ++++++++++++++------- .../adaptors/netbox/impl/NetboxHttpClientTest.java | 46 +--- .../netbox/property/NetboxPropertiesTest.java | 1 - .../provider/src/test/resources/badResponse.json | 4 + 12 files changed, 347 insertions(+), 384 deletions(-) create mode 100644 netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java delete mode 100644 netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Status.java create mode 100644 netbox-client/provider/src/test/resources/badResponse.json (limited to 'netbox-client/provider/src/test/java/org') diff --git a/netbox-client/provider/pom.xml b/netbox-client/provider/pom.xml index 2ffcaea9a..e4e22463a 100644 --- a/netbox-client/provider/pom.xml +++ b/netbox-client/provider/pom.xml @@ -50,11 +50,6 @@ httpclient ${apache.httpcomponents.client.version} - - org.apache.httpcomponents - httpasyncclient - 4.1.1 - org.slf4j slf4j-api @@ -64,6 +59,12 @@ sli-common compile + + org.onap.ccsdk.sli.core + sliPluginUtils-provider + ${project.version} + compile + diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java index e11fe8bcc..f770d1543 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/api/NetboxClient.java @@ -15,37 +15,45 @@ */ package org.onap.ccsdk.sli.adaptors.netbox.api; -import java.sql.SQLException; -import org.onap.ccsdk.sli.adaptors.netbox.model.IPAddress; -import org.onap.ccsdk.sli.adaptors.netbox.model.Prefix; +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 { +public interface NetboxClient extends SvcLogicJavaPlugin { /** * Assign next available IP in prefix and store it in the SDNC database, table IPAM_IP_ASSIGNEMENT. * - * @param prefix The prefix from which to get next available IP. - * @param serviceInstanceId The service instance ID uniquely identifying the service. - * @param vfModuleId The VF module ID uniquely identifying the VF. - * @return The IPAddress - * @throws IpamException If something goes wrong while communicating with the IPAM system. - * @throws SQLException If something goes wrong while communicating with the SDNC DB. + * @param parameters HashMap of parameters passed by the DG to this function + * + * + * + * + * + * + * + *
parameterMandatory/Optionaldescription
service_instance_idMandatoryThe service instance ID uniquely identifying the service.
vf_module_idMandatoryThe VF module ID uniquely identifying the VF.
prefix_idMandatoryThe prefix from which to get next available IP.
*/ - IPAddress assign(Prefix prefix, String serviceInstanceId, String vfModuleId) throws IpamException, SQLException; + QueryStatus assignIpAddress(Map parameters, SvcLogicContext ctx); /** - * Release the IP and remove the entry in the SDNC database, table IPAM_IP_ASSIGNEMENT. + * Release the IP and update the entry in the SDNC database, table IPAM_IP_ASSIGNEMENT. * - * @param ip The IP to release. - * @param serviceInstanceId The service instance ID uniquely identifying the service. - * @param vfModuleId The VF module ID uniquely identifying the VF. - * @throws IpamException If something goes wrong while communicating with the IPAM system. - * @throws SQLException If something goes wrong while communicating with the SDNC DB. + * @param parameters HashMap of parameters passed by the DG to this function + * + * + * + * + * + * + * + *
parameterMandatory/Optionaldescription
service_instance_idMandatoryThe service instance ID uniquely identifying the service.
vf_module_idMandatoryThe VF module ID uniquely identifying the VF.
ip_address_idMandatoryThe IP to release.
*/ - void unassign(IPAddress ip, String serviceInstanceId, String vfModuleId) throws IpamException, SQLException; + QueryStatus unassignIpAddress(Map parameters, SvcLogicContext ctx); } diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java index 036ff44d4..54700f6c7 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java @@ -15,127 +15,163 @@ */ package org.onap.ccsdk.sli.adaptors.netbox.impl; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSerializer; +import com.google.gson.JsonSyntaxException; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; import java.sql.SQLException; import java.util.ArrayList; -import java.util.concurrent.CompletionException; +import java.util.Map; import org.apache.http.HttpResponse; -import org.onap.ccsdk.sli.adaptors.netbox.api.IpamException; +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.Prefix; -import org.onap.ccsdk.sli.adaptors.netbox.model.Status; +import org.onap.ccsdk.sli.adaptors.netbox.model.IPStatus; import org.onap.ccsdk.sli.core.dblib.DbLibService; -import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +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, SvcLogicJavaPlugin { +public class NetboxClientImpl implements NetboxClient { + + private static final Logger LOG = LoggerFactory.getLogger(NetboxClientImpl.class); 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/"; private static final String EMPTY_STRING = ""; - private static final String ID_MISSING_MSG = "Id must be set"; + 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 ASSIGN_IP_SQL_STATEMENT = - "INSERT INTO IPAM_IP_ASSIGNEMENT (service_instance_id, vf_module_id, prefix_id, ip_address_id, ip_adress, ip_status) \n" - + "VALUES (?, ?, ?, ?, ?, ?)"; + "INSERT INTO IPAM_IP_ASSIGNEMENT (service_instance_id, vf_module_id, prefix_id, ip_address_id, ip_address, ip_status, ip_response_json) \n" + + "VALUES (?, ?, ?, ?, ?, ?, ?)"; private static final String UNASSIGN_IP_SQL_STATEMENT = - "DELETE FROM IPAM_IP_ASSIGNEMENT WHERE service_instance_id = ? AND vf_module_id = ? AND ip_address_id = ?"; + "UPDATE IPAM_IP_ASSIGNEMENT SET ip_status = ? WHERE service_instance_id = ? AND vf_module_id = ? AND ip_address_id = ?"; private final NetboxHttpClient client; - private final Gson gson; + private final DbLibService dbLibService; public NetboxClientImpl(final NetboxHttpClient client, final DbLibService dbLibService) { this.client = client; this.dbLibService = dbLibService; - final JsonSerializer vlanStatusDeserializer = (val, type, context) -> val.toJson(); - gson = new GsonBuilder() - .registerTypeAdapter(Status.class, vlanStatusDeserializer) - .create(); } @Override - public IPAddress assign(final Prefix prefix, final String serviceInstanceId, final String vfModuleId) - throws IpamException, SQLException { + public QueryStatus assignIpAddress(final Map parameters, final SvcLogicContext ctx) { - checkArgument(prefix.getId() != null); try { - IPAddress ipAddress = client - .post(String.format(NEXT_AVAILABLE_IP_IN_PREFIX_PATH, prefix.getId()), EMPTY_STRING) - .thenApply(this::getIpAddress) - .toCompletableFuture() - .join(); - - ArrayList args = Lists.newArrayList(serviceInstanceId, - vfModuleId, - String.valueOf(prefix.getId()), - String.valueOf(ipAddress.getId()), - ipAddress.getAddress(), - ipAddress.getStatus().getLabel()); - dbLibService.writeData(ASSIGN_IP_SQL_STATEMENT, args, null); + SliPluginUtils + .checkParameters(parameters, new String[]{SERVICE_INSTANCE_ID_PROP, VF_MODULE_ID_PROP, "prefix_id"}, + LOG); + } catch (SvcLogicException e) { + return QueryStatus.FAILURE; + } - return ipAddress; - } catch (CompletionException e) { - // Unwrap the CompletionException and wrap in IpamException - throw new IpamException("Fail to assign IP for Prefix(id= " + prefix.getId() + "). " + e.getMessage(), - e.getCause()); + final String serviceInstanceId = parameters.get(SERVICE_INSTANCE_ID_PROP); + LOG.trace("assignIpAddress: service_instance_id = {}", serviceInstanceId); + final String vfModuleId = parameters.get(VF_MODULE_ID_PROP); + LOG.trace("assignIpAddress: vf_module_id = {}", vfModuleId); + final String prefixId = parameters.get("prefix_id"); + LOG.trace("assignIpAddress: prefix_id = {}", prefixId); + + HttpResponse httpResp; + try { + httpResp = client + .post(String.format(NEXT_AVAILABLE_IP_IN_PREFIX_PATH, prefixId), EMPTY_STRING); + } catch (IOException e) { + LOG.error("Fail to assign IP for Prefix(id={}). {}", prefixId, e.getMessage(), e.getCause()); + return QueryStatus.FAILURE; } - } - @Override - public void unassign(final IPAddress ipAddress, final String serviceInstanceId, final String vfModuleId) - throws IpamException, SQLException { + 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; + } - checkArgument(ipAddress.getId() != null); + IPAddress ipAddress; try { - client.delete(String.format(IP_ADDRESS_PATH, ipAddress.getId())) - .thenAccept(this::checkResult) - .toCompletableFuture() - .join(); - - ArrayList args = Lists.newArrayList( - serviceInstanceId, - vfModuleId, - String.valueOf(ipAddress.getId())); - dbLibService.writeData(UNASSIGN_IP_SQL_STATEMENT, args, null); + 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; + } - } catch (CompletionException e) { - // Unwrap the CompletionException and wrap in IpamException - throw new IpamException( - "Fail to unassign IP for IPAddress(id= " + ipAddress.getId() + "). " + e.getMessage(), - e.getCause()); + ArrayList args = Lists.newArrayList(serviceInstanceId, + vfModuleId, + String.valueOf(prefixId), + String.valueOf(ipAddress.getId()), + ipAddress.getAddress(), + IPStatus.ASSIGNED.name(), + ipamRespJson); + + try { + dbLibService.writeData(ASSIGN_IP_SQL_STATEMENT, args, null); + } catch (SQLException e) { + LOG.error("Caught SQL exception", e); + return QueryStatus.FAILURE; } + + ctx.setAttribute("self_serve_netbox_ip_assignement.ip-address", ipAddress.getAddress()); + + return QueryStatus.SUCCESS; } - @VisibleForTesting - IPAddress getIpAddress(final HttpResponse response) { - if (response.getStatusLine().getStatusCode() != 201) { - throw new IllegalStateException(NetboxHttpClient.getBodyAsString(response)); + @Override + public QueryStatus unassignIpAddress(final Map parameters, final SvcLogicContext ctx) { + try { + SliPluginUtils + .checkParameters(parameters, new String[]{SERVICE_INSTANCE_ID_PROP, VF_MODULE_ID_PROP, "ip_address_id"}, + LOG); + } catch (SvcLogicException e) { + return QueryStatus.FAILURE; } - try (final Reader reader = new InputStreamReader(response.getEntity().getContent())) { - return gson.fromJson(reader, IPAddress.class); - } catch (final IOException e) { - throw new IllegalStateException(e); + + final String serviceInstanceId = parameters.get(SERVICE_INSTANCE_ID_PROP); + LOG.trace("assignIpAddress: service_instance_id = {}", serviceInstanceId); + final String vfModuleId = parameters.get(VF_MODULE_ID_PROP); + LOG.trace("assignIpAddress: vf_module_id = {}", vfModuleId); + final String ipAddressId = parameters.get("ip_address_id"); + LOG.trace("assignIpAddress: ip_address_id = {}", ipAddressId); + 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; } - } - private static void checkArgument(final boolean argument) throws IpamException { - if (!argument) { - throw new IpamException(ID_MISSING_MSG); + if (httpResp.getStatusLine().getStatusCode() - 200 >= 100) { + LOG.error("Fail to unassign IP for IPAddress(id={}). HTTP code={}.", ipAddressId, + httpResp.getStatusLine().getStatusCode()); + return QueryStatus.FAILURE; } - } - private void checkResult(final HttpResponse response) { - if (response.getStatusLine().getStatusCode() - 200 >= 100) { - throw new IllegalStateException( - "Netbox request failed with status: " + NetboxHttpClient.getBodyAsString(response)); + ArrayList args = Lists.newArrayList( + IPStatus.UNASSIGNED.name(), + serviceInstanceId, + vfModuleId, + String.valueOf(ipAddressId)); + try { + dbLibService.writeData(UNASSIGN_IP_SQL_STATEMENT, args, null); + } catch (SQLException e) { + LOG.error("Caught SQL exception", e); + return QueryStatus.FAILURE; } + + return QueryStatus.SUCCESS; } } diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClient.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClient.java index a77b4d3e9..505c5a77e 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClient.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClient.java @@ -24,31 +24,24 @@ import java.nio.charset.Charset; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.util.Scanner; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.function.Function; import javax.net.ssl.SSLContext; -import org.apache.http.HttpEntityEnclosingRequest; 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.HttpUriRequest; -import org.apache.http.concurrent.FutureCallback; +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.nio.client.CloseableHttpAsyncClient; -import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +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.api.IpamException; import org.onap.ccsdk.sli.adaptors.netbox.property.NetboxProperties; public class NetboxHttpClient implements AutoCloseable { private static final String APPLICATION_JSON = "application/json"; - private final CloseableHttpAsyncClient client; + private final CloseableHttpClient client; private final String url; private final String token; @@ -69,16 +62,10 @@ public class NetboxHttpClient implements AutoCloseable { } catch (final NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { throw new IllegalStateException("Can't create http client", e); } - client = HttpAsyncClientBuilder.create() + client = HttpClientBuilder.create() .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .setSSLContext(sslContext) .build(); - - } - - // Has to be public for blueprint container to access it - public void init() { - client.start(); } @Override @@ -86,66 +73,22 @@ public class NetboxHttpClient implements AutoCloseable { client.close(); } - CompletionStage post(final String uri, final String requestBody) { - return sendRequest(uri, requestBody, HttpPost::new); - } - - CompletionStage delete(final String uri) { - return sendRequest(uri, HttpDelete::new); + 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); } - static String getBodyAsString(final HttpResponse response) { - final String body; - if (response.getEntity() != null) { - try (final Scanner s = new java.util.Scanner(response.getEntity().getContent()).useDelimiter("\\A")) { - body = s.hasNext() ? s.next() : ""; - } catch (final IOException e) { - throw new IllegalStateException(e); - } - } else { - body = ""; - } - return response.toString() + "\n" + body; + HttpResponse delete(final String uri) throws IOException { + final HttpDelete request = new HttpDelete(url + uri); + setHeaders(request); + return client.execute(request); } - private CompletionStage sendRequest(final String uri, - final Function supplier) { - final T request = supplier.apply(url + uri); + private void setHeaders(final HttpRequestBase request) { request.addHeader(ACCEPT, APPLICATION_JSON); request.addHeader(CONTENT_TYPE, APPLICATION_JSON); request.addHeader(AUTHORIZATION, "Token " + token); - return sendRequest(request); - } - - private - CompletionStage sendRequest(final String uri, final String body, - final Function supplier) { - final T request = supplier.apply(url + uri); - request.addHeader(ACCEPT, APPLICATION_JSON); - request.addHeader(CONTENT_TYPE, APPLICATION_JSON); - request.addHeader(AUTHORIZATION, "Token " + token); - request.setEntity(new StringEntity(body, Charset.forName("UTF-8"))); - return sendRequest(request); - } - - private CompletionStage sendRequest(final HttpUriRequest request) { - final CompletableFuture future = new CompletableFuture<>(); - client.execute(request, new FutureCallback() { - @Override - public void completed(final HttpResponse httpResponse) { - future.complete(httpResponse); - } - - @Override - public void failed(final Exception e) { - future.completeExceptionally(new IpamException("Netbox request failed", e)); - } - - @Override - public void cancelled() { - future.cancel(false); - } - }); - return future; } } \ No newline at end of file diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPAddress.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPAddress.java index 6d62fff9f..4c2880bc4 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPAddress.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPAddress.java @@ -15,25 +15,20 @@ */ 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 Status.Values status; - private String address; + private static final Gson gson = new GsonBuilder().create(); - public void setStatus(Status.Values status) { - this.status = status; - } + private String address; public void setAddress(String address) { this.address = address; } - public Status.Values getStatus() { - return status; - } - public String getAddress() { return address; } @@ -47,12 +42,15 @@ public class IPAddress extends Identifiable { return false; } IPAddress ipAddress = (IPAddress) o; - return Objects.equals(status, ipAddress.status) && - Objects.equals(address, ipAddress.address); + return Objects.equals(address, ipAddress.address); } @Override public int hashCode() { - return Objects.hash(status, address); + return Objects.hash(address); + } + + public static IPAddress fromJson(final String json) { + return gson.fromJson(json, IPAddress.class); } } diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java new file mode 100644 index 000000000..05cc1ea29 --- /dev/null +++ b/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, UNASSIGNED, PENDING_ASSIGN, PENDING_UNASSIGN +} diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Status.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Status.java deleted file mode 100644 index c56828a80..000000000 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/Status.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.JsonElement; -import com.google.gson.JsonPrimitive; -import com.google.gson.annotations.SerializedName; - -public class Status { - - private Integer value; - private String label; - - public Integer getValue() { - return value; - } - - public void setValue(final Integer value) { - this.value = value; - } - - public String getLabel() { - return label; - } - - public void setLabel(final String label) { - this.label = label; - } - - public JsonElement toJson() { - return new JsonPrimitive(value); - } - - public enum Values { - @SerializedName("1") - ACTIVE(1, "Active"), - @SerializedName("2") - RESERVED(2, "Reserved"); - - private final int value; - private final String label; - - Values(final int value, final String label) { - this.value = value; - this.label = label; - } - - public int getValue() { - return value; - } - - public String getLabel() { - return label; - } - - public Status getStatus() { - final Status status = new Status(); - status.setValue(value); - status.setLabel(label); - return status; - } - - } -} diff --git a/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml b/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml index 950fd97b0..b667dcba5 100644 --- a/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml +++ b/netbox-client/provider/src/main/resources/org/opendaylight/blueprint/netbox-client.xml @@ -21,8 +21,7 @@ interface="org.onap.ccsdk.sli.core.dblib.DbLibService"/> - + diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java index f1eda736a..0f887a630 100644 --- a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java @@ -20,7 +20,6 @@ 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.serverError; @@ -33,37 +32,37 @@ 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.mock; +import static org.mockito.Mockito.doThrow; +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.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.UUID; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; 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.adaptors.netbox.api.IpamException; -import org.onap.ccsdk.sli.adaptors.netbox.model.IPAddress; -import org.onap.ccsdk.sli.adaptors.netbox.model.Prefix; -import org.onap.ccsdk.sli.adaptors.netbox.model.Status.Values; 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 { @@ -72,26 +71,50 @@ public class NetboxClientImplTest { @Rule public WireMockRule wm = new WireMockRule(wireMockConfig().dynamicPort()); - @Mock private DbLibService dbLib; + @Mock + private SvcLogicContext svcLogicContext; + @Mock + private Appender appender; + @Captor + private ArgumentCaptor captor; + private String token = "token"; private String serviceInstanceId = UUID.randomUUID().toString(); private String vfModuleId = UUID.randomUUID().toString(); + private Map params = ImmutableMap + .of("service_instance_id", serviceInstanceId, + "vf_module_id", vfModuleId, + "prefix_id", "3", + "ip_address_id", "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); - httpClient.init(); netboxClient = new NetboxClientImpl(httpClient, dbLib); + netboxClientMock = new NetboxClientImpl(httpClientMock, dbLib); + wm.addMockServiceRequestListener( (request, response) -> { System.out.println("Request URL :" + request.getAbsoluteUrl()); @@ -107,95 +130,157 @@ public class NetboxClientImplTest { } @Test - public void nextAvailableIpInPrefixTestNoId() throws SQLException { - Prefix prefix = mock(Prefix.class); - doReturn(null).when(prefix).getId(); - try { - netboxClient.assign(prefix, serviceInstanceId, vfModuleId); - } catch (IpamException e) { - Assert.assertEquals("Id must be set", e.getMessage()); - return; - } - Assert.fail(); + public void unassignIpAddressTestNoParams() { + QueryStatus status = netboxClient.unassignIpAddress(ImmutableMap.of(), svcLogicContext); + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("This method requires the parameters [service_instance_id,vf_module_id,ip_address_id], but no parameters were passed in"); } @Test - public void nextAvailableIpInPrefixTest() throws IOException, IpamException, SQLException { - Integer id = 3; - Prefix prefix = mock(Prefix.class); - doReturn(id).when(prefix).getId(); + public void unassignIpAddressFailedRequest() throws IOException { + doThrow(new IOException("Failed request")).when(httpClientMock).delete(anyString()); + QueryStatus status = netboxClientMock + .unassignIpAddress(params, svcLogicContext); - URL url = Resources.getResource("nextAvailableIpResponse.json"); - String response = Resources.toString(url, Charsets.UTF_8); + Assert.assertEquals(QueryStatus.FAILURE, status); + verifyLogEntry("Fail to unassign IP for IPAddress(id= 3). Failed request"); + } - String expectedUrl = "/api/ipam/prefixes/" + id + "/available-ips/"; - givenThat(post(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + @Test + public void unassignIpAddressServerError() { - netboxClient.assign(prefix, serviceInstanceId, vfModuleId); + String expectedUrl = "/api/ipam/ip-addresses/3/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(serverError())); - 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))); + 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 deleteIpTestError500() throws SQLException { - Integer id = 3; - IPAddress ipAddress = mock(IPAddress.class); - doReturn(id).when(ipAddress).getId(); + public void unassignIpAddressFailSQL() throws IOException, SQLException { - String expectedUrl = "/api/ipam/ip-addresses/" + id + "/"; - givenThat(delete(urlEqualTo(expectedUrl)).willReturn(serverError())); - try { - netboxClient.unassign(ipAddress, serviceInstanceId, vfModuleId); - } catch (IpamException e) { - Assert.assertEquals(IllegalStateException.class, e.getCause().getClass()); - Assert.assertTrue(e.getMessage().contains( - "Fail to unassign IP for IPAddress(id= 3). java.lang.IllegalStateException: Netbox request failed with status: HTTP/1.1 500 Server Error")); - return; - } - Assert.fail(); + String response = "{}"; + + String expectedUrl = "/api/ipam/ip-addresses/3/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + 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 deleteIpTest() throws IpamException, SQLException { - Integer id = 3; - IPAddress ipAddress = mock(IPAddress.class); - doReturn(id).when(ipAddress).getId(); - - String expectedUrl = "/api/ipam/ip-addresses/" + id + "/"; - givenThat(delete(urlEqualTo(expectedUrl)).willReturn(ok())); - netboxClient.unassign(ipAddress, serviceInstanceId, vfModuleId); + public void unassignIpAddressSuccess() throws IOException, SQLException { + String response = "{}"; + + String expectedUrl = "/api/ipam/ip-addresses/3/"; + givenThat(delete(urlEqualTo(expectedUrl)).willReturn(created().withBody(response))); + + 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))); + + 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], 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 getIpAddressTest() throws IOException { - StatusLine statusLine = mock(StatusLine.class); - doReturn(201).when(statusLine).getStatusCode(); + 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); - InputStream stream = new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8)); - HttpEntity entity = mock(HttpEntity.class); - doReturn(stream).when(entity).getContent(); + 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); - HttpResponse httpResponse = mock(HttpResponse.class); - doReturn(statusLine).when(httpResponse).getStatusLine(); - doReturn(entity).when(httpResponse).getEntity(); + String expectedUrl = "/api/ipam/prefixes/3/available-ips/"; + givenThat(post(urlEqualTo(expectedUrl)).willReturn(serverError().withBody(response))); - IPAddress ipAddress = netboxClient.getIpAddress(httpResponse); + QueryStatus status = netboxClient.assignIpAddress(params, svcLogicContext); - Assert.assertEquals("192.168.20.7/32", ipAddress.getAddress()); - Assert.assertEquals(Integer.valueOf(8), ipAddress.getId()); - Assert.assertEquals(Values.ACTIVE, ipAddress.getStatus()); + 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 allValues = captor.getAllValues(); + for (ILoggingEvent loggingEvent : allValues) { + Assert.assertTrue(loggingEvent.getFormattedMessage().contains(message)); + } + } + } \ No newline at end of file diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java index ee2861c0a..8634742ae 100644 --- a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientTest.java @@ -15,7 +15,6 @@ */ package org.onap.ccsdk.sli.adaptors.netbox.impl; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; 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; @@ -29,16 +28,12 @@ import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMoc import static org.apache.http.HttpHeaders.ACCEPT; import static org.apache.http.HttpHeaders.CONTENT_TYPE; -import com.github.tomakehurst.wiremock.http.Fault; import com.github.tomakehurst.wiremock.junit.WireMockRule; import java.io.IOException; -import java.util.concurrent.CompletionException; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.onap.ccsdk.sli.adaptors.netbox.api.IpamException; public class NetboxHttpClientTest { @@ -55,7 +50,6 @@ public class NetboxHttpClientTest { String token = "token"; httpClient = new NetboxHttpClient(baseUrl, token); - httpClient.init(); wm.addMockServiceRequestListener( (request, response) -> { @@ -72,11 +66,11 @@ public class NetboxHttpClientTest { } @Test - public void postTest() { + public void postTest() throws IOException { String expectedUrl = "/testPost"; givenThat(post(urlEqualTo(expectedUrl)).willReturn(ok())); - httpClient.post(expectedUrl, "").toCompletableFuture().join(); + httpClient.post(expectedUrl, ""); verify(postRequestedFor(urlEqualTo(expectedUrl)) .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) @@ -84,44 +78,12 @@ public class NetboxHttpClientTest { } @Test - public void postTestException() { - String expectedUrl = "/testPost"; - givenThat(post(urlEqualTo(expectedUrl)).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); - - try { - httpClient.post(expectedUrl, "").toCompletableFuture().join(); - } catch (CompletionException e) { - Assert.assertEquals(IpamException.class, e.getCause().getClass()); - Assert.assertEquals("Netbox request failed", e.getCause().getMessage()); - return; - } - Assert.fail(); - } - - @Test - public void deleteTest() { + public void deleteTest() throws IOException { String expectedUrl = "/testDelete"; givenThat(delete(urlEqualTo(expectedUrl)).willReturn(ok())); - - httpClient.delete(expectedUrl).toCompletableFuture().join(); - + httpClient.delete(expectedUrl); verify(deleteRequestedFor(urlEqualTo(expectedUrl)) .withHeader(ACCEPT, equalTo(APPLICATION_JSON)) .withHeader(CONTENT_TYPE, equalTo(APPLICATION_JSON))); } - - @Test - public void deleteTestException() { - String expectedUrl = "/testDelete"; - givenThat(delete(urlEqualTo(expectedUrl)).willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK))); - - try { - httpClient.delete(expectedUrl).toCompletableFuture().join(); - } catch (CompletionException e) { - Assert.assertEquals(IpamException.class, e.getCause().getClass()); - Assert.assertEquals("Netbox request failed", e.getCause().getMessage()); - return; - } - Assert.fail(); - } } diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java index d9916707f..be5aabfc2 100644 --- a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java @@ -56,7 +56,6 @@ public class NetboxPropertiesTest { "Missing configuration properties resource for Netbox: netbox.properties"); } - private void verifyLogEntry(String message) { verify(appender, times(1)).doAppend(captor.capture()); List allValues = captor.getAllValues(); diff --git a/netbox-client/provider/src/test/resources/badResponse.json b/netbox-client/provider/src/test/resources/badResponse.json new file mode 100644 index 000000000..713109fd9 --- /dev/null +++ b/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 -- cgit 1.2.3-korg From 8477931fc702262866d2d87c49cf5ec05032c267 Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Wed, 29 Aug 2018 15:05:53 -0400 Subject: Added support for external_key and resource_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic44f24c3228e6ffcabb23b3866aaab01cb2f552b Issue-ID: CCSDK-341 Signed-off-by: Alexis de Talhouët --- .../sli/adaptors/netbox/impl/NetboxClientImpl.java | 79 +++++++++++++++------- .../ccsdk/sli/adaptors/netbox/model/IPStatus.java | 2 +- .../adaptors/netbox/impl/NetboxClientImplTest.java | 33 +++++++-- 3 files changed, 84 insertions(+), 30 deletions(-) (limited to 'netbox-client/provider/src/test/java/org') diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java index 54700f6c7..e7b5284ab 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.Map; +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; @@ -38,20 +39,38 @@ 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/"; - private static final String EMPTY_STRING = ""; + + // 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) \n" + "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) \n" + "VALUES (?, ?, ?, ?, ?, ?, ?)"; private static final String UNASSIGN_IP_SQL_STATEMENT = - "UPDATE IPAM_IP_ASSIGNEMENT SET ip_status = ? WHERE service_instance_id = ? AND vf_module_id = ? AND ip_address_id = ?"; + "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(final NetboxHttpClient client, final DbLibService dbLibService) { @@ -64,23 +83,24 @@ public class NetboxClientImpl implements NetboxClient { try { SliPluginUtils - .checkParameters(parameters, new String[]{SERVICE_INSTANCE_ID_PROP, VF_MODULE_ID_PROP, "prefix_id"}, - LOG); + .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); - LOG.trace("assignIpAddress: service_instance_id = {}", serviceInstanceId); final String vfModuleId = parameters.get(VF_MODULE_ID_PROP); - LOG.trace("assignIpAddress: vf_module_id = {}", vfModuleId); final String prefixId = parameters.get("prefix_id"); - LOG.trace("assignIpAddress: prefix_id = {}", prefixId); + 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), EMPTY_STRING); + .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; @@ -109,18 +129,20 @@ public class NetboxClientImpl implements NetboxClient { return QueryStatus.FAILURE; } - ArrayList args = Lists.newArrayList(serviceInstanceId, + ArrayList args = Lists.newArrayList( + serviceInstanceId, vfModuleId, String.valueOf(prefixId), String.valueOf(ipAddress.getId()), ipAddress.getAddress(), IPStatus.ASSIGNED.name(), - ipamRespJson); + ipamRespJson, + externalKey); try { dbLibService.writeData(ASSIGN_IP_SQL_STATEMENT, args, null); } catch (SQLException e) { - LOG.error("Caught SQL exception", e); + LOG.error(SQL_EXCEPTION_MESSAGE, e); return QueryStatus.FAILURE; } @@ -133,18 +155,26 @@ public class NetboxClientImpl implements NetboxClient { public QueryStatus unassignIpAddress(final Map parameters, final SvcLogicContext ctx) { try { SliPluginUtils - .checkParameters(parameters, new String[]{SERVICE_INSTANCE_ID_PROP, VF_MODULE_ID_PROP, "ip_address_id"}, + .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); - LOG.trace("assignIpAddress: service_instance_id = {}", serviceInstanceId); - final String vfModuleId = parameters.get(VF_MODULE_ID_PROP); - LOG.trace("assignIpAddress: vf_module_id = {}", vfModuleId); - final String ipAddressId = parameters.get("ip_address_id"); - LOG.trace("assignIpAddress: ip_address_id = {}", ipAddressId); + final String externalKey = parameters.get(EXTERNAL_KEY_PROP); + + String ipAddressId; + ArrayList args = Lists.newArrayList( + serviceInstanceId, + externalKey); + try (CachedRowSet row = dbLibService.getData(GET_IP_ADDRESS_ID_SQL_STATEMENT, args, null)) { + ipAddressId = row.getString("ip_address_id"); + } catch (SQLException e) { + LOG.error(SQL_EXCEPTION_MESSAGE, e); + return QueryStatus.FAILURE; + } + HttpResponse httpResp; try { httpResp = client.delete(String.format(IP_ADDRESS_PATH, ipAddressId)); @@ -160,15 +190,16 @@ public class NetboxClientImpl implements NetboxClient { return QueryStatus.FAILURE; } - ArrayList args = Lists.newArrayList( - IPStatus.UNASSIGNED.name(), + args.clear(); + args = Lists.newArrayList( + IPStatus.DELETED.name(), serviceInstanceId, - vfModuleId, - String.valueOf(ipAddressId)); + externalKey); + try { dbLibService.writeData(UNASSIGN_IP_SQL_STATEMENT, args, null); } catch (SQLException e) { - LOG.error("Caught SQL exception", e); + LOG.error(SQL_EXCEPTION_MESSAGE, e); return QueryStatus.FAILURE; } diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java index 05cc1ea29..f3a74387a 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/model/IPStatus.java @@ -1,5 +1,5 @@ package org.onap.ccsdk.sli.adaptors.netbox.model; public enum IPStatus { - ASSIGNED, UNASSIGNED, PENDING_ASSIGN, PENDING_UNASSIGN + ASSIGNED, DELETED } diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java index 0f887a630..bc81f0b76 100644 --- a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java @@ -32,7 +32,9 @@ 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; @@ -48,6 +50,7 @@ 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; @@ -89,7 +92,8 @@ public class NetboxClientImplTest { .of("service_instance_id", serviceInstanceId, "vf_module_id", vfModuleId, "prefix_id", "3", - "ip_address_id", "3" + "external_key", "3", + "resource_name", "3" ); private NetboxHttpClient httpClient; @@ -133,12 +137,18 @@ public class NetboxClientImplTest { public void unassignIpAddressTestNoParams() { QueryStatus status = netboxClient.unassignIpAddress(ImmutableMap.of(), svcLogicContext); Assert.assertEquals(QueryStatus.FAILURE, status); - verifyLogEntry("This method requires the parameters [service_instance_id,vf_module_id,ip_address_id], but no parameters were passed in"); + verifyLogEntry( + "This method requires the parameters [service_instance_id,external_key], but no parameters were passed in."); } @Test - public void unassignIpAddressFailedRequest() throws IOException { + 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(crs).when(dbLib).getData(anyString(), any(ArrayList.class), eq(null)); + QueryStatus status = netboxClientMock .unassignIpAddress(params, svcLogicContext); @@ -147,11 +157,15 @@ public class NetboxClientImplTest { } @Test - public void unassignIpAddressServerError() { + 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(crs).when(dbLib).getData(anyString(), any(ArrayList.class), eq(null)); + QueryStatus status = netboxClient.unassignIpAddress(params, svcLogicContext); Assert.assertEquals(QueryStatus.FAILURE, status); @@ -166,6 +180,10 @@ public class NetboxClientImplTest { 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(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); @@ -181,6 +199,10 @@ public class NetboxClientImplTest { 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(crs).when(dbLib).getData(anyString(), any(ArrayList.class), eq(null)); + QueryStatus status = netboxClient.unassignIpAddress(params, svcLogicContext); verify(deleteRequestedFor(urlEqualTo(expectedUrl)) @@ -197,7 +219,8 @@ public class NetboxClientImplTest { 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], but no parameters were passed in"); + 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 -- cgit 1.2.3-korg From 7df24c6223d040df3a13588932878c049e7cf584 Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Wed, 5 Sep 2018 09:18:22 -0400 Subject: Add missing agr and iterate on row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I65c34d1a059c12ec2c0fd7e76f0119571e175846 Issue-ID: CCSDK-341 Signed-off-by: Alexis de Talhouët --- .../org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java | 8 ++++++-- .../onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'netbox-client/provider/src/test/java/org') diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java index e7b5284ab..b54a35b50 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImpl.java @@ -64,7 +64,7 @@ public class NetboxClientImpl implements NetboxClient { 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) \n" - + "VALUES (?, ?, ?, ?, ?, ?, ?)"; + + "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 = @@ -169,7 +169,11 @@ public class NetboxClientImpl implements NetboxClient { serviceInstanceId, externalKey); try (CachedRowSet row = dbLibService.getData(GET_IP_ADDRESS_ID_SQL_STATEMENT, args, null)) { - ipAddressId = row.getString("ip_address_id"); + 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; diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java index bc81f0b76..624a1906e 100644 --- a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java +++ b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplTest.java @@ -147,6 +147,7 @@ public class NetboxClientImplTest { 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 @@ -164,6 +165,7 @@ public class NetboxClientImplTest { 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); @@ -181,6 +183,7 @@ public class NetboxClientImplTest { 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)); @@ -201,6 +204,7 @@ public class NetboxClientImplTest { 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); -- cgit 1.2.3-korg From ed7162521270d33da1bdc57286b23c64e23e5b0f Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Sat, 9 Feb 2019 15:01:10 -0500 Subject: Rework property file load logic for grpc & netbox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We first try to load from the filesystem properties folder, if not found, then we load from the bundle itself. Change-Id: Ib4b422b1fe18f80b2f2258f96f3739d25bd756c9 Issue-ID: CCSDK-1038 Signed-off-by: Alexis de Talhouët --- features/ccsdk-sli-adaptors-all/pom.xml | 2 +- grpc-resource/provider/pom.xml | 6 ++ .../ccsdk/sli/adaptors/grpc/GrpcProperties.java | 88 ++++++--------------- .../provider/src/main/resources/grpc.properties | 6 +- netbox-client/provider/pom.xml | 10 +-- .../adaptors/netbox/property/NetboxProperties.java | 90 ++++++---------------- .../netbox/property/NetboxPropertiesTest.java | 66 ---------------- 7 files changed, 66 insertions(+), 202 deletions(-) mode change 100755 => 100644 grpc-resource/provider/src/main/resources/grpc.properties delete mode 100644 netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java (limited to 'netbox-client/provider/src/test/java/org') diff --git a/features/ccsdk-sli-adaptors-all/pom.xml b/features/ccsdk-sli-adaptors-all/pom.xml index 68ad0f776..1e3ba8ada 100644 --- a/features/ccsdk-sli-adaptors-all/pom.xml +++ b/features/ccsdk-sli-adaptors-all/pom.xml @@ -44,6 +44,7 @@ xml features
+ --> ${project.groupId} ccsdk-grpc-client @@ -51,7 +52,6 @@ xml features - --> ${project.groupId} ccsdk-netbox-client diff --git a/grpc-resource/provider/pom.xml b/grpc-resource/provider/pom.xml index 9c0a4a0d9..c567bba13 100644 --- a/grpc-resource/provider/pom.xml +++ b/grpc-resource/provider/pom.xml @@ -106,6 +106,12 @@ ${grpc.version} + + org.osgi + org.osgi.core + provided + + junit diff --git a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java index fef1a5963..96775f379 100644 --- a/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java +++ b/grpc-resource/provider/src/main/java/org/onap/ccsdk/sli/adaptors/grpc/GrpcProperties.java @@ -15,100 +15,62 @@ */ package org.onap.ccsdk.sli.adaptors.grpc; -import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.HashSet; -import java.util.Optional; +import java.io.InputStream; +import java.net.URL; import java.util.Properties; -import java.util.Set; -import org.onap.ccsdk.sli.core.utils.JREFileResolver; -import org.onap.ccsdk.sli.core.utils.KarafRootFileResolver; -import org.onap.ccsdk.sli.core.utils.PropertiesFileResolver; -import org.onap.ccsdk.sli.core.utils.common.BundleContextFileResolver; -import org.onap.ccsdk.sli.core.utils.common.SdncConfigEnvVarFileResolver; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Responsible for determining the properties file to use. - * - *
    - *
  1. A directory identified by the system environment variable SDNC_CONFIG_DIR
  2. - *
  3. A directory identified by the JRE argument grpc.properties
  4. - *
  5. A grpc.properties file located in the karaf root directory
  6. - *
- * - * Partial copy and adaptation of org.onap.ccsdk.sli.adaptors.aai.AAIServiceProvider - */ public class GrpcProperties { private static final Logger LOG = LoggerFactory.getLogger(GrpcProperties.class); private static final String GRPC_PROPERTY_FILE_NAME = "grpc.properties"; - private static final String MISSING_PROPERTY_FILE = - "Missing configuration properties resource for GRPC: " + GRPC_PROPERTY_FILE_NAME; + 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 BLUEPRINT_PROCESSOR_URL_PROP = "org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.url"; private static final String BLUEPRINT_PROCESSOR_PORT_PROP = "org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.port"; - private Set fileResolvers = new HashSet<>(); private Properties properties; public GrpcProperties() { - fileResolvers.add(new SdncConfigEnvVarFileResolver("Using property file (1) from environment variable")); - fileResolvers.add(new BundleContextFileResolver("Using property file (2) from BundleContext property", - GrpcProperties.class)); - fileResolvers.add(new JREFileResolver("Using property file (3) from JRE argument", GrpcProperties.class)); - fileResolvers.add(new KarafRootFileResolver("Using property file (4) from karaf root", this)); - loadProps(); } public String getUrl() { - checkArgument(properties != null); return properties.getProperty(BLUEPRINT_PROCESSOR_URL_PROP); } public int getPort() { - checkArgument(properties != null); return Integer.parseInt(properties.getProperty(BLUEPRINT_PROCESSOR_PORT_PROP)); } - private void checkArgument(final boolean argument) { - if (!argument) { - LOG.info("Propety file {} was missing, trying to reload it", GRPC_PROPERTY_FILE_NAME); - loadProps(); - if (properties == null) { - throw new IllegalArgumentException(MISSING_PROPERTY_FILE); - } - } - } - private void loadProps() { - // determines properties file as according to the priority described in the class header comment - final File propertiesFile = determinePropertiesFile(); - if (propertiesFile != null) { - try (FileInputStream fileInputStream = new FileInputStream(propertiesFile)) { - properties = new Properties(); - properties.load(fileInputStream); - } catch (final IOException e) { - String errorMsg = "Failed to load properties for file: " + propertiesFile.toString(); - LOG.error(errorMsg, errorMsg); - } - } - } + properties = new Properties(); + // Try to load config from dir + final String ccsdkConfigDir = + System.getProperty(PROPERTIES_DIR_KEY, DEFAULT_PROPERTIES_DIR) + "/" + GRPC_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 to load config from jar + final Bundle bundle = FrameworkUtil.getBundle(GrpcProperties.class); + final BundleContext ctx = bundle.getBundleContext(); + final URL url = ctx.getBundle().getResource(GRPC_PROPERTY_FILE_NAME); - private File determinePropertiesFile() { - for (final PropertiesFileResolver resolver : fileResolvers) { - final Optional fileOptional = resolver.resolveFile(GRPC_PROPERTY_FILE_NAME); - if (fileOptional.isPresent()) { - final File file = fileOptional.get(); - LOG.info("{} {}", resolver.getSuccessfulResolutionMessage(), file.getPath()); - return file; + try (InputStream inputStream = url.openStream()) { + properties.load(inputStream); + LOG.info("Loaded {} properties from file {}", properties.size(), GRPC_PROPERTY_FILE_NAME); + } catch (IOException e1) { + LOG.error("Failed to load properties for file: {} " + GRPC_PROPERTY_FILE_NAME, e1); } } - - LOG.error(MISSING_PROPERTY_FILE); - return null; } } diff --git a/grpc-resource/provider/src/main/resources/grpc.properties b/grpc-resource/provider/src/main/resources/grpc.properties old mode 100755 new mode 100644 index 2d4e795e6..650910eb9 --- a/grpc-resource/provider/src/main/resources/grpc.properties +++ b/grpc-resource/provider/src/main/resources/grpc.properties @@ -1,4 +1,5 @@ -# Copyright (C) 2019 Bell Canada +# +# 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. @@ -11,5 +12,6 @@ # 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. +# org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.url=blueprint-processor -org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.port=9111 \ No newline at end of file +org.onap.ccsdk.sli.adaptors.grpc.blueprint.processor.port=9111 diff --git a/netbox-client/provider/pom.xml b/netbox-client/provider/pom.xml index 3af22edb2..f7e8ccf92 100644 --- a/netbox-client/provider/pom.xml +++ b/netbox-client/provider/pom.xml @@ -79,6 +79,11 @@ ${project.version} compile
+ + org.osgi + org.osgi.core + provided + @@ -111,11 +116,6 @@ 1.2.3 test - - org.osgi - org.osgi.core - test - diff --git a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxProperties.java b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxProperties.java index ee493ec18..2eecf6e3a 100644 --- a/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxProperties.java +++ b/netbox-client/provider/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxProperties.java @@ -15,102 +15,62 @@ */ package org.onap.ccsdk.sli.adaptors.netbox.property; -import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.HashSet; -import java.util.Optional; +import java.io.InputStream; +import java.net.URL; import java.util.Properties; -import java.util.Set; - -import org.onap.ccsdk.sli.adaptors.netbox.api.IpamException; -import org.onap.ccsdk.sli.core.utils.JREFileResolver; -import org.onap.ccsdk.sli.core.utils.KarafRootFileResolver; -import org.onap.ccsdk.sli.core.utils.PropertiesFileResolver; -import org.onap.ccsdk.sli.core.utils.common.BundleContextFileResolver; -import org.onap.ccsdk.sli.core.utils.common.SdncConfigEnvVarFileResolver; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Responsible for determining the properties file to use. - * - *
    - *
  1. A directory identified by the system environment variable SDNC_CONFIG_DIR
  2. - *
  3. A directory identified by the JRE argument netbox.properties
  4. - *
  5. A netbox.properties file located in the karaf root directory
  6. - *
- * - * Partial copy and adaptation of org.onap.ccsdk.sli.adaptors.aai.AAIServiceProvider - */ 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 MISSING_PROPERTY_FILE = - "Missing configuration properties resource for Netbox: " + NETBOX_PROPERTY_FILE_NAME; + 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 Set fileResolvers = new HashSet<>(); private Properties properties; public NetboxProperties() { - fileResolvers.add(new SdncConfigEnvVarFileResolver("Using property file (1) from environment variable")); - fileResolvers.add(new BundleContextFileResolver("Using property file (2) from BundleContext property", - NetboxProperties.class)); - fileResolvers.add(new JREFileResolver("Using property file (3) from JRE argument", NetboxProperties.class)); - fileResolvers.add(new KarafRootFileResolver("Using property file (4) from karaf root", this)); - loadProps(); } public String getHost() { - checkArgument(properties != null); return properties.getProperty(NETBOX_URL_PROP); } public String getApiKey() { - checkArgument(properties != null); return properties.getProperty(NETBOX_API_KEY_PROP); } - private void checkArgument(final boolean argument) { - if (!argument) { - LOG.info("Propety file {} was missing, trying to reload it", NETBOX_PROPERTY_FILE_NAME); - loadProps(); - if (properties == null) { - throw new IllegalArgumentException(MISSING_PROPERTY_FILE); - } - } - } - private void loadProps() { - // determines properties file as according to the priority described in the class header comment - final File propertiesFile = determinePropertiesFile(); - if (propertiesFile != null) { - try (FileInputStream fileInputStream = new FileInputStream(propertiesFile)) { - properties = new Properties(); - properties.load(fileInputStream); - } catch (final IOException e) { - String errorMsg = "Failed to load properties for file: " + propertiesFile.toString(); - LOG.error(errorMsg, new IpamException(errorMsg)); - } - } - } + 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 to load config from jar + final Bundle bundle = FrameworkUtil.getBundle(NetboxProperties.class); + final BundleContext ctx = bundle.getBundleContext(); + final URL url = ctx.getBundle().getResource(NETBOX_PROPERTY_FILE_NAME); - private File determinePropertiesFile() { - for (final PropertiesFileResolver resolver : fileResolvers) { - final Optional fileOptional = resolver.resolveFile(NETBOX_PROPERTY_FILE_NAME); - if (fileOptional.isPresent()) { - final File file = fileOptional.get(); - LOG.info("{} {}", resolver.getSuccessfulResolutionMessage(), file.getPath()); - return file; + try (InputStream inputStream = url.openStream()) { + properties.load(inputStream); + 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); } } - - LOG.error(MISSING_PROPERTY_FILE, new IpamException(MISSING_PROPERTY_FILE)); - return null; } } diff --git a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java b/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java deleted file mode 100644 index be5aabfc2..000000000 --- a/netbox-client/provider/src/test/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.Appender; -import java.util.List; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.slf4j.LoggerFactory; - -@RunWith(MockitoJUnitRunner.class) -public class NetboxPropertiesTest { - - private NetboxProperties props; - - @Mock - private Appender appender; - @Captor - private ArgumentCaptor captor; - - @Before - public void setup() { - ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory - .getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); - logger.addAppender(appender); - } - - @Test - public void testMissingFile() { - props = new NetboxProperties(); - - verifyLogEntry( - "Missing configuration properties resource for Netbox: netbox.properties"); - } - - private void verifyLogEntry(String message) { - verify(appender, times(1)).doAppend(captor.capture()); - List allValues = captor.getAllValues(); - for (ILoggingEvent loggingEvent : allValues) { - Assert.assertTrue(loggingEvent.getFormattedMessage().contains(message)); - } - } -} \ No newline at end of file -- cgit 1.2.3-korg