summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/gerrit-verify.yaml151
-rw-r--r--checkstyle/pom.xml2
-rw-r--r--checkstyle/src/main/resources/cps-java-style.xml2
-rw-r--r--cps-application/pom.xml2
-rw-r--r--cps-application/src/main/resources/application.yml2
-rw-r--r--cps-bom/pom.xml2
-rw-r--r--cps-dependencies/pom.xml9
-rw-r--r--cps-events/pom.xml2
-rw-r--r--cps-ncmp-events/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml2
-rw-r--r--cps-ncmp-rest-stub/pom.xml2
-rw-r--r--cps-ncmp-rest/pom.xml2
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy26
-rw-r--r--cps-ncmp-service/pom.xml2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java13
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java89
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy65
-rw-r--r--cps-parent/pom.xml6
-rw-r--r--cps-path-parser/pom.xml2
-rw-r--r--cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathUtil.java8
-rw-r--r--cps-rest/docs/openapi/components.yml414
-rw-r--r--cps-rest/docs/openapi/cpsAdmin.yml232
-rw-r--r--cps-rest/docs/openapi/cpsAdminV1Deprecated.yml92
-rw-r--r--cps-rest/docs/openapi/cpsAdminV2.yml89
-rw-r--r--cps-rest/docs/openapi/cpsData.yml235
-rw-r--r--cps-rest/docs/openapi/cpsDataV1Deprecated.yml71
-rw-r--r--cps-rest/docs/openapi/cpsDataV2.yml127
-rw-r--r--cps-rest/docs/openapi/cpsQueryV1Deprecated.yml50
-rw-r--r--cps-rest/docs/openapi/cpsQueryV2.yml78
-rw-r--r--cps-rest/docs/openapi/openapi.yml116
-rw-r--r--cps-rest/pom.xml30
-rwxr-xr-xcps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java19
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy20
-rw-r--r--cps-ri/pom.xml7
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java15
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java33
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java50
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java4
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java8
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java28
-rw-r--r--cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java6
-rw-r--r--cps-service/pom.xml8
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsDataService.java14
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java14
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/YangParser.java34
-rw-r--r--cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java57
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy14
-rwxr-xr-xcps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy2
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy13
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/utils/YangParserHelperSpec.groovy33
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy48
-rw-r--r--cps-service/src/test/resources/bookstore-categories-data.json49
-rw-r--r--cps-service/src/test/resources/bookstore-categories-data.xml14
-rw-r--r--docker-compose/config/nginx/nginx.conf1
-rw-r--r--docker-compose/docker-compose.yml14
-rw-r--r--docs/api/swagger/cps/openapi.yaml1816
-rw-r--r--docs/api/swagger/ncmp/openapi.yaml88
-rw-r--r--docs/api/swagger/policy-executor/openapi.yaml315
-rw-r--r--docs/cps-delta-endpoints.rst53
-rw-r--r--docs/cps-delta-feature.rst13
-rw-r--r--docs/release-notes.rst38
-rw-r--r--integration-test/pom.xml2
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy3
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy2
-rw-r--r--jacoco-report/pom.xml2
-rw-r--r--k6-tests/ncmp/common/utils.js26
-rw-r--r--k6-tests/once-off-test/kafka/produce-avc-event.js99
-rw-r--r--k6-tests/resources/sampleAvcInputEvent.json38
-rw-r--r--policy-executor-stub/pom.xml2
-rw-r--r--policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java11
-rw-r--r--policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/Sleeper.java35
-rw-r--r--policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy22
-rw-r--r--pom.xml2
-rw-r--r--releases/3.5.3-container.yaml8
-rw-r--r--releases/3.5.3.yaml4
-rw-r--r--spotbugs/pom.xml2
-rw-r--r--version.properties2
80 files changed, 3520 insertions, 1504 deletions
diff --git a/.github/workflows/gerrit-verify.yaml b/.github/workflows/gerrit-verify.yaml
deleted file mode 100644
index 91849215af..0000000000
--- a/.github/workflows/gerrit-verify.yaml
+++ /dev/null
@@ -1,151 +0,0 @@
----
-name: Call Gerrit Verify
-
-# yamllint disable-line rule:truthy
-on:
- workflow_dispatch:
- inputs:
- GERRIT_BRANCH:
- description: "Branch that change is against"
- required: true
- type: string
- GERRIT_CHANGE_ID:
- description: "The ID for the change"
- required: true
- type: string
- GERRIT_CHANGE_NUMBER:
- description: "The Gerrit number"
- required: true
- type: string
- GERRIT_CHANGE_URL:
- description: "URL to the change"
- required: true
- type: string
- GERRIT_EVENT_TYPE:
- description: "Type of Gerrit event"
- required: true
- type: string
- GERRIT_PATCHSET_NUMBER:
- description: "The patch number for the change"
- required: true
- type: string
- GERRIT_PATCHSET_REVISION:
- description: "The revision sha"
- required: true
- type: string
- GERRIT_PROJECT:
- description: "Project in Gerrit"
- required: true
- type: string
- GERRIT_REFSPEC:
- description: "Gerrit refspec of change"
- required: true
- type: string
- secrets:
- GERRIT_SSH_PRIVKEY:
- description: "SSH Key for the authorized user account"
- required: true
-
-concurrency:
- # yamllint disable-line rule:line-length
- group: gerrit-verify-${{ github.workflow }}-${{ github.event.inputs.GERRIT_BRANCH}}-${{ github.event.inputs.GERRIT_CHANGE_ID || github.run_id }}
- cancel-in-progress: true
-
-jobs:
- prepare:
- runs-on: ubuntu-latest
- steps:
- - name: Clear votes
- # yamllint disable-line rule:line-length
- uses: lfit/gerrit-review-action@9627b9a144f2a2cad70707ddfae87c87dce60729 # v0.8
- with:
- host: ${{ vars.GERRIT_SERVER }}
- username: ${{ vars.GERRIT_SSH_USER }}
- key: ${{ secrets.GERRIT_SSH_PRIVKEY }}
- known_hosts: ${{ vars.GERRIT_KNOWN_HOSTS }}
- gerrit-change-number: ${{ inputs.GERRIT_CHANGE_NUMBER }}
- gerrit-patchset-number: ${{ inputs.GERRIT_PATCHSET_NUMBER }}
- vote-type: clear
- comment-only: true
- - name: Allow replication
- run: sleep 10s
-
- actionlint:
- needs: prepare
- runs-on: ubuntu-latest
- steps:
- - name: Gerrit Checkout
- # yamllint disable-line rule:line-length
- uses: lfit/checkout-gerrit-change-action@54d751e8bd167bc91f7d665dabe33fae87aaaa63 # v0.9
- with:
- gerrit-refspec: ${{ inputs.GERRIT_REFSPEC }}
- gerrit-project: ${{ inputs.GERRIT_PROJECT }}
- gerrit-url: ${{ vars.GERRIT_URL }}
- delay: "0s"
- - name: Download actionlint
- id: get_actionlint
- # yamllint disable-line rule:line-length
- run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
- shell: bash
- - name: Check workflow files
- run: ${{ steps.get_actionlint.outputs.executable }} -color
- shell: bash
-
- # run pre-commit tox env separately to get use of more parallel processing
- pre-commit:
- needs: prepare
- runs-on: ubuntu-latest
- steps:
- - name: Gerrit Checkout
- # yamllint disable-line rule:line-length
- uses: lfit/checkout-gerrit-change-action@54d751e8bd167bc91f7d665dabe33fae87aaaa63 # v0.9
- with:
- gerrit-refspec: ${{ inputs.GERRIT_REFSPEC }}
- gerrit-project: ${{ inputs.GERRIT_PROJECT }}
- gerrit-url: ${{ vars.GERRIT_URL }}
- delay: "0s"
- # yamllint disable-line rule:line-length
- - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
- with:
- python-version: "3.11"
- - name: Run static analysis and format checkers
- run: pipx run pre-commit run --all-files --show-diff-on-failure
-
- checkov-scan:
- needs: prepare
- runs-on: ubuntu-latest
- steps:
- - name: Gerrit Checkout
- # yamllint disable-line rule:line-length
- uses: lfit/checkout-gerrit-change-action@54d751e8bd167bc91f7d665dabe33fae87aaaa63 # v0.9
- with:
- gerrit-refspec: ${{ inputs.GERRIT_REFSPEC }}
- gerrit-project: ${{ inputs.GERRIT_PROJECT }}
- gerrit-url: ${{ vars.GERRIT_URL }}
- delay: "0s"
- submodules: "true"
- - name: Checkov GitHub Action
- uses: bridgecrewio/checkov-action@v12
- with:
- output_format: cli,sarif
- output_file_path: console,results.sarif
-
- vote:
- if: ${{ always() }}
- needs: [prepare, actionlint, pre-commit, checkov-scan]
- runs-on: ubuntu-latest
- steps:
- - name: Get conclusion
- uses: im-open/workflow-conclusion@e4f7c4980600fbe0818173e30931d3550801b992 # v2.2.3
- - name: Set vote
- # yamllint disable-line rule:line-length
- uses: lfit/gerrit-review-action@9627b9a144f2a2cad70707ddfae87c87dce60729 # v0.8
- with:
- host: ${{ vars.GERRIT_SERVER }}
- username: ${{ vars.GERRIT_SSH_USER }}
- key: ${{ secrets.GERRIT_SSH_PRIVKEY }}
- known_hosts: ${{ vars.GERRIT_KNOWN_HOSTS }}
- gerrit-change-number: ${{ inputs.GERRIT_CHANGE_NUMBER }}
- gerrit-patchset-number: ${{ inputs.GERRIT_PATCHSET_NUMBER }}
- vote-type: ${{ env.WORKFLOW_CONCLUSION }}
- comment-only: true
diff --git a/checkstyle/pom.xml b/checkstyle/pom.xml
index f618836d0d..0518655c18 100644
--- a/checkstyle/pom.xml
+++ b/checkstyle/pom.xml
@@ -26,7 +26,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>checkstyle</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<profiles>
<profile>
diff --git a/checkstyle/src/main/resources/cps-java-style.xml b/checkstyle/src/main/resources/cps-java-style.xml
index 67b2863695..d10484c31e 100644
--- a/checkstyle/src/main/resources/cps-java-style.xml
+++ b/checkstyle/src/main/resources/cps-java-style.xml
@@ -32,4 +32,4 @@
</module>
<module name="UnusedImports"/>
</module>
-</module> \ No newline at end of file
+</module>
diff --git a/cps-application/pom.xml b/cps-application/pom.xml
index 19710be80b..e8d32eac0e 100644
--- a/cps-application/pom.xml
+++ b/cps-application/pom.xml
@@ -28,7 +28,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml
index b97eabacb8..05b0d09ac5 100644
--- a/cps-application/src/main/resources/application.yml
+++ b/cps-application/src/main/resources/application.yml
@@ -190,7 +190,7 @@ logging:
ncmp:
policy-executor:
enabled: ${POLICY_SERVICE_ENABLED:false}
- defaultDecision: "allow"
+ defaultDecision: ${POLICY_SERVICE_DEFAULT_DECISION:"allow"}
server:
address: ${POLICY_SERVICE_URL:http://policy-executor-stub}
port: ${POLICY_SERVICE_PORT:8093}
diff --git a/cps-bom/pom.xml b/cps-bom/pom.xml
index 31aedab40e..93f4b818ff 100644
--- a/cps-bom/pom.xml
+++ b/cps-bom/pom.xml
@@ -25,7 +25,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>cps-bom</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<packaging>pom</packaging>
<description>This artifact contains dependencyManagement declarations of all published CPS components.</description>
diff --git a/cps-dependencies/pom.xml b/cps-dependencies/pom.xml
index adef9031ab..58e87a8031 100644
--- a/cps-dependencies/pom.xml
+++ b/cps-dependencies/pom.xml
@@ -27,7 +27,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>cps-dependencies</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<packaging>pom</packaging>
<name>${project.groupId}:${project.artifactId}</name>
@@ -126,7 +126,12 @@
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs</artifactId>
- <version>4.2.3</version>
+ <version>4.8.6</version>
+ </dependency>
+ <dependency>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-annotations</artifactId>
+ <version>3.1.3</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
diff --git a/cps-events/pom.xml b/cps-events/pom.xml
index e5fab868c2..16a8817080 100644
--- a/cps-events/pom.xml
+++ b/cps-events/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-events/pom.xml b/cps-ncmp-events/pom.xml
index b0b28992e7..bd81f74327 100644
--- a/cps-ncmp-events/pom.xml
+++ b/cps-ncmp-events/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
index c73a2519ac..aaf884f4dd 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-app/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-ncmp-rest-stub</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
</parent>
<artifactId>cps-ncmp-rest-stub-app</artifactId>
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
index eee0431904..e778e027b2 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/pom.xml
@@ -21,7 +21,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-ncmp-rest-stub</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
</parent>
<artifactId>cps-ncmp-rest-stub-service</artifactId>
diff --git a/cps-ncmp-rest-stub/pom.xml b/cps-ncmp-rest-stub/pom.xml
index 01604e89ff..be361a4504 100644
--- a/cps-ncmp-rest-stub/pom.xml
+++ b/cps-ncmp-rest-stub/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest/pom.xml b/cps-ncmp-rest/pom.xml
index adac504eae..d46767e72c 100644
--- a/cps-ncmp-rest/pom.xml
+++ b/cps-ncmp-rest/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
index 9d36d106c7..e87acacc74 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
@@ -129,19 +129,19 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
then: 'an HTTP response is returned with correct message and details'
assertTestResponse(response, expectedErrorCode, expectedErrorMessage, expectedErrorDetails)
where:
- scenario | exception || expectedErrorCode | expectedErrorMessage | expectedErrorDetails
- 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | sampleErrorDetails
- 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
- 'DMI Request' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || BAD_REQUEST | sampleErrorMessage | null
- 'Invalid Operation' | new InvalidOperationException('some reason') || BAD_REQUEST | 'some reason' | null
- 'Unsupported Operation' | new OperationNotSupportedException('not yet') || BAD_REQUEST | 'not yet' | null
- 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | null
- 'other' | new IllegalStateException(sampleErrorMessage) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
- 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | 'DataNode not found'
- 'Existing entry' | new AlreadyDefinedException('name',null) || CONFLICT | 'Already defined exception' | 'name already exists'
- 'Existing entries' | AlreadyDefinedException.forDataNodes(['A', 'B'], 'myAnchorName') || CONFLICT | 'Already defined exception' | '2 data node(s) already exist'
- 'Operation too large' | new PayloadTooLargeException(sampleErrorMessage) || PAYLOAD_TOO_LARGE | sampleErrorMessage | 'Check logs'
- 'Policy Executor' | new PolicyExecutorException(sampleErrorMessage, sampleErrorDetails) || CONFLICT | sampleErrorMessage | sampleErrorDetails
+ scenario | exception || expectedErrorCode | expectedErrorMessage | expectedErrorDetails
+ 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | sampleErrorDetails
+ 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
+ 'DMI Request' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || BAD_REQUEST | sampleErrorMessage | null
+ 'Invalid Operation' | new InvalidOperationException('some reason') || BAD_REQUEST | 'some reason' | null
+ 'Unsupported Operation' | new OperationNotSupportedException('not yet') || BAD_REQUEST | 'not yet' | null
+ 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | null
+ 'other' | new IllegalStateException(sampleErrorMessage) || INTERNAL_SERVER_ERROR | sampleErrorMessage | null
+ 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || NOT_FOUND | 'DataNode not found' | 'DataNode not found'
+ 'Existing entry' | new AlreadyDefinedException('name',null) || CONFLICT | 'Already defined exception' | 'name already exists'
+ 'Existing entries' | AlreadyDefinedException.forDataNodes(['A', 'B'], 'myAnchorName') || CONFLICT | 'Already defined exception' | '2 data node(s) already exist'
+ 'Operation too large' | new PayloadTooLargeException(sampleErrorMessage) || PAYLOAD_TOO_LARGE | sampleErrorMessage | 'Check logs'
+ 'Policy Executor' | new PolicyExecutorException(sampleErrorMessage, sampleErrorDetails, null) || CONFLICT | sampleErrorMessage | sampleErrorDetails
}
def 'Post request with exception returns correct HTTP Status.'() {
diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml
index 7871aafd6b..9ce9d51363 100644
--- a/cps-ncmp-service/pom.xml
+++ b/cps-ncmp-service/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java
index 6754965866..3c81d0f536 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java
@@ -39,7 +39,18 @@ public class NcmpException extends RuntimeException {
* @param details the error details
*/
public NcmpException(final String message, final String details) {
- super(message);
+ this(message, details, null);
+ }
+
+ /**
+ * Constructor with cause.
+ *
+ * @param message the error message
+ * @param details the error details
+ * @param cause the cause of the exception
+ */
+ public NcmpException(final String message, final String details, final Throwable cause) {
+ super(message, cause);
this.details = details;
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java
index 333c12271b..bb753b85f1 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java
@@ -35,8 +35,9 @@ public class PolicyExecutorException extends NcmpException {
*
* @param message response message
* @param details response details
+ * @param cause the cause of the exception
*/
- public PolicyExecutorException(final String message, final String details) {
- super(message, details);
+ public PolicyExecutorException(final String message, final String details, final Throwable cause) {
+ super(message, details, cause);
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
index caed28a648..af4331893d 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
@@ -23,6 +23,7 @@ package org.onap.cps.ncmp.impl.data.policyexecutor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import java.net.UnknownHostException;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
@@ -45,6 +46,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
@Slf4j
@Service
@@ -71,6 +73,8 @@ public class PolicyExecutor {
private final ObjectMapper objectMapper;
+ private static final Throwable NO_ERROR = null;
+
/**
* Use the Policy Executor to check permission for a cm write operation.
* Wil throw an exception when the operation is not permitted (work in progress)
@@ -88,26 +92,20 @@ public class PolicyExecutor {
final String changeRequestAsJson) {
log.trace("Policy Executor Enabled: {}", enabled);
if (enabled) {
- ResponseEntity<JsonNode> responseEntity = null;
try {
- responseEntity =
- getPolicyExecutorResponse(yangModelCmHandle, operationType, authorization, resourceIdentifier,
- changeRequestAsJson);
- } catch (final RuntimeException runtimeException) {
- processException(runtimeException);
- }
- if (responseEntity == null) {
- log.warn("No valid response from Policy Executor, ignored");
- return;
- }
- if (responseEntity.getStatusCode().is2xxSuccessful()) {
- if (responseEntity.getBody() == null) {
+ final ResponseEntity<JsonNode> responseEntity = getPolicyExecutorResponse(yangModelCmHandle,
+ operationType,
+ authorization,
+ resourceIdentifier,
+ changeRequestAsJson);
+ final JsonNode responseBody = responseEntity.getBody();
+ if (responseBody == null) {
log.warn("No valid response body from Policy Executor, ignored");
return;
}
- processSuccessResponse(responseEntity.getBody());
- } else {
- processNon2xxResponse(responseEntity.getStatusCode().value());
+ processSuccessResponse(responseBody);
+ } catch (final RuntimeException runtimeException) {
+ processException(runtimeException);
}
}
}
@@ -173,35 +171,17 @@ public class PolicyExecutor {
.block();
}
- private void processNon2xxResponse(final int httpStatusCode) {
- processFallbackResponse("Policy Executor returned HTTP Status code " + httpStatusCode + ".");
- }
-
- private void processException(final RuntimeException runtimeException) {
- if (runtimeException.getCause() instanceof TimeoutException) {
- processFallbackResponse("Policy Executor request timed out.");
- } else {
- log.warn("Request to Policy Executor failed with unexpected exception", runtimeException);
- throw runtimeException;
- }
- }
-
- private void processFallbackResponse(final String message) {
- final String decisionId = "N/A";
- final String decision = defaultDecision;
- final String warning = message + " Falling back to configured default decision: " + defaultDecision;
- log.warn(warning);
- processDecision(decisionId, decision, warning);
- }
-
private static void processSuccessResponse(final JsonNode responseBody) {
final String decisionId = responseBody.path("decisionId").asText("unknown id");
final String decision = responseBody.path("decision").asText("unknown");
final String messageFromPolicyExecutor = responseBody.path("message").asText();
- processDecision(decisionId, decision, messageFromPolicyExecutor);
+ processDecision(decisionId, decision, messageFromPolicyExecutor, NO_ERROR);
}
- private static void processDecision(final String decisionId, final String decision, final String details) {
+ private static void processDecision(final String decisionId,
+ final String decision,
+ final String details,
+ final Throwable optionalCauseOfError) {
log.trace("Policy Executor decision id: {} ", decisionId);
if ("allow".equals(decision)) {
log.trace("Operation allowed.");
@@ -209,8 +189,37 @@ public class PolicyExecutor {
log.warn("Policy Executor decision: {}", decision);
log.warn("Policy Executor message: {}", details);
final String message = "Operation not allowed. Decision id " + decisionId + " : " + decision;
- throw new PolicyExecutorException(message, details);
+ throw new PolicyExecutorException(message, details, optionalCauseOfError);
}
}
+ private void processException(final RuntimeException runtimeException) {
+ if (runtimeException instanceof WebClientResponseException) {
+ final WebClientResponseException webClientResponseException = (WebClientResponseException) runtimeException;
+ final int httpStatusCode = webClientResponseException.getStatusCode().value();
+ processFallbackResponse("Policy Executor returned HTTP Status code " + httpStatusCode + ".",
+ webClientResponseException);
+ } else {
+ final Throwable cause = runtimeException.getCause();
+ if (cause instanceof TimeoutException) {
+ processFallbackResponse("Policy Executor request timed out.", cause);
+ } else if (cause instanceof UnknownHostException) {
+ final String message
+ = String.format("Cannot connect to Policy Executor (%s:%s).", serverAddress, serverPort);
+ processFallbackResponse(message, cause);
+ } else {
+ log.warn("Request to Policy Executor failed with unexpected exception", runtimeException);
+ throw runtimeException;
+ }
+ }
+ }
+
+ private void processFallbackResponse(final String message, final Throwable cause) {
+ final String decisionId = "N/A";
+ final String decision = defaultDecision;
+ final String warning = message + " Falling back to configured default decision: " + defaultDecision;
+ log.warn(warning);
+ processDecision(decisionId, decision, warning, cause);
+ }
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java
index 4bc2f10218..1d4e3c8363 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventType.java
@@ -26,10 +26,10 @@ public enum LcmEventType {
private final String eventName;
- private final String eventTypeTemplate = "org.onap.ncmp.cmhandle-lcm-event.%s";
+ private static final String EVENT_TYPE_TEMPLATE = "org.onap.ncmp.cmhandle-lcm-event.%s";
LcmEventType(final String eventName) {
- this.eventName = String.format(eventTypeTemplate, eventName);
+ this.eventName = String.format(EVENT_TYPE_TEMPLATE, eventName);
}
public String getEventType() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
index 46c0ddeb93..33dcf5d623 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
@@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.reactive.function.client.WebClient
+import org.springframework.web.reactive.function.client.WebClientResponseException
import reactor.core.publisher.Mono
import spock.lang.Specification
@@ -59,6 +60,8 @@ class PolicyExecutorSpec extends Specification {
def setup() {
setupLogger()
objectUnderTest.enabled = true
+ objectUnderTest.serverAddress = 'some host'
+ objectUnderTest.serverPort = 'some port'
mockWebClient.post() >> mockRequestBodyUriSpec
mockRequestBodyUriSpec.uri(*_) >> mockRequestBodyUriSpec
mockRequestBodyUriSpec.header(*_) >> mockRequestBodyUriSpec
@@ -95,8 +98,8 @@ class PolicyExecutorSpec extends Specification {
}
def 'Permission check with non-2xx response and "allow" default decision.'() {
- given: 'other http response'
- mockResponse([], HttpStatus.I_AM_A_TEAPOT)
+ given: 'non-2xx http response'
+ mockErrorResponse()
and: 'the configured default decision is "allow"'
objectUnderTest.defaultDecision = 'allow'
when: 'permission is checked for an operation'
@@ -106,8 +109,8 @@ class PolicyExecutorSpec extends Specification {
}
def 'Permission check with non-2xx response and "other" default decision.'() {
- given: 'other http response'
- mockResponse([], HttpStatus.I_AM_A_TEAPOT)
+ given: 'non-2xx http response'
+ def webClientException = mockErrorResponse()
and: 'the configured default decision is NOT "allow"'
objectUnderTest.defaultDecision = 'deny by default'
when: 'permission is checked for an operation'
@@ -116,25 +119,23 @@ class PolicyExecutorSpec extends Specification {
def thrownException = thrown(PolicyExecutorException)
assert thrownException.message == 'Operation not allowed. Decision id N/A : deny by default'
assert thrownException.details == 'Policy Executor returned HTTP Status code 418. Falling back to configured default decision: deny by default'
+ and: 'the cause is the original web client exception'
+ assert thrownException.cause == webClientException
}
def 'Permission check with invalid response from Policy Executor.'() {
given: 'invalid response from Policy executor'
- mockResponseSpec.toEntity(*_) >> invalidResponse
+ mockResponseSpec.toEntity(*_) >> Mono.just(new ResponseEntity<>(null, HttpStatus.OK))
when: 'permission is checked for an operation'
objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', someValidJson)
then: 'system logs the expected message'
- assert getLogEntry(1) == expectedMessage
- where: 'following invalid responses are received'
- invalidResponse || expectedMessage
- Mono.empty() || 'No valid response from Policy Executor, ignored'
- Mono.just(new ResponseEntity<>(null, HttpStatus.OK)) || 'No valid response body from Policy Executor, ignored'
+ assert getLogEntry(1) == 'No valid response body from Policy Executor, ignored'
}
def 'Permission check with timeout exception.'() {
given: 'a timeout during the request'
- def cause = new TimeoutException()
- mockResponseSpec.toEntity(*_) >> { throw new RuntimeException(cause) }
+ def timeoutException = new TimeoutException()
+ mockResponseSpec.toEntity(*_) >> { throw new RuntimeException(timeoutException) }
and: 'the configured default decision is NOT "allow"'
objectUnderTest.defaultDecision = 'deny by default'
when: 'permission is checked for an operation'
@@ -143,6 +144,39 @@ class PolicyExecutorSpec extends Specification {
def thrownException = thrown(PolicyExecutorException)
assert thrownException.message == 'Operation not allowed. Decision id N/A : deny by default'
assert thrownException.details == 'Policy Executor request timed out. Falling back to configured default decision: deny by default'
+ and: 'the cause is the original time out exception'
+ assert thrownException.cause == timeoutException
+ }
+
+ def 'Permission check with unknown host.'() {
+ given: 'a unknown host exception during the request'
+ def unknownHostException = new UnknownHostException()
+ mockResponseSpec.toEntity(*_) >> { throw new RuntimeException(unknownHostException) }
+ and: 'the configured default decision is NOT "allow"'
+ objectUnderTest.defaultDecision = 'deny by default'
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', someValidJson)
+ then: 'Policy Executor exception is thrown'
+ def thrownException = thrown(PolicyExecutorException)
+ assert thrownException.message == 'Operation not allowed. Decision id N/A : deny by default'
+ assert thrownException.details == 'Cannot connect to Policy Executor (some host:some port). Falling back to configured default decision: deny by default'
+ and: 'the cause is the original unknown host exception'
+ assert thrownException.cause == unknownHostException
+ }
+
+ def 'Permission check with #scenario exception and default decision "allow".'() {
+ given: 'a #scenario exception during the request'
+ mockResponseSpec.toEntity(*_) >> { throw new RuntimeException(cause)}
+ and: 'the configured default decision is "allow"'
+ objectUnderTest.defaultDecision = 'allow'
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', someValidJson)
+ then: 'no exception is thrown'
+ noExceptionThrown()
+ where: 'the following exceptions are thrown during the request'
+ scenario | cause
+ 'timeout' | new TimeoutException()
+ 'unknown host' | new UnknownHostException()
}
def 'Permission check with other runtime exception.'() {
@@ -180,6 +214,13 @@ class PolicyExecutorSpec extends Specification {
mockResponseSpec.toEntity(*_) >> mono
}
+ def mockErrorResponse() {
+ def webClientResponseException = Mock(WebClientResponseException)
+ webClientResponseException.getStatusCode() >> HttpStatus.I_AM_A_TEAPOT
+ mockResponseSpec.toEntity(*_) >> { throw webClientResponseException }
+ return webClientResponseException
+ }
+
def setupLogger() {
def logger = LoggerFactory.getLogger(PolicyExecutor)
logger.setLevel(Level.TRACE)
diff --git a/cps-parent/pom.xml b/cps-parent/pom.xml
index 430f4b5cd8..256e7a7dee 100644
--- a/cps-parent/pom.xml
+++ b/cps-parent/pom.xml
@@ -32,7 +32,7 @@
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
@@ -154,12 +154,12 @@
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
- <version>4.4.2</version>
+ <version>4.8.6.4</version>
<dependencies>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs</artifactId>
- <version>4.2.3</version>
+ <version>4.8.6</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
diff --git a/cps-path-parser/pom.xml b/cps-path-parser/pom.xml
index f71d9aabcd..7b015ad74f 100644
--- a/cps-path-parser/pom.xml
+++ b/cps-path-parser/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathUtil.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathUtil.java
index bde9b0638f..4ede0d9c90 100644
--- a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathUtil.java
+++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathUtil.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,12 +59,10 @@ public class CpsPathUtil {
return getCpsPathBuilder(xpathSource).build().getNormalizedParentPath();
}
- public static String[] getXpathNodeIdSequence(final String xpathSource) {
- final List<String> containerNames = getCpsPathBuilder(xpathSource).build().getContainerNames();
- return containerNames.toArray(new String[containerNames.size()]);
+ public static List<String> getXpathNodeIdSequence(final String xpathSource) {
+ return getCpsPathBuilder(xpathSource).build().getContainerNames();
}
-
/**
* Returns boolean indicating xpath is an absolute path to a list element.
*
diff --git a/cps-rest/docs/openapi/components.yml b/cps-rest/docs/openapi/components.yml
new file mode 100644
index 0000000000..40f0e170ff
--- /dev/null
+++ b/cps-rest/docs/openapi/components.yml
@@ -0,0 +1,414 @@
+# ============LICENSE_START=======================================================
+# Copyright (c) 2021-2022 Bell Canada.
+# Modifications Copyright (C) 2021-2023 Nordix Foundation
+# Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
+# Modifications Copyright (C) 2022 Deutsche Telekom AG
+# ================================================================================
+# 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=========================================================
+
+components:
+ schemas:
+
+ AnchorDetails:
+ type: object
+ title: Anchor details by anchor Name
+ properties:
+ name:
+ type: string
+ example: my-anchor
+ dataspaceName:
+ type: string
+ example: my-dataspace
+ schemaSetName:
+ type: string
+ example: my-schema-set
+
+ DataspaceDetails:
+ type: object
+ title: Dataspace details by dataspace Name
+ properties:
+ name:
+ type: string
+ example: my-dataspace
+
+ ErrorMessage:
+ type: object
+ title: Error
+ properties:
+ status:
+ type: string
+ message:
+ type: string
+ details:
+ type: string
+
+ MultipartFile:
+ type: object
+ required:
+ - file
+ properties:
+ file:
+ type: string
+ description: multipartFile
+ format: binary
+
+ ModuleReferences:
+ type: object
+ title: Module reference object
+ properties:
+ name:
+ type: string
+ example: my-module-reference-name
+ namespace:
+ type: string
+ example: my-module-reference-namespace
+ revision:
+ type: string
+ example: my-module-reference-revision
+
+ SchemaSetDetails:
+ type: object
+ title: Schema set details by dataspace and schemasetName
+ required:
+ - "moduleReferences"
+ properties:
+ dataspaceName:
+ type: string
+ example: my-dataspace
+ moduleReferences:
+ type: array
+ items:
+ $ref: '#/components/schemas/ModuleReferences'
+ name:
+ type: string
+ example: my-schema-set
+
+ examples:
+ dataSample:
+ value:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 01
+ name: SciFi
+ - code: 02
+ name: kids
+ dataSampleXml:
+ value:
+ <stores xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <bookstore xmlns="org:onap:ccsdk:sample">
+ <bookstore-name>Chapters</bookstore-name>
+ <categories>
+ <code>1</code>
+ <name>SciFi</name>
+ <code>2</code>
+ <name>kids</name>
+ </categories>
+ </bookstore>
+ </stores>
+ dataSampleAcrossAnchors:
+ value:
+ - anchorName: bookstore1
+ dataNode:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 01
+ name: SciFi
+ - code: 02
+ name: kids
+ - anchorName: bookstore2
+ dataNode:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 01
+ name: SciFi
+ - code: 02
+ name: kids
+ deltaReportSample:
+ value:
+ - action: "create"
+ xpath: "/bookstore/categories/[@code=3]"
+ target-data:
+ code: 3,
+ name: "kidz"
+ - action: "remove"
+ xpath: "/bookstore/categories/[@code=1]"
+ source-data:
+ code: 1,
+ name: "Fiction"
+ - action: "replace"
+ xpath: "/bookstore/categories/[@code=2]"
+ source-data:
+ name: "Funny"
+ target-data:
+ name: "Comic"
+
+ parameters:
+ dataspaceNameInQuery:
+ name: dataspace-name
+ in: query
+ description: dataspace-name
+ required: true
+ schema:
+ type: string
+ example: my-dataspace
+ dataspaceNameInPath:
+ name: dataspace-name
+ in: path
+ description: dataspace-name
+ required: true
+ schema:
+ type: string
+ example: my-dataspace
+ anchorNameInPath:
+ name: anchor-name
+ in: path
+ description: anchor-name
+ required: true
+ schema:
+ type: string
+ example: my-anchor
+ sourceAnchorNameInPath:
+ name: source-anchor-name
+ in: path
+ description: source-anchor-name
+ required: true
+ schema:
+ type: string
+ example: my-anchor
+ schemaSetNameInQuery:
+ name: schema-set-name
+ in: query
+ description: schema-set-name
+ required: true
+ schema:
+ type: string
+ example: my-schema-set
+ schemaSetNameInPath:
+ name: schema-set-name
+ in: path
+ description: schema-set-name
+ required: true
+ schema:
+ type: string
+ example: my-schema-set
+ anchorNameInQuery:
+ name: anchor-name
+ in: query
+ description: anchor-name
+ required: true
+ schema:
+ type: string
+ example: my-anchor
+ targetAnchorNameInQuery:
+ name: target-anchor-name
+ in: query
+ description: target-anchor-name
+ required: true
+ schema:
+ type: string
+ example: my-anchor
+ xpathInQuery:
+ name: xpath
+ in: query
+ description: For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html
+ required: false
+ schema:
+ type: string
+ default: /
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: /shops/bookstore/categories[@code=1]
+ requiredXpathInQuery:
+ name: xpath
+ in: query
+ description: For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html
+ required: true
+ schema:
+ type: string
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: /shops/bookstore/categories[@code=1]
+ cpsPathInQuery:
+ name: cps-path
+ in: query
+ description: For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html
+ required: false
+ schema:
+ type: string
+ default: /
+ examples:
+ container cps path:
+ value: //bookstore
+ list attributes cps path:
+ value: //categories[@code=1]
+ includeDescendantsOptionInQuery:
+ name: include-descendants
+ in: query
+ description: include-descendants
+ required: false
+ schema:
+ type: boolean
+ default: false
+ example: false
+ observedTimestampInQuery:
+ name: observed-timestamp
+ in: query
+ description: observed-timestamp
+ required: false
+ schema:
+ type: string
+ example: '2021-03-21T00:10:34.030-0100'
+ apiVersionInPath:
+ name: apiVersion
+ in: path
+ description: apiVersion
+ required: true
+ schema:
+ type: string
+ enum: [v1, v2]
+ default: v2
+ contentTypeInHeader:
+ name: Content-Type
+ in: header
+ description: Content type in header
+ schema:
+ type: string
+ example: 'application/json'
+ required: true
+ descendantsInQuery:
+ name: descendants
+ in: query
+ description: Number of descendants to query. Allowed values are 'none', 'all', 'direct', 1 (for direct), -1 (for all), 0 (for none) and any positive number.
+ required: false
+ schema:
+ type: string
+ default: none
+ example: 3
+ pageIndexInQuery:
+ name: pageIndex
+ in: query
+ description: page index for pagination over anchors. It must be greater then zero if provided.
+ required: false
+ schema:
+ type: integer
+ example: 1
+ pageSizeInQuery:
+ name: pageSize
+ in: query
+ description: number of records (anchors) per page. It must be greater then zero if provided.
+ required: false
+ schema:
+ type: integer
+ example: 10
+ dryRunInQuery:
+ name: dry-run
+ in: query
+ description: Boolean flag to validate data, without persisting it. Default value is set to false.
+ required: false
+ schema:
+ type: boolean
+ default: false
+ example: false
+
+ responses:
+ NotFound:
+ description: The specified resource was not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 404
+ message: Resource Not Found
+ details: The requested resource is not found
+ Unauthorized:
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 401
+ message: Unauthorized request
+ details: This request is unauthorized
+ Forbidden:
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 403
+ message: Request Forbidden
+ details: This request is forbidden
+ BadRequest:
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 400
+ message: Bad Request
+ details: The provided request is not valid
+ Conflict:
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: 409
+ message: Conflicting request
+ details: The request cannot be processed as the resource is in use.
+ Ok:
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ value: ""
+ Created:
+ description: Created
+ content:
+ application/json:
+ schema:
+ type: string
+ example: my-resource
+ CreatedV2:
+ description: Created without response body
+ InternalServerError:
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ErrorMessage"
+ example:
+ status: 500
+ message: Internal Server Error
+ details: Internal Server Error occurred
+ NoContent:
+ description: No Content
+ content: {}
diff --git a/cps-rest/docs/openapi/cpsAdmin.yml b/cps-rest/docs/openapi/cpsAdmin.yml
new file mode 100644
index 0000000000..f394270dd5
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsAdmin.yml
@@ -0,0 +1,232 @@
+# ============LICENSE_START=======================================================
+# Copyright (c) 2021 Bell Canada.
+# Modifications Copyright (C) 2021-2022 Nordix Foundation
+# Modifications Copyright (C) 2022 TechMahindra Ltd.
+# ================================================================================
+# 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=========================================================
+
+dataspaces:
+ delete:
+ description: Delete a dataspace
+ tags:
+ - cps-admin
+ summary: Delete a dataspace
+ operationId: deleteDataspace
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInQuery'
+ responses:
+ '204':
+ $ref: 'components.yml#/components/responses/NoContent'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+schemaSet:
+ get:
+ description: Read all schema sets, given a dataspace
+ tags:
+ - cps-admin
+ summary: Get schema sets
+ operationId: getSchemaSets
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: 'components.yml#/components/schemas/SchemaSetDetails'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+schemaSetBySchemaSetName:
+ get:
+ description: Read a schema set given a schema set name and a dataspace
+ tags:
+ - cps-admin
+ summary: Get a schema set
+ operationId: getSchemaSet
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/schemaSetNameInPath'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: 'components.yml#/components/schemas/SchemaSetDetails'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ delete:
+ description: Delete a schema set given a schema set name and a dataspace
+ tags:
+ - cps-admin
+ summary: Delete a schema set
+ operationId: deleteSchemaSet
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/schemaSetNameInPath'
+ responses:
+ '204':
+ $ref: 'components.yml#/components/responses/NoContent'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+anchorsByDataspace:
+ get:
+ description: Read all anchors, given a dataspace
+ tags:
+ - cps-admin
+ summary: Get anchors
+ operationId: getAnchors
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: 'components.yml#/components/schemas/AnchorDetails'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+anchorByDataspaceAndAnchorName:
+ get:
+ description: Read an anchor given an anchor name and a dataspace
+ tags:
+ - cps-admin
+ summary: Get an anchor
+ operationId: getAnchor
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: 'components.yml#/components/schemas/AnchorDetails'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ delete:
+ description: Delete an anchor given an anchor name and a dataspace
+ tags:
+ - cps-admin
+ summary: Delete an anchor
+ operationId: deleteAnchor
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ responses:
+ '204':
+ $ref: 'components.yml#/components/responses/NoContent'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+adminDataspaces:
+ get:
+ description: Read all dataspaces
+ tags:
+ - cps-admin
+ summary: Get all dataspaces
+ operationId: getAllDataspaces
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: 'components.yml#/components/schemas/DataspaceDetails'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+adminDataspace:
+ get:
+ description: Read a dataspace given a dataspace name
+ tags:
+ - cps-admin
+ summary: Get a dataspace
+ operationId: getDataspace
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: 'components.yml#/components/schemas/DataspaceDetails'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
diff --git a/cps-rest/docs/openapi/cpsAdminV1Deprecated.yml b/cps-rest/docs/openapi/cpsAdminV1Deprecated.yml
new file mode 100644
index 0000000000..c92f773c30
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsAdminV1Deprecated.yml
@@ -0,0 +1,92 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2022 TechMahindra Ltd.
+# ================================================================================
+# 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=========================================================
+
+dataspaces:
+ post:
+ deprecated: true
+ description: Create a new dataspace
+ tags:
+ - cps-admin
+ summary: Create a dataspace
+ operationId: createDataspace
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInQuery'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/Created'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+anchorsByDataspace:
+ post:
+ deprecated: true
+ description: Create a new anchor in the given dataspace
+ tags:
+ - cps-admin
+ summary: Create an anchor
+ operationId: createAnchor
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/schemaSetNameInQuery'
+ - $ref: 'components.yml#/components/parameters/anchorNameInQuery'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/Created'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+schemaSet:
+ post:
+ deprecated: true
+ description: Create a new schema set in the given dataspace
+ tags:
+ - cps-admin
+ summary: Create a schema set
+ operationId: createSchemaSet
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/schemaSetNameInQuery'
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ $ref: 'components.yml#/components/schemas/MultipartFile'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/Created'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
diff --git a/cps-rest/docs/openapi/cpsAdminV2.yml b/cps-rest/docs/openapi/cpsAdminV2.yml
new file mode 100644
index 0000000000..e501ad8b15
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsAdminV2.yml
@@ -0,0 +1,89 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2022 TechMahindra Ltd.
+# ================================================================================
+# 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=========================================================
+
+dataspaces:
+ post:
+ description: Create a new dataspace
+ tags:
+ - cps-admin
+ summary: Create a dataspace
+ operationId: createDataspaceV2
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInQuery'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/CreatedV2'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+anchorsByDataspace:
+ post:
+ description: Create a new anchor in the given dataspace
+ tags:
+ - cps-admin
+ summary: Create an anchor
+ operationId: createAnchorV2
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/schemaSetNameInQuery'
+ - $ref: 'components.yml#/components/parameters/anchorNameInQuery'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/CreatedV2'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+schemaSet:
+ post:
+ description: Create a new schema set in the given dataspace
+ tags:
+ - cps-admin
+ summary: Create a schema set
+ operationId: createSchemaSetV2
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/schemaSetNameInQuery'
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ $ref: 'components.yml#/components/schemas/MultipartFile'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/CreatedV2'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml
new file mode 100644
index 0000000000..daf59bbfbf
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsData.yml
@@ -0,0 +1,235 @@
+# ============LICENSE_START=======================================================
+# Copyright (c) 2021-2022 Bell Canada.
+# Modifications Copyright (C) 2021-2022 Nordix Foundation
+# Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
+# Modifications Copyright (C) 2022 Deutsche Telekom AG
+# ================================================================================
+# 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=========================================================
+
+listElementByDataspaceAndAnchor:
+ post:
+ description: Add list element(s) to a list for a given anchor and dataspace
+ tags:
+ - cps-data
+ summary: Add list element(s)
+ operationId: addListElements
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/requiredXpathInQuery'
+ - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: string
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/Created'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ put:
+ description: Replace list content under a given parent, anchor and dataspace
+ tags:
+ - cps-data
+ summary: Replace list content
+ operationId: replaceListContent
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/requiredXpathInQuery'
+ - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ responses:
+ '200':
+ $ref: 'components.yml#/components/responses/Ok'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+
+nodesByDataspaceAndAnchor:
+ post:
+ description: Create a node for a given anchor and dataspace
+ tags:
+ - cps-data
+ summary: Create a node
+ operationId: createNode
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/dryRunInQuery'
+ - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: string
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object # Workaround to show example
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
+ responses:
+ '201':
+ $ref: 'components.yml#/components/responses/Created'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '409':
+ $ref: 'components.yml#/components/responses/Conflict'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ patch:
+ description: Update a data node leaves for a given dataspace and anchor and a parent node xpath. This operation
+ is currently supported for one top level data node only.
+ tags:
+ - cps-data
+ summary: Update node leaves
+ operationId: updateNodeLeaves
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: string
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
+ responses:
+ '200':
+ $ref: 'components.yml#/components/responses/Ok'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ delete:
+ description: Delete a datanode for a given dataspace and anchor given a node xpath.
+ tags:
+ - cps-data
+ summary: Delete a data node
+ operationId: deleteDataNode
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ responses:
+ '204':
+ $ref: 'components.yml#/components/responses/NoContent'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ put:
+ description: Replace a node with descendants for a given dataspace, anchor and a parent node xpath
+ tags:
+ - cps-data
+ summary: Replace a node with descendants
+ operationId: replaceNode
+ parameters:
+ - $ref: 'components.yml#/components/parameters/apiVersionInPath'
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ - $ref: 'components.yml#/components/parameters/contentTypeInHeader'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: string
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ application/xml:
+ schema:
+ type: object
+ xml:
+ name: stores
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleXml'
+ responses:
+ '200':
+ $ref: 'components.yml#/components/responses/Ok'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
diff --git a/cps-rest/docs/openapi/cpsDataV1Deprecated.yml b/cps-rest/docs/openapi/cpsDataV1Deprecated.yml
new file mode 100644
index 0000000000..3941856422
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsDataV1Deprecated.yml
@@ -0,0 +1,71 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2022-2023 TechMahindra Ltd.
+# ================================================================================
+# 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=========================================================
+
+nodeByDataspaceAndAnchor:
+ get:
+ description: Get a node with an option to retrieve all the children for a given anchor and dataspace
+ deprecated: true
+ tags:
+ - cps-data
+ summary: Get a node
+ operationId: getNodeByDataspaceAndAnchor
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/includeDescendantsOptionInQuery'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ x-codegen-request-body-name: xpath
+
+listElementByDataspaceAndAnchor:
+ delete:
+ description: Delete one or all list element(s) for a given anchor and dataspace
+ deprecated: true
+ tags:
+ - cps-data
+ summary: Delete one or all list element(s)
+ operationId: deleteListOrListElement
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/requiredXpathInQuery'
+ - $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
+ responses:
+ '204':
+ $ref: 'components.yml#/components/responses/NoContent'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
diff --git a/cps-rest/docs/openapi/cpsDataV2.yml b/cps-rest/docs/openapi/cpsDataV2.yml
new file mode 100644
index 0000000000..d5a8ef3891
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsDataV2.yml
@@ -0,0 +1,127 @@
+# ============LICENSE_START=======================================================
+# Copyright (c) 2022-2024 TechMahindra Ltd.
+# ================================================================================
+# 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=========================================================
+
+nodeByDataspaceAndAnchor:
+ get:
+ description: Get a node with an option to retrieve all the children for a given anchor and dataspace
+ tags:
+ - cps-data
+ summary: Get a node
+ operationId: getNodeByDataspaceAndAnchorV2
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/descendantsInQuery'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ x-codegen-request-body-name: xpath
+
+delta:
+ get:
+ description: Get delta between two anchors within a given dataspace
+ tags:
+ - cps-data
+ summary: Get delta between anchors in the same dataspace
+ operationId: getDeltaByDataspaceAndAnchors
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/sourceAnchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/targetAnchorNameInQuery'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/descendantsInQuery'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/deltaReportSample'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ x-codegen-request-body-name: xpath
+ post:
+ description: Get delta between an anchor in a dataspace and JSON payload
+ tags:
+ - cps-data
+ summary: Get delta between an anchor and JSON payload
+ operationId: getDeltaByDataspaceAnchorAndPayload
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/sourceAnchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/xpathInQuery'
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ json:
+ type: object
+ example:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 01
+ name: SciFi
+ - code: 02
+ name: kids
+ file:
+ type: string
+ format: binary
+ required:
+ - json
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/deltaReportSample'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '401':
+ $ref: 'components.yml#/components/responses/Unauthorized'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError' \ No newline at end of file
diff --git a/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml b/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml
new file mode 100644
index 0000000000..9db2823994
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml
@@ -0,0 +1,50 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Nordix Foundation
+# Modifications Copyright (c) 2022 Bell Canada.
+# Modifications Copyright (c) 2023 TechMahindra Ltd.
+# ================================================================================
+# 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=========================================================
+
+nodesByDataspaceAndAnchorAndCpsPath:
+ get:
+ description: Query data nodes for the given dataspace and anchor using CPS path
+ tags:
+ - cps-query
+ summary: Query data nodes
+ deprecated: true
+ operationId: getNodesByDataspaceAndAnchorAndCpsPath
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/cpsPathInQuery'
+ - $ref: 'components.yml#/components/parameters/includeDescendantsOptionInQuery'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ x-codegen-request-body-name: xpath
diff --git a/cps-rest/docs/openapi/cpsQueryV2.yml b/cps-rest/docs/openapi/cpsQueryV2.yml
new file mode 100644
index 0000000000..7f0ceff768
--- /dev/null
+++ b/cps-rest/docs/openapi/cpsQueryV2.yml
@@ -0,0 +1,78 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2023 TechMahindra Ltd.
+# ================================================================================
+# 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=========================================================
+
+nodesByDataspaceAndAnchorAndCpsPath:
+ get:
+ description: Query data nodes for the given dataspace and anchor using CPS path
+ tags:
+ - cps-query
+ summary: Query data nodes
+ operationId: getNodesByDataspaceAndAnchorAndCpsPathV2
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/anchorNameInPath'
+ - $ref: 'components.yml#/components/parameters/cpsPathInQuery'
+ - $ref: 'components.yml#/components/parameters/descendantsInQuery'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSample'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ x-codegen-request-body-name: xpath
+
+nodesByDataspaceAndCpsPath:
+ get:
+ description: Query data nodes for the given dataspace across anchors using CPS path
+ tags:
+ - cps-query
+ summary: Query data nodes across anchors
+ operationId: getNodesByDataspaceAndCpsPath
+ parameters:
+ - $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
+ - $ref: 'components.yml#/components/parameters/cpsPathInQuery'
+ - $ref: 'components.yml#/components/parameters/descendantsInQuery'
+ - $ref: 'components.yml#/components/parameters/pageIndexInQuery'
+ - $ref: 'components.yml#/components/parameters/pageSizeInQuery'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ examples:
+ dataSample:
+ $ref: 'components.yml#/components/examples/dataSampleAcrossAnchors'
+ '400':
+ $ref: 'components.yml#/components/responses/BadRequest'
+ '403':
+ $ref: 'components.yml#/components/responses/Forbidden'
+ '500':
+ $ref: 'components.yml#/components/responses/InternalServerError'
+ x-codegen-request-body-name: xpath
diff --git a/cps-rest/docs/openapi/openapi.yml b/cps-rest/docs/openapi/openapi.yml
new file mode 100644
index 0000000000..70f06fbee2
--- /dev/null
+++ b/cps-rest/docs/openapi/openapi.yml
@@ -0,0 +1,116 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021-2023 Nordix Foundation
+# Modifications Copyright (C) 2021 Pantheon.tech
+# Modifications Copyright (C) 2021 Bell Canada.
+# Modifications Copyright (C) 2022-2024 TechMahindra Ltd.
+# ================================================================================
+# 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.3
+info:
+ title: ONAP Open API v3 Configuration Persistence Service
+ description: Configuration Persistence Service is a Model Driven Generic Database
+ version: "3.5.2"
+ contact:
+ name: ONAP
+ url: "https://onap.readthedocs.io"
+ email: "onap-discuss@lists.onap.org"
+ license:
+ name: "Apache 2.0"
+ url: "http://www.apache.org/licenses/LICENSE-2.0"
+
+servers:
+ - url: /cps/api
+components:
+ securitySchemes:
+ basicAuth:
+ type: http
+ scheme: basic
+tags:
+ - name: cps-admin
+ description: cps Admin
+ - name: cps-data
+ description: cps Data
+paths:
+
+ /v1/dataspaces:
+ $ref: 'cpsAdminV1Deprecated.yml#/dataspaces'
+
+ /{apiVersion}/dataspaces:
+ $ref: 'cpsAdmin.yml#/dataspaces'
+
+ /v2/dataspaces:
+ $ref: 'cpsAdminV2.yml#/dataspaces'
+
+ /{apiVersion}/admin/dataspaces:
+ $ref: 'cpsAdmin.yml#/adminDataspaces'
+
+ /{apiVersion}/admin/dataspaces/{dataspace-name}:
+ $ref: 'cpsAdmin.yml#/adminDataspace'
+
+ /v1/dataspaces/{dataspace-name}/anchors:
+ $ref: 'cpsAdminV1Deprecated.yml#/anchorsByDataspace'
+
+ /v2/dataspaces/{dataspace-name}/anchors:
+ $ref: 'cpsAdminV2.yml#/anchorsByDataspace'
+
+ /{apiVersion}/dataspaces/{dataspace-name}/anchors:
+ $ref: 'cpsAdmin.yml#/anchorsByDataspace'
+
+ /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}:
+ $ref: 'cpsAdmin.yml#/anchorByDataspaceAndAnchorName'
+
+ /v1/dataspaces/{dataspace-name}/schema-sets:
+ $ref: 'cpsAdminV1Deprecated.yml#/schemaSet'
+
+ /v2/dataspaces/{dataspace-name}/schema-sets:
+ $ref: 'cpsAdminV2.yml#/schemaSet'
+
+ /{apiVersion}/dataspaces/{dataspace-name}/schema-sets:
+ $ref: 'cpsAdmin.yml#/schemaSet'
+
+ /{apiVersion}/dataspaces/{dataspace-name}/schema-sets/{schema-set-name}:
+ $ref: 'cpsAdmin.yml#/schemaSetBySchemaSetName'
+
+ /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
+ $ref: 'cpsDataV1Deprecated.yml#/nodeByDataspaceAndAnchor'
+
+ /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
+ $ref: 'cpsDataV2.yml#/nodeByDataspaceAndAnchor'
+
+ /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes:
+ $ref: 'cpsData.yml#/nodesByDataspaceAndAnchor'
+
+ /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
+ $ref: 'cpsDataV1Deprecated.yml#/listElementByDataspaceAndAnchor'
+
+ /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
+ $ref: 'cpsData.yml#/listElementByDataspaceAndAnchor'
+
+ /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta:
+ $ref: 'cpsDataV2.yml#/delta'
+
+ /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
+ $ref: 'cpsQueryV1Deprecated.yml#/nodesByDataspaceAndAnchorAndCpsPath'
+
+ /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
+ $ref: 'cpsQueryV2.yml#/nodesByDataspaceAndAnchorAndCpsPath'
+
+ /v2/dataspaces/{dataspace-name}/nodes/query:
+ $ref: 'cpsQueryV2.yml#/nodesByDataspaceAndCpsPath'
+
+security:
+ - basicAuth: []
diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml
index f115fdfd52..20fb299948 100644
--- a/cps-rest/pom.xml
+++ b/cps-rest/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -141,7 +141,7 @@
<goal>generate</goal>
</goals>
<configuration>
- <inputSpec>${project.basedir}/../docs/api/swagger/cps/openapi.yaml</inputSpec>
+ <inputSpec>${project.basedir}/docs/openapi/openapi.yml</inputSpec>
<invokerPackage>org.onap.cps.rest.controller</invokerPackage>
<modelPackage>org.onap.cps.rest.model</modelPackage>
<apiPackage>org.onap.cps.rest.api</apiPackage>
@@ -165,7 +165,7 @@
</goals>
<phase>compile</phase>
<configuration>
- <inputSpec>${project.basedir}/../docs/api/swagger/cps/openapi.yaml</inputSpec>
+ <inputSpec>${project.basedir}/docs/openapi/openapi.yml</inputSpec>
<generatorName>openapi-yaml</generatorName>
<configOptions>
<outputFile>openapi.yaml</outputFile>
@@ -174,6 +174,30 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resources</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.basedir}/target/classes/static/api-docs/cps-core</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${project.basedir}/target/generated-sources/openapi/</directory>
+ <includes>
+ <include>openapi.yaml</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
index f86073fb06..7390afcf98 100755
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
@@ -74,16 +74,21 @@ public class DataRestController implements CpsDataApi {
final String dataspaceName, final String anchorName,
final String contentTypeInHeader,
final String nodeData, final String parentNodeXpath,
- final String observedTimestamp) {
+ final Boolean dryRunEnabled, final String observedTimestamp) {
final ContentType contentType = getContentTypeFromHeader(contentTypeInHeader);
- if (isRootXpath(parentNodeXpath)) {
- cpsDataService.saveData(dataspaceName, anchorName, nodeData,
- toOffsetDateTime(observedTimestamp), contentType);
+ if (Boolean.TRUE.equals(dryRunEnabled)) {
+ cpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, nodeData, contentType);
+ return ResponseEntity.ok().build();
} else {
- cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath,
- nodeData, toOffsetDateTime(observedTimestamp), contentType);
+ if (isRootXpath(parentNodeXpath)) {
+ cpsDataService.saveData(dataspaceName, anchorName, nodeData,
+ toOffsetDateTime(observedTimestamp), contentType);
+ } else {
+ cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath,
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
+ }
+ return ResponseEntity.status(HttpStatus.CREATED).build();
}
- return new ResponseEntity<>(HttpStatus.CREATED);
}
@Override
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
index e101ea6c41..705c2fee91 100755
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
@@ -164,6 +164,26 @@ class DataRestControllerSpec extends Specification {
'with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_JSON | requestBodyJson || 0 | HttpStatus.BAD_REQUEST | expectedJsonData | ContentType.JSON
}
+ def 'Validate data using create a node API'() {
+ given: 'an endpoint to create a node'
+ def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
+ def parentNodeXpath = '/'
+ def dryRunEnabled = 'true'
+ when: 'post is invoked with json data and dry-run flag enabled'
+ def response =
+ mvc.perform(
+ post(endpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .param('xpath', parentNodeXpath)
+ .param('dry-run', dryRunEnabled)
+ .content(requestBodyJson)
+ ).andReturn().response
+ then: 'a 200 OK response is returned'
+ response.status == HttpStatus.OK.value()
+ then: 'the service was called with correct parameters'
+ 1 * mockCpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, requestBodyJson, ContentType.JSON)
+ }
+
def 'Create a child node #scenario'() {
given: 'endpoint to create a node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml
index 57e6528441..bcf6c802de 100644
--- a/cps-ri/pom.xml
+++ b/cps-ri/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -68,6 +68,11 @@
<artifactId>postgresql</artifactId>
<version>${postgres.version}</version>
</dependency>
+ <!-- Disable SpotBug Rules -->
+ <dependency>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-annotations</artifactId>
+ </dependency>
<!-- Add Hibernate support for Postgres datatype JSONB and Postgres arrays -->
<dependency>
<groupId>io.hypersistence</groupId>
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java
index ec46fea4cb..ee555f7dc8 100644
--- a/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java
@@ -341,8 +341,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
if (anchorIds.isEmpty()) {
fragmentEntities = fragmentRepository.findByDataspaceAndXpathIn(dataspaceEntity, ancestorXpaths);
} else {
- fragmentEntities = fragmentRepository.findByAnchorIdsAndXpathIn(
- anchorIds.toArray(new Long[0]), ancestorXpaths.toArray(new String[0]));
+ fragmentEntities = fragmentRepository.findByAnchorIdsAndXpathIn(anchorIds, ancestorXpaths);
}
}
@@ -475,7 +474,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
fragmentRepository.findAllXpathByAnchorAndXpathIn(anchorEntity, deleteChecklist);
if (onlySupportListDeletion) {
final Collection<String> xpathsToExistingListElements = xpathsToExistingContainers.stream()
- .filter(CpsPathUtil::isPathToListElement).collect(Collectors.toList());
+ .filter(CpsPathUtil::isPathToListElement).toList();
deleteChecklist.removeAll(xpathsToExistingListElements);
} else {
deleteChecklist.removeAll(xpathsToExistingContainers);
@@ -483,15 +482,19 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
final Collection<String> xpathsToExistingLists = deleteChecklist.stream()
.filter(xpath -> fragmentRepository.existsByAnchorAndXpathStartsWith(anchorEntity, xpath + "["))
- .collect(Collectors.toList());
+ .toList();
deleteChecklist.removeAll(xpathsToExistingLists);
if (!deleteChecklist.isEmpty()) {
throw new DataNodeNotFoundExceptionBatch(dataspaceName, anchorName, deleteChecklist);
}
- fragmentRepository.deleteByAnchorIdAndXpaths(anchorEntity.getId(), xpathsToExistingContainers);
- fragmentRepository.deleteListsByAnchorIdAndXpaths(anchorEntity.getId(), xpathsToExistingLists);
+ if (!xpathsToExistingContainers.isEmpty()) {
+ fragmentRepository.deleteByAnchorIdAndXpaths(anchorEntity.getId(), xpathsToExistingContainers);
+ }
+ for (final String listXpath : xpathsToExistingLists) {
+ fragmentRepository.deleteListByAnchorIdAndXpath(anchorEntity.getId(), listXpath);
+ }
}
@Override
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java
index 7fe14b3173..f7f750c983 100755
--- a/cps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/AnchorRepository.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,26 +46,26 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Long> {
Collection<AnchorEntity> findAllBySchemaSet(SchemaSetEntity schemaSetEntity);
- @Query(value = "SELECT * FROM anchor WHERE dataspace_id = :dataspaceId AND name = ANY (:anchorNames)",
+ @Query(value = "SELECT * FROM anchor WHERE dataspace_id = :dataspaceId AND name IN (:anchorNames)",
nativeQuery = true)
Collection<AnchorEntity> findAllByDataspaceIdAndNameIn(@Param("dataspaceId") int dataspaceId,
- @Param("anchorNames") String[] anchorNames);
+ @Param("anchorNames") Collection<String> anchorNames);
default Collection<AnchorEntity> findAllByDataspaceAndNameIn(final DataspaceEntity dataspaceEntity,
final Collection<String> anchorNames) {
- return findAllByDataspaceIdAndNameIn(dataspaceEntity.getId(), anchorNames.toArray(new String[0]));
+ return findAllByDataspaceIdAndNameIn(dataspaceEntity.getId(), anchorNames);
}
@Query(value = "SELECT a.* FROM anchor a"
+ " LEFT OUTER JOIN schema_set s ON a.schema_set_id = s.id"
- + " WHERE a.dataspace_id = :dataspaceId AND s.name = ANY (:schemaSetNames)",
+ + " WHERE a.dataspace_id = :dataspaceId AND s.name IN (:schemaSetNames)",
nativeQuery = true)
- Collection<AnchorEntity> findAllByDataspaceIdAndSchemaSetNameIn(@Param("dataspaceId") int dataspaceId,
- @Param("schemaSetNames") String[] schemaSetNames);
+ Collection<AnchorEntity> findAllByDataspaceIdAndSchemaSetNameIn(
+ @Param("dataspaceId") int dataspaceId, @Param("schemaSetNames") Collection<String> schemaSetNames);
default Collection<AnchorEntity> findAllByDataspaceAndSchemaSetNameIn(final DataspaceEntity dataspaceEntity,
final Collection<String> schemaSetNames) {
- return findAllByDataspaceIdAndSchemaSetNameIn(dataspaceEntity.getId(), schemaSetNames.toArray(new String[0]));
+ return findAllByDataspaceIdAndSchemaSetNameIn(dataspaceEntity.getId(), schemaSetNames);
}
Integer countByDataspace(DataspaceEntity dataspaceEntity);
@@ -80,7 +80,7 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Long> {
JOIN anchor ON anchor.schema_set_id = schema_set.id
WHERE
schema_set.dataspace_id = :dataspaceId
- AND module_name = ANY ( :moduleNames )
+ AND module_name IN (:moduleNames)
GROUP BY
anchor.id,
anchor.name,
@@ -90,25 +90,18 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Long> {
COUNT(DISTINCT module_name) = :sizeOfModuleNames
""", nativeQuery = true)
Collection<String> getAnchorNamesByDataspaceIdAndModuleNames(@Param("dataspaceId") int dataspaceId,
- @Param("moduleNames") String[] moduleNames,
+ @Param("moduleNames") Collection<String> moduleNames,
@Param("sizeOfModuleNames") int sizeOfModuleNames);
- default Collection<String> getAnchorNamesByDataspaceIdAndModuleNames(final int dataspaceId,
- final Collection<String> moduleNames,
- final int sizeOfModuleNames) {
- final String[] moduleNamesArray = moduleNames.toArray(new String[0]);
- return getAnchorNamesByDataspaceIdAndModuleNames(dataspaceId, moduleNamesArray, sizeOfModuleNames);
- }
-
@Modifying
- @Query(value = "DELETE FROM anchor WHERE dataspace_id = :dataspaceId AND name = ANY (:anchorNames)",
+ @Query(value = "DELETE FROM anchor WHERE dataspace_id = :dataspaceId AND name IN (:anchorNames)",
nativeQuery = true)
void deleteAllByDataspaceIdAndNameIn(@Param("dataspaceId") int dataspaceId,
- @Param("anchorNames") String[] anchorNames);
+ @Param("anchorNames") Collection<String> anchorNames);
default void deleteAllByDataspaceAndNameIn(final DataspaceEntity dataspaceEntity,
final Collection<String> anchorNames) {
- deleteAllByDataspaceIdAndNameIn(dataspaceEntity.getId(), anchorNames.toArray(new String[0]));
+ deleteAllByDataspaceIdAndNameIn(dataspaceEntity.getId(), anchorNames);
}
@Modifying
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java
index 8edc3f2311..9598230cdb 100755
--- a/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/FragmentRepository.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2023 Nordix Foundation.
+ * Copyright (C) 2021-2024 Nordix Foundation.
* Modifications Copyright (C) 2020-2021 Bell Canada.
* Modifications Copyright (C) 2020-2021 Pantheon.tech.
* Modifications Copyright (C) 2023 TechMahindra Ltd.
@@ -48,14 +48,14 @@ public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>,
new DataNodeNotFoundException(anchorEntity.getDataspace().getName(), anchorEntity.getName(), xpath));
}
- @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)",
+ @Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId AND xpath IN (:xpaths)",
nativeQuery = true)
List<FragmentEntity> findByAnchorIdAndXpathIn(@Param("anchorId") long anchorId,
- @Param("xpaths") String[] xpaths);
+ @Param("xpaths") Collection<String> xpaths);
default List<FragmentEntity> findByAnchorAndXpathIn(final AnchorEntity anchorEntity,
final Collection<String> xpaths) {
- return findByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths.toArray(new String[0]));
+ return findByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths);
}
@Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId \n"
@@ -70,58 +70,52 @@ public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>,
}
@Query(value = "SELECT fragment.* FROM fragment JOIN anchor ON anchor.id = fragment.anchor_id "
- + "WHERE dataspace_id = :dataspaceId AND xpath = ANY (:xpaths)", nativeQuery = true)
+ + "WHERE dataspace_id = :dataspaceId AND xpath IN (:xpaths)", nativeQuery = true)
List<FragmentEntity> findByDataspaceIdAndXpathIn(@Param("dataspaceId") int dataspaceId,
- @Param("xpaths") String[] xpaths);
+ @Param("xpaths") Collection<String> xpaths);
default List<FragmentEntity> findByDataspaceAndXpathIn(final DataspaceEntity dataspaceEntity,
final Collection<String> xpaths) {
- return findByDataspaceIdAndXpathIn(dataspaceEntity.getId(), xpaths.toArray(new String[0]));
+ return findByDataspaceIdAndXpathIn(dataspaceEntity.getId(), xpaths);
}
@Query(value = "SELECT * FROM fragment WHERE anchor_id IN (:anchorIds)"
- + " AND xpath = ANY (:xpaths)", nativeQuery = true)
- List<FragmentEntity> findByAnchorIdsAndXpathIn(@Param("anchorIds") Long[] anchorIds,
- @Param("xpaths") String[] xpaths);
+ + " AND xpath IN (:xpaths)", nativeQuery = true)
+ List<FragmentEntity> findByAnchorIdsAndXpathIn(@Param("anchorIds") Collection<Long> anchorIds,
+ @Param("xpaths") Collection<String> xpaths);
@Query(value = "SELECT * FROM fragment WHERE anchor_id = :anchorId LIMIT 1", nativeQuery = true)
Optional<FragmentEntity> findOneByAnchorId(@Param("anchorId") long anchorId);
@Modifying
- @Query(value = "DELETE FROM fragment WHERE anchor_id = ANY (:anchorIds)", nativeQuery = true)
- void deleteByAnchorIdIn(@Param("anchorIds") long[] anchorIds);
+ @Query(value = "DELETE FROM fragment WHERE anchor_id IN (:anchorIds)", nativeQuery = true)
+ void deleteByAnchorIdIn(@Param("anchorIds") Collection<Long> anchorIds);
default void deleteByAnchorIn(final Collection<AnchorEntity> anchorEntities) {
- deleteByAnchorIdIn(anchorEntities.stream().map(AnchorEntity::getId).mapToLong(id -> id).toArray());
+ deleteByAnchorIdIn(anchorEntities.stream().map(AnchorEntity::getId).toList());
}
@Modifying
- @Query(value = "DELETE FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)", nativeQuery = true)
- void deleteByAnchorIdAndXpaths(@Param("anchorId") long anchorId, @Param("xpaths") String[] xpaths);
-
- default void deleteByAnchorIdAndXpaths(final long anchorId, final Collection<String> xpaths) {
- deleteByAnchorIdAndXpaths(anchorId, xpaths.toArray(new String[0]));
- }
+ @Query(value = "DELETE FROM fragment WHERE anchor_id = :anchorId AND xpath IN (:xpaths)", nativeQuery = true)
+ void deleteByAnchorIdAndXpaths(@Param("anchorId") long anchorId, @Param("xpaths") Collection<String> xpaths);
@Modifying
- @Query(value = "DELETE FROM fragment f WHERE anchor_id = :anchorId AND xpath LIKE ANY (:xpathPatterns)",
+ @Query(value = "DELETE FROM fragment f WHERE anchor_id = :anchorId AND xpath LIKE :xpathPattern",
nativeQuery = true)
- void deleteByAnchorIdAndXpathLikeAny(@Param("anchorId") long anchorId,
- @Param("xpathPatterns") String[] xpathPatterns);
+ void deleteByAnchorIdAndXpathLike(@Param("anchorId") long anchorId, @Param("xpathPattern") String xpathPattern);
- default void deleteListsByAnchorIdAndXpaths(long anchorId, Collection<String> xpaths) {
- deleteByAnchorIdAndXpathLikeAny(anchorId,
- xpaths.stream().map(xpath -> EscapeUtils.escapeForSqlLike(xpath) + "[@%").toArray(String[]::new));
+ default void deleteListByAnchorIdAndXpath(final long anchorId, final String xpath) {
+ deleteByAnchorIdAndXpathLike(anchorId, EscapeUtils.escapeForSqlLike(xpath) + "[@%");
}
- @Query(value = "SELECT xpath FROM fragment WHERE anchor_id = :anchorId AND xpath = ANY (:xpaths)",
+ @Query(value = "SELECT xpath FROM fragment WHERE anchor_id = :anchorId AND xpath IN (:xpaths)",
nativeQuery = true)
List<String> findAllXpathByAnchorIdAndXpathIn(@Param("anchorId") long anchorId,
- @Param("xpaths") String[] xpaths);
+ @Param("xpaths") Collection<String> xpaths);
default List<String> findAllXpathByAnchorAndXpathIn(final AnchorEntity anchorEntity,
final Collection<String> xpaths) {
- return findAllXpathByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths.toArray(new String[0]));
+ return findAllXpathByAnchorIdAndXpathIn(anchorEntity.getId(), xpaths);
}
@Query(value = "SELECT EXISTS(SELECT 1 FROM fragment WHERE anchor_id = :anchorId"
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java
index c160fb1e38..4ca02a9c3c 100644
--- a/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/ModuleReferenceRepositoryImpl.java
@@ -20,6 +20,7 @@
package org.onap.cps.ri.repository;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
@@ -64,7 +65,7 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
}
final String tempTableName = tempTableCreator.createTemporaryTable(
- "moduleReferencesToCheckTemp", sqlData, "module_name", "revision");
+ "moduleReferencesToCheckTemp", sqlData, List.of("module_name", "revision"));
return identifyNewModuleReferencesForCmHandle(tempTableName);
}
@@ -118,6 +119,7 @@ public class ModuleReferenceRepositoryImpl implements ModuleReferenceQuery {
query.setParameter(4, dataspaceName);
}
+ @SuppressFBWarnings(value = "VA_FORMAT_STRING_USES_NEWLINE", justification = "no \n in string just in file format")
private String buildModuleReferencesSqlQuery(final String parentFragmentClause, final String childFragmentClause) {
return """
WITH Fragment AS (
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java
index 9357a5c6a7..b455bc04c0 100644
--- a/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
- * Modifications Copyright (C) 2023 Nordix Foundation
+ * Modifications Copyright (C) 2023-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,10 +61,10 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte
}
@Modifying
- @Query(value = "DELETE FROM schema_set WHERE dataspace_id = :dataspaceId AND name = ANY (:schemaSetNames)",
+ @Query(value = "DELETE FROM schema_set WHERE dataspace_id = :dataspaceId AND name IN (:schemaSetNames)",
nativeQuery = true)
void deleteByDataspaceIdAndNameIn(@Param("dataspaceId") final int dataspaceId,
- @Param("schemaSetNames") final String[] schemaSetNames);
+ @Param("schemaSetNames") final Collection<String> schemaSetNames);
/**
* Delete multiple schema sets in a given dataspace.
@@ -73,7 +73,7 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte
*/
default void deleteByDataspaceAndNameIn(final DataspaceEntity dataspaceEntity,
final Collection<String> schemaSetNames) {
- deleteByDataspaceIdAndNameIn(dataspaceEntity.getId(), schemaSetNames.toArray(new String[0]));
+ deleteByDataspaceIdAndNameIn(dataspaceEntity.getId(), schemaSetNames);
}
}
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java
index cc83ab7d94..25c1491502 100644
--- a/cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/TempTableCreator.java
@@ -1,6 +1,6 @@
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation.
+ * Copyright (C) 2022-2024 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,10 +22,8 @@ package org.onap.cps.ri.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
-import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -54,7 +52,7 @@ public class TempTableCreator {
*/
public String createTemporaryTable(final String prefix,
final Collection<List<String>> sqlData,
- final String... columnNames) {
+ final Collection<String> columnNames) {
final String tempTableName = prefix + UUID.randomUUID().toString().replace("-", "");
final StringBuilder sqlStringBuilder = new StringBuilder("CREATE TEMPORARY TABLE ");
sqlStringBuilder.append(tempTableName);
@@ -65,29 +63,21 @@ public class TempTableCreator {
return tempTableName;
}
- private static void defineColumns(final StringBuilder sqlStringBuilder, final String[] columnNames) {
- sqlStringBuilder.append('(');
- final Iterator<String> it = Arrays.stream(columnNames).iterator();
- while (it.hasNext()) {
- final String columnName = it.next();
- sqlStringBuilder.append(" ");
- sqlStringBuilder.append(columnName);
- sqlStringBuilder.append(" varchar NOT NULL");
- if (it.hasNext()) {
- sqlStringBuilder.append(",");
- }
- }
- sqlStringBuilder.append(")");
+ private static void defineColumns(final StringBuilder sqlStringBuilder, final Collection<String> columnNames) {
+ final String columns = columnNames.stream()
+ .map(columnName -> " " + columnName + " varchar NOT NULL")
+ .collect(Collectors.joining(","));
+ sqlStringBuilder.append('(').append(columns).append(')');
}
private static void insertData(final StringBuilder sqlStringBuilder,
final String tempTableName,
- final String[] columnNames,
+ final Collection<String> columnNames,
final Collection<List<String>> sqlData) {
final Collection<String> sqlInserts = new HashSet<>(sqlData.size());
for (final Collection<String> rowValues : sqlData) {
final Collection<String> escapedValues =
- rowValues.stream().map(EscapeUtils::escapeForSqlStringLiteral).collect(Collectors.toList());
+ rowValues.stream().map(EscapeUtils::escapeForSqlStringLiteral).toList();
sqlInserts.add("('" + String.join("','", escapedValues) + "')");
}
sqlStringBuilder.append("INSERT INTO ");
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java
index 9a11592310..831766cc9a 100644
--- a/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/YangResourceRepository.java
@@ -35,11 +35,7 @@ import org.springframework.stereotype.Repository;
public interface YangResourceRepository extends JpaRepository<YangResourceEntity, Integer>,
YangResourceNativeRepository, SchemaSetYangResourceRepository {
- List<YangResourceEntity> findAllByChecksumIn(String[] checksums);
-
- default List<YangResourceEntity> findAllByChecksumIn(final Collection<String> checksums) {
- return findAllByChecksumIn(checksums.toArray(new String[0]));
- }
+ List<YangResourceEntity> findAllByChecksumIn(Collection<String> checksums);
@Query(value = """
SELECT DISTINCT
diff --git a/cps-service/pom.xml b/cps-service/pom.xml
index 2a9c75f4a6..68cd206c96 100644
--- a/cps-service/pom.xml
+++ b/cps-service/pom.xml
@@ -29,7 +29,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
@@ -64,6 +64,11 @@
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
+ <!-- Disable SpotBug Rules -->
+ <dependency>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-annotations</artifactId>
+ </dependency>
<dependency>
<!-- For parsing JSON object -->
<groupId>com.google.code.gson</groupId>
@@ -139,6 +144,7 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+
<!-- T E S T D E P E N D E N C I E S -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
index 68e1880d77..b3eff8eb26 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java
@@ -322,4 +322,18 @@ public interface CpsDataService {
Map<String, String> yangResourcesNameToContentMap,
String targetData,
FetchDescendantsOption fetchDescendantsOption);
+
+
+ /**
+ * Validates JSON or XML data by parsing it using the schema associated to an anchor within the given dataspace.
+ * Validation is performed without persisting the data.
+ *
+ * @param dataspaceName the name of the dataspace where the anchor is located.
+ * @param anchorName the name of the anchor used to validate the data.
+ * @param parentNodeXpath the xpath of the parent node where the data is to be validated.
+ * @param nodeData the JSON or XML data to be validated.
+ * @param contentType the content type of the data (e.g., JSON or XML).
+ */
+ void validateData(String dataspaceName, String anchorName, String parentNodeXpath, String nodeData,
+ ContentType contentType);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
index eed4f09bf0..b1b545be68 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java
@@ -64,6 +64,7 @@ import org.springframework.stereotype.Service;
public class CpsDataServiceImpl implements CpsDataService {
private static final String ROOT_NODE_XPATH = "/";
+ private static final String PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH = "";
private static final long DEFAULT_LOCK_TIMEOUT_IN_MILLISECONDS = 300L;
private static final String NO_DATA_NODES = "No data nodes.";
@@ -358,6 +359,14 @@ public class CpsDataServiceImpl implements CpsDataService {
sendDataUpdatedEvent(anchor, listNodeXpath, Operation.DELETE, observedTimestamp);
}
+ @Override
+ public void validateData(final String dataspaceName, final String anchorName, final String parentNodeXpath,
+ final String nodeData, final ContentType contentType) {
+ final Anchor anchor = cpsAnchorService.getAnchor(dataspaceName, anchorName);
+ final String xpath = ROOT_NODE_XPATH.equals(parentNodeXpath) ? PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH :
+ CpsPathUtil.getNormalizedXpath(parentNodeXpath);
+ yangParser.validateData(contentType, nodeData, anchor, xpath);
+ }
private Collection<DataNode> rebuildSourceDataNodes(final String xpath, final Anchor sourceAnchor,
final Collection<DataNode> sourceDataNodes) {
@@ -422,7 +431,8 @@ public class CpsDataServiceImpl implements CpsDataService {
final String nodeData, final ContentType contentType) {
if (ROOT_NODE_XPATH.equals(parentNodeXpath)) {
- final ContainerNode containerNode = yangParser.parseData(contentType, nodeData, anchor, "");
+ final ContainerNode containerNode = yangParser.parseData(contentType, nodeData,
+ anchor, PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH);
final Collection<DataNode> dataNodes = new DataNodeBuilder()
.withContainerNode(containerNode)
.buildCollection();
@@ -450,7 +460,7 @@ public class CpsDataServiceImpl implements CpsDataService {
if (isRootNodeXpath(xpath)) {
final ContainerNode containerNode = yangParser.parseData(contentType, nodeData,
- yangResourcesNameToContentMap, "");
+ yangResourcesNameToContentMap, PARENT_NODE_XPATH_FOR_ROOT_NODE_XPATH);
final Collection<DataNode> dataNodes = new DataNodeBuilder()
.withContainerNode(containerNode)
.buildCollection();
diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangParser.java b/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
index dc23c6bc4a..168e0999d5 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/YangParser.java
@@ -21,6 +21,9 @@
package org.onap.cps.utils;
+import static org.onap.cps.utils.YangParserHelper.VALIDATE_AND_PARSE;
+import static org.onap.cps.utils.YangParserHelper.VALIDATE_ONLY;
+
import io.micrometer.core.annotation.Timed;
import java.util.Map;
import lombok.RequiredArgsConstructor;
@@ -57,11 +60,12 @@ public class YangParser {
final String parentNodeXpath) {
final SchemaContext schemaContext = getSchemaContext(anchor);
try {
- return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
+ return yangParserHelper
+ .parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_AND_PARSE);
} catch (final DataValidationException e) {
invalidateCache(anchor);
}
- return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
+ return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_AND_PARSE);
}
/**
@@ -78,7 +82,31 @@ public class YangParser {
final Map<String, String> yangResourcesNameToContentMap,
final String parentNodeXpath) {
final SchemaContext schemaContext = getSchemaContext(yangResourcesNameToContentMap);
- return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath);
+ return yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_AND_PARSE);
+ }
+
+ /**
+ * Parses data to validate it, using the schema context for given anchor.
+ *
+ * @param anchor the anchor used for node data validation
+ * @param parentNodeXpath the xpath of the parent node
+ * @param nodeData JSON or XML data string to validate
+ * @param contentType the content type of the data (e.g., JSON or XML)
+ * @throws DataValidationException if validation fails
+ */
+ public void validateData(final ContentType contentType,
+ final String nodeData,
+ final Anchor anchor,
+ final String parentNodeXpath) {
+ final SchemaContext schemaContext = getSchemaContext(anchor);
+ try {
+ yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_ONLY);
+ } catch (final DataValidationException e) {
+ invalidateCache(anchor);
+ log.error("Data validation failed for anchor: {}, xpath: {}, details: {}", anchor, parentNodeXpath,
+ e.getMessage());
+ }
+ yangParserHelper.parseData(contentType, nodeData, schemaContext, parentNodeXpath, VALIDATE_ONLY);
}
private SchemaContext getSchemaContext(final Anchor anchor) {
diff --git a/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java b/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
index 597164598a..5612945ea9 100644
--- a/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
+++ b/cps-service/src/main/java/org/onap/cps/utils/YangParserHelper.java
@@ -22,6 +22,7 @@ package org.onap.cps.utils;
import com.google.gson.JsonSyntaxException;
import com.google.gson.stream.JsonReader;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.io.StringReader;
import java.net.URISyntaxException;
@@ -29,6 +30,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLInputFactory;
@@ -70,6 +72,9 @@ public class YangParserHelper {
static final String DATA_ROOT_NODE_NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0";
static final String DATA_ROOT_NODE_TAG_NAME = "data";
+ static final String DATA_VALIDATION_FAILURE_MESSAGE = "Data Validation Failed";
+ static final boolean VALIDATE_ONLY = true;
+ static final boolean VALIDATE_AND_PARSE = false;
/**
* Parses data into NormalizedNode according to given schema context.
@@ -83,11 +88,20 @@ public class YangParserHelper {
public ContainerNode parseData(final ContentType contentType,
final String nodeData,
final SchemaContext schemaContext,
- final String parentNodeXpath) {
+ final String parentNodeXpath,
+ final boolean validateOnly) {
if (contentType == ContentType.JSON) {
- return parseJsonData(nodeData, schemaContext, parentNodeXpath);
+ final ContainerNode validatedAndParsedJson = parseJsonData(nodeData, schemaContext, parentNodeXpath);
+ if (validateOnly) {
+ return null;
+ }
+ return validatedAndParsedJson;
+ }
+ final NormalizedNodeResult normalizedNodeResult = parseXmlData(nodeData, schemaContext, parentNodeXpath);
+ if (validateOnly) {
+ return null;
}
- return parseXmlData(nodeData, schemaContext, parentNodeXpath);
+ return buildContainerNodeFormNormalizedNodeResult(normalizedNodeResult);
}
private ContainerNode parseJsonData(final String jsonData,
@@ -122,12 +136,13 @@ public class YangParserHelper {
jsonParserStream.parse(jsonReader);
} catch (final IOException | JsonSyntaxException | IllegalStateException | IllegalArgumentException exception) {
throw new DataValidationException(
- "Data Validation Failed", "Failed to parse json data. " + exception.getMessage(), exception);
+ DATA_VALIDATION_FAILURE_MESSAGE, "Failed to parse json data. " + exception.getMessage(), exception);
}
return dataContainerNodeBuilder.build();
}
- private ContainerNode parseXmlData(final String xmlData,
+ @SuppressFBWarnings(value = "DCN_NULLPOINTER_EXCEPTION", justification = "Problem originates in 3PP code")
+ private NormalizedNodeResult parseXmlData(final String xmlData,
final SchemaContext schemaContext,
final String parentNodeXpath) {
final XMLInputFactory factory = XMLInputFactory.newInstance();
@@ -164,12 +179,17 @@ public class YangParserHelper {
} catch (final XMLStreamException | URISyntaxException | IOException | SAXException | NullPointerException
| ParserConfigurationException | TransformerException exception) {
throw new DataValidationException(
- "Data Validation Failed", "Failed to parse xml data: " + exception.getMessage(), exception);
+ DATA_VALIDATION_FAILURE_MESSAGE, "Failed to parse xml data: " + exception.getMessage(), exception);
}
+ return normalizedNodeResult;
+ }
+
+ private ContainerNode buildContainerNodeFormNormalizedNodeResult(final NormalizedNodeResult normalizedNodeResult) {
+
final DataContainerChild dataContainerChild =
- (DataContainerChild) getFirstChildXmlRoot(normalizedNodeResult.getResult());
+ (DataContainerChild) getFirstChildXmlRoot(normalizedNodeResult.getResult());
final YangInstanceIdentifier.NodeIdentifier nodeIdentifier =
- new YangInstanceIdentifier.NodeIdentifier(dataContainerChild.getIdentifier().getNodeType());
+ new YangInstanceIdentifier.NodeIdentifier(dataContainerChild.getIdentifier().getNodeType());
return Builders.containerBuilder().withChild(dataContainerChild).withNodeIdentifier(nodeIdentifier).build();
}
@@ -181,12 +201,12 @@ public class YangParserHelper {
private static Map<String, Object> getDataSchemaNodeAndIdentifiersByXpath(final String parentNodeXpath,
final SchemaContext schemaContext) {
- final String[] xpathNodeIdSequence = xpathToNodeIdSequence(parentNodeXpath);
+ final List<String> xpathNodeIdSequence = xpathToNodeIdSequence(parentNodeXpath);
return findDataSchemaNodeAndIdentifiersByXpathNodeIdSequence(xpathNodeIdSequence, schemaContext.getChildNodes(),
new ArrayList<>());
}
- private static String[] xpathToNodeIdSequence(final String xpath) {
+ private static List<String> xpathToNodeIdSequence(final String xpath) {
try {
return CpsPathUtil.getXpathNodeIdSequence(xpath);
} catch (final PathParsingException pathParsingException) {
@@ -196,17 +216,16 @@ public class YangParserHelper {
}
private static Map<String, Object> findDataSchemaNodeAndIdentifiersByXpathNodeIdSequence(
- final String[] xpathNodeIdSequence,
+ final List<String> xpathNodeIdSequence,
final Collection<? extends DataSchemaNode> dataSchemaNodes,
final Collection<QName> dataSchemaNodeIdentifiers) {
- final String currentXpathNodeId = xpathNodeIdSequence[0];
+ final String currentXpathNodeId = xpathNodeIdSequence.get(0);
final DataSchemaNode currentDataSchemaNode = dataSchemaNodes.stream()
.filter(dataSchemaNode -> currentXpathNodeId.equals(dataSchemaNode.getQName().getLocalName()))
.findFirst().orElseThrow(() -> schemaNodeNotFoundException(currentXpathNodeId));
dataSchemaNodeIdentifiers.add(currentDataSchemaNode.getQName());
- if (xpathNodeIdSequence.length <= 1) {
- final Map<String, Object> dataSchemaNodeAndIdentifiers =
- new HashMap<>();
+ if (xpathNodeIdSequence.size() <= 1) {
+ final Map<String, Object> dataSchemaNodeAndIdentifiers = new HashMap<>();
dataSchemaNodeAndIdentifiers.put("dataSchemaNode", currentDataSchemaNode);
dataSchemaNodeAndIdentifiers.put("dataSchemaNodeIdentifiers", dataSchemaNodeIdentifiers);
return dataSchemaNodeAndIdentifiers;
@@ -217,13 +236,11 @@ public class YangParserHelper {
((DataNodeContainer) currentDataSchemaNode).getChildNodes(),
dataSchemaNodeIdentifiers);
}
- throw schemaNodeNotFoundException(xpathNodeIdSequence[1]);
+ throw schemaNodeNotFoundException(xpathNodeIdSequence.get(1));
}
- private static String[] getNextLevelXpathNodeIdSequence(final String[] xpathNodeIdSequence) {
- final String[] nextXpathNodeIdSequence = new String[xpathNodeIdSequence.length - 1];
- System.arraycopy(xpathNodeIdSequence, 1, nextXpathNodeIdSequence, 0, nextXpathNodeIdSequence.length);
- return nextXpathNodeIdSequence;
+ private static List<String> getNextLevelXpathNodeIdSequence(final List<String> xpathNodeIdSequence) {
+ return xpathNodeIdSequence.subList(1, xpathNodeIdSequence.size());
}
private static DataValidationException schemaNodeNotFoundException(final String schemaNodeIdentifier) {
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
index 9846b30158..8c208a1cf8 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -546,6 +546,20 @@ class CpsDataServiceImplSpec extends Specification {
1 * mockDataUpdateEventsService.publishCpsDataUpdateEvent(anchor2, '/', DELETE, observedTimestamp)
}
+ def "Validating #scenario when dry run is enabled."() {
+ given: 'schema set for given anchors and dataspace references bookstore model'
+ setupSchemaSetMocks('bookstore.yang')
+ when: 'validating the data with the given parameters'
+ objectUnderTest.validateData(dataspaceName, anchorName, parentNodeXpath, data,contentType)
+ then: 'the appropriate yang parser method is invoked with correct parameters'
+ yangParser.validateData(contentType, data, anchor, xpath)
+ where: 'the following parameters were used'
+ scenario | parentNodeXpath | xpath | contentType | data
+ 'JSON data with root node xpath' | '/' | '' | ContentType.JSON | '{"bookstore":{"bookstore-name":"Easons"}}'
+ 'JSON data with specific xpath' | '/bookstore' | '/bookstore' | ContentType.JSON | '{"bookstore-name":"Easons"}'
+ 'XML data with specific xpath' | '/bookstore' | '/bookstore' | ContentType.XML | '<bookstore-name>Easons</bookstore-name>'
+ }
+
def 'Start session.'() {
when: 'start session method is called'
objectUnderTest.startSession()
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
index 05c8983fc2..9f3456280e 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
@@ -171,6 +171,6 @@ class E2ENetworkSliceSpec extends Specification {
expect: 'schema context is built with no exception indicating the schema set being valid '
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourcesNameToContentMap).getSchemaContext()
and: 'data is parsed with no exception indicating the model match'
- new YangParserHelper().parseData(ContentType.JSON, jsonData, schemaContext, '') != null
+ new YangParserHelper().parseData(ContentType.JSON, jsonData, schemaContext, '', false) != null
}
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy
index e305abee86..f028d5d5d9 100644
--- a/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/spi/model/DataNodeBuilderSpec.groovy
@@ -35,6 +35,7 @@ class DataNodeBuilderSpec extends Specification {
def objectUnderTest = new DataNodeBuilder()
def yangParserHelper = new YangParserHelper()
+ def validateAndParse = false
def expectedLeavesByXpathMap = [
'/test-tree' : [],
@@ -60,7 +61,7 @@ class DataNodeBuilderSpec extends Specification {
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext()
and: 'the json data parsed into container node object'
def jsonData = TestUtils.getResourceFileContent('test-tree.json')
- def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '')
+ def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '', validateAndParse)
when: 'the container node is converted to a data node'
def result = objectUnderTest.withContainerNode(containerNode).build()
def mappedResult = TestUtils.getFlattenMapByXpath(result)
@@ -80,7 +81,7 @@ class DataNodeBuilderSpec extends Specification {
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext()
and: 'the json data parsed into container node object'
def jsonData = '{ "branch": [{ "name": "Branch", "nest": { "name": "Nest", "birds": ["bird"] } }] }'
- def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '/test-tree')
+ def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '/test-tree', validateAndParse)
when: 'the container node is converted to a data node with parent node xpath defined'
def result = objectUnderTest.withContainerNode(containerNode).withParentNodeXpath('/test-tree').build()
def mappedResult = TestUtils.getFlattenMapByXpath(result)
@@ -96,7 +97,7 @@ class DataNodeBuilderSpec extends Specification {
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext()
and: 'the json data parsed into container node object'
def jsonData = TestUtils.getResourceFileContent('ietf/data/ietf-network-topology-sample-rfc8345.json')
- def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '')
+ def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '', validateAndParse)
when: 'the container node is converted to a data node '
def result = objectUnderTest.withContainerNode(containerNode).build()
def mappedResult = TestUtils.getFlattenMapByXpath(result)
@@ -129,7 +130,7 @@ class DataNodeBuilderSpec extends Specification {
def parentNodeXpath = "/networks/network[@network-id='otn-hc']/link[@link-id='D1,1-2-1,D2,2-1-1']"
and: 'the json data fragment parsed into container node object for given parent node xpath'
def jsonData = '{"source": {"source-node": "D1", "source-tp": "1-2-1"}}'
- def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext,parentNodeXpath)
+ def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext,parentNodeXpath, validateAndParse)
when: 'the container node is converted to a data node with given parent node xpath'
def result = objectUnderTest.withContainerNode(containerNode).withParentNodeXpath(parentNodeXpath).build()
then: 'the resulting data node represents a child of augmentation node'
@@ -144,7 +145,7 @@ class DataNodeBuilderSpec extends Specification {
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent) getSchemaContext()
and: 'the json data fragment parsed into container node object'
def jsonData = TestUtils.getResourceFileContent('data-with-choice-node.json')
- def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '')
+ def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, '', validateAndParse)
when: 'the container node is converted to a data node'
def result = objectUnderTest.withContainerNode(containerNode).build()
def mappedResult = TestUtils.getFlattenMapByXpath(result)
@@ -162,7 +163,7 @@ class DataNodeBuilderSpec extends Specification {
and: 'parent node xpath referencing parent of list element'
def parentNodeXpath = '/test-tree'
and: 'the json data fragment (list element) parsed into container node object'
- def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, parentNodeXpath)
+ def containerNode = yangParserHelper.parseData(ContentType.JSON, jsonData, schemaContext, parentNodeXpath, validateAndParse)
when: 'the container node is converted to a data node collection'
def result = objectUnderTest.withContainerNode(containerNode).withParentNodeXpath(parentNodeXpath).buildCollection()
def resultXpaths = result.collect { it.getXpath() }
diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/YangParserHelperSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/YangParserHelperSpec.groovy
index 073383113d..e1490c28ab 100644
--- a/cps-service/src/test/groovy/org/onap/cps/utils/YangParserHelperSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/utils/YangParserHelperSpec.groovy
@@ -30,6 +30,8 @@ import spock.lang.Specification
class YangParserHelperSpec extends Specification {
def objectUnderTest = new YangParserHelper()
+ def validateOnly = true
+ def validateAndParse = false
def 'Parsing a valid multicontainer Json String.'() {
given: 'a yang model (file)'
@@ -38,7 +40,7 @@ class YangParserHelperSpec extends Specification {
def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('multipleDataTree.yang')
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent).getSchemaContext()
when: 'the json data is parsed'
- def result = objectUnderTest.parseData(ContentType.JSON, jsonData, schemaContext, '')
+ def result = objectUnderTest.parseData(ContentType.JSON, jsonData, schemaContext, '', validateAndParse)
then: 'a ContainerNode holding collection of normalized nodes is returned'
result.body().getAt(index) instanceof NormalizedNode == true
then: 'qualified name of children created is as expected'
@@ -56,7 +58,7 @@ class YangParserHelperSpec extends Specification {
def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('bookstore.yang')
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent).getSchemaContext()
when: 'the data is parsed'
- NormalizedNode result = objectUnderTest.parseData(contentType, fileData, schemaContext, '')
+ NormalizedNode result = objectUnderTest.parseData(contentType, fileData, schemaContext, '', validateAndParse)
then: 'the result is a normalized node of the correct type'
if (revision) {
result.identifier.nodeType == QName.create(namespace, revision, localName)
@@ -74,7 +76,7 @@ class YangParserHelperSpec extends Specification {
def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('bookstore.yang')
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent).getSchemaContext()
when: 'invalid data is parsed'
- objectUnderTest.parseData(contentType, invalidData, schemaContext, '')
+ objectUnderTest.parseData(contentType, invalidData, schemaContext, '', validateAndParse)
then: 'an exception is thrown'
thrown(DataValidationException)
where: 'the following invalid data is provided'
@@ -92,7 +94,7 @@ class YangParserHelperSpec extends Specification {
def yangResourcesMap = TestUtils.getYangResourcesAsMap('test-tree.yang')
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourcesMap).getSchemaContext()
when: 'json string is parsed'
- def result = objectUnderTest.parseData(contentType, nodeData, schemaContext, parentNodeXpath)
+ def result = objectUnderTest.parseData(contentType, nodeData, schemaContext, parentNodeXpath, validateAndParse)
then: 'a ContainerNode holding collection of normalized nodes is returned'
result.body().getAt(0) instanceof NormalizedNode == true
then: 'result represents a node of expected type'
@@ -112,7 +114,7 @@ class YangParserHelperSpec extends Specification {
def yangResourcesMap = TestUtils.getYangResourcesAsMap('test-tree.yang')
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourcesMap).getSchemaContext()
when: 'json string is parsed'
- objectUnderTest.parseData(ContentType.JSON, '{"nest": {"name" : "Nest", "birds": ["bird"]}}', schemaContext, parentNodeXpath)
+ objectUnderTest.parseData(ContentType.JSON, '{"nest": {"name" : "Nest", "birds": ["bird"]}}', schemaContext, parentNodeXpath, validateAndParse)
then: 'expected exception is thrown'
thrown(DataValidationException)
where:
@@ -129,7 +131,7 @@ class YangParserHelperSpec extends Specification {
def yangResourcesMap = TestUtils.getYangResourcesAsMap('bookstore.yang')
def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourcesMap).getSchemaContext()
when: 'malformed json string is parsed'
- objectUnderTest.parseData(ContentType.JSON, invalidJson, schemaContext, '')
+ objectUnderTest.parseData(ContentType.JSON, invalidJson, schemaContext, '', validateAndParse)
then: 'an exception is thrown'
thrown(DataValidationException)
where: 'the following malformed json is provided'
@@ -145,7 +147,7 @@ class YangParserHelperSpec extends Specification {
and: 'some json data with space in the array elements'
def jsonDataWithSpacesInArrayElement = TestUtils.getResourceFileContent('bookstore.json')
when: 'that json data is parsed'
- objectUnderTest.parseData(ContentType.JSON, jsonDataWithSpacesInArrayElement, schemaContext, '')
+ objectUnderTest.parseData(ContentType.JSON, jsonDataWithSpacesInArrayElement, schemaContext, '', validateAndParse)
then: 'no exception thrown'
noExceptionThrown()
}
@@ -162,5 +164,22 @@ class YangParserHelperSpec extends Specification {
'xpath contains list attributes with /' | '/test-tree/branch[@name=\'/Branch\']/categories[@id=\'/broken\']' || ['test-tree','branch','categories']
}
+ def 'Validating #scenario xpath String.'() {
+ given: 'a data model (file) is provided'
+ def fileData = TestUtils.getResourceFileContent(contentFile)
+ and: 'the schema context is built for that data model'
+ def yangResourceNameToContent = TestUtils.getYangResourcesAsMap('bookstore.yang')
+ def schemaContext = YangTextSchemaSourceSetBuilder.of(yangResourceNameToContent).getSchemaContext()
+ when: 'the data is parsed to be validated'
+ objectUnderTest.parseData(contentType, fileData, schemaContext, parentNodeXpath, validateOnly)
+ then: 'no exception is thrown'
+ noExceptionThrown()
+ where:
+ scenario | parentNodeXpath | contentFile | contentType
+ 'JSON without parent node' | '' | 'bookstore.json' | ContentType.JSON
+ 'JSON with parent node' | '/bookstore' | 'bookstore-categories-data.json' | ContentType.JSON
+ 'XML without parent node' | '' | 'bookstore.xml' | ContentType.XML
+ 'XML with parent node' | '/bookstore' | 'bookstore-categories-data.xml' | ContentType.XML
+ }
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy
index 18d0502e30..6c52becbe1 100644
--- a/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/utils/YangParserSpec.groovy
@@ -26,7 +26,6 @@ import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.model.Anchor
import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder
import org.onap.cps.yang.YangTextSchemaSourceSet
-import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode
import org.opendaylight.yangtools.yang.model.api.SchemaContext
import spock.lang.Specification
@@ -47,6 +46,8 @@ class YangParserSpec extends Specification {
def containerNodeFromYangUtils = Mock(ContainerNode)
def noParent = ''
+ def validateOnly = true
+ def validateAndParse = false
def setup() {
mockYangTextSchemaSourceSetCache.get('my dataspace', 'my schema') >> mockYangTextSchemaSourceSet
@@ -55,7 +56,7 @@ class YangParserSpec extends Specification {
def 'Parsing data.'() {
given: 'the yang parser (utility) always returns a container node'
- mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent) >> containerNodeFromYangUtils
+ mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent, validateAndParse) >> containerNodeFromYangUtils
when: 'parsing some json data'
def result = objectUnderTest.parseData(ContentType.JSON, 'some json', anchor, noParent)
then: 'the schema source set for the correct dataspace and schema set is retrieved form the cache'
@@ -68,7 +69,7 @@ class YangParserSpec extends Specification {
def 'Parsing data with exception on first attempt.'() {
given: 'the yang parser throws an exception on the first attempt only'
- mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent) >> { throw new DataValidationException(noParent, noParent) } >> containerNodeFromYangUtils
+ mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent, validateAndParse) >> { throw new DataValidationException(noParent, noParent) } >> containerNodeFromYangUtils
when: 'attempt to parse some data'
def result = objectUnderTest.parseData(ContentType.JSON, 'some json', anchor, noParent)
then: 'the cache is cleared for the correct dataspace and schema'
@@ -79,7 +80,7 @@ class YangParserSpec extends Specification {
def 'Parsing data with exception on all attempts.'() {
given: 'the yang parser always throws an exception'
- mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent) >> { throw new DataValidationException(noParent, noParent) }
+ mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent, validateAndParse) >> { throw new DataValidationException(noParent, noParent) }
when: 'attempt to parse some data'
objectUnderTest.parseData(ContentType.JSON, 'some json', anchor, noParent)
then: 'a data validation exception is thrown'
@@ -94,9 +95,46 @@ class YangParserSpec extends Specification {
when: 'parsing some json data'
def result = objectUnderTest.parseData(ContentType.JSON, 'some json', yangResourcesNameToContentMap, noParent)
then: 'the yang parser helper always returns a container node'
- 1 * mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent) >> containerNodeFromYangUtils
+ 1 * mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent, validateAndParse) >> containerNodeFromYangUtils
and: 'the result is the same container node as return from yang utils'
assert result == containerNodeFromYangUtils
}
+ def 'Validating #scenario data using Yang parser with cache retrieval.'() {
+ given: 'the yang parser (utility) is set up and schema context is available'
+ mockYangParserHelper.parseData(contentType, 'some json', mockSchemaContext, noParent, validateOnly)
+ when: 'attempt to parse data with no parent node xpath'
+ objectUnderTest.validateData(contentType, 'some json or xml data', anchor, noParent)
+ then: 'the correct schema set is retrieved from the cache for the dataspace and schema'
+ 1 * mockYangTextSchemaSourceSetCache.get('my dataspace', 'my schema') >> mockYangTextSchemaSourceSet
+ and: 'no cache entries are removed during validation'
+ 0 * mockYangTextSchemaSourceSetCache.removeFromCache(*_)
+ where:
+ scenario | contentType
+ 'JSON' | ContentType.JSON
+ 'XML' | ContentType.XML
+ }
+
+ def 'Validating data when parsing fails on first attempt and recovers.'() {
+ given: 'the Yang parser throws an exception on the first attempt but succeeds on the second'
+ mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent, validateOnly) >> { throw new DataValidationException(noParent, noParent) } >> null
+ when: 'attempting to parse JSON data'
+ objectUnderTest.validateData(ContentType.JSON, 'some json', anchor, noParent)
+ then: 'the cache is cleared for the correct dataspace and schema after the first failure'
+ 1 * mockYangTextSchemaSourceSetCache.removeFromCache('my dataspace', 'my schema')
+ and: 'no exceptions are thrown after the second attempt'
+ noExceptionThrown()
+ }
+
+ def 'Validating data with repeated parsing failures leading to exception.'() {
+ given: 'the yang parser throws an exception on the first attempt only'
+ mockYangParserHelper.parseData(ContentType.JSON, 'some json', mockSchemaContext, noParent, validateOnly) >> { throw new DataValidationException(noParent, noParent) }
+ when: 'attempting to parse JSON data'
+ objectUnderTest.validateData(ContentType.JSON, 'some json', anchor, noParent)
+ then: 'a data validation exception is thrown'
+ thrown(DataValidationException)
+ and: 'the cache is cleared for the correct dataspace and schema after the failure'
+ 1 * mockYangTextSchemaSourceSetCache.removeFromCache('my dataspace', 'my schema')
+ }
+
}
diff --git a/cps-service/src/test/resources/bookstore-categories-data.json b/cps-service/src/test/resources/bookstore-categories-data.json
new file mode 100644
index 0000000000..7dc22b17f7
--- /dev/null
+++ b/cps-service/src/test/resources/bookstore-categories-data.json
@@ -0,0 +1,49 @@
+{
+ "categories": [
+ {
+ "code": "01/1",
+ "name": "SciFi",
+ "books": [
+ {
+ "authors": [
+ "Iain M. Banks"
+ ],
+ "lang": "en/it",
+ "price": "895",
+ "pub_year": "1994",
+ "title": "Feersum Endjinn/Endjinn Feersum"
+ },
+ {
+ "authors": [
+ "Ursula K. Le Guin",
+ "Joe Haldeman",
+ "Orson Scott Card",
+ "david Brin",
+ "Rober Silverberg",
+ "Dan Simmons",
+ "Greg Bear"
+ ],
+ "lang": "en",
+ "price": "1099",
+ "pub_year": "1999",
+ "title": "Far Horizons"
+ }
+ ]
+ },
+ {
+ "name": "kids",
+ "code": "02",
+ "books": [
+ {
+ "authors": [
+ "Philip Pullman"
+ ],
+ "lang": "en",
+ "price": "699",
+ "pub_year": "1995",
+ "title": "The Golden Compass"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/cps-service/src/test/resources/bookstore-categories-data.xml b/cps-service/src/test/resources/bookstore-categories-data.xml
new file mode 100644
index 0000000000..c8592c1f90
--- /dev/null
+++ b/cps-service/src/test/resources/bookstore-categories-data.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<categories>
+ <code>1</code>
+ <name>SciFi</name>
+ <books>
+ <title>2001: A Space Odyssey</title>
+ <lang>en</lang>
+ <authors>
+ Iain M. Banks
+ </authors>
+ <pub_year>1994</pub_year>
+ <price>895</price>
+ </books>
+</categories> \ No newline at end of file
diff --git a/docker-compose/config/nginx/nginx.conf b/docker-compose/config/nginx/nginx.conf
index 61fed515c3..7d6b997f77 100644
--- a/docker-compose/config/nginx/nginx.conf
+++ b/docker-compose/config/nginx/nginx.conf
@@ -22,6 +22,7 @@ http {
upstream cps-and-ncmp {
least_conn;
server docker-compose-cps-and-ncmp-1:8080;
+ ### DEBUG: Disable next line for easier debugging on 1 instance (see also docker-compose.yml)
server docker-compose-cps-and-ncmp-2:8080;
}
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index 1e47d47382..e7703d8d68 100644
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -23,6 +23,7 @@ services:
### docker-compose --profile dmi-stub --profile tracing up -d -> run CPS with stubbed dmi-plugin (for open telemetry tracing testing make ONAP_TRACING_ENABLED "true" later "http://localhost:16686" can be accessed from browser)
### docker-compose --profile dmi-stub --profile policy-executor-stub up -d -> run CPS with stubbed dmi-plugin and policy executor stub (for policy executor service testing make POLICY_SERVICE_ENABLED "true")
### to disable notifications make notification.enabled to false & comment out kafka/zookeeper services ###
+ ### DEBUG: Look for '### DEBUG' comments to enable CPS-NCMP debugging
dbpostgresql:
container_name: dbpostgresql
@@ -60,18 +61,23 @@ services:
ONAP_OTEL_SAMPLER_JAEGER_REMOTE_ENDPOINT: http://jaeger-service:14250
ONAP_OTEL_EXPORTER_ENDPOINT: http://jaeger-service:4317
POLICY_SERVICE_ENABLED: 'false'
+ POLICY_SERVICE_DEFAULT_DECISION: 'deny from env'
+ JAVA_TOOL_OPTIONS: "-XX:InitialRAMPercentage=75.0 -XX:MaxRAMPercentage=75.0"
+ ### DEBUG: Uncomment next line to enable java debugging
+ ### DEBUG: JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
restart: unless-stopped
depends_on:
- dbpostgresql
deploy:
+ ### DEBUG: For easier debugging use just 1 instance (also update docker-compose/config/nginx/nginx.conf !)
replicas: 2
resources:
- reservations:
- cpus: '2'
- memory: 2G
limits:
cpus: '3'
- memory: 3G
+ memory: 2G
+ ### DEBUG: Uncomment next 2 lines to enable java debugging (ensure 'ports' aligns with 'deploy')
+ ### DEBUG ports:
+ ### DEBUG - ${CPS_CORE_DEBUG_PORT:-5005}:5005
nginx:
container_name: nginx-loadbalancer
diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml
index 74b5234828..d22b2887a6 100644
--- a/docs/api/swagger/cps/openapi.yaml
+++ b/docs/api/swagger/cps/openapi.yaml
@@ -11,14 +11,14 @@ info:
title: ONAP Open API v3 Configuration Persistence Service
version: 3.5.2
servers:
- - url: /cps/api
+- url: /cps/api
security:
- - basicAuth: []
+- basicAuth: []
tags:
- - description: cps Admin
- name: cps-admin
- - description: cps Data
- name: cps-data
+- description: cps Admin
+ name: cps-admin
+- description: cps Data
+ name: cps-data
paths:
/v1/dataspaces:
post:
@@ -26,13 +26,13 @@ paths:
description: Create a new dataspace
operationId: createDataspace
parameters:
- - description: dataspace-name
- in: query
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
+ - description: dataspace-name
+ in: query
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
responses:
"201":
content:
@@ -83,29 +83,29 @@ paths:
description: Internal Server Error
summary: Create a dataspace
tags:
- - cps-admin
+ - cps-admin
/{apiVersion}/dataspaces:
delete:
description: Delete a dataspace
operationId: deleteDataspace
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: query
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: query
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
responses:
"204":
content: {}
@@ -152,19 +152,19 @@ paths:
description: Internal Server Error
summary: Delete a dataspace
tags:
- - cps-admin
+ - cps-admin
/v2/dataspaces:
post:
description: Create a new dataspace
operationId: createDataspaceV2
parameters:
- - description: dataspace-name
- in: query
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
+ - description: dataspace-name
+ in: query
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
responses:
"201":
description: Created without response body
@@ -210,22 +210,22 @@ paths:
description: Internal Server Error
summary: Create a dataspace
tags:
- - cps-admin
+ - cps-admin
/{apiVersion}/admin/dataspaces:
get:
description: Read all dataspaces
operationId: getAllDataspaces
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
responses:
"200":
content:
@@ -267,29 +267,29 @@ paths:
description: Internal Server Error
summary: Get all dataspaces
tags:
- - cps-admin
+ - cps-admin
/{apiVersion}/admin/dataspaces/{dataspace-name}:
get:
description: Read a dataspace given a dataspace name
operationId: getDataspace
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
responses:
"200":
content:
@@ -329,34 +329,34 @@ paths:
description: Internal Server Error
summary: Get a dataspace
tags:
- - cps-admin
+ - cps-admin
/v1/dataspaces/{dataspace-name}/anchors:
post:
deprecated: true
description: Create a new anchor in the given dataspace
operationId: createAnchor
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: schema-set-name
- in: query
- name: schema-set-name
- required: true
- schema:
- example: my-schema-set
- type: string
- - description: anchor-name
- in: query
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: schema-set-name
+ in: query
+ name: schema-set-name
+ required: true
+ schema:
+ example: my-schema-set
+ type: string
+ - description: anchor-name
+ in: query
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
responses:
"201":
content:
@@ -407,33 +407,33 @@ paths:
description: Internal Server Error
summary: Create an anchor
tags:
- - cps-admin
+ - cps-admin
/v2/dataspaces/{dataspace-name}/anchors:
post:
description: Create a new anchor in the given dataspace
operationId: createAnchorV2
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: schema-set-name
- in: query
- name: schema-set-name
- required: true
- schema:
- example: my-schema-set
- type: string
- - description: anchor-name
- in: query
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: schema-set-name
+ in: query
+ name: schema-set-name
+ required: true
+ schema:
+ example: my-schema-set
+ type: string
+ - description: anchor-name
+ in: query
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
responses:
"201":
description: Created without response body
@@ -479,29 +479,29 @@ paths:
description: Internal Server Error
summary: Create an anchor
tags:
- - cps-admin
+ - cps-admin
/{apiVersion}/dataspaces/{dataspace-name}/anchors:
get:
description: "Read all anchors, given a dataspace"
operationId: getAnchors
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
responses:
"200":
content:
@@ -543,36 +543,36 @@ paths:
description: Internal Server Error
summary: Get anchors
tags:
- - cps-admin
+ - cps-admin
/{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}:
delete:
description: Delete an anchor given an anchor name and a dataspace
operationId: deleteAnchor
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
responses:
"204":
content: {}
@@ -609,35 +609,35 @@ paths:
description: Internal Server Error
summary: Delete an anchor
tags:
- - cps-admin
+ - cps-admin
get:
description: Read an anchor given an anchor name and a dataspace
operationId: getAnchor
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
responses:
"200":
content:
@@ -677,27 +677,27 @@ paths:
description: Internal Server Error
summary: Get an anchor
tags:
- - cps-admin
+ - cps-admin
/v1/dataspaces/{dataspace-name}/schema-sets:
post:
deprecated: true
description: Create a new schema set in the given dataspace
operationId: createSchemaSet
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: schema-set-name
- in: query
- name: schema-set-name
- required: true
- schema:
- example: my-schema-set
- type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: schema-set-name
+ in: query
+ name: schema-set-name
+ required: true
+ schema:
+ example: my-schema-set
+ type: string
requestBody:
content:
multipart/form-data:
@@ -754,26 +754,26 @@ paths:
description: Internal Server Error
summary: Create a schema set
tags:
- - cps-admin
+ - cps-admin
/v2/dataspaces/{dataspace-name}/schema-sets:
post:
description: Create a new schema set in the given dataspace
operationId: createSchemaSetV2
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: schema-set-name
- in: query
- name: schema-set-name
- required: true
- schema:
- example: my-schema-set
- type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: schema-set-name
+ in: query
+ name: schema-set-name
+ required: true
+ schema:
+ example: my-schema-set
+ type: string
requestBody:
content:
multipart/form-data:
@@ -825,29 +825,29 @@ paths:
description: Internal Server Error
summary: Create a schema set
tags:
- - cps-admin
+ - cps-admin
/{apiVersion}/dataspaces/{dataspace-name}/schema-sets:
get:
description: "Read all schema sets, given a dataspace"
operationId: getSchemaSets
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
responses:
"200":
content:
@@ -889,36 +889,36 @@ paths:
description: Internal Server Error
summary: Get schema sets
tags:
- - cps-admin
+ - cps-admin
/{apiVersion}/dataspaces/{dataspace-name}/schema-sets/{schema-set-name}:
delete:
description: Delete a schema set given a schema set name and a dataspace
operationId: deleteSchemaSet
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: schema-set-name
- in: path
- name: schema-set-name
- required: true
- schema:
- example: my-schema-set
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: schema-set-name
+ in: path
+ name: schema-set-name
+ required: true
+ schema:
+ example: my-schema-set
+ type: string
responses:
"204":
content: {}
@@ -965,35 +965,35 @@ paths:
description: Internal Server Error
summary: Delete a schema set
tags:
- - cps-admin
+ - cps-admin
get:
description: Read a schema set given a schema set name and a dataspace
operationId: getSchemaSet
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: schema-set-name
- in: path
- name: schema-set-name
- required: true
- schema:
- example: my-schema-set
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: schema-set-name
+ in: path
+ name: schema-set-name
+ required: true
+ schema:
+ example: my-schema-set
+ type: string
responses:
"200":
content:
@@ -1033,7 +1033,7 @@ paths:
description: Internal Server Error
summary: Get a schema set
tags:
- - cps-admin
+ - cps-admin
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
get:
deprecated: true
@@ -1041,40 +1041,40 @@ paths:
anchor and dataspace
operationId: getNodeByDataspaceAndAnchor
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
- - description: include-descendants
- in: query
- name: include-descendants
- required: false
- schema:
- default: false
- example: false
- type: boolean
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: include-descendants
+ in: query
+ name: include-descendants
+ required: false
+ schema:
+ default: false
+ example: false
+ type: boolean
responses:
"200":
content:
@@ -1118,7 +1118,7 @@ paths:
description: Internal Server Error
summary: Get a node
tags:
- - cps-data
+ - cps-data
x-codegen-request-body-name: xpath
/v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/node:
get:
@@ -1126,42 +1126,42 @@ paths:
anchor and dataspace
operationId: getNodeByDataspaceAndAnchorV2
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
- - description: "Number of descendants to query. Allowed values are 'none', 'all',\
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: "Number of descendants to query. Allowed values are 'none', 'all',\
\ 'direct', 1 (for direct), -1 (for all), 0 (for none) and any positive\
\ number."
- in: query
- name: descendants
- required: false
- schema:
- default: none
- example: "3"
- type: string
+ in: query
+ name: descendants
+ required: false
+ schema:
+ default: none
+ example: "3"
+ type: string
responses:
"200":
content:
@@ -1205,7 +1205,7 @@ paths:
description: Internal Server Error
summary: Get a node
tags:
- - cps-data
+ - cps-data
x-codegen-request-body-name: xpath
/{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes:
delete:
@@ -1213,49 +1213,49 @@ paths:
xpath.
operationId: deleteDataNode
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
- - description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
responses:
"204":
content: {}
@@ -1292,63 +1292,63 @@ paths:
description: Internal Server Error
summary: Delete a data node
tags:
- - cps-data
+ - cps-data
patch:
description: Update a data node leaves for a given dataspace and anchor and
a parent node xpath. This operation is currently supported for one top level
data node only.
operationId: updateNodeLeaves
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
- - description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
- - description: Content type in header
- in: header
- name: Content-Type
- required: true
- schema:
- example: application/json
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: true
+ schema:
+ example: application/json
+ type: string
requestBody:
content:
application/json:
@@ -1410,61 +1410,61 @@ paths:
description: Internal Server Error
summary: Update node leaves
tags:
- - cps-data
+ - cps-data
post:
description: Create a node for a given anchor and dataspace
operationId: createNode
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
- - description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
- - description: Content type in header
- in: header
- name: Content-Type
- required: true
- schema:
- example: application/json
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: true
+ schema:
+ example: application/json
+ type: string
requestBody:
content:
application/json:
@@ -1534,62 +1534,62 @@ paths:
description: Internal Server Error
summary: Create a node
tags:
- - cps-data
+ - cps-data
put:
description: "Replace a node with descendants for a given dataspace, anchor\
\ and a parent node xpath"
operationId: replaceNode
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
- - description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
- - description: Content type in header
- in: header
- name: Content-Type
- required: true
- schema:
- example: application/json
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: true
+ schema:
+ example: application/json
+ type: string
requestBody:
content:
application/json:
@@ -1651,45 +1651,45 @@ paths:
description: Internal Server Error
summary: Replace a node with descendants
tags:
- - cps-data
+ - cps-data
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
delete:
deprecated: true
description: Delete one or all list element(s) for a given anchor and dataspace
operationId: deleteListOrListElement
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: true
- schema:
- type: string
- - description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: true
+ schema:
+ type: string
+ - description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
responses:
"204":
content: {}
@@ -1726,61 +1726,61 @@ paths:
description: Internal Server Error
summary: Delete one or all list element(s)
tags:
- - cps-data
+ - cps-data
/{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes:
post:
description: Add list element(s) to a list for a given anchor and dataspace
operationId: addListElements
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: true
- schema:
- type: string
- - description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
- - description: Content type in header
- in: header
- name: Content-Type
- required: true
- schema:
- example: application/json
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: true
+ schema:
+ type: string
+ - description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: true
+ schema:
+ example: application/json
+ type: string
requestBody:
content:
application/json:
@@ -1840,53 +1840,53 @@ paths:
description: Internal Server Error
summary: Add list element(s)
tags:
- - cps-data
+ - cps-data
put:
description: "Replace list content under a given parent, anchor and dataspace"
operationId: replaceListContent
parameters:
- - description: apiVersion
- in: path
- name: apiVersion
- required: true
- schema:
- default: v2
- enum:
- - v1
- - v2
- type: string
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: true
- schema:
- type: string
- - description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
+ - description: apiVersion
+ in: path
+ name: apiVersion
+ required: true
+ schema:
+ default: v2
+ enum:
+ - v1
+ - v2
+ type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: true
+ schema:
+ type: string
+ - description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
requestBody:
content:
application/json:
@@ -1939,55 +1939,55 @@ paths:
description: Internal Server Error
summary: Replace list content
tags:
- - cps-data
+ - cps-data
/v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta:
get:
description: Get delta between two anchors within a given dataspace
operationId: getDeltaByDataspaceAndAnchors
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: source-anchor-name
- in: path
- name: source-anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: target-anchor-name
- in: query
- name: target-anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
- - description: "Number of descendants to query. Allowed values are 'none', 'all',\
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: source-anchor-name
+ in: path
+ name: source-anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: target-anchor-name
+ in: query
+ name: target-anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: "Number of descendants to query. Allowed values are 'none', 'all',\
\ 'direct', 1 (for direct), -1 (for all), 0 (for none) and any positive\
\ number."
- in: query
- name: descendants
- required: false
- schema:
- default: none
- example: "3"
- type: string
+ in: query
+ name: descendants
+ required: false
+ schema:
+ default: none
+ example: "3"
+ type: string
responses:
"200":
content:
@@ -2031,38 +2031,38 @@ paths:
description: Internal Server Error
summary: Get delta between anchors in the same dataspace
tags:
- - cps-data
+ - cps-data
x-codegen-request-body-name: xpath
post:
description: Get delta between an anchor in a dataspace and JSON payload
operationId: getDeltaByDataspaceAnchorAndPayload
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: source-anchor-name
- in: path
- name: source-anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
- examples:
- container xpath:
- value: /shops/bookstore
- list attributes xpath:
- value: "/shops/bookstore/categories[@code=1]"
- in: query
- name: xpath
- required: false
- schema:
- default: /
- type: string
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: source-anchor-name
+ in: path
+ name: source-anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
+ examples:
+ container xpath:
+ value: /shops/bookstore
+ list attributes xpath:
+ value: "/shops/bookstore/categories[@code=1]"
+ in: query
+ name: xpath
+ required: false
+ schema:
+ default: /
+ type: string
requestBody:
content:
multipart/form-data:
@@ -2121,47 +2121,47 @@ paths:
description: Internal Server Error
summary: Get delta between an anchor and JSON payload
tags:
- - cps-data
+ - cps-data
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
get:
deprecated: true
description: Query data nodes for the given dataspace and anchor using CPS path
operationId: getNodesByDataspaceAndAnchorAndCpsPath
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
- examples:
- container cps path:
- value: //bookstore
- list attributes cps path:
- value: "//categories[@code=1]"
- in: query
- name: cps-path
- required: false
- schema:
- default: /
- type: string
- - description: include-descendants
- in: query
- name: include-descendants
- required: false
- schema:
- default: false
- example: false
- type: boolean
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+ examples:
+ container cps path:
+ value: //bookstore
+ list attributes cps path:
+ value: "//categories[@code=1]"
+ in: query
+ name: cps-path
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: include-descendants
+ in: query
+ name: include-descendants
+ required: false
+ schema:
+ default: false
+ example: false
+ type: boolean
responses:
"200":
content:
@@ -2205,49 +2205,49 @@ paths:
description: Internal Server Error
summary: Query data nodes
tags:
- - cps-query
+ - cps-query
x-codegen-request-body-name: xpath
/v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
get:
description: Query data nodes for the given dataspace and anchor using CPS path
operationId: getNodesByDataspaceAndAnchorAndCpsPathV2
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: anchor-name
- in: path
- name: anchor-name
- required: true
- schema:
- example: my-anchor
- type: string
- - description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
- examples:
- container cps path:
- value: //bookstore
- list attributes cps path:
- value: "//categories[@code=1]"
- in: query
- name: cps-path
- required: false
- schema:
- default: /
- type: string
- - description: "Number of descendants to query. Allowed values are 'none', 'all',\
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: anchor-name
+ in: path
+ name: anchor-name
+ required: true
+ schema:
+ example: my-anchor
+ type: string
+ - description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+ examples:
+ container cps path:
+ value: //bookstore
+ list attributes cps path:
+ value: "//categories[@code=1]"
+ in: query
+ name: cps-path
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: "Number of descendants to query. Allowed values are 'none', 'all',\
\ 'direct', 1 (for direct), -1 (for all), 0 (for none) and any positive\
\ number."
- in: query
- name: descendants
- required: false
- schema:
- default: none
- example: "3"
- type: string
+ in: query
+ name: descendants
+ required: false
+ schema:
+ default: none
+ example: "3"
+ type: string
responses:
"200":
content:
@@ -2291,7 +2291,7 @@ paths:
description: Internal Server Error
summary: Query data nodes
tags:
- - cps-query
+ - cps-query
x-codegen-request-body-name: xpath
/v2/dataspaces/{dataspace-name}/nodes/query:
get:
@@ -2299,51 +2299,51 @@ paths:
path
operationId: getNodesByDataspaceAndCpsPath
parameters:
- - description: dataspace-name
- in: path
- name: dataspace-name
- required: true
- schema:
- example: my-dataspace
- type: string
- - description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
- examples:
- container cps path:
- value: //bookstore
- list attributes cps path:
- value: "//categories[@code=1]"
- in: query
- name: cps-path
- required: false
- schema:
- default: /
- type: string
- - description: "Number of descendants to query. Allowed values are 'none', 'all',\
+ - description: dataspace-name
+ in: path
+ name: dataspace-name
+ required: true
+ schema:
+ example: my-dataspace
+ type: string
+ - description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
+ examples:
+ container cps path:
+ value: //bookstore
+ list attributes cps path:
+ value: "//categories[@code=1]"
+ in: query
+ name: cps-path
+ required: false
+ schema:
+ default: /
+ type: string
+ - description: "Number of descendants to query. Allowed values are 'none', 'all',\
\ 'direct', 1 (for direct), -1 (for all), 0 (for none) and any positive\
\ number."
- in: query
- name: descendants
- required: false
- schema:
- default: none
- example: "3"
- type: string
- - description: page index for pagination over anchors. It must be greater then
- zero if provided.
- in: query
- name: pageIndex
- required: false
- schema:
- example: 1
- type: integer
- - description: number of records (anchors) per page. It must be greater then
- zero if provided.
- in: query
- name: pageSize
- required: false
- schema:
- example: 10
- type: integer
+ in: query
+ name: descendants
+ required: false
+ schema:
+ default: none
+ example: "3"
+ type: string
+ - description: page index for pagination over anchors. It must be greater then
+ zero if provided.
+ in: query
+ name: pageIndex
+ required: false
+ schema:
+ example: 1
+ type: integer
+ - description: number of records (anchors) per page. It must be greater then
+ zero if provided.
+ in: query
+ name: pageSize
+ required: false
+ schema:
+ example: 10
+ type: integer
responses:
"200":
content:
@@ -2387,7 +2387,7 @@ paths:
description: Internal Server Error
summary: Query data nodes across anchors
tags:
- - cps-query
+ - cps-query
x-codegen-request-body-name: xpath
components:
examples:
@@ -2396,52 +2396,52 @@ components:
test:bookstore:
bookstore-name: Chapters
categories:
- - code: 1
- name: SciFi
- - code: 2
- name: kids
+ - code: 1
+ name: SciFi
+ - code: 2
+ name: kids
dataSampleXml:
value: <stores xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <bookstore xmlns="org:onap:ccsdk:sample">
<bookstore-name>Chapters</bookstore-name> <categories> <code>1</code> <name>SciFi</name>
<code>2</code> <name>kids</name> </categories> </bookstore> </stores>
deltaReportSample:
value:
- - action: create
- xpath: "/bookstore/categories/[@code=3]"
- target-data:
- code: "3,"
- name: kidz
- - action: remove
- xpath: "/bookstore/categories/[@code=1]"
- source-data:
- code: "1,"
- name: Fiction
- - action: replace
- xpath: "/bookstore/categories/[@code=2]"
- source-data:
- name: Funny
- target-data:
- name: Comic
+ - action: create
+ xpath: "/bookstore/categories/[@code=3]"
+ target-data:
+ code: "3,"
+ name: kidz
+ - action: remove
+ xpath: "/bookstore/categories/[@code=1]"
+ source-data:
+ code: "1,"
+ name: Fiction
+ - action: replace
+ xpath: "/bookstore/categories/[@code=2]"
+ source-data:
+ name: Funny
+ target-data:
+ name: Comic
dataSampleAcrossAnchors:
value:
- - anchorName: bookstore1
- dataNode:
- test:bookstore:
- bookstore-name: Chapters
- categories:
- - code: 1
- name: SciFi
- - code: 2
- name: kids
- - anchorName: bookstore2
- dataNode:
- test:bookstore:
- bookstore-name: Chapters
- categories:
- - code: 1
- name: SciFi
- - code: 2
- name: kids
+ - anchorName: bookstore1
+ dataNode:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 1
+ name: SciFi
+ - code: 2
+ name: kids
+ - anchorName: bookstore2
+ dataNode:
+ test:bookstore:
+ bookstore-name: Chapters
+ categories:
+ - code: 1
+ name: SciFi
+ - code: 2
+ name: kids
parameters:
dataspaceNameInQuery:
description: dataspace-name
@@ -2459,8 +2459,8 @@ components:
schema:
default: v2
enum:
- - v1
- - v2
+ - v1
+ - v2
type: string
dataspaceNameInPath:
description: dataspace-name
@@ -2725,19 +2725,19 @@ components:
format: binary
type: string
required:
- - file
+ - file
type: object
SchemaSetDetails:
example:
dataspaceName: my-dataspace
name: my-schema-set
moduleReferences:
- - name: my-module-reference-name
- namespace: my-module-reference-namespace
- revision: my-module-reference-revision
- - name: my-module-reference-name
- namespace: my-module-reference-namespace
- revision: my-module-reference-revision
+ - name: my-module-reference-name
+ namespace: my-module-reference-namespace
+ revision: my-module-reference-revision
+ - name: my-module-reference-name
+ namespace: my-module-reference-namespace
+ revision: my-module-reference-revision
properties:
dataspaceName:
example: my-dataspace
@@ -2750,7 +2750,7 @@ components:
example: my-schema-set
type: string
required:
- - moduleReferences
+ - moduleReferences
title: Schema set details by dataspace and schemasetName
type: object
ModuleReferences:
@@ -2777,16 +2777,16 @@ components:
test:bookstore:
bookstore-name: Chapters
categories:
- - code: 1
- name: SciFi
- - code: 2
- name: kids
+ - code: 1
+ name: SciFi
+ - code: 2
+ name: kids
type: object
file:
format: binary
type: string
required:
- - json
+ - json
type: object
securitySchemes:
basicAuth:
diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml
index a227addda5..871090fc7c 100644
--- a/docs/api/swagger/ncmp/openapi.yaml
+++ b/docs/api/swagger/ncmp/openapi.yaml
@@ -20,13 +20,14 @@ paths:
schema:
example: ncmp-datastore:running
type: string
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
- description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
@@ -130,13 +131,14 @@ paths:
schema:
example: ncmp-datastore:running
type: string
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
- description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
@@ -264,13 +266,14 @@ paths:
schema:
example: ncmp-datastore:running
type: string
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
- description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
@@ -377,13 +380,14 @@ paths:
schema:
example: ncmp-datastore:running
type: string
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
- description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
@@ -495,13 +499,14 @@ paths:
schema:
example: ncmp-datastore:running
type: string
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
- description: The format of resource identifier depend on the associated DMI
Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but
@@ -824,13 +829,14 @@ paths:
handle
operationId: getModuleReferencesByCmHandle
parameters:
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
responses:
"200":
@@ -880,13 +886,14 @@ paths:
\ with options to filter on module name and revision"
operationId: getModuleDefinitions
parameters:
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
- description: Filter for a module name.This is an optional parameter
in: query
@@ -1017,13 +1024,14 @@ paths:
description: Retrieve CM handle details and properties by cm handle id
operationId: retrieveCmHandleDetailsById
parameters:
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
responses:
"200":
@@ -1070,13 +1078,14 @@ paths:
description: Get CM handle properties by cm handle id
operationId: getCmHandlePublicPropertiesByCmHandleId
parameters:
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
responses:
"200":
@@ -1210,13 +1219,14 @@ paths:
description: Get CM handle state by cm handle id
operationId: getCmHandleStateByCmHandleId
parameters:
- - description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ - description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network\
+ \ CM Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
responses:
"200":
@@ -1464,14 +1474,15 @@ components:
schema:
example: ncmp-datastore:running
type: string
- cmHandleInPath:
- description: "The identifier for a network function, network element, subnetwork\
- \ or any other cm object by managed Network CM Proxy"
+ cmHandleReferenceInPath:
+ description: "The identifier (cmHandle or alternate) for a network function,\
+ \ network element, subnetwork or any other cm object by managed Network CM\
+ \ Proxy"
in: path
name: cm-handle
required: true
schema:
- example: my-cm-handle
+ example: my-cm-handle-reference
type: string
resourceIdentifierInQuery:
description: The format of resource identifier depend on the associated DMI
@@ -1558,6 +1569,15 @@ components:
required: true
schema:
type: string
+ cmHandleInPath:
+ description: "The identifier for a network function, network element, subnetwork\
+ \ or any other cm object by managed Network CM Proxy"
+ in: path
+ name: cm-handle
+ required: true
+ schema:
+ example: my-cm-handle
+ type: string
cpsPathInQuery:
description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
examples:
diff --git a/docs/api/swagger/policy-executor/openapi.yaml b/docs/api/swagger/policy-executor/openapi.yaml
index 6b73d98ed6..1248c0d08b 100644
--- a/docs/api/swagger/policy-executor/openapi.yaml
+++ b/docs/api/swagger/policy-executor/openapi.yaml
@@ -18,55 +18,170 @@
openapi: 3.0.3
info:
+ description: Allows NCMP to execute a policy defined by a third party implementation
+ before proceeding with a CM operation
title: Policy Executor
- description: "Allows NCMP to execute a policy defined by a third party implementation before proceeding with a CM operation"
version: 1.0.0
+servers:
+- url: /
+security:
+- bearerAuth: []
tags:
- - name: policy-executor
- description: "Execute all your policies"
+- description: Execute all your policies
+ name: policy-executor
paths:
/policy-executor/api/v1/{action}:
post:
- description: "Fire a Policy action"
+ description: Fire a Policy action
operationId: executePolicyAction
parameters:
- - $ref: '#/components/parameters/authorizationInHeader'
- - $ref: '#/components/parameters/actionInPath'
- requestBody:
+ - description: Bearer token may be used to identify client as part of a policy
+ explode: false
+ in: header
+ name: Authorization
+ required: false
+ schema:
+ type: string
+ style: simple
+ - description: "The policy action. Currently supported options: 'execute'"
+ explode: false
+ in: path
+ name: action
required: true
- description: "The action request body"
+ schema:
+ example: execute
+ type: string
+ style: simple
+ requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PolicyExecutionRequest'
- tags:
- - policy-executor
+ description: The action request body
+ required: true
responses:
- '200':
- description: "Successful policy execution"
+ "200":
content:
application/json:
schema:
$ref: '#/components/schemas/PolicyExecutionResponse'
- '400':
- $ref: '#/components/responses/BadRequest'
- '401':
- $ref: '#/components/responses/Unauthorized'
- '403':
- $ref: '#/components/responses/Forbidden'
- '500':
- $ref: '#/components/responses/InternalServerError'
-
+ description: Successful policy execution
+ "400":
+ content:
+ application/json:
+ example:
+ status: 400
+ message: Bad Request
+ details: The provided request is not valid
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Bad request
+ "401":
+ content:
+ application/json:
+ example:
+ status: 401
+ message: Unauthorized request
+ details: This request is unauthorized
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Unauthorized request
+ "403":
+ content:
+ application/json:
+ example:
+ status: 403
+ message: Request Forbidden
+ details: This request is forbidden
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Request forbidden
+ "500":
+ content:
+ application/json:
+ example:
+ status: 500
+ message: Internal Server Error
+ details: Internal server error occurred
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Internal server error
+ tags:
+ - policy-executor
components:
- securitySchemes:
- bearerAuth:
- type: http
- description: "Bearer token (from client that called CPS-NCMP),used by policies to identify the client"
- scheme: bearer
+ parameters:
+ actionInPath:
+ description: "The policy action. Currently supported options: 'execute'"
+ explode: false
+ in: path
+ name: action
+ required: true
+ schema:
+ example: execute
+ type: string
+ style: simple
+ authorizationInHeader:
+ description: Bearer token may be used to identify client as part of a policy
+ explode: false
+ in: header
+ name: Authorization
+ required: false
+ schema:
+ type: string
+ style: simple
+ responses:
+ BadRequest:
+ content:
+ application/json:
+ example:
+ status: 400
+ message: Bad Request
+ details: The provided request is not valid
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Bad request
+ Unauthorized:
+ content:
+ application/json:
+ example:
+ status: 401
+ message: Unauthorized request
+ details: This request is unauthorized
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Unauthorized request
+ Forbidden:
+ content:
+ application/json:
+ example:
+ status: 403
+ message: Request Forbidden
+ details: This request is forbidden
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Request forbidden
+ InternalServerError:
+ content:
+ application/json:
+ example:
+ status: 500
+ message: Internal Server Error
+ details: Internal server error occurred
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Internal server error
+ NotImplemented:
+ content:
+ application/json:
+ example:
+ status: 501
+ message: Not Implemented
+ details: Method not implemented
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ description: Method not (yet) implemented
schemas:
ErrorMessage:
- type: object
- title: Error
properties:
status:
type: string
@@ -74,125 +189,73 @@ components:
type: string
details:
type: string
-
- Request:
+ title: Error
type: object
+ Request:
+ example:
+ schema: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
+ data: "{}"
properties:
schema:
+ description: The schema for the data in this request. The schema name should
+ include the type of operation
+ example: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
type: string
- description: "The schema for the data in this request. The schema name should include the type of operation"
- example: "org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0"
data:
+ description: The data related to the request. The format of the object is
+ determined by the schema
type: object
- description: "The data related to the request. The format of the object is determined by the schema"
required:
- - schema
- - data
-
- PolicyExecutionRequest:
+ - data
+ - schema
type: object
+ PolicyExecutionRequest:
+ example:
+ decisionType: allow
+ requests:
+ - schema: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
+ data: "{}"
+ - schema: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
+ data: "{}"
properties:
decisionType:
- type: string
description: "The type of decision. Currently supported options: 'allow'"
- example: "allow"
+ example: allow
+ type: string
requests:
- type: array
items:
$ref: '#/components/schemas/Request'
+ type: array
required:
- - decisionType
- - requests
-
- PolicyExecutionResponse:
+ - decisionType
+ - requests
type: object
+ PolicyExecutionResponse:
+ example:
+ decision: deny
+ decisionId: 550e8400-e29b-41d4-a716-446655440000
+ message: Object locked due to recent change
properties:
decisionId:
+ description: Unique ID for the decision (for auditing purposes)
+ example: 550e8400-e29b-41d4-a716-446655440000
type: string
- description: "Unique ID for the decision (for auditing purposes)"
- example: "550e8400-e29b-41d4-a716-446655440000"
decision:
- type: string
description: "The decision outcome. Currently supported values: 'allow','deny'"
- example: "deny"
+ example: deny
+ type: string
message:
+ description: Additional information regarding the decision outcome
+ example: Object locked due to recent change
type: string
- description: "Additional information regarding the decision outcome"
- example: "Object locked due to recent change"
required:
- - decisionId
- - decision
- - message
-
- responses:
- BadRequest:
- description: "Bad request"
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- example:
- status: 400
- message: "Bad Request"
- details: "The provided request is not valid"
- Unauthorized:
- description: "Unauthorized request"
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- example:
- status: 401
- message: "Unauthorized request"
- details: "This request is unauthorized"
- Forbidden:
- description: "Request forbidden"
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- example:
- status: 403
- message: "Request Forbidden"
- details: "This request is forbidden"
-
- InternalServerError:
- description: "Internal server error"
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- example:
- status: 500
- message: "Internal Server Error"
- details: "Internal server error occurred"
-
- NotImplemented:
- description: "Method not (yet) implemented"
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- example:
- status: 501
- message: "Not Implemented"
- details: "Method not implemented"
-
- parameters:
- actionInPath:
- name: action
- in: path
- description: "The policy action. Currently supported options: 'execute'"
- required: true
- schema:
- type: string
- example: "execute"
- authorizationInHeader:
- name: Authorization
- in: header
- description: "Bearer token may be used to identify client as part of a policy"
- schema:
- type: string
-
-security:
- - bearerAuth: []
+ - decision
+ - decisionId
+ - message
+ type: object
+ securitySchemes:
+ bearerAuth:
+ description: "Bearer token (from client that called CPS-NCMP),used by policies\
+ \ to identify the client"
+ scheme: bearer
+ type: http
diff --git a/docs/cps-delta-endpoints.rst b/docs/cps-delta-endpoints.rst
index ecb7550f44..47f52dc670 100644
--- a/docs/cps-delta-endpoints.rst
+++ b/docs/cps-delta-endpoints.rst
@@ -1,38 +1,53 @@
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
.. http://creativecommons.org/licenses/by/4.0
-.. Copyright (C) 2021 Pantheon.tech
.. Copyright (C) 2024 TechMahindra Ltd.
.. _cpsDeltaEndpoints:
-.. toctree::
- :maxdepth: 1
-
CPS Delta Endpoints
###################
-The CPS Delta feature provides 1 endpoint:
+The CPS Delta feature provides two endpoints:
+
+1. GET /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta
+2. POST /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta
-- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta
+Common Parameters of both the endpoints
+---------------------------------------
+Common Path Parameters
+^^^^^^^^^^^^^^^^^^^^^^
+The following parameters are common inputs between the two endpoints:
+ - **dataspace-name:** name of dataspace where the anchor(s) to be used for delta generation are stored.
+ - **source-anchor-name:** the source anchor name, the data under this anchor will be the reference data for delta report generation
-Description
------------
-The following is a Get endpoint, which allows the user to find the delta between configurations stored under two anchors within the same dataspace.
+Common Query Parameter
+^^^^^^^^^^^^^^^^^^^^^^
+Both the endpoint need the following query parameters as input:
+ - **xpath:** the xpath to a particular data node.
+ - Example: /bookstore/categories[@code='1']
-Path Parameters
----------------
-The endpoint takes 2 path parameters as input:
- - **dataspace-name:** name of dataspace where the 2 anchors to be used for delta generation are stored.
- - **anchor-name:** the source anchor name, the data under this anchor will be the reference data for delta report generation
+Description of API 1: Delta between 2 Anchors
+---------------------------------------------
+This API performs a GET operation, which allows the user to find the delta between configurations stored under two anchors within the same dataspace. The API has following input parameters:
-Query Parameters
-----------------
-The endpoint takes 3 query parameters as input:
- - **target-anchor-name:** the data retrieved from target anchor gets compared against the data retrieved from source anchor
- - **xpath:** the xpath to a particular data node, Example: /bookstore/categories[@code='1']
+Specific Query Parameters
+^^^^^^^^^^^^^^^^^^^^^^^^^
+The endpoint takes following additional/specific query parameters as input:
+ - **target-anchor-name:** the data retrieved from target anchor is compared against the data retrieved from source anchor
- **descendants:** specifies the number of descendants to query.
+Description of API 2: Delta between Anchor and JSON payload
+-----------------------------------------------------------
+This API performs a POST operation, which allows the user to find the delta between configurations stored under an anchors and a JSON payload provided as part of the request. The API has the following input parameters:
+
+Request Body for Endpoint 2
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The endpoint accepts a **multipart/form-data** input as part of request body. This allows the user to provide the following inputs as part of request body:
+ - **JSON payload:** this field accepts a valid JSON string as an input. The data provided as part of this JSON will be parsed using the schema, the schema is either retrieved using the anchor name or it can be provided as part of request body using the optional parameter of request body defined below. Once the JSON is parsed and validated, it is compared to the data fetched from the source anchor and the delta report is generated.
+ - **schema-context:** this is an optional parameter and allows the user to provide the schema of the JSON payload, as a yang or zip file, and this schema can be used to parse the JSON string in case the schema of JSON differs from the schema associated with source anchor. If the schema of JSON payload is similar to the schema associated with the anchor then this parameter can be left empty.
+
Sample Delta Report
-------------------
+Both the APIs have the same format for the delta report. The format is as follows:
.. code-block:: json
diff --git a/docs/cps-delta-feature.rst b/docs/cps-delta-feature.rst
index 34aa43df53..ee3df45378 100644
--- a/docs/cps-delta-feature.rst
+++ b/docs/cps-delta-feature.rst
@@ -1,6 +1,5 @@
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
.. http://creativecommons.org/licenses/by/4.0
-.. Copyright (C) 2021 Pantheon.tech
.. Copyright (C) 2024 TechMahindra Ltd.
.. _cpsDelta:
@@ -10,24 +9,26 @@
CPS Delta Feature
#################
-- The concept of CPS Delta Feature is to have the ability to find the delta or difference between two configurations stored in CPS DB.
+- The concept of CPS Delta Feature is to have the ability to find the delta or difference between two configurations in CPS.
-- The Delta feature brings a new functionality:
+- The Delta feature provides two new endpoints, providing the following functionalities:
- Ability to find the delta between the configurations stored in two anchors within the same dataspace.
+ - Ability to find the delta between the configurations stored under an anchor and a JSON payload provided as part of REST request.
-The calculated differences can then be used to generate a Delta Report which can be sent over the Kafka Notification Service to the user.
+The difference found are compiled into a Delta Report returned by the server. This report can be used in several different ways, one such use case is sending it over the Kafka Notification Service to the user.
Delta Report Format
-------------------
-The Delta Report is based on the RFC 9144, which defines a set of parameters to be included in the Delta Report. In CPS only the relevant parameters defined in RFC 9144 are used. These include:
- - **action:** This parameter defines how the data nodes changed between two configurations. If data nodes are added, deleted or modified then the 'action' parameter in the delta report will be set to 'create', 'remove' or 'replace' respectively for each data node.
+The Delta Report is based on the RFC 6902 and RFC 9144, which define a set of parameters to be included in the Delta Report. In CPS only the relevant parameters defined in the RFCs are used. These include:
+ - **action:** This parameter defines how the data nodes changed between two configurations. If data nodes are added, deleted or modified then the 'action' parameter in the delta report will be set to one of the following pre-defined operation values, i.e., 'create', 'remove' or 'replace' respectively for each data node.
- **xpath:** This parameter will provide the xpath of each data node that has been either added, deleted or modified.
- **source-data:** this parameter is added to the delta report when a data node is removed or updated, this represents the source/reference data against which the delta is being generated. In case of newly added data node this field is not included in the delta report.
- **target-data:** this parameter is added to the delta report when a data node is added or updated, this represents the data values that are being compared to the source data. In case of a data node being removed this field is not included in the delta report.
**Note.** In case of an existing data node being modified, both the source-data and target-data fields are present in the delta report.
+**Additional Information.** `Analysis of RFC 9144 and RFC 6902 for Delta Report generation <https://lf-onap.atlassian.net/wiki/spaces/DW/pages/16523520/Analysis+of+RFC+9144+and+RFC6902+for+Delta+Report+generation>`_
Mechanism for Delta generation
------------------------------
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
index 7340e7a788..cebb1c0800 100644
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -16,6 +16,34 @@ CPS Release Notes
.. * * * OSLO * * *
.. ====================
+Version: 3.5.4
+==============
+
+Release Data
+------------
+
++--------------------------------------+--------------------------------------------------------+
+| **CPS Project** | |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Docker images** | onap/cps-and-ncmp:3.5.4 |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release designation** | 3.5.4 Oslo |
+| | |
++--------------------------------------+--------------------------------------------------------+
+| **Release date** | Not yet released |
+| | |
++--------------------------------------+--------------------------------------------------------+
+
+Bug Fixes
+---------
+3.5.4
+
+Features
+--------
+3.5.4
+
Version: 3.5.3
==============
@@ -32,17 +60,25 @@ Release Data
| **Release designation** | 3.5.3 Oslo |
| | |
+--------------------------------------+--------------------------------------------------------+
-| **Release date** | Not yet released |
+| **Release date** | 2024 October 04 |
| | |
+--------------------------------------+--------------------------------------------------------+
Bug Fixes
---------
3.5.3
+ - `CPS-2353 <https://lf-onap.atlassian.net/browse/CPS-2353>`_ Slow cmHandle registration when we use moduleSetTag, alternateId and dataProducerIdentifier
+ - `CPS-2395 <https://lf-onap.atlassian.net/browse/CPS-2395>`_ Retry mechanism (with back off algorithm) is removed with more frequent watchdog poll
+ - `CPS-2409 <https://lf-onap.atlassian.net/browse/CPS-2409>`_ Return NONE for get effective trust level api if the trust level caches empty (restart case)
+ - `CPS-2430 <https://lf-onap.atlassian.net/browse/CPS-2430>`_ Fix memory leak related to using arrays in Hibernate
+
Features
--------
3.5.3
+ - `CPS-2247 <https://lf-onap.atlassian.net/browse/CPS-2247>`_ Policy Executor: Invoke Policy Executor and handle 'deny' response
+ - `CPS-2412 <https://lf-onap.atlassian.net/browse/CPS-2412>`_ Policy Executor: handle errors
+ - `CPS-2417 <https://lf-onap.atlassian.net/browse/CPS-2417>`_ Remove Hazelcast cache for prefix resolver
Version: 3.5.2
diff --git a/integration-test/pom.xml b/integration-test/pom.xml
index ef8fdc819e..b26ec5b0c9 100644
--- a/integration-test/pom.xml
+++ b/integration-test/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
index c93a5274e6..b08d1c1548 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
@@ -20,15 +20,14 @@
package org.onap.cps.integration.base
-
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.RecordedRequest
-import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper
+
import java.util.concurrent.TimeUnit
/**
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy
index 1d4d19bee0..56d4bfaee4 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/PolicyExecutorIntegrationSpec.groovy
@@ -68,7 +68,7 @@ class PolicyExecutorIntegrationSpec extends CpsIntegrationSpecBase {
'accepted cm handle' | 'ch-1' | 'mock expects "ABC"' || 201 || 'allow'
'un-accepted cm handle' | 'ch-2' | 'mock expects "ABC"' || 409 || 'deny from mock server (dispatcher)'
'timeout' | 'ch-3' | 'mock expects "ABC"' || 409 || 'test default decision'
- 'invalid authorization' | 'ch-1' | 'something else' || 500 || '401 Unauthorized from POST http://localhost:8790/policy-executor/api/v1/execute'
+ 'invalid authorization' | 'ch-1' | 'something else' || 409 || 'test default decision'
}
}
diff --git a/jacoco-report/pom.xml b/jacoco-report/pom.xml
index 503500f529..298a0e76bd 100644
--- a/jacoco-report/pom.xml
+++ b/jacoco-report/pom.xml
@@ -5,7 +5,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/k6-tests/ncmp/common/utils.js b/k6-tests/ncmp/common/utils.js
index b52866c3fb..7873732361 100644
--- a/k6-tests/ncmp/common/utils.js
+++ b/k6-tests/ncmp/common/utils.js
@@ -86,22 +86,22 @@ export function makeCustomSummaryReport(testResults, scenarioConfig) {
'#,Test Name,Unit,Fs Requirement,Current Expectation,Actual',
makeSummaryCsvLine('0', 'HTTP request failures for all tests', 'rate of failed requests', 'http_req_failed', 0, testResults, scenarioConfig),
makeSummaryCsvLine('1', 'Registration of CM-handles', 'CM-handles/second', 'cmhandles_created_per_second', 110, testResults, scenarioConfig),
- makeSummaryCsvLine('2', 'De-registration of CM-handles', 'CM-handles/second', 'cmhandles_deleted_per_second', 80, testResults, scenarioConfig),
- makeSummaryCsvLine('3a', 'CM-handle ID search with No filter', 'milliseconds', 'id_search_nofilter_duration', 4000, testResults, scenarioConfig),
- makeSummaryCsvLine('3b', 'CM-handle ID search with Module filter', 'milliseconds', 'id_search_module_duration', 4000, testResults, scenarioConfig),
- makeSummaryCsvLine('3c', 'CM-handle ID search with Property filter', 'milliseconds', 'id_search_property_duration', 4000, testResults, scenarioConfig),
- makeSummaryCsvLine('3d', 'CM-handle ID search with Cps Path filter', 'milliseconds', 'id_search_cpspath_duration', 4000, testResults, scenarioConfig),
- makeSummaryCsvLine('3e', 'CM-handle ID search with Trust Level filter', 'milliseconds', 'id_search_trustlevel_duration', 4000, testResults, scenarioConfig),
- makeSummaryCsvLine('4a', 'CM-handle search with No filter', 'milliseconds', 'cm_search_nofilter_duration', 30000, testResults, scenarioConfig),
- makeSummaryCsvLine('4b', 'CM-handle search with Module filter', 'milliseconds', 'cm_search_module_duration', 30000, testResults, scenarioConfig),
- makeSummaryCsvLine('4c', 'CM-handle search with Property filter', 'milliseconds', 'cm_search_property_duration', 30000, testResults, scenarioConfig),
- makeSummaryCsvLine('4d', 'CM-handle search with Cps Path filter', 'milliseconds', 'cm_search_cpspath_duration', 30000, testResults, scenarioConfig),
- makeSummaryCsvLine('4e', 'CM-handle search with Trust Level filter', 'milliseconds', 'cm_search_trustlevel_duration', 30000, testResults, scenarioConfig),
- makeSummaryCsvLine('5a', 'NCMP overhead for Synchronous single CM-handle pass-through read', 'milliseconds', 'ncmp_overhead_passthrough_read', 40, testResults, scenarioConfig),
+ makeSummaryCsvLine('2', 'De-registration of CM-handles', 'CM-handles/second', 'cmhandles_deleted_per_second', 90, testResults, scenarioConfig),
+ makeSummaryCsvLine('3a', 'CM-handle ID search with No filter', 'milliseconds', 'id_search_nofilter_duration', 400, testResults, scenarioConfig),
+ makeSummaryCsvLine('3b', 'CM-handle ID search with Module filter', 'milliseconds', 'id_search_module_duration', 200, testResults, scenarioConfig),
+ makeSummaryCsvLine('3c', 'CM-handle ID search with Property filter', 'milliseconds', 'id_search_property_duration', 1300, testResults, scenarioConfig),
+ makeSummaryCsvLine('3d', 'CM-handle ID search with Cps Path filter', 'milliseconds', 'id_search_cpspath_duration', 1300, testResults, scenarioConfig),
+ makeSummaryCsvLine('3e', 'CM-handle ID search with Trust Level filter', 'milliseconds', 'id_search_trustlevel_duration', 10000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4a', 'CM-handle search with No filter', 'milliseconds', 'cm_search_nofilter_duration', 14000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4b', 'CM-handle search with Module filter', 'milliseconds', 'cm_search_module_duration', 16000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4c', 'CM-handle search with Property filter', 'milliseconds', 'cm_search_property_duration', 16000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4d', 'CM-handle search with Cps Path filter', 'milliseconds', 'cm_search_cpspath_duration', 16000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4e', 'CM-handle search with Trust Level filter', 'milliseconds', 'cm_search_trustlevel_duration', 26000, testResults, scenarioConfig),
+ makeSummaryCsvLine('5a', 'NCMP overhead for Synchronous single CM-handle pass-through read', 'milliseconds', 'ncmp_overhead_passthrough_read', 30, testResults, scenarioConfig),
makeSummaryCsvLine('5b', 'NCMP overhead for Synchronous single CM-handle pass-through read with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_read_alt_id', 60, testResults, scenarioConfig),
makeSummaryCsvLine('6a', 'NCMP overhead for Synchronous single CM-handle pass-through write', 'milliseconds', 'ncmp_overhead_passthrough_write', 30, testResults, scenarioConfig),
makeSummaryCsvLine('6b', 'NCMP overhead for Synchronous single CM-handle pass-through write with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_write_alt_id', 60, testResults, scenarioConfig),
- makeSummaryCsvLine('7', 'Legacy batch read operation', 'events/second', 'legacy_batch_read_cmhandles_per_second', 1100, testResults, scenarioConfig),
+ makeSummaryCsvLine('7', 'Legacy batch read operation', 'events/second', 'legacy_batch_read_cmhandles_per_second', 1500, testResults, scenarioConfig),
];
return summaryCsvLines.join('\n') + '\n';
}
diff --git a/k6-tests/once-off-test/kafka/produce-avc-event.js b/k6-tests/once-off-test/kafka/produce-avc-event.js
new file mode 100644
index 0000000000..981a21af65
--- /dev/null
+++ b/k6-tests/once-off-test/kafka/produce-avc-event.js
@@ -0,0 +1,99 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+import { crypto } from 'k6/experimental/webcrypto';
+import { check } from 'k6';
+import { Writer, SchemaRegistry, SCHEMA_TYPE_STRING } from 'k6/x/kafka';
+
+const testEventPayload = JSON.stringify(JSON.parse(open('../../resources/sampleAvcInputEvent.json')));
+const schemaRegistry = new SchemaRegistry();
+const kafkaProducer = new Writer({
+ brokers: ['localhost:9092'],
+ topic: 'dmi-cm-events',
+ autoCreateTopic: true,
+ batchSize: 5000,
+ compression: 'gzip',
+ requestTimeout: 30000
+});
+
+const TOTAL_MESSAGES = 100000;
+const VIRTUAL_USERS = 1000;
+
+export const options = {
+ setupTimeout: '1m',
+ teardownTimeout: '1m',
+ scenarios: {
+ produceKafkaMessages: {
+ executor: 'shared-iterations',
+ exec: 'sendKafkaMessages',
+ vus: VIRTUAL_USERS,
+ iterations: TOTAL_MESSAGES,
+ maxDuration: '10m',
+ }
+ }
+};
+
+function getCloudEventHeaders() {
+ return {
+ ce_type: 'org.onap.cps.ncmp.events.avc1_0_0.AvcEvent',
+ ce_source: 'DMI',
+ ce_destination: 'dmi-cm-events',
+ ce_specversion: '1.0',
+ ce_time: new Date().toISOString(),
+ ce_id: crypto.randomUUID(),
+ ce_dataschema: 'urn:cps:org.onap.cps.ncmp.events.avc1_0_0.AvcEvent:1.0.0',
+ ce_correlationid: crypto.randomUUID()
+ };
+}
+
+export function sendKafkaMessages() {
+ const cloudEventHeaders = getCloudEventHeaders();
+
+ const avcCloudEvent = {
+ key: schemaRegistry.serialize({
+ data: cloudEventHeaders.ce_correlationid,
+ schemaType: SCHEMA_TYPE_STRING,
+ }),
+ value: schemaRegistry.serialize({
+ data: testEventPayload,
+ schemaType: SCHEMA_TYPE_STRING
+ }),
+ headers: cloudEventHeaders
+ };
+
+ try {
+ kafkaProducer.produce({ messages: [avcCloudEvent] });
+
+ const isMessageSent = check(kafkaProducer, {
+ 'Message sent successfully': (producer) => producer != null,
+ });
+
+ if (!isMessageSent) {
+ console.error('Failed to send message:', avcCloudEvent);
+ }
+
+ } catch (error) {
+ console.error('Error during message production:', error, avcCloudEvent);
+ }
+}
+
+export function teardown() {
+ kafkaProducer.close();
+}
diff --git a/k6-tests/resources/sampleAvcInputEvent.json b/k6-tests/resources/sampleAvcInputEvent.json
new file mode 100644
index 0000000000..4c9cd721df
--- /dev/null
+++ b/k6-tests/resources/sampleAvcInputEvent.json
@@ -0,0 +1,38 @@
+{
+ "data": {
+ "push-change-update": {
+ "datastore-changes": {
+ "ietf-yang-patch:yang-patch": {
+ "patch-id": "34534ffd98",
+ "edit": [
+ {
+ "edit-id": "ded43434-1",
+ "operation": "replace",
+ "target": "ancestor:ancestor/parent[@id='parent1']/child[@id='child1']/grandchild[@id='grandchild1']/relation[@id='relation1']",
+ "value": {
+ "attributes": []
+ }
+ },
+ {
+ "edit-id": "ded43434-2",
+ "operation": "create",
+ "target": "ancestor:ancestor/parent[@id='parent1']/child[@id='child1']/grandchild[@id='grandchild1']/relation[@id='relation1']",
+ "value": {
+ "attributes": [
+ {
+ "isHoAllowed": false
+ }
+ ]
+ }
+ },
+ {
+ "edit-id": "ded43434-3",
+ "operation": "delete",
+ "target": "ancestor:ancestor/parent[@id='parent1']/child[@id='child1']/grandchild[@id='grandchild1']/relation[@id='relation1']"
+ }
+ ]
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/policy-executor-stub/pom.xml b/policy-executor-stub/pom.xml
index 35ff835505..420f565f9b 100644
--- a/policy-executor-stub/pom.xml
+++ b/policy-executor-stub/pom.xml
@@ -6,7 +6,7 @@
<parent>
<groupId>org.onap.cps</groupId>
<artifactId>cps-parent</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<relativePath>../cps-parent/pom.xml</relativePath>
</parent>
diff --git a/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
index cdd26c96e9..88073c0a0f 100644
--- a/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
+++ b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
@@ -41,9 +41,11 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
public class PolicyExecutorStubController implements PolicyExecutorApi {
+ private final Sleeper sleeper;
private final ObjectMapper objectMapper;
private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("(\\d{3})");
private int decisionCounter = 0;
+ private static int slowResponseTimeInSeconds = 40;
@Override
public ResponseEntity<PolicyExecutionResponse> executePolicyAction(
@@ -85,7 +87,14 @@ public class PolicyExecutorStubController implements PolicyExecutorApi {
final String decisionId = String.valueOf(++decisionCounter);
final String decision;
final String message;
-
+ if (targetIdentifier.toLowerCase(Locale.getDefault()).contains("slow")) {
+ try {
+ sleeper.haveALittleRest(slowResponseTimeInSeconds);
+ } catch (final InterruptedException e) {
+ log.trace("Sleep interrupted, re-interrupting the thread");
+ Thread.currentThread().interrupt(); // Re-interrupt the thread
+ }
+ }
if (targetIdentifier.toLowerCase(Locale.getDefault()).contains("cps-is-great")) {
decision = "allow";
message = "All good";
diff --git a/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/Sleeper.java b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/Sleeper.java
new file mode 100644
index 0000000000..8f904cc5f2
--- /dev/null
+++ b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/Sleeper.java
@@ -0,0 +1,35 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.policyexecutor.stub.controller;
+
+import java.util.concurrent.TimeUnit;
+import org.springframework.stereotype.Service;
+
+/**
+ * This class is a successfull experiment to extract out sleep functionality so the interrupted exception handling can
+ * be covered with a test (e.g. using spy ion Sleeper) and help to get too 100% code coverage.
+ */
+@Service
+public class Sleeper {
+ public void haveALittleRest(final int timeInSeconds) throws InterruptedException {
+ TimeUnit.SECONDS.sleep(timeInSeconds);
+ }
+}
diff --git a/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
index 064e0234a3..44460daa7e 100644
--- a/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
+++ b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
@@ -25,6 +25,7 @@ import org.onap.cps.policyexecutor.stub.model.NcmpDelete
import org.onap.cps.policyexecutor.stub.model.PolicyExecutionRequest
import org.onap.cps.policyexecutor.stub.model.PolicyExecutionResponse
import org.onap.cps.policyexecutor.stub.model.Request
+import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.HttpStatus
@@ -43,8 +44,15 @@ class PolicyExecutorStubControllerSpec extends Specification {
@Autowired
ObjectMapper objectMapper
+ @SpringBean
+ Sleeper sleeper = Spy()
+
def url = '/policy-executor/api/v1/some-action'
+ def setup() {
+ PolicyExecutorStubController.slowResponseTimeInSeconds = 1
+ }
+
def 'Execute policy action.'() {
given: 'a policy execution request with target: #targetIdentifier'
def requestBody = createRequestBody(targetIdentifier)
@@ -66,6 +74,7 @@ class PolicyExecutorStubControllerSpec extends Specification {
targetIdentifier || expectedDecsisonId | expectedDecision | expectedMessage
'some fdn' || '1' | 'deny' | "Only FDNs containing 'cps-is-great' are allowed"
'fdn with cps-is-great' || '2' | 'allow' | 'All good'
+ 'slow' || '3' | 'deny' | "Only FDNs containing 'cps-is-great' are allowed"
}
def 'Execute policy action with a HTTP error code.'() {
@@ -118,6 +127,19 @@ class PolicyExecutorStubControllerSpec extends Specification {
assert response.status == HttpStatus.BAD_REQUEST.value()
}
+ def 'Execute policy action with interrupted exception during slow response.'() {
+ given: 'a policy execution request with target: "slow"'
+ def requestBody = createRequestBody('slow')
+ sleeper.haveALittleRest(_) >> { throw new InterruptedException() }
+ when: 'request is posted'
+ mockMvc.perform(post(url)
+ .header('Authorization','some string')
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBody))
+ then: 'response status is Bad Request'
+ noExceptionThrown()
+ }
+
def 'Execute policy action with missing or invalid attributes.'() {
given: 'a policy execution request with decisionType=#decisionType, schema=#schema, targetIdentifier=#targetIdentifier'
def requestBody = createRequestBody(decisionType, schema, targetIdentifier)
diff --git a/pom.xml b/pom.xml
index 8347b1fe70..8796d53c74 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
<groupId>org.onap.cps</groupId>
<artifactId>cps-aggregator</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<packaging>pom</packaging>
<name>cps</name>
diff --git a/releases/3.5.3-container.yaml b/releases/3.5.3-container.yaml
new file mode 100644
index 0000000000..de99979bb6
--- /dev/null
+++ b/releases/3.5.3-container.yaml
@@ -0,0 +1,8 @@
+distribution_type: container
+container_release_tag: 3.5.3
+project: cps
+log_dir: cps-maven-docker-stage-master/946/
+ref: ef70022bddcb18a17c4afe2332cafa78621ab8b5
+containers:
+ - name: 'cps-and-ncmp'
+ version: '3.5.3-20241004T144917Z'
diff --git a/releases/3.5.3.yaml b/releases/3.5.3.yaml
new file mode 100644
index 0000000000..db6944c3c8
--- /dev/null
+++ b/releases/3.5.3.yaml
@@ -0,0 +1,4 @@
+distribution_type: maven
+log_dir: cps-maven-stage-master/954/
+project: cps
+version: 3.5.3
diff --git a/spotbugs/pom.xml b/spotbugs/pom.xml
index 1433bd3a39..aaa3d9500d 100644
--- a/spotbugs/pom.xml
+++ b/spotbugs/pom.xml
@@ -25,7 +25,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.cps</groupId>
<artifactId>spotbugs</artifactId>
- <version>3.5.3-SNAPSHOT</version>
+ <version>3.5.4-SNAPSHOT</version>
<properties>
<nexusproxy>https://nexus.onap.org</nexusproxy>
diff --git a/version.properties b/version.properties
index 5b9387554a..fa9fe7b6dc 100644
--- a/version.properties
+++ b/version.properties
@@ -22,7 +22,7 @@
major=3
minor=5
-patch=3
+patch=4
base_version=${major}.${minor}.${patch}