api:\r
cps-base-path: /cps/api\r
ncmp-base-path: /ncmp\r
+ ncmp-inventory-base-path: /ncmpInventory\r
\r
spring:\r
main:\r
url: /api-docs/cps-core/openapi.yaml\r
- name: cps-ncmp\r
url: /api-docs/cps-ncmp/openapi.yaml\r
+ - name: cps-ncmp-inventory\r
+ url: /api-docs/cps-ncmp/openapi-inventory.yaml\r
+\r
\r
security:\r
# comma-separated uri patterns which do not require authorization\r
- permit-uri: /manage/**,/swagger-ui/**,/swagger-resources/**,/api-docs\r
+ permit-uri: /manage/**,/swagger-ui.html,/swagger-ui/**,/swagger-resources/**,/api-docs/**\r
auth:\r
username: ${CPS_USERNAME}\r
password: ${CPS_PASSWORD}\r
schema:
type: string
default: /
- resourceIdentifierInPath:
+ resourceIdentifierInQuery:
name: resourceIdentifier
- in: path
- description: Resource identifier to get/set the resource data
+ in: query
+ description: The format of resource identifier depend on the associated DMI Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but it can really be anything.
required: true
+ allowReserved: true
schema:
type: string
+ examples:
+ sample1:
+ value:
+ resourceIdentifier: \parent\child
+ sample2:
+ value:
+ resourceIdentifier: \parent\listElement[key=value]
+ sample3:
+ value:
+ resourceIdentifier: \parent\listElement[key=value]\grandChild
+ sample4:
+ value:
+ resourceIdentifier: parent=1,child=abc
acceptParamInHeader:
name: Accept
in: header
schema:
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
+ 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])
contentParamInHeader:
name: Content-Type
in: header
--- /dev/null
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+
+updateDmiRegistration:
+ post:
+ description: Register a DMI Plugin with any new, updated or removed CM Handles.
+ tags:
+ - network-cm-proxy-inventory
+ summary: DMI notifies NCMP of new CM Handles
+ operationId: updateDmiPluginRegistration
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: 'components.yaml#/components/schemas/RestDmiPluginRegistration'
+ responses:
+ 201:
+ $ref: 'components.yaml#/components/responses/Created'
+ 400:
+ $ref: 'components.yaml#/components/responses/BadRequest'
+ 401:
+ $ref: 'components.yaml#/components/responses/Unauthorized'
+ 403:
+ $ref: 'components.yaml#/components/responses/Forbidden'
# ============LICENSE_START=======================================================
# Copyright (C) 2021 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
+# Modifications Copyright (C) 2021 Bell Canada
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
404:
$ref: 'components.yaml#/components/responses/NotFound'
-updateDmiRegistration:
- post:
- description: Register a DMI Plugin with any new, updated or removed CM Handles.
- tags:
- - network-cm-proxy
- summary: DMI notifies NCMP of new CM Handles
- operationId: updateDmiPluginRegistration
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: 'components.yaml#/components/schemas/RestDmiPluginRegistration'
- responses:
- 201:
- $ref: 'components.yaml#/components/responses/Created'
- 400:
- $ref: 'components.yaml#/components/responses/BadRequest'
- 401:
- $ref: 'components.yaml#/components/responses/Unauthorized'
- 403:
- $ref: 'components.yaml#/components/responses/Forbidden'
-
getResourceDataForPassthroughOperational:
get:
tags:
operationId: getResourceDataOperationalForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
- - $ref: 'components.yaml#/components/parameters/resourceIdentifierInPath'
+ - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/acceptParamInHeader'
- - $ref: 'components.yaml#/components/parameters/fieldsParamInQuery'
- - $ref: 'components.yaml#/components/parameters/depthParamInQuery'
+ - $ref: 'components.yaml#/components/parameters/optionsParamInQuery'
responses:
200:
$ref: 'components.yaml#/components/responses/Ok'
operationId: getResourceDataRunningForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
- - $ref: 'components.yaml#/components/parameters/resourceIdentifierInPath'
+ - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/acceptParamInHeader'
- - $ref: 'components.yaml#/components/parameters/fieldsParamInQuery'
- - $ref: 'components.yaml#/components/parameters/depthParamInQuery'
+ - $ref: 'components.yaml#/components/parameters/optionsParamInQuery'
responses:
200:
$ref: 'components.yaml#/components/responses/Ok'
operationId: createResourceDataRunningForCmHandle
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
- - $ref: 'components.yaml#/components/parameters/resourceIdentifierInPath'
+ - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery'
- $ref: 'components.yaml#/components/parameters/contentParamInHeader'
requestBody:
required: true
--- /dev/null
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+
+openapi: 3.0.1
+info:
+ title: NCMP Inventory API
+ description: NCMP Inventory API
+ version: "1.0"
+servers:
+ - url: /ncmpInventory
+paths:
+ /v1/ch:
+ $ref: 'ncmp-inventory.yml#/updateDmiRegistration'
- url: /ncmp
paths:
/v1/cm-handles/{cm-handle}/node:
- $ref: 'ncmproxy.yml#/nodeByCmHandleAndXpath'
+ $ref: 'ncmp.yml#/nodeByCmHandleAndXpath'
/v1/cm-handles/{cm-handle}/list-node:
- $ref: 'ncmproxy.yml#/listNodeByCmHandleAndXpath'
+ $ref: 'ncmp.yml#/listNodeByCmHandleAndXpath'
/v1/cm-handles/{cm-handle}/nodes/query:
- $ref: 'ncmproxy.yml#/nodesByCmHandleAndCpsPath'
+ $ref: 'ncmp.yml#/nodesByCmHandleAndCpsPath'
/v1/cm-handles/{cm-handle}/nodes:
- $ref: 'ncmproxy.yml#/nodesByCmHandleAndXpath'
+ $ref: 'ncmp.yml#/nodesByCmHandleAndXpath'
- /v1/ch:
- $ref: 'ncmproxy.yml#/updateDmiRegistration'
+ /v1/ch/{cm-handle}/data/ds/ncmp-datastore:passthrough-operational:
+ $ref: 'ncmp.yml#/getResourceDataForPassthroughOperational'
- /v1/ch/{cm-handle}/data/ds/ncmp-datastore:passthrough-operational/{resourceIdentifier}:
- $ref: 'ncmproxy.yml#/getResourceDataForPassthroughOperational'
-
- /v1/ch/{cm-handle}/data/ds/ncmp-datastore:passthrough-running/{resourceIdentifier}:
- $ref: 'ncmproxy.yml#/resourceDataForPassthroughRunning'
+ /v1/ch/{cm-handle}/data/ds/ncmp-datastore:passthrough-running:
+ $ref: 'ncmp.yml#/resourceDataForPassthroughRunning'
/v1/ch/{cm-handle}/modules:
- $ref: 'ncmproxy.yml#/fetchModuleReferencesByCmHandle'
\ No newline at end of file
+ $ref: 'ncmp.yml#/fetchModuleReferencesByCmHandle'
\ No newline at end of file
<artifactId>swagger-codegen-maven-plugin</artifactId>
<executions>
<execution>
- <id>code-gen</id>
+ <id>ncmp-code-gen</id>
<goals>
<goal>generate</goal>
</goals>
</configOptions>
</configuration>
</execution>
+ <execution>
+ <id>ncmp-code-gen-inventory</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <inputSpec>${project.basedir}/docs/openapi/openapi-inventory.yml</inputSpec>
+ <invokerPackage>org.onap.cps.ncmp.rest.controller</invokerPackage>
+ <modelPackage>org.onap.cps.ncmp.rest.model</modelPackage>
+ <apiPackage>org.onap.cps.ncmp.rest.api</apiPackage>
+ <language>spring</language>
+ <generateSupportingFiles>false</generateSupportingFiles>
+ <configOptions>
+ <sourceFolder>src/gen/java</sourceFolder>
+ <dateLibrary>java11</dateLibrary>
+ <interfaceOnly>true</interfaceOnly>
+ <useTags>true</useTags>
+ </configOptions>
+ </configuration>
+ </execution>
+ <execution>
+ <id>ncmp-inventory-openapi-yaml-gen</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <inputSpec>${project.basedir}/docs/openapi/openapi-inventory.yml</inputSpec>
+ <language>openapi-yaml</language>
+ <configOptions>
+ <outputFile>openapi-inventory.yaml</outputFile>
+ </configOptions>
+ </configuration>
+ </execution>
</executions>
</plugin>
<plugin>
<resource>
<directory>${project.basedir}/target/generated-sources/swagger/</directory>
<includes>
- <include>openapi.yaml</include>
+ <include>openapi*.yaml</include>
</includes>
</resource>
</resources>
* Copyright (C) 2021 Pantheon.tech
* Modifications (C) 2021 Nordix Foundation
* Modification Copyright (C) 2021 highstreet technologies GmbH
+ * Modifications (C) 2021 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package org.onap.cps.ncmp.rest.controller;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Collection;
import javax.validation.Valid;
-import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
import org.onap.cps.ncmp.rest.api.NetworkCmProxyApi;
-import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleReference;
private final NetworkCmProxyDataService networkCmProxyDataService;
- private final ObjectMapper objectMapper;
-
/**
* Constructor Injection for Dependencies.
* @param networkCmProxyDataService Data Service Interface
- * @param objectMapper Object Mapper
*/
- public NetworkCmProxyController(final NetworkCmProxyDataService networkCmProxyDataService,
- final ObjectMapper objectMapper) {
+ public NetworkCmProxyController(final NetworkCmProxyDataService networkCmProxyDataService) {
this.networkCmProxyDataService = networkCmProxyDataService;
- this.objectMapper = objectMapper;
}
/**
return new ResponseEntity<>(DataMapUtils.toDataMap(dataNode), HttpStatus.OK);
}
- /**
- * Update DMI Plugin Registration (used for first registration also).
- * @param restDmiPluginRegistration the registration data
- */
- @Override
- public ResponseEntity<Void> updateDmiPluginRegistration(
- final @Valid RestDmiPluginRegistration restDmiPluginRegistration) {
- final DmiPluginRegistration dmiPluginRegistration =
- convertRestObjectToJavaApiObject(restDmiPluginRegistration);
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
- return new ResponseEntity<>(HttpStatus.CREATED);
- }
-
/**
* Query Data Nodes.
* @deprecated This Method is no longer used as part of NCMP.
*
* @param cmHandle cm handle identifier
* @param resourceIdentifier resource identifier
- * @param accept accept header parameter
- * @param fields fields query parameter
- * @param depth depth query parameter
+ * @param acceptParamInHeader accept header parameter
+ * @param optionsParamInQuery options query parameter
* @return {@code ResponseEntity} response from dmi plugin
*/
@Override
public ResponseEntity<Object> getResourceDataOperationalForCmHandle(final String cmHandle,
- final String resourceIdentifier,
- final String accept,
- final @Valid String fields,
- final @Min(1) @Valid Integer depth) {
+ final @NotNull @Valid String resourceIdentifier,
+ final String acceptParamInHeader,
+ final @Valid String optionsParamInQuery) {
final Object responseObject = networkCmProxyDataService.getResourceDataOperationalForCmHandle(cmHandle,
resourceIdentifier,
- accept,
- fields,
- depth);
+ acceptParamInHeader,
+ optionsParamInQuery);
return ResponseEntity.ok(responseObject);
}
*
* @param cmHandle cm handle identifier
* @param resourceIdentifier resource identifier
- * @param accept accept header parameter
- * @param fields fields query parameter
- * @param depth depth query parameter
+ * @param acceptParamInHeader accept header parameter
+ * @param optionsParamInQuery options query parameter
* @return {@code ResponseEntity} response from dmi plugin
*/
@Override
public ResponseEntity<Object> getResourceDataRunningForCmHandle(final String cmHandle,
- final String resourceIdentifier,
- final String accept,
- final @Valid String fields,
- final @Min(1) @Valid Integer depth) {
+ final @NotNull @Valid String resourceIdentifier,
+ final String acceptParamInHeader,
+ final @Valid String optionsParamInQuery) {
final Object responseObject = networkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle(cmHandle,
resourceIdentifier,
- accept,
- fields,
- depth);
+ acceptParamInHeader,
+ optionsParamInQuery);
return ResponseEntity.ok(responseObject);
}
* Create resource data in datastore pass through running
* for given cm-handle.
*
- * @param cmHandle cm handle identifier
* @param resourceIdentifier resource identifier
+ * @param cmHandle cm handle identifier
* @param requestBody requestBody
* @param contentType content type of body
* @return {@code ResponseEntity} response from dmi plugi
*/
@Override
- public ResponseEntity<Void> createResourceDataRunningForCmHandle(final String cmHandle,
- final String resourceIdentifier,
+ public ResponseEntity<Void> createResourceDataRunningForCmHandle(final String resourceIdentifier,
+ final String cmHandle,
final String requestBody,
final String contentType) {
networkCmProxyDataService.createResourceDataPassThroughRunningForCmHandle(cmHandle,
return new ResponseEntity<>(new Gson().toJson(moduleReferences), HttpStatus.OK);
}
- private DmiPluginRegistration convertRestObjectToJavaApiObject(
- final RestDmiPluginRegistration restDmiPluginRegistration) {
- return objectMapper.convertValue(restDmiPluginRegistration, DmiPluginRegistration.class);
- }
-
}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.rest.controller;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import javax.validation.Valid;
+import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
+import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
+import org.onap.cps.ncmp.rest.api.NetworkCmProxyInventoryApi;
+import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("${rest.api.ncmp-inventory-base-path}")
+public class NetworkCmProxyInventoryController implements NetworkCmProxyInventoryApi {
+
+ private final NetworkCmProxyDataService networkCmProxyDataService;
+ private final ObjectMapper objectMapper;
+
+ /**
+ * Constructor Injection for Dependencies.
+ * @param networkCmProxyDataService Data Service Interface
+ * @param objectMapper Object Mapper
+ */
+ public NetworkCmProxyInventoryController(final NetworkCmProxyDataService networkCmProxyDataService,
+ final ObjectMapper objectMapper) {
+ this.networkCmProxyDataService = networkCmProxyDataService;
+ this.objectMapper = objectMapper;
+ }
+
+ /**
+ * Update DMI Plugin Registration (used for first registration also).
+ * @param restDmiPluginRegistration the registration data
+ */
+ @Override
+ public ResponseEntity<Void> updateDmiPluginRegistration(
+ final @Valid RestDmiPluginRegistration restDmiPluginRegistration) {
+ final DmiPluginRegistration dmiPluginRegistration =
+ convertRestObjectToJavaApiObject(restDmiPluginRegistration);
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
+ return new ResponseEntity<>(HttpStatus.CREATED);
+ }
+
+ private DmiPluginRegistration convertRestObjectToJavaApiObject(
+ final RestDmiPluginRegistration restDmiPluginRegistration) {
+ return objectMapper.convertValue(restDmiPluginRegistration, DmiPluginRegistration.class);
+ }
+
+}
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
-import com.fasterxml.jackson.databind.ObjectMapper
import com.google.gson.Gson
-import org.onap.cps.TestUtils
import org.onap.cps.ncmp.api.NetworkCmProxyDataService
import org.onap.cps.spi.model.DataNodeBuilder
import org.spockframework.spring.SpringBean
@SpringBean
NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
- @SpringBean
- ObjectMapper objectMapper = new ObjectMapper()
-
@Value('${rest.api.ncmp-base-path}/v1')
def ncmpBasePathV1
response.contentAsString.contains('"leaf":"value"')
}
- def 'Register CM Handle Event' () {
- given: 'jsonData'
- def jsonData = TestUtils.getResourceFileContent('dmi-registration.json')
- when: 'post request is performed'
- def response = mvc.perform(
- post("$ncmpBasePathV1/ch")
- .contentType(MediaType.APPLICATION_JSON)
- .content(jsonData)
- ).andReturn().response
- then: 'the cm handles are registered with the service'
- 1 * mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(_)
- and: 'response status is created'
- response.status == HttpStatus.CREATED.value()
- }
-
def 'Get Resource Data from pass-through operational.' () {
given: 'resource data url'
def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-operational" +
- "/testResourceIdentifier?fields=testFields&depth=5"
+ "?resourceIdentifier=parent/child&options=(a=1,b=2)"
when: 'get data resource request is performed'
def response = mvc.perform(
get(getUrl)
).andReturn().response
then: 'the NCMP data service is called with getResourceDataOperationalForCmHandle'
1 * mockNetworkCmProxyDataService.getResourceDataOperationalForCmHandle('testCmHandle',
- 'testResourceIdentifier',
+ 'parent/child',
'application/json',
- 'testFields',
- 5)
+ '(a=1,b=2)')
and: 'response status is Ok'
response.status == HttpStatus.OK.value()
}
- def 'Get Resource Data from pass-through running.' () {
+ def 'Get Resource Data from pass-through running with #scenario value in resource identifier param.' () {
given: 'resource data url'
def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
- "/testResourceIdentifier?fields=testFields&depth=5"
+ "?resourceIdentifier=" + resourceIdentifier + "&options=(a=1,b=2)"
and: 'ncmp service returns json object'
mockNetworkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceIdentifier',
- 'application/json',
- 'testFields',
- 5) >> '{valid-json}'
+ resourceIdentifier,
+ 'application/json',
+ '(a=1,b=2)') >> '{valid-json}'
when: 'get data resource request is performed'
def response = mvc.perform(
get(getUrl)
response.status == HttpStatus.OK.value()
and: 'response contains valid object body'
response.getContentAsString() == '{valid-json}'
+ where: 'tokens are used in the resource identifier parameter'
+ scenario | resourceIdentifier
+ '/' | 'id/with/slashes'
+ '?' | 'idWith?'
+ ',' | 'idWith,'
+ '=' | 'idWith='
+ '[]' | 'idWith[]'
+ '? needs to be encoded as %3F' | 'idWith%3F'
}
def 'Create Resource Data from pass-through running with #scenario.' () {
given: 'resource data url'
def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-running" +
- "/testResourceIdentifier"
+ "?resourceIdentifier=parent/child"
when: 'get data resource request is performed'
def response = mvc.perform(
post(getUrl)
).andReturn().response
then: 'ncmp service method to create resource called'
1 * mockNetworkCmProxyDataService.createResourceDataPassThroughRunningForCmHandle('testCmHandle',
- 'testResourceIdentifier', requestBody, 'application/json;charset=UTF-8')
+ 'parent/child', requestBody, 'application/json;charset=UTF-8')
and: 'resource is created'
response.status == HttpStatus.CREATED.value()
where: 'given request body'
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.rest.controller
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.onap.cps.TestUtils
+import org.onap.cps.ncmp.api.NetworkCmProxyDataService
+import org.spockframework.spring.SpringBean
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
+import org.springframework.context.annotation.Import
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.test.web.servlet.MockMvc
+import spock.lang.Specification
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+
+@WebMvcTest(NetworkCmProxyInventoryController)
+@Import(ObjectMapper)
+class NetworkCmProxyInventoryControllerSpec extends Specification {
+
+ @Autowired
+ MockMvc mvc
+
+ @SpringBean
+ NetworkCmProxyDataService mockNetworkCmProxyDataService = Mock()
+
+ @Value('${rest.api.ncmp-inventory-base-path}/v1')
+ def ncmpBasePathV1
+
+ def 'Register CM Handle Event' () {
+ given: 'jsonData'
+ def jsonData = TestUtils.getResourceFileContent('dmi-registration.json')
+ when: 'post request is performed'
+ def response = mvc.perform(
+ post("$ncmpBasePathV1/ch")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(jsonData)
+ ).andReturn().response
+ then: 'the cm handles are registered with the service'
+ 1 * mockNetworkCmProxyDataService.updateDmiRegistrationAndSyncModule(_)
+ and: 'response status is created'
+ response.status == HttpStatus.CREATED.value()
+ }
+
+}
+
rest:
api:
ncmp-base-path: /ncmp
-spring:
+ ncmp-inventory-base-path: /ncmpInventory
*
* @param cmHandle cm handle
* @param resourceIdentifier resource identifier
- * @param accept accept param
- * @param fields fields query
- * @param depth depth query
+ * @param acceptParamInHeader accept param
+ * @param optionsParamInQuery options query
* @return {@code Object} resource data
*/
Object getResourceDataOperationalForCmHandle(@NotNull String cmHandle,
@NotNull String resourceIdentifier,
- String accept,
- String fields,
- Integer depth);
+ String acceptParamInHeader,
+ String optionsParamInQuery);
/**
* Get resource data for data store pass-through running
*
* @param cmHandle cm handle
* @param resourceIdentifier resource identifier
- * @param acceptParam accept param
- * @param fields fields query
- * @param depth depth query
+ * @param acceptParamInHeader accept param
+ * @param optionsParamInQuery options query
* @return {@code Object} resource data
*/
Object getResourceDataPassThroughRunningForCmHandle(@NotNull String cmHandle,
@NotNull String resourceIdentifier,
- String acceptParam,
- String fields,
- Integer depth);
+ String acceptParamInHeader,
+ String optionsParamInQuery);
/**
* Create resource data for data store pass-through running
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.ModuleReference;
import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Override
public Object getResourceDataOperationalForCmHandle(final @NotNull String cmHandle,
final @NotNull String resourceIdentifier,
- final String acceptParam,
- final String fieldsQueryParam,
- final Integer depthQueryParam) {
+ final String acceptParamInHeader,
+ final String optionsParamInQuery) {
final DataNode cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
final String dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
final ResponseEntity<Object> response = dmiOperations.getResourceDataOperationalFromDmi(dmiServiceName,
cmHandle,
resourceIdentifier,
- fieldsQueryParam,
- depthQueryParam,
- acceptParam,
+ optionsParamInQuery,
+ acceptParamInHeader,
dmiRequestBody);
return handleResponse(response);
}
@Override
public Object getResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle,
final @NotNull String resourceIdentifier,
- final String acceptParam,
- final String fields,
- final Integer depth) {
+ final String acceptParamInHeader,
+ final String optionsParamInQuery) {
final DataNode cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
final String dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
final String dmiRequestBody = getGenericRequestBody(cmHandleDataNode);
final ResponseEntity<Object> response = dmiOperations.getResourceDataPassThroughRunningFromDmi(dmiServiceName,
cmHandle,
resourceIdentifier,
- fields,
- depth,
- acceptParam,
+ optionsParamInQuery,
+ acceptParamInHeader,
dmiRequestBody);
return handleResponse(response);
}
}
private static void handleResponseForPost(final @NotNull ResponseEntity<String> responseEntity) {
- if (responseEntity.getStatusCode() != HttpStatus.OK) {
+ if (!HttpStatus.valueOf(responseEntity.getStatusCodeValue()).is2xxSuccessful()) {
throw new NcmpException("Not able to create resource data.",
"DMI status code: " + responseEntity.getStatusCodeValue()
+ ", DMI response body: " + responseEntity.getBody());
cmHandleJsonData, NO_TIMESTAMP);
for (final PersistenceCmHandle persistenceCmHandle : persistenceCmHandlesList.getPersistenceCmHandles()) {
- createAnchorAndSyncModel(persistenceCmHandle);
+ syncModulesAndCreateAnchor(persistenceCmHandle);
}
}
- protected void createAnchorAndSyncModel(final PersistenceCmHandle persistenceCmHandle) {
- createAnchor(persistenceCmHandle);
+ protected void syncModulesAndCreateAnchor(final PersistenceCmHandle persistenceCmHandle) {
fetchAndSyncModules(persistenceCmHandle);
+ createAnchor(persistenceCmHandle);
}
private static PersistenceCmHandle toPersistenceCmHandle(final String dmiPluginService,
final List<ModuleReference> unknownModuleReferences = new ArrayList<>();
prepareModuleSubsets(moduleReferencesFromCmHandle, existingModuleReferences, unknownModuleReferences);
- final Map<String, String> newYangResourcesModuleNameToContentMap =
- getNewYangResourcesFromDmi(persistenceCmHandle, unknownModuleReferences, cmHandlePropertiesAsMap);
-
+ final Map<String, String> newYangResourcesModuleNameToContentMap;
+ if (unknownModuleReferences.size() > 0) {
+ newYangResourcesModuleNameToContentMap = getNewYangResourcesFromDmi(persistenceCmHandle,
+ unknownModuleReferences, cmHandlePropertiesAsMap);
+ } else {
+ newYangResourcesModuleNameToContentMap = new HashMap<>();
+ }
cpsModuleService.createSchemaSetFromModules(NF_PROXY_DATASPACE_NAME, persistenceCmHandle.getId(),
newYangResourcesModuleNameToContentMap, existingModuleReferences);
}
private List<ModuleReference> fetchModuleReferencesFromDmi(final PersistenceCmHandle persistenceCmHandle,
final Map<String, String> cmHandlePropertiesAsMap) {
- final GenericRequestBody requestBodyObject = GenericRequestBody.builder()
- .operation(GenericRequestBody.OperationEnum.READ)
+ final GenericRequestBody genericRequestBody = GenericRequestBody.builder()
.cmHandleProperties(cmHandlePropertiesAsMap)
.build();
- final String jsonBody = prepareOperationBody(requestBodyObject);
+ final String jsonBodyWithOnlyCmHandleProperties = prepareOperationBody(genericRequestBody);
final ResponseEntity<String> dmiFetchModulesResponseEntity =
dmiOperations.getResourceFromDmiWithJsonData(persistenceCmHandle.getDmiServiceName(),
- jsonBody, persistenceCmHandle.getId(), "modules");
+ jsonBodyWithOnlyCmHandleProperties, persistenceCmHandle.getId(), "modules");
return toModuleReferences(dmiFetchModulesResponseEntity);
}
final JsonArray moduleReferencesAsJson = getModuleReferencesAsJson(unknownModuleReferences);
final JsonObject data = new JsonObject();
data.add("modules", moduleReferencesAsJson);
- final GenericRequestBody dmiRequestBodyObject = GenericRequestBody.builder()
- .operation(GenericRequestBody.OperationEnum.READ)
- .dataType(MediaType.APPLICATION_JSON_VALUE)
- .data(data.toString())
- .cmHandleProperties(cmHandlePropertiesAsMap)
- .build();
- return prepareOperationBody(dmiRequestBodyObject);
+ final JsonObject jsonRequestObject = new JsonObject();
+ jsonRequestObject.add("data", data);
+ final Gson gson = new Gson();
+ jsonRequestObject.add("cmHandleProperties", gson.toJsonTree(cmHandlePropertiesAsMap));
+ return jsonRequestObject.toString();
}
private static JsonArray getModuleReferencesAsJson(final List<ModuleReference> unknownModuleReferences) {
private Map<String, String> getNewYangResourcesFromDmi(final PersistenceCmHandle persistenceCmHandle,
final List<ModuleReference> unknownModuleReferences,
final Map<String, String> cmHandlePropertiesAsMap) {
- final String jsonData = getRequestBodyToFetchYangResourceFromDmi(
+ final String jsonDataWithDataAndCmHandleProperties = getRequestBodyToFetchYangResourceFromDmi(
unknownModuleReferences, cmHandlePropertiesAsMap);
final ResponseEntity<String> moduleResourcesAsJsonString = dmiOperations.getResourceFromDmiWithJsonData(
persistenceCmHandle.getDmiServiceName(),
- jsonData,
+ jsonDataWithDataAndCmHandleProperties,
persistenceCmHandle.getId(),
"moduleResources");
private static final String DMI_CM_HANDLE_PATH = "/v1/ch/{cmHandle}";
private static final String DMI_CM_HANDLE_DATASTORE_PATH = DMI_CM_HANDLE_PATH + "/data/ds";
private static final String URL_SEPARATOR = "/";
+ private static final String RESOURCE_IDENTIFIER = "resourceIdentifier";
+ private static final String OPTIONS_QUERY_KEY = "options";
+
/**
* Constructor for {@code DmiOperations}. This method also manipulates url properties.
* @param dmiServiceName dmi service name
* @param cmHandle network resource identifier
* @param resourceId resource identifier
- * @param fieldsQuery fields query
- * @param depthQuery depth query
- * @param acceptParam accept parameter
+ * @param optionsParamInQuery options query
+ * @param acceptParamInHeader accept parameter
* @param jsonBody json body for put operation
* @return {@code ResponseEntity} response entity
*/
public ResponseEntity<Object> getResourceDataOperationalFromDmi(final String dmiServiceName,
final String cmHandle,
final String resourceId,
- final String fieldsQuery,
- final Integer depthQuery,
- final String acceptParam,
+ final String optionsParamInQuery,
+ final String acceptParamInHeader,
final String jsonBody) {
final var dmiResourceDataUrl = getDmiDatastoreUrl(dmiServiceName, cmHandle, resourceId,
- fieldsQuery, depthQuery, DataStoreEnum.PASSTHROUGH_OPERATIONAL);
- final var httpHeaders = prepareHeader(acceptParam);
+ optionsParamInQuery, DataStoreEnum.PASSTHROUGH_OPERATIONAL);
+ final var httpHeaders = prepareHeader(acceptParamInHeader);
return dmiRestClient.putOperationWithJsonData(dmiResourceDataUrl, jsonBody, httpHeaders);
}
* @param dmiServiceName dmi service name
* @param cmHandle network resource identifier
* @param resourceId resource identifier
- * @param fieldsQuery fields query
- * @param depthQuery depth query
- * @param acceptParam accept parameter
+ * @param optionsParamInQuery fields query
+ * @param acceptParamInHeader accept parameter
* @param jsonBody json body for put operation
* @return {@code ResponseEntity} response entity
*/
public ResponseEntity<Object> getResourceDataPassThroughRunningFromDmi(final String dmiServiceName,
final String cmHandle,
final String resourceId,
- final String fieldsQuery,
- final Integer depthQuery,
- final String acceptParam,
+ final String optionsParamInQuery,
+ final String acceptParamInHeader,
final String jsonBody) {
final var dmiResourceDataUrl = getDmiDatastoreUrl(dmiServiceName, cmHandle, resourceId,
- fieldsQuery, depthQuery, DataStoreEnum.PASSTHROUGH_RUNNING);
- final var httpHeaders = prepareHeader(acceptParam);
+ optionsParamInQuery, DataStoreEnum.PASSTHROUGH_RUNNING);
+ final var httpHeaders = prepareHeader(acceptParamInHeader);
return dmiRestClient.putOperationWithJsonData(dmiResourceDataUrl, jsonBody, httpHeaders);
}
final String cmHandle,
final String resourceId,
final String jsonBody) {
- final var stringBuilder = getStringBuilderForPassThroughRunningUrl(dmiServiceName,
+ final var stringBuilder = getStringBuilderForPassThroughUrl(dmiServiceName,
cmHandle, resourceId, DataStoreEnum.PASSTHROUGH_RUNNING);
return dmiRestClient.postOperationWithJsonData(stringBuilder.toString(), jsonBody, new HttpHeaders());
}
private String getDmiDatastoreUrl(final String dmiServiceName,
final String cmHandle,
final String resourceId,
- final String fieldsQuery,
- final Integer depthQuery,
+ final String optionsParamInQuery,
final DataStoreEnum dataStoreEnum) {
- final var stringBuilder = getStringBuilderForPassThroughRunningUrl(dmiServiceName,
+ final var stringBuilder = getStringBuilderForPassThroughUrl(dmiServiceName,
cmHandle, resourceId, dataStoreEnum);
- appendFieldsAndDepth(stringBuilder, fieldsQuery, depthQuery);
+ appendOptionsQuery(stringBuilder, optionsParamInQuery);
return stringBuilder.toString();
}
@NotNull
- private StringBuilder getStringBuilderForPassThroughRunningUrl(final String dmiServiceName,
- final String cmHandle,
- final String resourceId,
- final DataStoreEnum dataStoreEnum) {
+ private StringBuilder getStringBuilderForPassThroughUrl(final String dmiServiceName,
+ final String cmHandle,
+ final String resourceId,
+ final DataStoreEnum dataStoreEnum) {
final var stringBuilder = new StringBuilder(dmiServiceName);
stringBuilder.append(DMI_API_PATH);
stringBuilder.append(DMI_CM_HANDLE_DATASTORE_PATH.replace("{cmHandle}", cmHandle));
stringBuilder.append(URL_SEPARATOR + dataStoreEnum.getValue());
- stringBuilder.append(URL_SEPARATOR + resourceId);
+ stringBuilder.append("?" + RESOURCE_IDENTIFIER + "=" + resourceId);
return stringBuilder;
}
- private void appendFieldsAndDepth(final StringBuilder stringBuilder,
- final String fieldsQuery,
- final Integer depthQuery) {
- final var doesFieldExists = (fieldsQuery != null && !fieldsQuery.isEmpty());
- if (doesFieldExists) {
- stringBuilder.append("?").append("fields=").append(fieldsQuery);
- }
- if (depthQuery != null) {
- if (doesFieldExists) {
- stringBuilder.append("&");
- } else {
- stringBuilder.append("?");
- }
- stringBuilder.append("depth=").append(depthQuery);
+ private void appendOptionsQuery(final StringBuilder stringBuilder,
+ final String optionsParamInQuery) {
+ if (optionsParamInQuery != null) {
+ stringBuilder.append("&").append(OPTIONS_QUERY_KEY).append("=").append(optionsParamInQuery);
}
}
private HttpHeaders prepareHeader(final String acceptParam) {
final var httpHeaders = new HttpHeaders();
- if (acceptParam != null && !acceptParam.isEmpty()) {
- httpHeaders.set(HttpHeaders.ACCEPT, acceptParam);
- }
+ httpHeaders.set(HttpHeaders.ACCEPT, acceptParam);
return httpHeaders;
}
}
mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
'testCmHandle',
'testResourceId',
- 'testFieldQuery',
- 5,
+ '(a=1,b=2)',
'testAcceptParam',
'{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('result-json', HttpStatus.OK)
when: 'get resource data is called'
def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
'testResourceId',
'testAcceptParam',
- 'testFieldQuery',
- 5)
+ '(a=1,b=2)')
then: 'dmi returns ok response'
response == 'result-json'
}
def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
'testResourceId',
'testAcceptParam',
- 'testFieldQuery',
- 5)
+ '(a=1,b=2)')
then: 'exception is thrown with the expected details'
def exceptionThrown = thrown(NcmpException.class)
exceptionThrown.details == 'testException'
mockDmiOperations.getResourceDataOperationalFromDmi('testDmiService',
'testCmHandle',
'testResourceId',
- 'testFieldQuery',
- 5,
+ '(a=1,b=2)',
'testAcceptParam',
'{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
>> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
def response = objectUnderTest.getResourceDataOperationalForCmHandle('testCmHandle',
'testResourceId',
'testAcceptParam',
- 'testFieldQuery',
- 5)
+ '(a=1,b=2)')
then: 'exception is thrown'
def exceptionThrown = thrown(NcmpException.class)
and: 'details contains the original response'
mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
'testCmHandle',
'testResourceId',
- 'testFieldQuery',
- 5,
+ '(a=1,b=2)',
'testAcceptParam',
'{"operation":"read","cmHandleProperties":{"testName":"testValue"}}') >> new ResponseEntity<>('{result-json}', HttpStatus.OK)
when: 'get resource data is called'
def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
'testResourceId',
'testAcceptParam',
- 'testFieldQuery',
- 5)
+ '(a=1,b=2)')
then: 'get resource data returns expected response'
response == '{result-json}'
}
def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
'testResourceId',
'testAcceptParam',
- 'testFieldQuery',
- 5)
+ '(a=1,b=2)')
then: 'exception is thrown with the expected details'
def exceptionThrown = thrown(NcmpException.class)
exceptionThrown.details == 'testException'
mockDmiOperations.getResourceDataPassThroughRunningFromDmi('testDmiService',
'testCmHandle',
'testResourceId',
- 'testFieldQuery',
- 5,
+ '(a=1,b=2)',
'testAcceptParam',
'{"operation":"read","cmHandleProperties":{"testName":"testValue"}}')
>> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
def response = objectUnderTest.getResourceDataPassThroughRunningForCmHandle('testCmHandle',
'testResourceId',
'testAcceptParam',
- 'testFieldQuery',
- 5)
+ '(a=1,b=2)')
then: 'exception is thrown'
def exceptionThrown = thrown(NcmpException.class)
and: 'details contains the original response'
'testResourceId',
'{"operation":"create","dataType":"application/json","data":"{some-json}","cmHandleProperties":'
+ expectedJsonForCmhandleProperties+ '}')
- >> { new ResponseEntity<>(HttpStatus.OK) }
+ >> { new ResponseEntity<>(HttpStatus.CREATED) }
where:
scenario | includeCmHandleProperties || expectedJsonForCmhandleProperties
'with' | true || '{"testName":"testValue"}'
}
def 'Sync model for a (new) cm handle with #scenario'() {
- given: 'DMI Plug-in returns a list of module references'
- def knownModule1 = new ModuleReference('module1', '1')
- def knownOtherModule = new ModuleReference('some other module', 'some revision')
- and: 'persistence cm handle is given'
+ given: 'persistence cm handle is given'
def cmHandleForModelSync = new PersistenceCmHandle(id:'some cm handle', dmiServiceName: 'some service name')
and: 'additional properties are set as required'
if (additionalProperties!=null) {
}
and: 'dmi operations returns some module references'
def jsonData = TestUtils.getResourceFileContent('cmHandleModules.json')
- def expectedJsonBody = '{"operation":"read","cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
+ def expectedJsonBody = '{"cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
mockDmiProperties.getAuthUsername() >> 'someUser'
mockDmiProperties.getAuthPassword() >> 'somePassword'
def moduleReferencesFromCmHandleAsJson = new ResponseEntity<String>(jsonData, HttpStatus.OK)
mockDmiOperations.getResourceFromDmiWithJsonData('some service name', expectedJsonBody, 'some cm handle', 'modules') >> moduleReferencesFromCmHandleAsJson
and: 'CPS-Core returns list of known modules'
- mockCpsModuleService.getYangResourceModuleReferences(_) >> [knownModule1, knownOtherModule]
+ mockCpsModuleService.getYangResourceModuleReferences(_) >> existingModuleResourcesInCps
and: 'DMI-Plugin returns resource(s) for "new" module(s)'
def moduleResources = new ResponseEntity<String>(sdncReponseBody, HttpStatus.OK)
- def jsonDataToFetchYangResource = '{"operation":"read","dataType":"application/json","data":"{\\"modules\\":[{\\"name\\":\\"module2\\",\\"revision\\":\\"1\\"}]}","cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
+ def jsonDataToFetchYangResource = '{"data":{"modules":[{"name":"module1","revision":"1"}]},"cmHandleProperties":' + expectedJsonForAdditionalProperties + '}'
mockDmiOperations.getResourceFromDmiWithJsonData('some service name', jsonDataToFetchYangResource, 'some cm handle', 'moduleResources') >> moduleResources
when: 'module Sync is triggered'
- objectUnderTest.createAnchorAndSyncModel(cmHandleForModelSync)
+ objectUnderTest.syncModulesAndCreateAnchor(cmHandleForModelSync)
then: 'the CPS module service is called once with the correct parameters'
- 1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), expectedYangResourceToContentMap, [knownModule1])
+ 1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), expectedYangResourceToContentMap, expectedKnownModules)
and: 'admin service create anchor method has been called with correct parameters'
1 * mockCpsAdminService.createAnchor(expectedDataspaceName, cmHandleForModelSync.getId(), cmHandleForModelSync.getId())
where: 'the following responses are received from SDNC'
- scenario | additionalProperties | sdncReponseBody || expectedYangResourceToContentMap | expectedJsonForAdditionalProperties
- 'one unknown module' | ['name1':'value1'] | '[{"moduleName" : "someModule", "revision" : "1","yangSource": "[some yang source]"}]' || [someModule: 'some yang source'] | '{"name1":"value1"}'
- 'no add. properties' | [:] | '[{"moduleName" : "someModule", "revision" : "1","yangSource": "[some yang source]"}]' || [someModule: 'some yang source'] | '{}'
- 'additional properties is null' | null | '[{"moduleName" : "someModule", "revision" : "1","yangSource": "[some yang source]"}]' || [someModule: 'some yang source'] | '{}'
- 'no unknown module' | [:] | '[]' || [:] | '{}'
+ scenario | additionalProperties | existingModuleResourcesInCps | sdncReponseBody || expectedYangResourceToContentMap | expectedKnownModules | expectedJsonForAdditionalProperties
+ 'one unknown module' | ['name1':'value1'] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{"name1":"value1"}'
+ 'no add. properties' | [:] | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{}'
+ 'additional properties is null' | null | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | '[{"moduleName" : "module1", "revision" : "1","yangSource": "[some yang source]"}]' || [module1: 'some yang source'] | [new ModuleReference('module2', '2')] |'{}'
+ 'no unknown module' | [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '[]' || [:] | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] |'{}'
}
def 'Getting Yang Resources.'() {
1 * mockCpsModuleService.getYangResourcesModuleReferences('NFP-Operational','some cm handle')
}
+ def 'Create the request body to get yang resources from DMI.'() {
+ given: 'the expected json request'
+ def expectedRequestBody = '{"data":{"modules":[{"name":"module1","revision":"1"},{"name":"module2","revision":"2"}]},"cmHandleProperties":{"name1":"value1"}}'
+ and: 'module references and cm handle properties'
+ def moduleReferences = [new ModuleReference('module1', '1'),new ModuleReference('module2', '2')]
+ def cmHandleProperties = ['name1':'value1']
+ when: 'get request body to fetch yang resources from DMI is called'
+ def result = objectUnderTest.getRequestBodyToFetchYangResourceFromDmi(moduleReferences, cmHandleProperties)
+ then: 'the result is the same as the expected request body'
+ result == expectedRequestBody
+ }
+
def getObjectUnderTestWithModelSyncDisabled() {
def objectUnderTest = Spy(new NetworkCmProxyDataServiceImpl(mockDmiOperations, mockCpsModuleService,
mockCpsDataService, mockCpsQueryService, mockCpsAdminService, spyObjectMapper))
- objectUnderTest.createAnchorAndSyncModel(_) >> null
+ objectUnderTest.syncModulesAndCreateAnchor(_) >> null
return objectUnderTest
}
def 'call get resource data for pass-through:operational datastore from DMI.'() {
given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-operational/testResourceId?fields=testFieldsQuery&depth=10'
+ def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
+ '/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child&options=(a=1,b=2)'
when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataOperationalFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'testResourceId',
- 'testFieldsQuery',
- 10,
- 'testAcceptJson',
- 'testJsonbody')
+ objectUnderTest.getResourceDataOperationalFromDmi('testDmiBasePath',
+ 'testCmhandle',
+ 'parent/child',
+ '(a=1,b=2)',
+ 'testAcceptJson',
+ 'testJsonbody')
then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
+ 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
}
def 'call get resource data for pass-through:running datastore from DMI.'() {
+ given: 'expected url'
+ def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
+ '/ncmp-datastore:passthrough-running?resourceIdentifier=parent/child&options=(a=1,b=2)'
+ when: 'get resource data is called to DMI'
+ objectUnderTest.getResourceDataPassThroughRunningFromDmi('testDmiBasePath',
+ 'testCmhandle',
+ 'parent/child',
+ '(a=1,b=2)',
+ 'testAcceptJson',
+ 'testJsonbody')
+ then: 'the put operation is executed with the correct URL'
+ 1 * mockDmiRestClient.putOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
+ }
+ def 'call get resource data for pass-through:operational datastore from DMI when options is null.'() {
given: 'expected url'
def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-running/testResourceId?fields=testFieldsQuery&depth=10'
+ '/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child'
when: 'get resource data is called to DMI'
- objectUnderTest.getResourceDataPassThroughRunningFromDmi('testDmiBasePath',
+ objectUnderTest.getResourceDataOperationalFromDmi('testDmiBasePath',
'testCmhandle',
- 'testResourceId',
- 'testFieldsQuery',
- 10,
+ 'parent/child',
+ null,
'testAcceptJson',
'testJsonbody')
then: 'the put operation is executed with the correct URL'
}
def 'call create resource data for pass-through:running datastore from DMI.'() {
given: 'expected url'
- def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
- '/ncmp-datastore:passthrough-running/testResourceId'
+ def expectedUrl = 'testDmiBasePath/dmi/v1/ch/testCmhandle/data/ds' +
+ '/ncmp-datastore:passthrough-running?resourceIdentifier=parent/child'
when: 'get resource data is called to DMI'
- objectUnderTest.createResourceDataPassThroughRunningFromDmi('testDmiBasePath',
- 'testCmhandle',
- 'testResourceId',
- 'testJsonbody')
+ objectUnderTest.createResourceDataPassThroughRunningFromDmi('testDmiBasePath',
+ 'testCmhandle',
+ 'parent/child',
+ 'testJsonbody')
then: 'the put operation is executed with the correct URL'
- 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
+ 1 * mockDmiRestClient.postOperationWithJsonData(expectedUrl, 'testJsonbody', _ as HttpHeaders)
}
def 'Call get resource from dmi.'() {
},
{
"moduleName": "module2",
- "revision": "1",
+ "revision": "2",
"namespace": "some namespace"
}]
}
\ No newline at end of file
* `http://localhost:<port-number>/swagger-ui.html`
* `http://localhost:<port-number>/api-docs/cps-core/openapi.yaml`
* `http://localhost:<port-number>/api-docs/cps-ncmp/openapi.yaml`
+* `http://localhost:<port-number>/api-docs/cps-ncmp/openapi-inventory.yaml`
with <port-number> being either `8080` if running the plain Java build or retrieved using following command
if running from `docker-compose`:
CPS Admin Guide
###############
-.. warning:: draft
-
.. toctree::
:maxdepth: 1
Logging & Diagnostics
=====================
+
+General Guidelines
+------------------
+CPS-Core logs are sent to `STDOUT` in order to leverage the Kubernetes logging architecture.
+
+These logs are available using the following command:
+
+.. code:: bash
+
+ kubectl logs <cps-core-pod>
+
+The default configuration for CPS logs is the INFO level.
+
+This architecture also makes all logs ready to be sent to an Elastic-search Log-stash and Kibana (ELK) stack or similar.
+
+Enabling tracing for all executed sql statements is done by changing hibernate
+loggers log level
+
+Logger configuration is provided as a chart resource :
+
+ +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
+ | cps-component-service-name | logback.xml location |
+ +================================+=================================================================================================================================+
+ | cps-core | `logback.xml <https://github.com/onap/oom/blob/master/kubernetes/cps/components/cps-core/resources/config/logback.xml>`_ |
+ +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
+ | cps-temporal | `logback.xml <https://github.com/onap/oom/blob/master/kubernetes/cps/components/cps-temporal/resources/config/logback.xml>`_ |
+ +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
+ | ncmp-dmi-plugin | Not yet applicable to DMI-Plugin |
+ +--------------------------------+---------------------------------------------------------------------------------------------------------------------------------+
+
+Monitoring
+==========
+Once CPS-Core is deployed, information related to the running instance of the application is available
+
+.. code::
+
+ http://<cps-component-service-name>:8081/manage/info/
+
+Health
+------
+
+Cps-Core health status and state can be checked using the following endpoint.
+This also includes both the liveliness state and readiness state.
+
+.. code::
+
+ http://<cps-component-service-name>:8081/manage/health/
+
+Metrics
+-------
+
+Prometheus Metrics can be checked at the following endpoint
+
+.. code::
+
+ http://<cps-component-service-name>:8081/manage/prometheus
\ No newline at end of file
--- /dev/null
+openapi: 3.0.1
+info:
+ title: NCMP Inventory API
+ description: NCMP Inventory API
+ version: "1.0"
+servers:
+- url: /ncmpInventory
+paths:
+ /v1/ch:
+ post:
+ tags:
+ - network-cm-proxy-inventory
+ summary: DMI notifies NCMP of new CM Handles
+ description: "Register a DMI Plugin with any new, updated or removed CM Handles."
+ operationId: updateDmiPluginRegistration
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/RestDmiPluginRegistration'
+ required: true
+ responses:
+ "201":
+ description: Created
+ content: {}
+ "400":
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ "401":
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ "403":
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+components:
+ schemas:
+ RestDmiPluginRegistration:
+ type: object
+ properties:
+ dmiPlugin:
+ type: string
+ example: onap-dmi-plugin
+ createdCmHandles:
+ type: array
+ items:
+ $ref: '#/components/schemas/RestCmHandle'
+ updatedCmHandles:
+ type: array
+ items:
+ $ref: '#/components/schemas/RestCmHandle'
+ removedCmHandles:
+ type: array
+ items:
+ type: string
+ RestCmHandle:
+ required:
+ - cmHandle
+ type: object
+ properties:
+ cmHandle:
+ type: string
+ example: cmHandle123
+ cmHandleProperties:
+ $ref: '#/components/schemas/RestCmHandleAdditionalProperties'
+ RestCmHandleAdditionalProperties:
+ type: object
+ additionalProperties:
+ type: string
+ example: system-001
+ ErrorMessage:
+ title: Error
+ type: object
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ details:
+ type: string
--- /dev/null
+module dmi-registry {
+
+ yang-version 1.1;
+
+ namespace \"org:onap:cps:ncmp\";
+
+ prefix dmi-reg;
+
+ organization \"Nordix Foundation\";
+
+ contact \"rahul.tyagi@est.tech\";
+
+ revision \"2021-05-20\" {
+ description
+ \"Initial Version\";
+ }
+
+ container dmi-registry {
+
+ list cm-handles {
+
+ key \"id\";
+
+ leaf id {
+ type string;
+ }
+
+ leaf dmi-service-name {
+ type string;
+ }
+
+ list additional-properties {
+
+ key \"name\";
+
+ leaf name {
+ type string;
+ }
+
+ leaf value {
+ type string;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
CPS Architecture
################
-.. warning:: draft
-
.. toctree::
:maxdepth: 1
The Configuration Persistence Service (CPS) provides storage for run-time configuration and operational
parameters that need to be used by ONAP.
-In this release CPS is no longer a stand alone component and is released along with Cps-Temporal and the NCMP-DMI Plugin.
+In this release CPS is no longer a stand alone component and is released along with Cps-Temporal and the NCMP-DMI-Plugin.
Project page describing eventual scope and ambition is here:
`Configuration Persistence Service Project <https://wiki.onap.org/display/DW/Configuration+Persistence+Service+Project>`_
This page reflects the state for Istanbul-R9 release.
-.. image:: _static/cps-r8-arch-diagram.png
+.. image:: _static/star.png
+ :class: float-left
+
+**Note:** SDC and AAI interfaces have not yet been implemented.
+
+.. image:: _static/cps-r9-arch-diagram.png
API definitions
===============
-Configuration Persistence Service provides following interfaces.
+Configuration Persistence Service provides the following interfaces.
.. list-table::
:header-rows: 1
- Protocol
* - CPS-E-01
- Administrative Data Management
- - - create/delete dataspace
+ - - create dataspace
- create/delete schema set
- create/delete anchor
- REST
- REST
* - CPS-E-04
- Change Notification
- - *Not available in Honolulu-R8*
- - *N/A*
+ - - Kafka is used as the event messaging system
+ - running instance is supplied independently from ONAP DMaaP component or any Kafka instance deployed from ONAP
+ - published events contain Timestamp, Dataspace, Schema set, Anchor and JSON Data Payload
+ - DMaaP
* - CPS-E-05
- xNF Data Access
- - read xNF data
- query xNF data
- REST
+ * - CPS-E-06
+ - Temporal Data Access
+ - - data storage and access
+ - REST
+ * - CPS-E-07
+ - Admin
+ - - logging levels and configuration
+ - monitoring
+ - health including liveliness state and readiness state
+ - metrics through Prometheus
+ - Various
The CPS Basic Concepts are described in :doc:`modeling`.
CPS Path
########
-.. warning:: draft
-
.. toctree::
:maxdepth: 1
CPS Design
##########
-.. warning:: draft
-
.. toctree::
:maxdepth: 1
Offered APIs
============
-CPS supports the public APIs listed in the link below:
+CPS supports the public APIs listed in the following sections.
+
+CPS-Core
+--------
+
+CPS-Core functionality.
:download:`CPS Rest OpenApi Specification <api/swagger/cps/openapi.yaml>`
+CPS-NCMP
+--------
+
+XNF data access and module information.
+
:download:`CPS NCMP RestOpenApi Specification <api/swagger/ncmp/openapi.yaml>`
-Exposed API
------------
+CPS-NCMP-Inventory
+------------------
+
+DMI-Plugin Inventory.
+
+:download:`CPS NCMP RestOpenApi Inventory Specification <api/swagger/ncmp/openapi-inventory.yaml>`
+
+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.
.. code-block:: bash
- “http://<hostname>:<port>/v3/api-docs?group=cps-docket”
+ http://<hostname>:<port>/v3/api-docs?group=cps-docket
+
+Additionally, the Swagger User Interface can be found at the following URI. The component may be changed between CPS-Core, CPS-NCMP
+and CPS-NCMP-Inventory 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#/
+
+Consumed APIs
+=============
+
+CPS Core uses API's from the following ONAP components
+
+* DMI-Plugin: REST based interface which is used to provide integration
+ and allow the DMI registry API's have access to the corresponding NCMP API's within CPS Core.
+ More information on the DMI-Plugins offered APIs can be found on the `DMI-Plugin's Design Page <https://docs.onap.org/projects/onap-cps-ncmp-dmi-plugin/en/latest/design.html>`_.
CPS Path
========
.. THIS IS USED INTERNALLY IN CPS ONLY
.. _cps-framework-doc:
-CPS-Core Documentation
-----------------------
-
-.. warning:: draft
+CPS Documentation
+-----------------
.. toctree::
:maxdepth: 1
deployment.rst
release-notes.rst
-ONAP DMI Plugin Documentation
+DMI-Plugin Documentation
-----------------------------
-* `DMI Plugin(placeholder) `_
+* `DMI-Plugin <https://docs.onap.org/projects/onap-cps-ncmp-dmi-plugin/en/latest/index.html>`_
CPS-Temporal Documentation
--------------------------
-* `CPS Temporal(placeholder) `_
+* `CPS-Temporal <https://docs.onap.org/projects/onap-cps-cps-temporal/en/latest/index.html>`_
.. Copyright (C) 2021 Pantheon.tech
.. _modeling:
+.. toctree::
+ :maxdepth: 1
+
CPS Modeling
############
-.. warning:: draft
+CPS-Core Modeling
+=================
-.. toctree::
- :maxdepth: 1
-
-Basic Concepts
-==============
+Data Model
+----------
.. image:: _static/cps-modeling-concepts.png
:alt: Basic entities relationship
+Basic Concepts
+--------------
+
Administrative entities
- **Dataspace** is a primary logical separation of data.
and uniquely identified by its name (within its own dataspace). Same YANG resources (source files) can be
referenced by multiple schema sets from different dataspaces.
-- **Anchor** identifies the unique data set (data record) within a dataspace
+- **Anchor** identifies the unique data set (data record) within a dataspace.
Anchor always references a schema set within same dataspace which describes a data model of associated data.
Multiple anchors may reference same schema set. Anchor is uniquely identified by its name (within own dataspace).
Querying
-- **CPS Path** is used to query data nodes. The CPS Path is described in detail in the :doc:`cps-path` sub-page.
+- **CPS Path** is used to query data nodes. The CPS Path is described in detail in :doc:`cps-path`.
-CPS Path
-========
+NCMP Modeling
+=============
-.. toctree::
- :maxdepth: 1
+Data Model
+----------
+
+NCMP stores DMI-Plugin and CM Handle relations using a data model described as per this Yang module.
+
+:download:`DMI Yang Module <api/yang/dmiYangResource.yang>`
+
+Basic Concepts
+--------------
+
+- **CM-Handle** represents an instance a modeled Network Function(node) in ONAP.
+
+ These are stored as Anchors within CPS-Core.
+
+- **Datastores** represent different views of the cm data.
- cps-path.rst
+ Datastores are defined for NCMP to access the CPS running or operational datastores. Currently supported datastores are:
+ +--------------------------------+-------------------------------------+-------------------------+
+ | Datastore | Configurations | Data access type |
+ +================================+=====================================+=========================+
+ | Passthrough-operational | config-true, config-false | read-only |
+ +--------------------------------+-------------------------------------+-------------------------+
+ | Passthrough-running | config-true | read-write |
+ +--------------------------------+-------------------------------------+-------------------------+
\ No newline at end of file
CPS Overview
============
-.. warning:: draft
-
The Configuration Persistence Service (CPS) is a platform component that is designed to serve as a
data repository for runtime data that needs persistence.
information, meaning it is information that doesn't belong in A&AI. In principle, some parameters might be both
configuration and operational parameters depending on how they are used.
+CPS Components
+--------------
+
+CPS-Core
+########
+This is the component of CPS which encompasses the generic storage of Yang module data.
+
+**NCMP**
+
+The Network Configuration Management Proxy (NCMP) provides access to network configuration data and is a part of CPS-Core.
+NCMP accesses all network Data-Model-Inventory (DMI) information via NCMP-DMI-Plugins. The ONAP0-DMI-Plugin described in the next section is one such plugin.
+
+**Note:** This documentation will often refer to "CPS-NCMP" which is the component (container image) that contains both CPS-Core and NCMP since NCMP is not a stand-alone component
+even though CPS-Core could be deployed without the NCMP extension.
+
+NCMP-DMI-Plugin
+####################
+
+The Data-Model-Inventory (DMI) Plugin is a rest interface used to synchronize CM-Handles data between CPS and DMI through the DMI-Plugin.
+This is built previously from the CPS-NF-Proxy component.
+
+CPS-Temporal
+############
+
+This service is responsible to provide a time oriented perspective for
+operational network data. It provides features to store and retrieve sequences
+of configurations or states along with the associated times when they occurred
+or have been observed.
+
CPS Project
-----------
CPS Release Notes
=================
-.. warning:: draft
-
.. contents::
:depth: 2
..
.. * * * ISTANBUL * * *
.. ========================
+Version: 2.0.1
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project** | |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images** | onap/cps-and-ncmp:2.0.1 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation** | 2.0.1 Istanbul |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release date** | 2021-14-10 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+
+ - `CPS-594 <https://jira.onap.org/browse/CPS-594>`_ SQL ConstraintViolationException when updating the list node element using PATCH List node API
+ - `CPS-653 <https://jira.onap.org/browse/CPS-653>`_ cmHandleProperties not supported by dmi in fetch modules
+ - `CPS-673 <https://jira.onap.org/browse/CPS-673>`_ Improvement and cleanup for CPS Core charts
+ - `CPS-691 <https://jira.onap.org/browse/CPS-691>`_ NCMP no master index label on index documentation page
+
+Known Limitations, Issues and Workarounds
+-----------------------------------------
+
+*System Limitations*
+
+Limitations to the amount of child nodes that can be added to the fix above. The current limit is 3.
+
+*Known Vulnerabilities*
+
+ - `CPS-725 <https://jira.onap.org/browse/CPS-725>`_ fix sample docker compose of cps/ncmp and onap dmi plugin
+
+*Workarounds*
+
+Add recursive method to save list node data to loop through all corresponding child nodes.
+
+Security Notes
+--------------
+
+*Fixed Security Issues*
+
+ - `CPS-581 <https://jira.onap.org/browse/CPS-581>`_ Remove security vulnerabilities
+
+*Known Security Issues*
+
+None
+
Version: 2.0.0
==============
| **Release designation** | 2.0.0 Istanbul |
| | |
+--------------------------------------+--------------------------------------------------------+
-| **Release date** | 2021-14-10 |
+| **Release date** | 2021-14-09 |
| | |
+--------------------------------------+--------------------------------------------------------+
Features
--------
-* Register DMI Plugins with NCMP for CM Handle registrations.
+* Register DMI-Plugins with NCMP for CM Handle registrations.
* Update, Create and Remove CM Handles.
* Add support for retrieving and writing CM Handle data through NCMP datastores.
* Automatic retrieval and caching of model information for CM Handles within NCMP.
-.. _istanbul_deliverable:
-
Deliverables
------------
Bug Fixes
---------
+ - `CPS-310 <https://jira.onap.org/browse/CPS-310>`_ Data schema migration from Honolulu to Istanbul is failing
- `CPS-316 <https://jira.onap.org/browse/CPS-316>`_ Xpath cannot be created for augmentation data node
- `CPS-336 <https://jira.onap.org/browse/CPS-336>`_ Ends-with functionality in cpsPath does not conform with standard xPath behavior
+ - `CPS-345 <https://jira.onap.org/browse/CPS-345>`_ Leaf String value comparison matches mix of single and double quotes
+ - `CPS-357 <https://jira.onap.org/browse/CPS-357>`_ cps-review-verification-maven-master Jenkins job is failing when running csit test
- `CPS-367 <https://jira.onap.org/browse/CPS-367>`_ Get descendent does not support xpaths that end in list values
- - `CPS-377 <https://jira.onap.org/browse/CPS-377>`_ Init ran model validation is failing, error details are not provided
+ - `CPS-377 <https://jira.onap.org/browse/CPS-377>`_ Init ran model validation is failing error details are not provided
- `CPS-422 <https://jira.onap.org/browse/CPS-422>`_ REST 404 response returned instead of 400 for POST/PUT/PATCH request types
- `CPS-450 <https://jira.onap.org/browse/CPS-450>`_ Datanode query using full path to node causes NPE
+ - `CPS-451 <https://jira.onap.org/browse/CPS-451>`_ cps-ran-schema-model@2021-01-28.yang missing root container
+ - `CPS-464 <https://jira.onap.org/browse/CPS-464>`_ Request to update node leaves (patch) responds with Internal Server Error
+ - `CPS-465 <https://jira.onap.org/browse/CPS-465>`_ Request to update node leaves (patch) responds with json parsing failure
- `CPS-466 <https://jira.onap.org/browse/CPS-466>`_ Concurrent requests to create schema sets for the same yang model are not supported
- `CPS-479 <https://jira.onap.org/browse/CPS-479>`_ Get Nodes API does not always return the object from the root
+ - `CPS-500 <https://jira.onap.org/browse/CPS-500>`_ Special Character Limitations of cpsPath Queries
- `CPS-501 <https://jira.onap.org/browse/CPS-501>`_ Put DataNode API has missing transaction and error handling for concurrency issues
- - `CPS-504 <https://jira.onap.org/browse/CPS-504>`_ Checkstyle rules are not enforced for cps-ncmp-dmi-plugin
- - `CPS-515 <https://jira.onap.org/browse/CPS-515>`_ Maven build is not failing when test containers are not able to run
- - `CPS-520 <https://jira.onap.org/browse/CPS-520>`_ Fix docker profile in cps-temporal and cps-ncmp-dmi-plugin
- `CPS-524 <https://jira.onap.org/browse/CPS-524>`_ Issue with CPSData API to add an item to an existing list node
- `CPS-560 <https://jira.onap.org/browse/CPS-560>`_ Response from cps query using text() contains escape characters
- `CPS-566 <https://jira.onap.org/browse/CPS-566>`_ Can't access grandparent node through ancestor axis
- - `CPS-586 <https://jira.onap.org/browse/CPS-586>`_ App username and password environment variables are missing from temporal docker compose
+ - `CPS-573 <https://jira.onap.org/browse/CPS-573>`_ /v1/ch/PNFDemo1/modules returning 401 unauthorised.
+ - `CPS-587 <https://jira.onap.org/browse/CPS-587>`_ cps-ncmp-service NullpointerException when DmiPluginRegistration has no additionProperties
+ - `CPS-591 <https://jira.onap.org/browse/CPS-591>`_ CPS-Core Leaf stored as integer is being returned from DB as float
+ - `CPS-601 <https://jira.onap.org/browse/CPS-601>`_ CPS swagger-ui does not show NCMP endpoints
+ - `CPS-616 <https://jira.onap.org/browse/CPS-616>`_ NCMP base path does not conform to agreed API URL
+ - `CPS-630 <https://jira.onap.org/browse/CPS-630>`_ Incorrect information sent when same anchor is updated faster than notification service processes
+ - `CPS-635 <https://jira.onap.org/browse/CPS-635>`_ Module Resource call does not include body
This document provides the release notes for Istanbul release.
* Service components
- - CPS Core and NCMP
- - CPS Temporal
- - DMI Plugin
+ - CPS-NCMP
+ - CPS-Temporal
+ - DMI-Plugin
* Additional resources that CPS utilizes deployed using ONAP common charts
Known Limitations, Issues and Workarounds
-----------------------------------------
- - `CPS-524 <https://jira.onap.org/browse/CPS-524>`_ Issue with CPSData API to add an item to an existing list node
-
*System Limitations*
Limitations to the amount of child nodes that can be added to the fix above. The current limit is 3.
*Known Vulnerabilities*
-None
+ - `CPS-594 <https://jira.onap.org/browse/CPS-594>`_ SQL ConstraintViolationException when updating the list node element using PATCH List node API
+ - `CPS-653 <https://jira.onap.org/browse/CPS-653>`_ cmHandleProperties not supported by dmi in fetch modules
+ - `CPS-673 <https://jira.onap.org/browse/CPS-673>`_ Improvement and cleanup for CPS Core charts
*Workarounds*
*Fixed Security Issues*
- `CPS-249 <https://jira.onap.org/browse/CPS-249>`_ Exception stack trace is exposed
- - `CPS-581 <https://jira.onap.org/browse/CPS-581>`_ Remove security vulnerabilities
*Known Security Issues*
+ - `CPS-581 <https://jira.onap.org/browse/CPS-581>`_ Remove security vulnerabilities
+
Test Results
------------
* `Integration tests`