diff options
-rw-r--r-- | docs/_static/cps-r9-ncmp-dmi-plugin-interface-diagram.png | bin | 0 -> 24561 bytes | |||
-rw-r--r-- | docs/architecture.rst | 39 | ||||
-rw-r--r-- | docs/design.rst | 24 | ||||
-rw-r--r-- | docs/index.rst | 17 | ||||
-rw-r--r-- | docs/modeling.rst | 10 | ||||
-rw-r--r-- | docs/openapi/components.yml | 74 | ||||
-rw-r--r-- | docs/openapi/openapi.yml | 12 | ||||
-rw-r--r-- | src/main/java/org/onap/cps/ncmp/dmi/rest/controller/DmiRestController.java | 61 | ||||
-rw-r--r-- | src/main/java/org/onap/cps/ncmp/dmi/service/DmiService.java | 24 | ||||
-rw-r--r-- | src/main/java/org/onap/cps/ncmp/dmi/service/DmiServiceImpl.java | 29 | ||||
-rw-r--r-- | src/main/java/org/onap/cps/ncmp/dmi/service/operation/SdncOperations.java | 47 | ||||
-rw-r--r-- | src/main/resources/application.yml | 2 | ||||
-rw-r--r-- | src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy | 38 | ||||
-rw-r--r-- | src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy | 23 | ||||
-rw-r--r-- | src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy | 33 | ||||
-rw-r--r-- | src/test/resources/GetModules.json | 1 |
16 files changed, 220 insertions, 214 deletions
diff --git a/docs/_static/cps-r9-ncmp-dmi-plugin-interface-diagram.png b/docs/_static/cps-r9-ncmp-dmi-plugin-interface-diagram.png Binary files differnew file mode 100644 index 00000000..6c5903d2 --- /dev/null +++ b/docs/_static/cps-r9-ncmp-dmi-plugin-interface-diagram.png diff --git a/docs/architecture.rst b/docs/architecture.rst index 65125764..65e10d45 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -6,8 +6,6 @@ DMI Plugin Architecture ####################### -.. warning:: draft - .. toctree:: :maxdepth: 1 @@ -15,14 +13,9 @@ DMI Plugin Architecture High Level Component Definition and Architectural Relationships =============================================================== -The DMI plugin provides a gateway for registration of CM Handles within CPS - -Project implementation proposal page describing scope is here: -`CPS-390 Spike: Define and Agree DMI Plugin REST Interface <https://wiki.onap.org/display/DW/CPS-390+Spike%3A+Define+and+Agree+DMI+Plugin+REST+Interface>`_ +The DMI plugin provides a gateway for registration and syncing of CM Handles within CPS. -This page reflects the state for Istanbul-R9 release. - -.. image:: _static/dmi-plugin-r9-arch-diagram.PNG +.. image:: _static/cps-r9-ncmp-dmi-plugin-interface-diagram.png API definitions =============== @@ -30,11 +23,33 @@ API definitions The DMI plugin provides following interfaces. .. list-table:: - :header-rows: 0 + :header-rows: 1 * - Interface name - Interface definition - Interface capabilities - Protocol - -The DMI plugin Basic Concepts are described in :doc:`modeling`. + * - CPS-E-05 + - Provides external clients with xNF data access and module information + - - Create data + - Delete data + - Update data + - Read data + - Query data + - Query module references + - REST + * - CPS-NCMP-I-01 + - DMI Plugin Inventory + - - Register Plug-in CM-Handles + - REST + * - DMI-I-01 + - Provides NCMP with xNF data access and module information + - - Create data + - Delete data + - Update data + - Read data + - Query data + - Query module references + - REST + +More details on the CPS interface CPS-E-05 which is responsible for the DMI Plugin can be found on the `CPS Architecture Page <https://docs.onap.org/projects/onap-cps/en/latest/architecture.html>`_.
\ No newline at end of file diff --git a/docs/design.rst b/docs/design.rst index e65c5aed..708feeb3 100644 --- a/docs/design.rst +++ b/docs/design.rst @@ -9,8 +9,6 @@ DMI Plugin Design ################# -.. warning:: draft - .. toctree:: :maxdepth: 1 @@ -19,10 +17,10 @@ Offered APIs The DMI Plugin supports the public APIs listed in the link below: -:download:`DMI Rest OpenApi Specification <openapi/openapi.yml>` +:download:`DMI Rest OpenApi Specification <openapi/openapi.yaml>` -Exposed API ------------ +View Offered APIs +----------------- The standard for API definition in the RESTful API world is the OpenAPI Specification (OAS). The OAS 3, which is based on the original "Swagger Specification", is being widely used in API developments. @@ -31,10 +29,16 @@ Specification can be accessed using following URI: .. code-block:: bash - “http://<hostname>:<port>/v3/api-docs?group=dmi-plugin-docket” + http://<hostname>:<port>/v3/api-docs?group=dmi-plugin-docket + +Additionally, the Swagger User Interface can be found at the following URI. The component may be changed between CPS-Core +and CPS-NCMP using the drop down table in the top right: + +.. code-block:: bash + + http://<hostname>:<port>/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/ -DMI Plugin CM Handles -===================== +Consumed APIs +============= -Several DMI Plugin APIs use the cm-handle parameter. -The DMI Plugin CM Handles are described in detail in :doc:`dmi-plugin-cm-handle`. +- SDNC: REST based interface exposed by the SDNC client. This is used to retrieve the yang resources and modules for CPS. diff --git a/docs/index.rst b/docs/index.rst index 54da6148..7d1fcf37 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,34 +8,27 @@ .. THIS IS USED INTERNALLY IN CPS ONLY .. _dmi-framework-doc: -DMI Plugin Documentation for the Istanbul-R9 Release +DMI-Plugin Documentation for the Istanbul-R9 Release ---------------------------------------------------- -.. warning:: draft - .. toctree:: :maxdepth: 1 overview.rst architecture.rst + admin-guide.rst design.rst modeling.rst deployment.rst release-notes.rst -CPS-Core Documentation for the Istanbul-R9 Release +CPS-NCMP Documentation for the Istanbul-R9 Release --------------------------------------------------------- -.. toctree:: - :maxdepth: 3 - -* `CPS Core(placeholder) `_ +* `CPS-NCMP <https://docs.onap.org/projects/onap-cps/en/latest/index.html>`_ CPS-Temporal Documentation for the Istanbul-R9 Release ------------------------------------------------------ -.. toctree:: - :maxdepth: 1 - -* `CPS Temporal(placeholder) `_
\ No newline at end of file +* `CPS-Temporal <https://docs.onap.org/projects/onap-cps-cps-temporal/en/latest/index.html>`_ diff --git a/docs/modeling.rst b/docs/modeling.rst index 63f25b7c..fdfcef06 100644 --- a/docs/modeling.rst +++ b/docs/modeling.rst @@ -6,13 +6,9 @@ DMI Plugin Modeling ################### -.. warning:: draft - .. toctree:: :maxdepth: 1 -Basic Concepts -============== - -.. image:: _static/dmi-plugin-modeling-concepts.png - :alt: Basic entities relationship +The DMI Plugin acts as a proxy and as such does not have its own data model. For more information on the data which +is passed through the DMI Plugin, please refer to the `NCMP Modeling Section <https://docs.onap.org/projects/onap-cps/en/latest/modeling.html#ncmp-modeling>`_ +of the `CPS Modeling Page <https://docs.onap.org/projects/onap-cps/en/latest/modeling.html>`_. diff --git a/docs/openapi/components.yml b/docs/openapi/components.yml index 736639d8..30e5987f 100644 --- a/docs/openapi/components.yml +++ b/docs/openapi/components.yml @@ -19,14 +19,15 @@ components: items: type: string - DmiModuleReadRequestBody: + ModuleReferencesRequest: + type: object + properties: + cmHandleProperties: + $ref: '#/components/schemas/cmHandleProperties' + + ModuleResourcesReadRequest: type: object properties: - operation: - type: string - enum: [read] - dataType: - type: string data: type: object properties: @@ -36,14 +37,11 @@ components: type: object properties: name: - type: string + $ref: '#/components/schemas/name' revision: - type: string + $ref: '#/components/schemas/revision' cmHandleProperties: - type: object - additionalProperties: - type: string - example: system-001 + $ref: '#/components/schemas/cmHandleProperties' ModuleSet: type: object @@ -56,7 +54,7 @@ components: moduleName: type: string revision: - type: string + $ref: '#/components/schemas/revision' namespace: type: string @@ -73,7 +71,7 @@ components: moduleName: type: string revision: - type: string + $ref: '#/components/schemas/revision' DataAccessReadRequest: type: object @@ -82,9 +80,7 @@ components: type: string enum: [ read ] cmHandleProperties: - type: object - additionalProperties: - type: string + $ref: '#/components/schemas/cmHandleProperties' DataAccessWriteRequest: type: object @@ -97,9 +93,21 @@ components: data: type: string cmHandleProperties: - type: object - additionalProperties: - type: string + $ref: '#/components/schemas/cmHandleProperties' + + cmHandleProperties: + type: object + additionalProperties: + type: string + example: {"prop1":"value1","prop2":"value2"} + + name: + type: string + example: someName + + revision: + type: string + example: someRevision responses: NotFound: @@ -174,19 +182,21 @@ components: type: string enum: [ application/json, application/yang-data+json ] - fieldsParamInQuery: - name: fields + optionsParamInQuery: + name: options in: query - description: Fields parameter to filter resource + description: options parameter in query, it is mandatory to wrap key(s)=value(s) in parenthesis'()'. required: false schema: type: string - - depthParamInQuery: - name: depth - in: query - description: Depth parameter for response - required: false - schema: - type: integer - minimum: 1
\ No newline at end of file + allowReserved: true + examples: + sample1: + value: + options: (key1=value1,key2=value2) + sample2: + value: + options: (key1=value1,key2=value1/value2) + sample3: + value: + options: (key1=10,key2=value2,key3=[val31,val32])
\ No newline at end of file diff --git a/docs/openapi/openapi.yml b/docs/openapi/openapi.yml index 1e7b38c9..83c05abb 100644 --- a/docs/openapi/openapi.yml +++ b/docs/openapi/openapi.yml @@ -37,7 +37,7 @@ paths: - dmi-plugin summary: Get all modules for cm handle description: Get all modules for given cm handle - operationId: getModulesForCmHandle + operationId: getModuleReferences parameters: - name: cmHandle in: path @@ -50,7 +50,7 @@ paths: content: application/json: schema: - $ref: 'components.yml#/components/schemas/DataAccessReadRequest' + $ref: 'components.yml#/components/schemas/ModuleReferencesRequest' responses: '200': description: OK @@ -113,7 +113,7 @@ paths: content: application/json: schema: - $ref: 'components.yml#/components/schemas/DmiModuleReadRequestBody' + $ref: 'components.yml#/components/schemas/ModuleResourcesReadRequest' responses: '200': description: OK @@ -139,8 +139,7 @@ paths: - $ref: 'components.yml#/components/parameters/cmHandleInPath' - $ref: 'components.yml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yml#/components/parameters/acceptParamInHeader' - - $ref: 'components.yml#/components/parameters/fieldsParamInQuery' - - $ref: 'components.yml#/components/parameters/depthParamInQuery' + - $ref: 'components.yml#/components/parameters/optionsParamInQuery' requestBody: description: Operational body content: @@ -168,8 +167,7 @@ paths: - $ref: 'components.yml#/components/parameters/cmHandleInPath' - $ref: 'components.yml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yml#/components/parameters/acceptParamInHeader' - - $ref: 'components.yml#/components/parameters/fieldsParamInQuery' - - $ref: 'components.yml#/components/parameters/depthParamInQuery' + - $ref: 'components.yml#/components/parameters/optionsParamInQuery' requestBody: description: Operational body content: 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 2c2536ff..b17280ae 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,18 +20,16 @@ package org.onap.cps.ncmp.dmi.rest.controller; -import static org.onap.cps.ncmp.dmi.model.DmiModuleReadRequestBody.OperationEnum.READ; - import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import javax.validation.Valid; -import javax.validation.constraints.Min; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.dmi.model.CmHandles; import org.onap.cps.ncmp.dmi.model.DataAccessReadRequest; import org.onap.cps.ncmp.dmi.model.DataAccessWriteRequest; -import org.onap.cps.ncmp.dmi.model.DmiModuleReadRequestBody; +import org.onap.cps.ncmp.dmi.model.ModuleReferencesRequest; +import org.onap.cps.ncmp.dmi.model.ModuleResourcesReadRequest; import org.onap.cps.ncmp.dmi.model.ModuleSet; import org.onap.cps.ncmp.dmi.model.YangResources; import org.onap.cps.ncmp.dmi.rest.api.DmiPluginApi; @@ -59,8 +57,8 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { } @Override - public ResponseEntity<ModuleSet> getModulesForCmHandle(final String cmHandle, - final @Valid DataAccessReadRequest body) { + public ResponseEntity<ModuleSet> getModuleReferences(final String cmHandle, + final @Valid ModuleReferencesRequest body) { // For onap-dmi-plugin we don't need cmHandleProperties, so DataAccessReadRequest is not used. final var moduleSet = dmiService.getModulesForCmHandle(cmHandle); return ResponseEntity.ok(moduleSet); @@ -68,14 +66,11 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { @Override public ResponseEntity<YangResources> retrieveModuleResources( - final @Valid DmiModuleReadRequestBody dmiModuleReadRequestBody, - final String cmHandle) { - if (READ.equals(dmiModuleReadRequestBody.getOperation())) { - final var moduleReferenceList = convertRestObjectToJavaApiObject(dmiModuleReadRequestBody); - final var response = dmiService.getModuleResources(cmHandle, moduleReferenceList); - return new ResponseEntity<>(response, HttpStatus.OK); - } - return new ResponseEntity<>(HttpStatus.CONFLICT); + final @Valid ModuleResourcesReadRequest moduleResourcesReadRequest, + final String cmHandle) { + final List<ModuleReference> moduleReferences = convertRestObjectToJavaApiObject(moduleResourcesReadRequest); + final YangResources yangResources = dmiService.getModuleResources(cmHandle, moduleReferences); + return new ResponseEntity<>(yangResources, HttpStatus.OK); } /** @@ -114,64 +109,58 @@ public class DmiRestController implements DmiPluginApi, DmiPluginInternalApi { /** * This method fetches the resource for given cm handle using pass through operational. It filters the response on - * the basis of depth and field query parameters and returns response. + * the basis of options query parameters and returns response. * * @param resourceIdentifier resource identifier to fetch data * @param cmHandle cm handle identifier * @param dataAccessReadRequest data Access Read Request - * @param accept accept header parameter - * @param fields fields to filter the response data - * @param depth depth parameter for the response + * @param acceptParamInHeader accept header parameter + * @param optionsParamInQuery options query parameter * @return {@code ResponseEntity} response entity */ @Override public ResponseEntity<Object> getResourceDataOperationalForCmHandle(final String resourceIdentifier, final String cmHandle, final @Valid DataAccessReadRequest dataAccessReadRequest, - final String accept, - final @Valid String fields, - final @Min(1) @Valid Integer depth) { + final String acceptParamInHeader, + final @Valid String optionsParamInQuery) { final var modulesListAsJson = dmiService.getResourceDataOperationalForCmHandle(cmHandle, resourceIdentifier, - accept, - fields, - depth, + acceptParamInHeader, + optionsParamInQuery, dataAccessReadRequest.getCmHandleProperties()); return ResponseEntity.ok(modulesListAsJson); } /** * This method fetches the resource for given cm handle using pass through running. It filters the response on the - * basis of depth and field query parameters and returns response. + * basis of options query parameters and returns response. * * @param resourceIdentifier resource identifier to fetch data * @param cmHandle cm handle identifier * @param dataAccessReadRequest data Access Read Request - * @param accept accept header parameter - * @param fields fields to filter the response data - * @param depth depth parameter for the response + * @param acceptParamInHeader accept header parameter + * @param optionsParamInQuery options query parameter * @return {@code ResponseEntity} response entity */ @Override public ResponseEntity<Object> getResourceDataPassthroughRunningForCmHandle(final String resourceIdentifier, final String cmHandle, final @Valid DataAccessReadRequest dataAccessReadRequest, - final String accept, - final @Valid String fields, - final @Min(1) @Valid Integer depth) { + final String acceptParamInHeader, + final @Valid String optionsParamInQuery) { final var modulesListAsJson = dmiService.getResourceDataPassThroughRunningForCmHandle(cmHandle, resourceIdentifier, - accept, - fields, - depth, + acceptParamInHeader, + optionsParamInQuery, dataAccessReadRequest.getCmHandleProperties()); return ResponseEntity.ok(modulesListAsJson); } private List<ModuleReference> convertRestObjectToJavaApiObject( - final DmiModuleReadRequestBody dmiModuleSchemaReadRequestBody) { + final ModuleResourcesReadRequest moduleResourcesReadRequest) { return objectMapper - .convertValue(dmiModuleSchemaReadRequestBody.getData().getModules(), + .convertValue(moduleResourcesReadRequest.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 753810a2..c6910399 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 @@ -61,40 +61,36 @@ public interface DmiService { /** * This method use to fetch the resource data from cm handle for datastore pass-through operational and resource - * Identifier. Fields and depths query parameter are used to filter the response from network resource. + * Identifier. Options 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 acceptParamInHeader accept header parameter + * @param optionsParamInQuery options 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, + String acceptParamInHeader, + String optionsParamInQuery, Map<String, String> cmHandlePropertyMap); /** * This method use to fetch the resource data from cm handle for datastore pass-through running and resource - * Identifier. Fields and depths query parameter are used to filter the response from network resource. + * Identifier. Options 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 acceptParamInHeader accept header parameter + * @param optionsParamInQuery options query parameter * @param cmHandlePropertyMap cm handle properties * @return {@code Object} response from network function */ Object getResourceDataPassThroughRunningForCmHandle(@NotNull String cmHandle, @NotNull String resourceIdentifier, - String acceptParam, - String fieldsQuery, - Integer depthQuery, + String acceptParamInHeader, + String optionsParamInQuery, Map<String, String> cmHandlePropertyMap); /** 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 844cc4de..b66e5c1b 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 @@ -60,13 +60,12 @@ public class DmiServiceImpl implements DmiService { private NcmpRestClient ncmpRestClient; private ObjectMapper objectMapper; private DmiPluginProperties dmiPluginProperties; - private static final String CONTENT_QUERY_PASSTHROUGH_OPERATIONAL = "content=all"; - private static final String CONTENT_QUERY_PASSTHROUGH_RUNNING = "content=config"; + private static final String RESTCONF_CONTENT_PASSTHROUGH_OPERATIONAL_QUERY_PARAM = "content=all"; + private static final String REST_CONF_CONTENT_PASSTHROUGH_RUNNING_QUERY_PARAM = "content=config"; private static final String RESPONSE_CODE = "response code : "; private static final String MESSAGE = " message : "; private static final String IETF_NETCONF_MONITORING_OUTPUT = "ietf-netconf-monitoring:output"; - /** * Constructor. * @@ -178,34 +177,30 @@ 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 String acceptParamInHeader, + final String optionsParamInQuery, final Map<String, String> cmHandlePropertyMap) { // not using cmHandlePropertyMap of onap dmi impl , other dmi impl might use this. final ResponseEntity<String> responseEntity = sdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceIdentifier, - fieldsQuery, - depthQuery, - acceptParam, - CONTENT_QUERY_PASSTHROUGH_OPERATIONAL); + optionsParamInQuery, + acceptParamInHeader, + RESTCONF_CONTENT_PASSTHROUGH_OPERATIONAL_QUERY_PARAM); return prepareAndSendResponse(responseEntity, cmHandle); } @Override public Object getResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle, final @NotNull String resourceIdentifier, - final String acceptParam, - final String fieldsQuery, - final Integer depthQuery, + final String acceptParamInHeader, + final String optionsParamInQuery, final Map<String, String> cmHandlePropertyMap) { // not using cmHandlePropertyMap of onap dmi impl , other dmi impl might use this. final ResponseEntity<String> responseEntity = sdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceIdentifier, - fieldsQuery, - depthQuery, - acceptParam, - CONTENT_QUERY_PASSTHROUGH_RUNNING); + optionsParamInQuery, + acceptParamInHeader, + REST_CONF_CONTENT_PASSTHROUGH_RUNNING_QUERY_PARAM); return prepareAndSendResponse(responseEntity, cmHandle); } 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 73503d23..98371bf9 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,6 +20,7 @@ package org.onap.cps.ncmp.dmi.service.operation; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; import org.apache.groovy.parser.antlr4.util.StringUtils; @@ -92,23 +93,22 @@ public class SdncOperations { * * @param nodeId network resource identifier * @param resourceId resource identifier - * @param fieldsValue fields query - * @param depthValue depth query - * @param acceptParam accept parameter + * @param optionsParamInQuery fields query + * @param acceptParamInHeader accept parameter + * @param restconfContentQueryParam restconf content query param * @return {@code ResponseEntity} response entity */ public ResponseEntity<String> getResouceDataForOperationalAndRunning(final String nodeId, final String resourceId, - final String fieldsValue, - final Integer depthValue, - final String acceptParam, - final String contentQuery) { + final String optionsParamInQuery, + final String acceptParamInHeader, + final String restconfContentQueryParam) { final String getResourceDataUrl = prepareResourceDataUrl(nodeId, resourceId, - getQueryList(fieldsValue, depthValue, contentQuery)); + buildQueryParamList(optionsParamInQuery, restconfContentQueryParam)); final HttpHeaders httpHeaders = new HttpHeaders(); - if (!StringUtils.isEmpty(acceptParam)) { - httpHeaders.set(HttpHeaders.ACCEPT, acceptParam); + if (!StringUtils.isEmpty(acceptParamInHeader)) { + httpHeaders.set(HttpHeaders.ACCEPT, acceptParamInHeader); } return sdncRestconfClient.getOperation(getResourceDataUrl, httpHeaders); } @@ -131,20 +131,25 @@ public class SdncOperations { } @NotNull - private List<String> getQueryList(final String fieldsValue, final Integer depthValue, final String contentQuery) { - final List<String> 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); + private List<String> buildQueryParamList(final String optionsParamInQuery, final String restconfContentQueryParam) { + final List<String> queryParamAsList = getOptionsParamAsList(optionsParamInQuery); + queryParamAsList.add(restconfContentQueryParam); + return queryParamAsList; + } + + private List<String> getOptionsParamAsList(final String optionsParamInQuery) { + final List<String> queryParamAsList = new LinkedList<>(); + if (!StringUtils.isEmpty(optionsParamInQuery)) { + final String tempQuery = stripParenthesisFromOptionsQuery(optionsParamInQuery); + queryParamAsList.addAll(Arrays.asList(tempQuery.split(","))); } - return queryList; + return queryParamAsList; } + @NotNull + private String stripParenthesisFromOptionsQuery(final String optionsParamInQuery) { + return optionsParamInQuery.substring(1, optionsParamInQuery.length() - 1); + } @NotNull private String prepareGetSchemaUrl(final String nodeId) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0ea666e1..1a3b843f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -54,7 +54,7 @@ management: cps-core: baseUrl: http://${CPS_CORE_HOST}:${CPS_CORE_PORT} - dmiRegistrationUrl : /ncmp/v1/ch + dmiRegistrationUrl : /ncmpInventory/v1/ch auth: username: ${CPS_CORE_USERNAME} password: ${CPS_CORE_PASSWORD} diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy index 256db4e9..ac78928d 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/rest/controller/DmiRestControllerSpec.groovy @@ -65,7 +65,7 @@ class DmiRestControllerSpec extends Specification { given: 'REST endpoint for getting all modules' def getModuleUrl = "$basePathV1/ch/node1/modules" and: 'get modules for cm-handle returns a json' - def json = '{"operation" : "read", "cmHandleProperties" : {}}' + def json = '{"cmHandleProperties" : {}}' def moduleSetSchema = new ModuleSetSchemas(namespace:'some-namespace', moduleName:'some-moduleName', revision:'some-revision') @@ -101,7 +101,7 @@ class DmiRestControllerSpec extends Specification { given: 'REST endpoint for getting all modules' def getModuleUrl = "$basePathV1/ch/node1/modules" and: 'given request body and get modules for cm-handle throws #exceptionClass' - def json = '{"operation" : "read", "cmHandleProperties" : {}}' + def json = '{"cmHandleProperties" : {}}' mockDmiService.getModulesForCmHandle('node1') >> { throw Mock(exceptionClass) } when: 'post is invoked' def response = mvc.perform( post(getModuleUrl) @@ -150,7 +150,7 @@ class DmiRestControllerSpec extends Specification { def 'Retrieve module resources.'() { given: 'an endpoint and json data' def getModulesEndpoint = "$basePathV1/ch/some-cm-handle/moduleResources" - String jsonData = getJsonDataForGetModules('read') + String jsonData = TestUtils.getResourceFileContent('GetModules.json') and: 'the DMI service returns the yang resources' ModuleReference moduleReference1 = new ModuleReference(name: 'ietf-yang-library', revision: '2016-06-21') ModuleReference moduleReference2 = new ModuleReference(name: 'nc-notifications', revision: '2008-07-14') @@ -169,22 +169,10 @@ class DmiRestControllerSpec extends Specification { response.getContentAsString() == '[{"yangSource":"\\"some-data\\"","moduleName":"NAME","revision":"REVISION"}]' } - def 'Retrieve module resources with invalid operation.'() { - given: 'an endpoint and json data with invalid operation value' - def getModulesEndpoint = "$basePathV1/ch/some-cm-handle/moduleResources" - def jsonData = getJsonDataForGetModules('invalid operation') - when: 'get module resource api is invoked' - def response = mvc.perform(post(getModulesEndpoint) - .contentType(MediaType.APPLICATION_JSON) - .content(jsonData)).andReturn().response - then: 'a conflict status is returned' - response.status == HttpStatus.CONFLICT.value() - } - def 'Retrieve module resources with exception handling.'() { given: 'an endpoint and json data' def getModulesEndpoint = "$basePathV1/ch/some-cm-handle/moduleResources" - String jsonData = getJsonDataForGetModules('read') + String jsonData = TestUtils.getResourceFileContent('GetModules.json') and: 'the service method is invoked to get module resources and throws an exception' mockDmiService.getModuleResources('some-cm-handle', _) >> { throw Mock(ModuleResourceNotFoundException.class) } when: 'get module resource api is invoked' @@ -198,7 +186,7 @@ class DmiRestControllerSpec extends Specification { def 'Get resource data for pass-through operational from cm handle.'() { given: 'Get resource data url' def getResourceDataForCmHandleUrl = "${basePathV1}/ch/some-cmHandle/data/ds/ncmp-datastore:passthrough-operational" + - "?resourceIdentifier=abc/xyz&fields=myfields&depth=5" + "?resourceIdentifier=parent/child&options=(fields=myfields,depth=5)" def json = '{"cmHandleProperties" : { "prop1" : "value1", "prop2" : "value2"}}' when: 'get resource data PUT api is invoked' def response = mvc.perform( @@ -209,10 +197,9 @@ class DmiRestControllerSpec extends Specification { response.status == HttpStatus.OK.value() and: 'dmi service called with get resource data for cm handle' 1 * mockDmiService.getResourceDataOperationalForCmHandle('some-cmHandle', - 'abc/xyz', + 'parent/child', 'application/json', - 'myfields', - 5, + '(fields=myfields,depth=5)', ['prop1': 'value1', 'prop2': 'value2']) } @@ -243,7 +230,7 @@ class DmiRestControllerSpec extends Specification { def 'Get resource data for pass-through running from cm handle with #scenario value in resource identifier param.'() { given: 'Get resource data url' def getResourceDataForCmHandleUrl = "${basePathV1}/ch/some-cmHandle/data/ds/ncmp-datastore:passthrough-running" + - "?resourceIdentifier="+resourceIdentifier+"&fields=testFields&depth=5" + "?resourceIdentifier="+resourceIdentifier+"&options=(fields=myfields,depth=5)" def json = '{"cmHandleProperties" : { "prop1" : "value1", "prop2" : "value2"}}' when: 'get resource data PUT api is invoked' def response = mvc.perform( @@ -256,8 +243,7 @@ class DmiRestControllerSpec extends Specification { 1 * mockDmiService.getResourceDataPassThroughRunningForCmHandle('some-cmHandle', resourceIdentifier, 'application/json', - 'testFields', - 5, + '(fields=myfields,depth=5)', ['prop1':'value1', 'prop2':'value2']) where: 'tokens are used in the resource identifier parameter' scenario | resourceIdentifier @@ -269,10 +255,4 @@ class DmiRestControllerSpec extends Specification { '? needs to be encoded as %3F' | 'idWith%3F' } - - def getJsonDataForGetModules(operation) { - def jsonData = TestUtils.getResourceFileContent('GetModules.json') - return jsonData.replace('${operation-for-test}', operation) - } - } diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy index 4c6bc750..9325d59b 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/DmiServiceImplSpec.groovy @@ -210,15 +210,14 @@ class DmiServiceImplSpec extends Specification { def cmHandle = 'testCmHandle' def resourceId = 'testResourceId' def acceptHeaderParam = 'testAcceptParam' - def fieldsParam = 'testFields' - def depthParam = 10 + def optionsParam = '(fields=x/y/z,depth=10,test=abc)' def contentQuery = 'content=all' and: 'sdnc operation returns OK response' - mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) + mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, optionsParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) when: 'get resource data from cm handles service method invoked' def response = objectUnderTest.getResourceDataOperationalForCmHandle(cmHandle, resourceId, acceptHeaderParam, - fieldsParam, depthParam, null) + optionsParam, null) then: 'response have expected json' response == 'response json' } @@ -228,14 +227,13 @@ class DmiServiceImplSpec extends Specification { def cmHandle = 'testCmHandle' def resourceId = 'testResourceId' def acceptHeaderParam = 'testAcceptParam' - def fieldsParam = 'testFields' - def depthParam = 10 + def optionsParam = '(fields=x/y/z,depth=10,test=abc)' and: 'sdnc operation returns "NOT_FOUND" response' - mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, depthParam, acceptHeaderParam, _ as String) >> new ResponseEntity<>(HttpStatus.NOT_FOUND) + mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, optionsParam, acceptHeaderParam, _ as String) >> new ResponseEntity<>(HttpStatus.NOT_FOUND) when: 'get resource data from cm handles service method invoked' objectUnderTest.getResourceDataOperationalForCmHandle(cmHandle, resourceId, acceptHeaderParam, - fieldsParam, depthParam, null) + optionsParam, null) then: 'resource data not found' thrown(ResourceDataNotFound.class) } @@ -245,16 +243,15 @@ class DmiServiceImplSpec extends Specification { def cmHandle = 'testCmHandle' def resourceId = 'testResourceId' def acceptHeaderParam = 'testAcceptParam' - def fieldsParam = 'testFields' - def depthParam = 10 + def optionsParam = '(fields=x/y/z,depth=10,test=abc)' def contentQuery = 'content=config' and: 'sdnc operation returns OK response' - mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, fieldsParam, - depthParam, acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) + mockSdncOperations.getResouceDataForOperationalAndRunning(cmHandle, resourceId, optionsParam, + acceptHeaderParam, contentQuery) >> new ResponseEntity<>('response json', HttpStatus.OK) when: 'get resource data from cm handles service method invoked' def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle(cmHandle, resourceId, acceptHeaderParam, - fieldsParam, depthParam, null) + optionsParam, null) then: 'response have expected json' response == 'response json' } diff --git a/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy b/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy index 95a9c0a7..4411971a 100644 --- a/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy +++ b/src/test/groovy/org/onap/cps/ncmp/dmi/service/operation/SdncOperationsSpec.groovy @@ -61,10 +61,10 @@ class SdncOperationsSpec extends Specification { def 'Get resource data from node to SDNC.'() { given: 'expected url, topology-id, sdncOperation object' - def expectedUrl = '/rests/data/network-topology:network-topology/topology=test-topology/node=node1/yang-ext:mount/testResourceId?fields=testFields&depth=10&content=testContent' + def expectedUrl = '/rests/data/network-topology:network-topology/topology=test-topology/node=node1/yang-ext:mount/testResourceId?a=1&b=2&content=testContent' when: 'called get modules from node' objectUnderTest.getResouceDataForOperationalAndRunning('node1', 'testResourceId', - 'testFields', 10, 'testAcceptParam', 'content=testContent') + '(a=1,b=2)', 'testAcceptParam', 'content=testContent') then: 'the get operation is executed with the correct URL' 1 * mockSdncRestClient.getOperation(expectedUrl, _ as HttpHeaders) } @@ -77,4 +77,33 @@ class SdncOperationsSpec extends Specification { then: 'the post operation is executed with the correct URL and data' 1 * mockSdncRestClient.postOperationWithJsonData(expectedUrl, 'requestData', _ as HttpHeaders) } + + def 'build query param list for SDNC where options contains a #scenario'() { + when: 'build query param list is called with #scenario' + def result = objectUnderTest.buildQueryParamList(optionsParamInQuery,'d=4') + then: 'result equals to expected result' + result == expectedResult + where: 'following parameters are used' + scenario | optionsParamInQuery || expectedResult + 'single key-value pair' | '(a=x)' || ['a=x','d=4'] + 'multiple key-value pairs'| '(a=x,b=y,c=z)' || ['a=x','b=y','c=z','d=4'] + '/ as special char' | '(a=x,b=y,c=t/z)' || ['a=x','b=y','c=t/z','d=4'] + '" as special char' | '(a=x,b=y,c="z")' || ['a=x','b=y','c="z"','d=4'] + '[] as special char' | '(a=x,b=y,c=[z])' || ['a=x','b=y','c=[z]','d=4'] + '= in value' | '(a=(x=y),b=x=y)' || ['a=(x=y)','b=x=y','d=4'] + } + + def 'options parameters contains a comma #scenario'() { + // https://jira.onap.org/browse/CPS-719 + when: 'build query param list is called with #scenario' + def result = objectUnderTest.buildQueryParamList(optionsParamInQuery,'d=4') + then: 'expect 2 elements from options +1 from content query param (2+1) = 3 elements' + def expectedNoOfElements = 3 + and: 'results contains more elements than expected' + result.size() > expectedNoOfElements + where: 'following parameters are used' + scenario | optionsParamInQuery + '"," in value' | '(a=(x,y),b=y)' + '"," in string value' | '(a="x,y",b=y)' + } } diff --git a/src/test/resources/GetModules.json b/src/test/resources/GetModules.json index 98e41672..57f5aefd 100644 --- a/src/test/resources/GetModules.json +++ b/src/test/resources/GetModules.json @@ -1,5 +1,4 @@ { - "operation": "${operation-for-test}", "data": { "modules": [ { |