diff options
author | niamhcore <niamh.core@est.tech> | 2021-07-30 16:25:16 +0100 |
---|---|---|
committer | niamhcore <niamh.core@est.tech> | 2021-08-10 13:33:52 +0100 |
commit | 3139ece993c68ce7e40d166acdd5d9572a3a8a1e (patch) | |
tree | 4a9ee12234815d6f5bc14557d5228c53b66f3b81 /src/main | |
parent | 2270d76e4f33ad231cdae317e88ea1769297cfec (diff) |
Retrieve yang-resources for one or more modules
Updating openapi to add a new rest endpoint
Updating restconf client to support post with json
Adding a ModuleResourceNotFound exception
Adding a test util class
Fixing merge conflict
Refactoring SDNC operations
Issue-ID: CPS-484
Signed-off-by: niamhcore <niamh.core@est.tech>
Change-Id: Id76dfe4cb12053771883e0271153d7bf7cd98548
Diffstat (limited to 'src/main')
8 files changed, 214 insertions, 32 deletions
diff --git a/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java b/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java index a6ec6dfa..49db7d8b 100644 --- a/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java +++ b/src/main/java/org/onap/cps/ncmp/dmi/exception/DmiExceptionHandler.java @@ -46,7 +46,7 @@ public class DmiExceptionHandler { return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception); } - @ExceptionHandler({ModulesNotFoundException.class}) + @ExceptionHandler({ModulesNotFoundException.class, ModuleResourceNotFoundException.class}) public static ResponseEntity<Object> handleNotFoundExceptions(final DmiException exception) { return buildErrorResponse(HttpStatus.NOT_FOUND, exception); } diff --git a/src/main/java/org/onap/cps/ncmp/dmi/exception/ModuleResourceNotFoundException.java b/src/main/java/org/onap/cps/ncmp/dmi/exception/ModuleResourceNotFoundException.java new file mode 100644 index 00000000..65db2712 --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/exception/ModuleResourceNotFoundException.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 ModuleResourceNotFoundException extends DmiException { + + private static final long serialVersionUID = 4764849097602543408L; + + private static final String ERROR_MESSAGE = "Module resource not found for given cmHandle: "; + + /** + * Constructor. + * + * @param cmHandle the cm handle + * @param details the details of the error + */ + public ModuleResourceNotFoundException(final String cmHandle, final String details) { + super(ERROR_MESSAGE + cmHandle, details); + } +} diff --git a/src/main/java/org/onap/cps/ncmp/dmi/model/ModuleReference.java b/src/main/java/org/onap/cps/ncmp/dmi/model/ModuleReference.java new file mode 100644 index 00000000..cb9b7cbb --- /dev/null +++ b/src/main/java/org/onap/cps/ncmp/dmi/model/ModuleReference.java @@ -0,0 +1,37 @@ +/* + * ============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.model; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +/** + * Module Reference. + */ +@Getter +@Setter +@EqualsAndHashCode +public class ModuleReference { + + private String name; + private String revision; +} 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 0e1d3d67..5725f094 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 @@ -20,14 +20,17 @@ package org.onap.cps.ncmp.dmi.rest.controller; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import javax.validation.Valid; 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.rest.api.DmiPluginApi; import org.onap.cps.ncmp.dmi.rest.api.DmiPluginInternalApi; import org.onap.cps.ncmp.dmi.service.DmiService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -40,9 +43,11 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { private DmiService dmiService; - @Autowired - public DmiRestController(final DmiService dmiService) { + private ObjectMapper objectMapper; + + public DmiRestController(final DmiService dmiService, final ObjectMapper objectMapper) { this.dmiService = dmiService; + this.objectMapper = objectMapper; } @Override @@ -52,11 +57,25 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { return new ResponseEntity<>(modulesListAsJson, HttpStatus.OK); } + @Override + public ResponseEntity<Object> retrieveModuleResources(@Valid final ModuleRequestParent moduleRequestParent, + final String cmHandle) { + if (moduleRequestParent.getOperation().toString().equals("read")) { + final var moduleReferenceList = convertRestObjectToJavaApiObject(moduleRequestParent); + final var response = dmiService.getModuleResources(cmHandle, moduleReferenceList); + if (response.isEmpty()) { + return new ResponseEntity<>(response, HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(response, HttpStatus.OK); + } + return new ResponseEntity<>("Unsupported operation", HttpStatus.CONFLICT); + } + /** * This method register given list of cm-handles to ncmp. * * @param cmHandles list of cm-handles - * @return (@code ResponseEntity) response entity + * @return (@ code ResponseEntity) response entity */ public ResponseEntity<String> registerCmHandles(final @Valid CmHandles cmHandles) { final List<String> cmHandlesList = cmHandles.getCmHandles(); @@ -66,4 +85,9 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { dmiService.registerCmHandles(cmHandlesList); return new ResponseEntity<>("cm-handle registered successfully.", HttpStatus.CREATED); } + + private List<ModuleReference> convertRestObjectToJavaApiObject(final ModuleRequestParent moduleRequestParent) { + return objectMapper + .convertValue(moduleRequestParent.getData().getModules(), new TypeReference<List<ModuleReference>>() {}); + } } 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 d9196ecb..aeff3dc6 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 @@ -22,6 +22,7 @@ package org.onap.cps.ncmp.dmi.service; import java.util.List; import org.onap.cps.ncmp.dmi.exception.DmiException; +import org.onap.cps.ncmp.dmi.model.ModuleReference; /** * Interface for handling Dmi plugin Data. @@ -45,4 +46,12 @@ public interface DmiService { */ void registerCmHandles(List<String> cmHandles); + /** + * Get module resources for the given cm handle and modules. + * + * @param cmHandle cmHandle + * @param modules a list of module data + * @return returns all module resources + */ + String getModuleResources(String cmHandle, List<ModuleReference> modules); } 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 990a421e..bf0689ca 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 @@ -23,15 +23,19 @@ package org.onap.cps.ncmp.dmi.service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import lombok.extern.slf4j.Slf4j; +import net.minidev.json.JSONArray; import org.apache.groovy.parser.antlr4.util.StringUtils; 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.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; @@ -39,7 +43,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; - @Service @Slf4j public class DmiServiceImpl implements DmiService { @@ -53,19 +56,19 @@ public class DmiServiceImpl implements DmiService { * Constructor. * * @param dmiPluginProperties dmiPluginProperties - * @param ncmpRestClient ncmpRestClient - * @param objectMapper objectMapper - * @param sdncOperations sdncOperations + * @param ncmpRestClient ncmpRestClient + * @param sdncOperations sdncOperations + * @param objectMapper objectMapper */ @Autowired public DmiServiceImpl(final DmiPluginProperties dmiPluginProperties, - final NcmpRestClient ncmpRestClient, - final ObjectMapper objectMapper, - final SdncOperations sdncOperations) { + final NcmpRestClient ncmpRestClient, + final SdncOperations sdncOperations, final ObjectMapper objectMapper) { this.dmiPluginProperties = dmiPluginProperties; this.ncmpRestClient = ncmpRestClient; this.objectMapper = objectMapper; this.sdncOperations = sdncOperations; + this.objectMapper = objectMapper; } @Override @@ -79,16 +82,33 @@ 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()); } } @Override + public String getModuleResources(final String cmHandle, final List<ModuleReference> moduleReferences) { + final JSONArray getModuleResponses = new JSONArray(); + for (final var moduleReference : moduleReferences) { + final var moduleRequest = createModuleRequest(moduleReference); + final var responseEntity = sdncOperations.getModuleResource(cmHandle, moduleRequest); + if (responseEntity.getStatusCode() == HttpStatus.OK) { + getModuleResponses.add(responseEntity.getBody()); + } 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."); + } + } + return getModuleResponses.toJSONString(); + } + + @Override public void registerCmHandles(final List<String> cmHandles) { final CmHandleOperation cmHandleOperation = new CmHandleOperation(); cmHandleOperation.setDmiPlugin(dmiPluginProperties.getDmiServiceName()); final List<CreatedCmHandle> createdCmHandleList = new ArrayList<>(); - for (final String cmHandle: cmHandles) { + for (final String cmHandle : cmHandles) { final CreatedCmHandle createdCmHandle = new CreatedCmHandle(); createdCmHandle.setCmHandle(cmHandle); createdCmHandleList.add(createdCmHandle); @@ -100,7 +120,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<String> responseEntity = ncmpRestClient.registerCmHandlesWithNcmp(cmHandlesJson); if (!(responseEntity.getStatusCode() == HttpStatus.CREATED)) { @@ -108,4 +128,20 @@ public class DmiServiceImpl implements DmiService { } } + private String createModuleRequest(final ModuleReference moduleReference) { + final var ietfNetconfModuleReferences = new LinkedHashMap<>(); + ietfNetconfModuleReferences.put("ietf-netconf-monitoring:identifier", moduleReference.getName()); + ietfNetconfModuleReferences.put("ietf-netconf-monitoring:version", moduleReference.getRevision()); + final var writer = objectMapper.writer().withRootName("ietf-netconf-monitoring:input"); + final String moduleRequest; + try { + 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()); + throw new DmiException("Unable to process JSON.", + "JSON exception occurred when creating the module request.", e); + } + return moduleRequest; + } } 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 cf7c50a5..adac5e64 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 @@ -30,6 +30,7 @@ import org.springframework.web.client.RestTemplate; @Component public class SdncRestconfClient { + private SdncProperties sdncProperties; private RestTemplate restTemplate; @@ -42,16 +43,34 @@ public class SdncRestconfClient { * restconf get operation on sdnc. * * @param getResourceUrl sdnc get url - * * @return the response entity */ public ResponseEntity<String> getOperation(final String getResourceUrl) { final String sdncBaseUrl = sdncProperties.getBaseUrl(); final String sdncRestconfUrl = sdncBaseUrl.concat(getResourceUrl); + final var httpEntity = new HttpEntity<>(configureHttpHeaders()); + return restTemplate.getForEntity(sdncRestconfUrl, String.class, httpEntity); + } + + /** + * restconf post operation on sdnc. + * + * @param postResourceUrl sdnc post resource url + * @param jsonData json data + * @return the response entity + */ + public ResponseEntity<String> postOperationWithJsonData(final String postResourceUrl, + final String jsonData) { + final var sdncBaseUrl = sdncProperties.getBaseUrl(); + final var sdncRestconfUrl = sdncBaseUrl.concat(postResourceUrl); + final var httpEntity = new HttpEntity<>(jsonData, configureHttpHeaders()); + return restTemplate.postForEntity(sdncRestconfUrl, httpEntity, String.class); + } + + private HttpHeaders configureHttpHeaders() { final var httpHeaders = new HttpHeaders(); httpHeaders.setBasicAuth(sdncProperties.getAuthUsername(), sdncProperties.getAuthPassword()); - httpHeaders.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString()); - final var httpEntity = new HttpEntity<>(httpHeaders); - return restTemplate.getForEntity(sdncRestconfUrl, String.class, httpEntity); + httpHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + return httpHeaders; } } 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 4e4e7217..0d1c3438 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,7 +20,6 @@ package org.onap.cps.ncmp.dmi.service.operation; -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.ResponseEntity; @@ -29,29 +28,32 @@ import org.springframework.stereotype.Component; @Component public class SdncOperations { - private static final String TOPOLOGY_URL_TEMPLATE = "/rests/data/network-topology:network-topology" - + "/topology={topologyId}"; + + private static final String TOPOLOGY_URL_TEMPLATE_DATA = + "/rests/data/network-topology:network-topology/topology={topologyId}"; + private static final String TOPOLOGY_URL_TEMPLATE_OPERATIONAL = + "/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"; private SdncProperties sdncProperties; private SdncRestconfClient sdncRestconfClient; - private final String topologyUrl; - private final String topologyMountUrlTemplate; + private final String topologyUrlData; + private final String topologyUrlOperational; /** - * Constructor for {@code SdncOperations}. This method also manipulates - * url properties. + * Constructor for {@code SdncOperations}. This method also manipulates url properties. * - * @param sdncProperties {@code SdncProperties} + * @param sdncProperties {@code SdncProperties} * @param sdncRestconfClient {@code SdncRestconfClient} */ - public SdncOperations(final SdncProperties sdncProperties, final SdncRestconfClient sdncRestconfClient) { this.sdncProperties = sdncProperties; this.sdncRestconfClient = sdncRestconfClient; - topologyUrl = TOPOLOGY_URL_TEMPLATE.replace("{topologyId}", this.sdncProperties.getTopologyId()); - topologyMountUrlTemplate = topologyUrl + MOUNT_URL_TEMPLATE; + topologyUrlOperational = + TOPOLOGY_URL_TEMPLATE_OPERATIONAL.replace("{topologyId}", this.sdncProperties.getTopologyId()); + topologyUrlData = TOPOLOGY_URL_TEMPLATE_DATA.replace("{topologyId}", this.sdncProperties.getTopologyId()); } /** @@ -65,11 +67,28 @@ public class SdncOperations { return sdncRestconfClient.getOperation(urlWithNodeId); } - @NotNull + /** + * Get module schema. + * + * @param nodeId node ID + * @param moduleProperties module properties + * @return response entity + */ + public ResponseEntity<String> getModuleResource(final String nodeId, final String moduleProperties) { + final String getYangResourceUrl = prepareGetOperationSchemaUrl(nodeId); + return sdncRestconfClient.postOperationWithJsonData(getYangResourceUrl, moduleProperties); + } + private String prepareGetSchemaUrl(final String nodeId) { - final String topologyMountUrl = topologyMountUrlTemplate; + final var topologyMountUrl = topologyUrlData + MOUNT_URL_TEMPLATE; final String topologyMountUrlWithNodeId = topologyMountUrl.replace("{nodeId}", nodeId); final String resourceUrl = topologyMountUrlWithNodeId.concat(GET_SCHEMA_URL); return resourceUrl; } + + private String prepareGetOperationSchemaUrl(final String nodeId) { + final var topologyMountUrl = topologyUrlOperational + MOUNT_URL_TEMPLATE; + final var topologyMountUrlWithNodeId = topologyMountUrl.replace("{nodeId}", nodeId); + return topologyMountUrlWithNodeId.concat(GET_SCHEMA_SOURCES_URL); + } } |