From e398be5923a47650b109512c795244cdc2b5eb10 Mon Sep 17 00:00:00 2001 From: tragait Date: Fri, 6 Aug 2021 17:01:31 +0100 Subject: implement passthough operational for dmi Issue-ID: CPS-486 Signed-off-by: tragait Change-Id: Icf48fa93ea1f0d8a27d2e7e1ab0cfd6096a765ec --- .../ncmp/dmi/exception/ResourceDataNotFound.java | 38 ++++++++ .../dmi/rest/controller/DmiRestController.java | 34 ++++++- .../org/onap/cps/ncmp/dmi/service/DmiService.java | 25 ++++- .../onap/cps/ncmp/dmi/service/DmiServiceImpl.java | 46 ++++++++-- .../dmi/service/client/SdncRestconfClient.java | 20 +++- .../ncmp/dmi/service/operation/SdncOperations.java | 102 +++++++++++++++++++-- 6 files changed, 240 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/onap/cps/ncmp/dmi/exception/ResourceDataNotFound.java (limited to 'src/main') diff --git a/src/main/java/org/onap/cps/ncmp/dmi/exception/ResourceDataNotFound.java b/src/main/java/org/onap/cps/ncmp/dmi/exception/ResourceDataNotFound.java new file mode 100644 index 00000000..dbef3477 --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/exception/ResourceDataNotFound.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.exception; + +public class ResourceDataNotFound extends DmiException { + + private static final long serialVersionUID = 881438585188332404L; + + private static final String ERROR_MESSAGE = "Resource data not found for the given cmHandles: "; + + /** + * Constructor. + * + * @param cmHandle cmHandle identifier + * @param details the error details + */ + public ResourceDataNotFound(final String cmHandle, final String details) { + super(ERROR_MESSAGE + cmHandle, details); + } +} diff --git a/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java b/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java index 5725f094..969e08d3 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java @@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.dmi.model.CmHandles; import org.onap.cps.ncmp.dmi.model.ModuleReference; import org.onap.cps.ncmp.dmi.model.ModuleRequestParent; +import org.onap.cps.ncmp.dmi.model.OperationalRequest; import org.onap.cps.ncmp.dmi.rest.api.DmiPluginApi; import org.onap.cps.ncmp.dmi.rest.api.DmiPluginInternalApi; import org.onap.cps.ncmp.dmi.service.DmiService; @@ -59,7 +60,7 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { @Override public ResponseEntity retrieveModuleResources(@Valid final ModuleRequestParent moduleRequestParent, - final String cmHandle) { + final String cmHandle) { if (moduleRequestParent.getOperation().toString().equals("read")) { final var moduleReferenceList = convertRestObjectToJavaApiObject(moduleRequestParent); final var response = dmiService.getModuleResources(cmHandle, moduleReferenceList); @@ -86,8 +87,37 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { return new ResponseEntity<>("cm-handle registered successfully.", HttpStatus.CREATED); } + /** + * This method fetches the resource for given cm handle using pass + * through option. It filters the response on the basis of depth and field + * query parameters and returns response. + * + * @param cmHandle cm handle identifier + * @param resourceIdentifier resource identifier to fetch data + * @param body operational body + * @param accept accept header parameter + * @param fields fields to filter the response data + * @param depth depth parameter for the response + * @return {@code ResponseEntity} response entity + */ + @Override + public ResponseEntity getResourceDataOperationalForCmHandle(final String cmHandle, + final String resourceIdentifier, + final @Valid OperationalRequest body, + final String accept, + final @Valid String fields, + final @Valid Integer depth) { + final var modulesListAsJson = dmiService.getResourceDataOperationalForCmHandle(cmHandle, + resourceIdentifier, + accept, + fields, + depth, + body.getCmHandleProperties()); + return ResponseEntity.ok(modulesListAsJson); + } + private List convertRestObjectToJavaApiObject(final ModuleRequestParent moduleRequestParent) { return objectMapper .convertValue(moduleRequestParent.getData().getModules(), new TypeReference>() {}); } -} +} \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java index aeff3dc6..528eb641 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java @@ -21,6 +21,8 @@ package org.onap.cps.ncmp.dmi.service; import java.util.List; +import java.util.Map; +import javax.validation.constraints.NotNull; import org.onap.cps.ncmp.dmi.exception.DmiException; import org.onap.cps.ncmp.dmi.model.ModuleReference; @@ -54,4 +56,25 @@ public interface DmiService { * @return returns all module resources */ String getModuleResources(String cmHandle, List modules); -} + + /** + * This method use to fetch the resource data from cm handle + * for given datasource and Identifier. Fields and depths query + * parameter are used to filter the response from network resource. + * + * @param cmHandle cm handle identifier + * @param resourceIdentifier resource identifier + * @param acceptParam accept header parameter + * @param fieldsQuery fields query parameter + * @param depthQuery depth query parameter + * @param cmHandlePropertyMap cm handle properties + * + * @return {@code Object} response from network function + */ + Object getResourceDataOperationalForCmHandle(@NotNull String cmHandle, + @NotNull String resourceIdentifier, + String acceptParam, + String fieldsQuery, + Integer depthQuery, + Map cmHandlePropertyMap); +} \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java index bf0689ca..32c8526c 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java @@ -25,20 +25,22 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import net.minidev.json.JSONArray; import org.apache.groovy.parser.antlr4.util.StringUtils; +import org.jetbrains.annotations.NotNull; import org.onap.cps.ncmp.dmi.config.DmiPluginConfig.DmiPluginProperties; import org.onap.cps.ncmp.dmi.exception.CmHandleRegistrationException; import org.onap.cps.ncmp.dmi.exception.DmiException; import org.onap.cps.ncmp.dmi.exception.ModuleResourceNotFoundException; import org.onap.cps.ncmp.dmi.exception.ModulesNotFoundException; +import org.onap.cps.ncmp.dmi.exception.ResourceDataNotFound; import org.onap.cps.ncmp.dmi.model.CmHandleOperation; import org.onap.cps.ncmp.dmi.model.CreatedCmHandle; import org.onap.cps.ncmp.dmi.model.ModuleReference; import org.onap.cps.ncmp.dmi.service.client.NcmpRestClient; import org.onap.cps.ncmp.dmi.service.operation.SdncOperations; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -60,10 +62,9 @@ public class DmiServiceImpl implements DmiService { * @param sdncOperations sdncOperations * @param objectMapper objectMapper */ - @Autowired public DmiServiceImpl(final DmiPluginProperties dmiPluginProperties, - final NcmpRestClient ncmpRestClient, - final SdncOperations sdncOperations, final ObjectMapper objectMapper) { + final NcmpRestClient ncmpRestClient, + final SdncOperations sdncOperations, final ObjectMapper objectMapper) { this.dmiPluginProperties = dmiPluginProperties; this.ncmpRestClient = ncmpRestClient; this.objectMapper = objectMapper; @@ -82,7 +83,7 @@ public class DmiServiceImpl implements DmiService { return responseBody; } else { throw new DmiException("SDNC is not able to process request.", - "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); + "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); } } @@ -97,7 +98,7 @@ public class DmiServiceImpl implements DmiService { } else { log.error("SDNC did not return a module resource for the given cmHandle {}", cmHandle); throw new ModuleResourceNotFoundException(cmHandle, - "SDNC did not return a module resource for the given cmHandle."); + "SDNC did not return a module resource for the given cmHandle."); } } return getModuleResponses.toJSONString(); @@ -120,7 +121,7 @@ public class DmiServiceImpl implements DmiService { } catch (final JsonProcessingException e) { log.error("Parsing error occurred while converting cm-handles to JSON {}", cmHandles); throw new DmiException("Internal Server Error.", - "Parsing error occurred while converting given cm-handles object list to JSON "); + "Parsing error occurred while converting given cm-handles object list to JSON "); } final ResponseEntity responseEntity = ncmpRestClient.registerCmHandlesWithNcmp(cmHandlesJson); if (!(responseEntity.getStatusCode() == HttpStatus.CREATED)) { @@ -128,6 +129,31 @@ public class DmiServiceImpl implements DmiService { } } + @Override + public Object getResourceDataOperationalForCmHandle(final @NotNull String cmHandle, + final @NotNull String resourceIdentifier, + final String acceptParam, + final String fieldsQuery, + final Integer depthQuery, + final Map cmHandlePropertyMap) { + // not using cmHandlePropertyMap of onap dmi impl , other dmi impl might use this. + final ResponseEntity responseEntity = sdncOperations.getResouceDataForOperational(cmHandle, + resourceIdentifier, + fieldsQuery, + depthQuery, + acceptParam); + return prepareAndSendResponse(responseEntity, cmHandle); + } + + private String prepareAndSendResponse(final ResponseEntity responseEntity, final String cmHandle) { + if (responseEntity.getStatusCode() == HttpStatus.OK) { + return responseEntity.getBody(); + } else { + throw new ResourceDataNotFound(cmHandle, + "response code : " + responseEntity.getStatusCode() + " message : " + responseEntity.getBody()); + } + } + private String createModuleRequest(final ModuleReference moduleReference) { final var ietfNetconfModuleReferences = new LinkedHashMap<>(); ietfNetconfModuleReferences.put("ietf-netconf-monitoring:identifier", moduleReference.getName()); @@ -138,10 +164,10 @@ public class DmiServiceImpl implements DmiService { moduleRequest = writer.writeValueAsString(ietfNetconfModuleReferences); } catch (final JsonProcessingException e) { log.error("JSON exception occurred when creating the module request for the given module reference {}", - moduleReference.getName()); + moduleReference.getName()); throw new DmiException("Unable to process JSON.", - "JSON exception occurred when creating the module request.", e); + "JSON exception occurred when creating the module request.", e); } return moduleRequest; } -} +} \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java b/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java index adac5e64..499033d3 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/client/SdncRestconfClient.java @@ -43,12 +43,26 @@ public class SdncRestconfClient { * restconf get operation on sdnc. * * @param getResourceUrl sdnc get url + * * @return the response entity */ public ResponseEntity getOperation(final String getResourceUrl) { + return getOperation(getResourceUrl, new HttpHeaders()); + } + + /** + * Overloaded restconf get operation on sdnc with http headers. + * + * @param getResourceUrl sdnc get url + * @param httpHeaders http headers + * + * @return the response entity + */ + public ResponseEntity getOperation(final String getResourceUrl, final HttpHeaders httpHeaders) { final String sdncBaseUrl = sdncProperties.getBaseUrl(); final String sdncRestconfUrl = sdncBaseUrl.concat(getResourceUrl); - final var httpEntity = new HttpEntity<>(configureHttpHeaders()); + httpHeaders.setBasicAuth(sdncProperties.getAuthUsername(), sdncProperties.getAuthPassword()); + final var httpEntity = new HttpEntity<>(httpHeaders); return restTemplate.getForEntity(sdncRestconfUrl, String.class, httpEntity); } @@ -60,7 +74,7 @@ public class SdncRestconfClient { * @return the response entity */ public ResponseEntity postOperationWithJsonData(final String postResourceUrl, - final String jsonData) { + final String jsonData) { final var sdncBaseUrl = sdncProperties.getBaseUrl(); final var sdncRestconfUrl = sdncBaseUrl.concat(postResourceUrl); final var httpEntity = new HttpEntity<>(jsonData, configureHttpHeaders()); @@ -73,4 +87,4 @@ public class SdncRestconfClient { httpHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); return httpHeaders; } -} +} \ No newline at end of file diff --git a/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java b/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java index 0d1c3438..358da590 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java @@ -20,19 +20,23 @@ package org.onap.cps.ncmp.dmi.service.operation; +import java.util.LinkedList; +import java.util.List; +import org.apache.groovy.parser.antlr4.util.StringUtils; +import org.jetbrains.annotations.NotNull; import org.onap.cps.ncmp.dmi.config.DmiConfiguration.SdncProperties; import org.onap.cps.ncmp.dmi.service.client.SdncRestconfClient; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @Component public class SdncOperations { - private static final String TOPOLOGY_URL_TEMPLATE_DATA = - "/rests/data/network-topology:network-topology/topology={topologyId}"; + "/rests/data/network-topology:network-topology/topology={topologyId}"; private static final String TOPOLOGY_URL_TEMPLATE_OPERATIONAL = - "/rests/operations/network-topology:network-topology/topology={topologyId}"; + "/rests/operations/network-topology:network-topology/topology={topologyId}"; private static final String MOUNT_URL_TEMPLATE = "/node={nodeId}/yang-ext:mount"; private static final String GET_SCHEMA_URL = "/ietf-netconf-monitoring:netconf-state/schemas"; private static final String GET_SCHEMA_SOURCES_URL = "/ietf-netconf-monitoring:get-schema"; @@ -52,7 +56,7 @@ public class SdncOperations { this.sdncProperties = sdncProperties; this.sdncRestconfClient = sdncRestconfClient; topologyUrlOperational = - TOPOLOGY_URL_TEMPLATE_OPERATIONAL.replace("{topologyId}", this.sdncProperties.getTopologyId()); + TOPOLOGY_URL_TEMPLATE_OPERATIONAL.replace("{topologyId}", this.sdncProperties.getTopologyId()); topologyUrlData = TOPOLOGY_URL_TEMPLATE_DATA.replace("{topologyId}", this.sdncProperties.getTopologyId()); } @@ -79,11 +83,52 @@ public class SdncOperations { return sdncRestconfClient.postOperationWithJsonData(getYangResourceUrl, moduleProperties); } + /** + * This method fetches the resource data for given node identifier on given resource + * using sdnc client. + * + * @param nodeId network resource identifier + * @param resourceId resource identifier + * @param fieldsValue fields query + * @param depthValue depth query + * @param acceptParam accept parameter + * @return {@code ResponseEntity} response entity + */ + public ResponseEntity getResouceDataForOperational(final String nodeId, + final String resourceId, + final String fieldsValue, + final Integer depthValue, + final String acceptParam) { + final String getResourceDataUrl = prepareResourceDataUrl(nodeId, + resourceId, + getQueryList(fieldsValue, depthValue, "content=all")); + final HttpHeaders httpHeaders = new HttpHeaders(); + if (!StringUtils.isEmpty(acceptParam)) { + httpHeaders.set(HttpHeaders.ACCEPT, acceptParam); + } + return sdncRestconfClient.getOperation(getResourceDataUrl, httpHeaders); + } + + @NotNull + private List getQueryList(final String fieldsValue, final Integer depthValue, final String contentQuery) { + final List queryList = new LinkedList<>(); + if (!StringUtils.isEmpty(fieldsValue)) { + queryList.add("fields=" + fieldsValue); + } + if (depthValue != null) { + queryList.add("depth=" + depthValue); + } + if (!StringUtils.isEmpty(contentQuery)) { + queryList.add(contentQuery); + } + return queryList; + } + + + @NotNull private String prepareGetSchemaUrl(final String nodeId) { - final var topologyMountUrl = topologyUrlData + MOUNT_URL_TEMPLATE; - final String topologyMountUrlWithNodeId = topologyMountUrl.replace("{nodeId}", nodeId); - final String resourceUrl = topologyMountUrlWithNodeId.concat(GET_SCHEMA_URL); - return resourceUrl; + final var getSchemaUrl = addResource(addTopologyDataUrlwithNode(nodeId), GET_SCHEMA_URL); + return getSchemaUrl; } private String prepareGetOperationSchemaUrl(final String nodeId) { @@ -91,4 +136,43 @@ public class SdncOperations { final var topologyMountUrlWithNodeId = topologyMountUrl.replace("{nodeId}", nodeId); return topologyMountUrlWithNodeId.concat(GET_SCHEMA_SOURCES_URL); } -} + + @NotNull + private String prepareResourceDataUrl(final String nodeId, + final String resourceId, + final List queryList) { + final var resourceDataUrl = addQuery(addResource(addTopologyDataUrlwithNode(nodeId), resourceId), queryList); + return resourceDataUrl; + } + + @NotNull + private String addResource(final String url, final String resourceId) { + if (resourceId.startsWith("/")) { + return url.concat(resourceId); + } else { + return url.concat("/" + resourceId); + } + } + + @NotNull + private String addQuery(final String url, final List queryList) { + if (queryList.isEmpty()) { + return url; + } + final StringBuilder urlBuilder = new StringBuilder(url); + urlBuilder.append("?"); + urlBuilder.append(queryList.get(0)); + for (int i = 1; i < queryList.size(); i++) { + urlBuilder.append("&"); + urlBuilder.append(queryList.get(i)); + } + return urlBuilder.toString(); + } + + @NotNull + private String addTopologyDataUrlwithNode(final String nodeId) { + final String topologyMountUrl = topologyUrlData + MOUNT_URL_TEMPLATE; + return topologyMountUrl.replace("{nodeId}", nodeId); + } + +} \ No newline at end of file -- cgit 1.2.3-korg