From: Sourabh Sourabh Date: Thu, 26 Jan 2023 12:03:10 +0000 (+0000) Subject: Merge "Springboot Integration tests improvements" X-Git-Tag: 3.2.2~16 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=528cf81a398b679e17ebccc446b759548722e7cc;hp=665e22472f9658a4d439da0323e6e8760ec60840;p=cps.git Merge "Springboot Integration tests improvements" --- diff --git a/INFO.yaml b/INFO.yaml index ca4f250ca..cb4499644 100755 --- a/INFO.yaml +++ b/INFO.yaml @@ -47,21 +47,21 @@ meetings: time: '08:00 America/New_York' committers: - <<: *onap_releng_ptl - - name: 'Aditya Puthuparambil' - email: 'aditya.puthuparambil@bell.ca' - company: 'Bell Canada' - id: 'puthuparambil.aditya' - timezone: 'Europe/Dublin' - - name: 'Joseph Keenan' - email: 'joseph.keenan@est.tech' - company: 'Ericsson Software Technology' - id: 'JosephKeenan' - timezone: 'Europe/Dublin' - name: 'Sourabh Sharma' email: 'sourabh.sourabh@est.tech' company: 'Ericsson Software Technology' id: 'sourabh_sourabh' timezone: 'Europe/Dublin' + - name: 'Luke Gleeson' + email: 'luke.gleeson@est.tech' + company: 'Ericsson Software Technology' + id: 'lukegleeson' + timezone: 'Europe/Dublin' + - name: 'Priyank Maheshwari' + email: 'priyank.maheshwari@est.tech' + company: 'Ericsson Software Technology' + id: 'mpriyank' + timezone: 'Europe/Dublin' repositories: - cps tsc: diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml index b5b10b0f7..f7fe46e4e 100644 --- a/cps-application/src/main/resources/application.yml +++ b/cps-application/src/main/resources/application.yml @@ -1,7 +1,7 @@ # ============LICENSE_START======================================================= # Copyright (C) 2021 Pantheon.tech # Modifications Copyright (C) 2021-2022 Bell Canada -# Modifications Copyright (C) 2021-2022 Nordix Foundation +# Modifications Copyright (C) 2021-2023 Nordix Foundation # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -84,16 +84,15 @@ spring: properties: spring.deserializer.key.delegate.class: org.apache.kafka.common.serialization.StringDeserializer spring.deserializer.value.delegate.class: org.springframework.kafka.support.serializer.JsonDeserializer - spring.json.value.default.type: org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent spring.json.use.type.headers: false jackson: - default-property-inclusion: NON_NULL - serialization: - FAIL_ON_EMPTY_BEANS: false + default-property-inclusion: NON_NULL + serialization: + FAIL_ON_EMPTY_BEANS: false sql: - init: - mode: ALWAYS + init: + mode: ALWAYS app: ncmp: async-m2m: @@ -104,6 +103,7 @@ app: events: topic: ${LCM_EVENTS_TOPIC:ncmp-events} + notification: enabled: true data-updated: diff --git a/cps-ncmp-events/src/main/resources/schemas/avc-event-schema-v1.json b/cps-ncmp-events/src/main/resources/schemas/avc-event-schema-v1.json new file mode 100644 index 000000000..6db03f6eb --- /dev/null +++ b/cps-ncmp-events/src/main/resources/schemas/avc-event-schema-v1.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "urn:cps:org.onap.cps.ncmp.events:avc-event-schema:v1", + "$ref": "#/definitions/AvcEvent", + "definitions": { + "AvcEvent": { + "description": "The payload for AVC event.", + "type": "object", + "properties": { + "eventId": { + "description": "The unique id identifying the event generated by DMI for this AVC event.", + "type": "string" + }, + "eventCorrelationId": { + "description": "The request id passed by NCMP for this AVC event.", + "type": "string" + }, + "eventTime": { + "description": "The time of the AVC event. The expected format is 'yyyy-MM-dd'T'HH:mm:ss.SSSZ'.", + "type": "string" + }, + "eventTarget": { + "description": "The target of the AVC event.", + "type": "string" + }, + "eventType": { + "description": "The type of the AVC event.", + "type": "string" + }, + "eventSchema": { + "description": "The event schema for AVC events.", + "type": "string" + }, + "eventSchemaVersion": { + "description": "The event schema version for AVC events.", + "type": "string" + }, + "event": { + "$ref": "#/definitions/Event" + } + }, + "required": [ + "eventId", + "eventCorrelationId", + "eventTime", + "eventTarget", + "eventType", + "eventSchema", + "eventSchemaVersion" + ] + }, + "Event": { + "description": "The AVC event content.", + "type": "object" + } + } +} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java index a9e7164fd..bc6624dee 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (c) 2022 Nordix Foundation. + * Copyright (c) 2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,9 @@ public class NcmpAsyncRequestResponseEventConsumer { * * @param dmiAsyncRequestResponseEvent the event to be consumed and produced. */ - @KafkaListener(topics = "${app.ncmp.async-m2m.topic}") + @KafkaListener( + topics = "${app.ncmp.async-m2m.topic}", + properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent"}) public void consumeAndForward(final DmiAsyncRequestResponseEvent dmiAsyncRequestResponseEvent) { log.debug("Consuming event {} ...", dmiAsyncRequestResponseEvent); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java index 5c3cb60c2..ac2bd4596 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/SynchronizationCacheConfig.java @@ -38,7 +38,7 @@ import org.springframework.context.annotation.Configuration; @Configuration public class SynchronizationCacheConfig { - public static final int MODULE_SYNC_STARTED_TTL_SECS = 120; + public static final int MODULE_SYNC_STARTED_TTL_SECS = 600; public static final int DATA_SYNC_SEMAPHORE_TTL_SECS = 1800; private static final QueueConfig commonQueueConfig = createQueueConfig(); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java new file mode 100644 index 000000000..79a36bf50 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventConsumer.java @@ -0,0 +1,53 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.notifications.avc; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.event.model.AvcEvent; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +/** + * Listener for AVC events. + */ +@Component +@Slf4j +@RequiredArgsConstructor +@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true) +public class AvcEventConsumer { + + private final AvcEventProducer avcEventProducer; + + /** + * Consume the specified event. + * + * @param avcEvent the event to be consumed and produced. + */ + @KafkaListener( + topics = "dmi-cm-events", + properties = {"spring.json.value.default.type=org.onap.cps.ncmp.event.model.AvcEvent"}) + public void consumeAndForward(final AvcEvent avcEvent) { + log.debug("Consuming AVC event {} ...", avcEvent); + avcEventProducer.sendMessage(avcEvent); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java new file mode 100644 index 000000000..531de4641 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventMapper.java @@ -0,0 +1,50 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.notifications.avc; + +import java.util.UUID; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.onap.cps.ncmp.event.model.AvcEvent; + + +/** + * Mapper for converting incoming {@link AvcEvent} to outgoing {@link AvcEvent}. + */ +@Mapper(componentModel = "spring") +public interface AvcEventMapper { + + @Mapping(source = "eventTime", target = "eventTime") + @Mapping(source = "eventId", target = "eventId", qualifiedByName = "avcEventId") + @Mapping(source = "eventCorrelationId", target = "eventCorrelationId") + @Mapping(source = "eventSchema", target = "eventSchema") + @Mapping(source = "eventSchemaVersion", target = "eventSchemaVersion") + @Mapping(source = "eventTarget", target = "eventTarget") + @Mapping(source = "eventType", target = "eventType") + AvcEvent toOutgoingAvcEvent(AvcEvent incomingAvcEvent); + + @Named("avcEventId") + static String getAvcEventId(String eventId) { + return UUID.randomUUID().toString(); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java new file mode 100644 index 000000000..049f66100 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducer.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.notifications.avc; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.event.model.AvcEvent; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +/** + * Producer for AVC events. + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class AvcEventProducer { + + private final KafkaTemplate kafkaTemplate; + + private final AvcEventMapper avcEventMapper; + + /** + * Sends message to the configured topic with a message key. + * + * @param incomingAvcEvent message payload + */ + public void sendMessage(final AvcEvent incomingAvcEvent) { + // generate new event id while keeping other data + final AvcEvent outgoingAvcEvent = avcEventMapper.toOutgoingAvcEvent(incomingAvcEvent); + log.debug("Forwarding AVC event {} to topic {} ", outgoingAvcEvent.getEventId(), "cm-events"); + kafkaTemplate.send("cm-events", outgoingAvcEvent.getEventId(), outgoingAvcEvent); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java index 3fbebe077..d778afc3e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasks.java @@ -71,13 +71,13 @@ public class ModuleSyncTasks { moduleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle); cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.READY); } catch (final Exception e) { - log.warn("Processing of {} module sync failed.", cmHandleId); + log.warn("Processing of {} module sync failed due to reason {}.", cmHandleId, e.getMessage()); syncUtils.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.LOCKED_MODULE_SYNC_FAILED, e.getMessage()); setCmHandleStateLocked(yangModelCmHandle, compositeState.getLockReason()); cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED); } - log.debug("{} is now in {} state", cmHandleId, compositeState.getCmHandleState().name()); + log.info("{} is now in {} state", cmHandleId, compositeState.getCmHandleState().name()); } lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandelStatePerCmHandle); } finally { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy new file mode 100644 index 000000000..0089f777d --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/notifications/avc/AvcEventProducerIntegrationSpec.groovy @@ -0,0 +1,83 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.impl.notifications.avc + +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.kafka.clients.consumer.KafkaConsumer +import org.mapstruct.factory.Mappers +import org.onap.cps.ncmp.api.impl.async.NcmpAsyncRequestResponseEventMapper +import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.event.model.AvcEvent +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.annotation.DirtiesContext +import org.testcontainers.spock.Testcontainers + +import java.time.Duration + +@SpringBootTest(classes = [AvcEventProducer, AvcEventConsumer, ObjectMapper, JsonObjectMapper]) +@Testcontainers +@DirtiesContext +class AvcEventProducerIntegrationSpec extends MessagingBaseSpec { + + @SpringBean + AvcEventMapper avcEventMapper = Mappers.getMapper(AvcEventMapper.class) + + @SpringBean + AvcEventProducer avcEventProducer = new AvcEventProducer(kafkaTemplate, avcEventMapper) + + @SpringBean + AvcEventConsumer acvEventConsumer = new AvcEventConsumer(avcEventProducer) + + @Autowired + JsonObjectMapper jsonObjectMapper + + def kafkaConsumer = new KafkaConsumer<>(consumerConfigProperties('ncmp-group')) + + def 'Consume and forward valid message'() { + given: 'consumer has a subscription' + kafkaConsumer.subscribe(['cm-events'] as List) + and: 'an event is sent' + def jsonData = TestUtils.getResourceFileContent('sampleAvcInputEvent.json') + def testEventSent = jsonObjectMapper.convertJsonString(jsonData, AvcEvent.class) + when: 'the event is consumed' + acvEventConsumer.consumeAndForward(testEventSent) + and: 'the topic is polled' + def records = kafkaConsumer.poll(Duration.ofMillis(1500)) + then: 'poll returns one record' + assert records.size() == 1 + and: 'record can be converted to AVC event' + def record = records.iterator().next() + def convertedAvcEvent = jsonObjectMapper.convertJsonString(record.value(), AvcEvent) + and: 'consumed forwarded NCMP event id differs from DMI event id' + assert testEventSent.eventId != convertedAvcEvent.getEventId() + and: 'correlation id matches' + assert testEventSent.eventCorrelationId == convertedAvcEvent.getEventCorrelationId() + and: 'timestamps match' + assert testEventSent.eventTime == convertedAvcEvent.getEventTime() + and: 'target matches' + assert testEventSent.eventTarget == convertedAvcEvent.getEventTarget() + } + +} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy index f7c41ecdf..bb0ce8745 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (c) 2022 Nordix Foundation. + * Copyright (c) 2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,14 +33,14 @@ import spock.lang.Specification class MessagingBaseSpec extends Specification { - static { - Runtime.getRuntime().addShutdownHook(new Thread(kafkaTestContainer::stop)) - } - def setupSpec() { kafkaTestContainer.start() } + def cleanupSpec() { + kafkaTestContainer.stop() + } + static kafkaTestContainer = new KafkaContainer(DockerImageName.parse('registry.nordix.org/onaptest/confluentinc/cp-kafka:6.2.1').asCompatibleSubstituteFor('confluentinc/cp-kafka')) def producerConfigProperties() { diff --git a/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json b/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json new file mode 100644 index 000000000..d7d252b9a --- /dev/null +++ b/cps-ncmp-service/src/test/resources/sampleAvcInputEvent.json @@ -0,0 +1,12 @@ +{ + "eventId": "4cb32729-85e3-44d1-aa6e-c923b9b059a5", + "eventCorrelationId": "68f15800-8ed4-4bae-9e53-27a9e03e1911", + "eventTime": "2022-12-12T14:29:23.876+0000", + "eventTarget": "NCMP", + "eventType": "org.onap.cps.ncmp.event.model.AvcEvent", + "eventSchema": "urn:cps:org.onap.cps.ncmp.event.model.AvcEvent", + "eventSchemaVersion": "v1", + "event": { + "payload": "Hello world!" + } +} \ No newline at end of file diff --git a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/performance/CpsPathUtilPerfTest.groovy b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/performance/CpsPathUtilPerfTest.groovy index e5e304b47..1dfd194c8 100644 --- a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/performance/CpsPathUtilPerfTest.groovy +++ b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/performance/CpsPathUtilPerfTest.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation + * Copyright (C) 2022-2023 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,9 +35,8 @@ class CpsPathUtilPerfTest extends Specification { CpsPathUtil.getNormalizedXpath('//child[@other-leaf=1]/leaf-name[text()="search"]/ancestor::parent') } stopWatch.stop() - then: 'it takes less then 1,100 milliseconds' - // In CI this actually takes about 0.3-0.5 sec which is approx. 50+ parser executions per millisecond! - assert stopWatch.getTotalTimeMillis() < 1100 + then: 'it takes less then 2100 milliseconds' + assert stopWatch.getTotalTimeMillis() < 2100 } } diff --git a/cps-rest/docs/openapi/components.yml b/cps-rest/docs/openapi/components.yml index e700da6ea..60b4ca318 100644 --- a/cps-rest/docs/openapi/components.yml +++ b/cps-rest/docs/openapi/components.yml @@ -1,7 +1,7 @@ # ============LICENSE_START======================================================= # Copyright (c) 2021-2022 Bell Canada. # Modifications Copyright (C) 2021-2022 Nordix Foundation -# Modifications Copyright (C) 2022 TechMahindra Ltd. +# Modifications Copyright (C) 2022-2023 TechMahindra Ltd. # Modifications Copyright (C) 2022 Deutsche Telekom AG # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); @@ -240,6 +240,15 @@ components: type: string example: 'application/json' required: true + descendantsInQuery: + name: descendants + in: query + description: descendents to query depth of children. allowed values are none, all, any number starting from -1 + required: false + schema: + type: string + default: none + example: 3 responses: NotFound: diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml index 0dc388706..1d60e1f78 100644 --- a/cps-rest/docs/openapi/cpsData.yml +++ b/cps-rest/docs/openapi/cpsData.yml @@ -1,7 +1,7 @@ # ============LICENSE_START======================================================= # Copyright (c) 2021-2022 Bell Canada. # Modifications Copyright (C) 2021-2022 Nordix Foundation -# Modifications Copyright (C) 2022 TechMahindra Ltd. +# Modifications Copyright (C) 2022-2023 TechMahindra Ltd. # Modifications Copyright (C) 2022 Deutsche Telekom AG # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,39 +19,6 @@ # 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: getNodeByDataspaceAndAnchor - 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/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' - '401': - $ref: 'components.yml#/components/responses/Unauthorized' - '403': - $ref: 'components.yml#/components/responses/Forbidden' - '500': - $ref: 'components.yml#/components/responses/InternalServerError' - x-codegen-request-body-name: xpath - listElementByDataspaceAndAnchor: post: description: Add list element(s) to a list for a given anchor and dataspace diff --git a/cps-rest/docs/openapi/cpsDataV1Deprecated.yml b/cps-rest/docs/openapi/cpsDataV1Deprecated.yml index 194ca3e07..67ddecd2a 100644 --- a/cps-rest/docs/openapi/cpsDataV1Deprecated.yml +++ b/cps-rest/docs/openapi/cpsDataV1Deprecated.yml @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (C) 2022 TechMahindra Ltd. +# 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. @@ -16,6 +16,39 @@ # 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' + '401': + $ref: 'components.yml#/components/responses/Unauthorized' + '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 diff --git a/cps-rest/docs/openapi/cpsDataV2.yml b/cps-rest/docs/openapi/cpsDataV2.yml new file mode 100644 index 000000000..61663ab3a --- /dev/null +++ b/cps-rest/docs/openapi/cpsDataV2.yml @@ -0,0 +1,49 @@ +# ============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 + 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' + '401': + $ref: 'components.yml#/components/responses/Unauthorized' + '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/cpsQuery.yml b/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml similarity index 94% rename from cps-rest/docs/openapi/cpsQuery.yml rename to cps-rest/docs/openapi/cpsQueryV1Deprecated.yml index 45fc70c86..6ec117f31 100644 --- a/cps-rest/docs/openapi/cpsQuery.yml +++ b/cps-rest/docs/openapi/cpsQueryV1Deprecated.yml @@ -1,7 +1,7 @@ # ============LICENSE_START======================================================= # Copyright (C) 2021 Nordix Foundation # Modifications Copyright (c) 2022 Bell Canada. -# Modifications Copyright (c) 2022 TechMahindra Ltd. +# 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. @@ -24,9 +24,9 @@ nodesByDataspaceAndAnchorAndCpsPath: tags: - cps-query summary: Query data nodes + deprecated: true operationId: getNodesByDataspaceAndAnchorAndCpsPath parameters: - - $ref: 'components.yml#/components/parameters/apiVersionInPath' - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' - $ref: 'components.yml#/components/parameters/anchorNameInPath' - $ref: 'components.yml#/components/parameters/cpsPathInQuery' diff --git a/cps-rest/docs/openapi/cpsQueryV2.yml b/cps-rest/docs/openapi/cpsQueryV2.yml new file mode 100644 index 000000000..5bfd1bbd2 --- /dev/null +++ b/cps-rest/docs/openapi/cpsQueryV2.yml @@ -0,0 +1,49 @@ +# ============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' + '401': + $ref: 'components.yml#/components/responses/Unauthorized' + '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 index 0918b56c3..0ac825a6d 100644 --- a/cps-rest/docs/openapi/openapi.yml +++ b/cps-rest/docs/openapi/openapi.yml @@ -2,7 +2,7 @@ # Copyright (C) 2021 Nordix Foundation # Modifications Copyright (C) 2021 Pantheon.tech # Modifications Copyright (C) 2021 Bell Canada. -# Modifications Copyright (C) 2022 TechMahindra Ltd. +# Modifications 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. @@ -89,8 +89,11 @@ paths: /{apiVersion}/dataspaces/{dataspace-name}/schema-sets/{schema-set-name}: $ref: 'cpsAdmin.yml#/schemaSetBySchemaSetName' - /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/node: - $ref: 'cpsData.yml#/nodeByDataspaceAndAnchor' + /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' @@ -101,8 +104,11 @@ paths: /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes: $ref: 'cpsData.yml#/listElementByDataspaceAndAnchor' - /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query: - $ref: 'cpsQuery.yml#/nodesByDataspaceAndAnchorAndCpsPath' + /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' security: - basicAuth: [] 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 30bed1277..3a9c764bc 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 @@ -3,7 +3,7 @@ * Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021-2022 Nordix Foundation - * Modifications Copyright (C) 2022 TechMahindra Ltd. + * Modifications Copyright (C) 2023 TechMahindra Ltd. * Modifications Copyright (C) 2022 Deutsche Telekom AG * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -93,8 +93,8 @@ public class DataRestController implements CpsDataApi { } @Override - public ResponseEntity getNodeByDataspaceAndAnchor(final String apiVersion, - final String dataspaceName, final String anchorName, final String xpath, final Boolean includeDescendants) { + public ResponseEntity getNodeByDataspaceAndAnchor(final String dataspaceName, + final String anchorName, final String xpath, final Boolean includeDescendants) { final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants) ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS; final DataNode dataNode = cpsDataService.getDataNode(dataspaceName, anchorName, xpath, @@ -103,6 +103,17 @@ public class DataRestController implements CpsDataApi { return new ResponseEntity<>(DataMapUtils.toDataMapWithIdentifier(dataNode, prefix), HttpStatus.OK); } + @Override + public ResponseEntity getNodeByDataspaceAndAnchorV2(final String dataspaceName, final String anchorName, + final String xpath, final String fetchDescendantsOptionAsString) { + final FetchDescendantsOption fetchDescendantsOption = + FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString); + final DataNode dataNode = cpsDataService.getDataNode(dataspaceName, anchorName, xpath, + fetchDescendantsOption); + final String prefix = prefixResolver.getPrefix(dataspaceName, anchorName, xpath); + return new ResponseEntity<>(DataMapUtils.toDataMapWithIdentifier(dataNode, prefix), HttpStatus.OK); + } + @Override public ResponseEntity updateNodeLeaves(final String apiVersion, final String dataspaceName, final String anchorName, final Object jsonData, final String parentNodeXpath, final String observedTimestamp) { @@ -151,4 +162,5 @@ public class DataRestController implements CpsDataApi { String.format("observed-timestamp must be in '%s' format", ISO_TIMESTAMP_FORMAT)); } } + } diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java index 3e162ae68..81938dcd9 100644 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/QueryRestController.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada. - * Modifications Copyright (C) 2022 TechMahindra Ltd. + * Modifications 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. @@ -49,22 +49,36 @@ public class QueryRestController implements CpsQueryApi { private final PrefixResolver prefixResolver; @Override - public ResponseEntity getNodesByDataspaceAndAnchorAndCpsPath(final String apiVersion, - final String dataspaceName, final String anchorName, final String cpsPath, final Boolean includeDescendants) { + public ResponseEntity getNodesByDataspaceAndAnchorAndCpsPath(final String dataspaceName, + final String anchorName, final String cpsPath, final Boolean includeDescendants) { final FetchDescendantsOption fetchDescendantsOption = Boolean.TRUE.equals(includeDescendants) ? FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS : FetchDescendantsOption.OMIT_DESCENDANTS; + return executeNodesByDataspaceQueryAndCreateResponse(dataspaceName, anchorName, cpsPath, + fetchDescendantsOption); + } + + @Override + public ResponseEntity getNodesByDataspaceAndAnchorAndCpsPathV2(final String dataspaceName, + final String anchorName, final String cpsPath, final String fetchDescendantsOptionAsString) { + final FetchDescendantsOption fetchDescendantsOption = + FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString); + return executeNodesByDataspaceQueryAndCreateResponse(dataspaceName, anchorName, cpsPath, + fetchDescendantsOption); + } + + private ResponseEntity executeNodesByDataspaceQueryAndCreateResponse(final String dataspaceName, + final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) { final Collection dataNodes = cpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption); - final List> dataMaps = new ArrayList<>(dataNodes.size()); + final List> dataNodesAsListOfMaps = new ArrayList<>(dataNodes.size()); String prefix = null; for (final DataNode dataNode : dataNodes) { if (prefix == null) { prefix = prefixResolver.getPrefix(dataspaceName, anchorName, dataNode.getXpath()); } final Map dataMap = DataMapUtils.toDataMapWithIdentifier(dataNode, prefix); - dataMaps.add(dataMap); + dataNodesAsListOfMaps.add(dataMap); } - - return new ResponseEntity<>(jsonObjectMapper.asJsonString(dataMaps), HttpStatus.OK); + return new ResponseEntity<>(jsonObjectMapper.asJsonString(dataNodesAsListOfMaps), HttpStatus.OK); } } 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 94f62f8c2..16d106ba6 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 @@ -4,6 +4,7 @@ * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2022 Deutsche Telekom AG + * Modifications 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. @@ -68,6 +69,7 @@ class DataRestControllerSpec extends Specification { def basePath def dataNodeBaseEndpoint + def dataNodeBaseEndpointV2 def dataspaceName = 'my_dataspace' def anchorName = 'my_anchor' def noTimestamp = null @@ -94,6 +96,7 @@ class DataRestControllerSpec extends Specification { def setup() { dataNodeBaseEndpoint = "$basePath/v1/dataspaces/$dataspaceName" + dataNodeBaseEndpointV2 = "$basePath/v2/dataspaces/$dataspaceName" } def 'Create a node: #scenario.'() { @@ -237,6 +240,28 @@ class DataRestControllerSpec extends Specification { 'with descendants' | dataNodeWithChild | 'true' || INCLUDE_ALL_DESCENDANTS | true | 'parent' } + + def 'Get data node using v2 api'() { + given: 'the service returns data node' + def xpath = 'some xPath' + def endpoint = "$dataNodeBaseEndpointV2/anchors/$anchorName/node" + mockCpsDataService.getDataNode(dataspaceName, anchorName, xpath, {descendantsOption -> { + assert descendantsOption.depth == 2}}) >> dataNodeWithChild + when: 'get request is performed through REST API' + def response = + mvc.perform( + get(endpoint) + .param('xpath', xpath) + .param('descendants', '2')) + .andReturn().response + then: 'a success response is returned' + assert response.status == HttpStatus.OK.value() + and: 'the response contains the root node identifier' + assert response.contentAsString.contains('parent') + and: 'the response contains child is true' + assert response.contentAsString.contains('"child"') == true + } + def 'Update data node leaves: #scenario.'() { given: 'endpoint to update a node ' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy index 27ca0cc09..b881c3832 100644 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy @@ -3,6 +3,7 @@ * Copyright (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech + * Modifications 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. @@ -58,13 +59,19 @@ class QueryRestControllerSpec extends Specification { @Value('${rest.api.cps-base-path}') def basePath + def dataspaceName = 'my_dataspace' + def anchorName = 'my_anchor' + def cpsPath = 'some cps-path' + def dataNodeEndpointV2 + + def setup() { + dataNodeEndpointV2 = "$basePath/v2/dataspaces/$dataspaceName/anchors/$anchorName/nodes/query" + } + def 'Query data node by cps path for the given dataspace and anchor with #scenario.'() { given: 'service method returns a list containing a data node' def dataNode1 = new DataNodeBuilder().withXpath('/xpath') .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build() - def dataspaceName = 'my_dataspace' - def anchorName = 'my_anchor' - def cpsPath = 'some cps-path' mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, expectedCpsDataServiceOption) >> [dataNode1, dataNode1] and: 'the query endpoint' def dataNodeEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName/nodes/query" @@ -84,4 +91,23 @@ class QueryRestControllerSpec extends Specification { 'no descendant explicitly' | 'false' || OMIT_DESCENDANTS 'descendants' | 'true' || INCLUDE_ALL_DESCENDANTS } + + def 'Query data node v2 api by cps path for the given dataspace and anchor with #scenario.'() { + given: 'service method returns a list containing a data node' + def dataNode1 = new DataNodeBuilder().withXpath('/xpath') + .withLeaves([leaf: 'value', leafList: ['leaveListElement1', 'leaveListElement2']]).build() + mockCpsQueryService.queryDataNodes(dataspaceName, anchorName, cpsPath, { descendantsOption -> { + assert descendantsOption.depth == 2}}) >> [dataNode1, dataNode1] + when: 'query data nodes API is invoked' + def response = + mvc.perform( + get(dataNodeEndpointV2) + .param('cps-path', cpsPath) + .param('descendants', '2')) + .andReturn().response + then: 'the response contains the the datanode in json format' + assert response.status == HttpStatus.OK.value() + assert response.getContentAsString().contains('{"xpath":{"leaf":"value","leafList":["leaveListElement1","leaveListElement2"]}}') + } + } diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java index 2fdfa0528..2ffbb4ae0 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020 Nordix Foundation. + * Copyright (C) 2020-2023 Nordix Foundation. * Modifications Copyright (C) 2021 Pantheon.tech * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,6 +40,7 @@ import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -58,6 +59,7 @@ import org.hibernate.annotations.TypeDef; @Entity @Table(name = "fragment") @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) +@EqualsAndHashCode(onlyExplicitlyIncluded = true) public class FragmentEntity implements Serializable { private static final long serialVersionUID = 7737669789097119667L; @@ -68,6 +70,7 @@ public class FragmentEntity implements Serializable { @NotNull @Column(columnDefinition = "text") + @EqualsAndHashCode.Include private String xpath; @Column(name = "parent_id") diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index 5b0683e97..d2b7273fe 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2020-2022 Bell Canada. * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -61,6 +61,7 @@ import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.DataNodeBuilder; import org.onap.cps.spi.repository.AnchorRepository; import org.onap.cps.spi.repository.DataspaceRepository; +import org.onap.cps.spi.repository.FragmentNativeRepository; import org.onap.cps.spi.repository.FragmentQueryBuilder; import org.onap.cps.spi.repository.FragmentRepository; import org.onap.cps.spi.utils.SessionManager; @@ -78,6 +79,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private final FragmentRepository fragmentRepository; private final JsonObjectMapper jsonObjectMapper; private final SessionManager sessionManager; + private final FragmentNativeRepository fragmentNativeRepositoryImpl; private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?]){0,1})"; @@ -262,13 +264,28 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService final FetchDescendantsOption fetchDescendantsOption) { final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName); - final List fragmentEntities = - fragmentRepository.findByAnchorAndMultipleCpsPaths(anchorEntity.getId(), xpaths); - final Collection dataNodesCollection = new ArrayList<>(fragmentEntities.size()); - for (final FragmentEntity fragmentEntity : fragmentEntities) { - dataNodesCollection.add(toDataNode(fragmentEntity, fetchDescendantsOption)); + + final Collection nonRootXpaths = new HashSet<>(xpaths); + final boolean haveRootXpath = nonRootXpaths.removeIf(CpsDataPersistenceServiceImpl::isRootXpath); + + final Collection normalizedXpaths = new HashSet<>(nonRootXpaths.size()); + for (final String xpath : nonRootXpaths) { + try { + normalizedXpaths.add(CpsPathUtil.getNormalizedXpath(xpath)); + } catch (final PathParsingException e) { + log.warn("Error parsing xpath \"{}\" in getDataNodes: {}", xpath, e.getMessage()); + } + } + final Collection fragmentEntities = + new HashSet<>(fragmentRepository.findByAnchorAndMultipleCpsPaths(anchorEntity.getId(), normalizedXpaths)); + + if (haveRootXpath) { + final List fragmentExtracts = fragmentRepository.getTopLevelFragments(dataspaceEntity, + anchorEntity); + fragmentEntities.addAll(FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts)); } - return dataNodesCollection; + + return toDataNodes(fragmentEntities, fetchDescendantsOption); } private FragmentEntity getFragmentWithoutDescendantsByXpath(final String dataspaceName, @@ -449,6 +466,15 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService .withChildDataNodes(childDataNodes).build(); } + private Collection toDataNodes(final Collection fragmentEntities, + final FetchDescendantsOption fetchDescendantsOption) { + final Collection dataNodes = new ArrayList<>(fragmentEntities.size()); + for (final FragmentEntity fragmentEntity : fragmentEntities) { + dataNodes.add(toDataNode(fragmentEntity, fetchDescendantsOption)); + } + return dataNodes; + } + private List getChildDataNodes(final FragmentEntity fragmentEntity, final FetchDescendantsOption fetchDescendantsOption) { if (fetchDescendantsOption.hasNext()) { @@ -630,7 +656,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private boolean deleteDataNode(final FragmentEntity parentFragmentEntity, final String targetXpath) { final String normalizedTargetXpath = CpsPathUtil.getNormalizedXpath(targetXpath); if (parentFragmentEntity.getXpath().equals(normalizedTargetXpath)) { - fragmentRepository.delete(parentFragmentEntity); + fragmentNativeRepositoryImpl.deleteFragmentEntity(parentFragmentEntity.getId()); return true; } if (parentFragmentEntity.getChildFragments() diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java new file mode 100644 index 000000000..4cfd79dee --- /dev/null +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepository.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.spi.repository; + +/** + * This interface is used in delete fragment entity by id with child using native sql queries. + */ +public interface FragmentNativeRepository { + void deleteFragmentEntity(long fragmentEntityId); +} diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java new file mode 100644 index 000000000..57dca568f --- /dev/null +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java @@ -0,0 +1,61 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.spi.repository; + +import java.sql.PreparedStatement; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import org.hibernate.Session; +import org.springframework.stereotype.Repository; + +@Repository +public class FragmentNativeRepositoryImpl implements FragmentNativeRepository { + + private static final String DROP_FRAGMENT_CONSTRAINT + = "ALTER TABLE fragment DROP CONSTRAINT fragment_parent_id_fkey;"; + private static final String ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE + = "ALTER TABLE fragment ADD CONSTRAINT fragment_parent_id_fkey FOREIGN KEY (parent_id) " + + "REFERENCES fragment (id) ON DELETE CASCADE;"; + private static final String DELETE_FRAGMENT = "DELETE FROM fragment WHERE id =?;"; + private static final String ADD_ORIGINAL_FRAGMENT_CONSTRAINT + = "ALTER TABLE fragment ADD CONSTRAINT fragment_parent_id_fkey FOREIGN KEY (parent_id) " + + "REFERENCES fragment (id) ON DELETE NO ACTION;"; + + @PersistenceContext + private EntityManager entityManager; + + @Override + public void deleteFragmentEntity(final long fragmentEntityId) { + final Session session = entityManager.unwrap(Session.class); + session.doWork(connection -> { + try (PreparedStatement preparedStatement = connection.prepareStatement( + DROP_FRAGMENT_CONSTRAINT + + ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE + + DELETE_FRAGMENT + + DROP_FRAGMENT_CONSTRAINT + + ADD_ORIGINAL_FRAGMENT_CONSTRAINT)) { + preparedStatement.setLong(1, fragmentEntityId); + preparedStatement.executeUpdate(); + } + }); + } +} + diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryMultiPathQueryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryMultiPathQueryImpl.java index b936e5c76..8c357bbb3 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryMultiPathQueryImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepositoryMultiPathQueryImpl.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. + * Copyright (C) 2022-2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ package org.onap.cps.spi.repository; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import javax.persistence.EntityManager; @@ -46,6 +47,9 @@ public class FragmentRepositoryMultiPathQueryImpl implements FragmentRepositoryM @Transactional public List findByAnchorAndMultipleCpsPaths(final Integer anchorId, final Collection cpsPathQueryList) { + if (cpsPathQueryList.isEmpty()) { + return Collections.emptyList(); + } final Collection> sqlData = new HashSet<>(cpsPathQueryList.size()); for (final String query : cpsPathQueryList) { final List row = new ArrayList<>(1); diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy index b6d2c5d65..ba8425fef 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceQueryDataNodeSpec.groovy @@ -3,6 +3,7 @@ * Copyright (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021 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. @@ -22,6 +23,7 @@ package org.onap.cps.spi.impl import org.onap.cps.spi.CpsDataPersistenceService +import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.exceptions.CpsPathException import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql @@ -41,7 +43,7 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { @Sql([CLEAR_DATA, SET_DATA]) def 'Cps Path query for leaf value(s) with : #scenario.'() { when: 'a query is executed to get a data node by the given cps path' - def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_SHOP_EXAMPLE, cpsPath, includeDescendantsOption) + def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_SHOP_EXAMPLE, cpsPath, fetchDescendantsOption) then: 'the correct number of parent nodes are returned' result.size() == expectedNumberOfParentNodes then: 'the correct data is returned' @@ -49,10 +51,12 @@ class CpsDataPersistenceQueryDataNodeSpec extends CpsPersistenceSpecBase { assert it.getChildDataNodes().size() == expectedNumberOfChildNodes } where: 'the following data is used' - scenario | cpsPath | includeDescendantsOption || expectedNumberOfParentNodes | expectedNumberOfChildNodes - 'String and no descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@title="Dune"]' | OMIT_DESCENDANTS || 1 | 0 - 'Integer and descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@price=5]' | INCLUDE_ALL_DESCENDANTS || 1 | 1 - 'No condition no descendants' | '/shops/shop[@id=1]/categories' | OMIT_DESCENDANTS || 3 | 0 + scenario | cpsPath | fetchDescendantsOption || expectedNumberOfParentNodes | expectedNumberOfChildNodes + 'String and no descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@title="Dune"]' | OMIT_DESCENDANTS || 1 | 0 + 'Integer and descendants' | '/shops/shop[@id=1]/categories[@code=1]/book[@price=5]' | INCLUDE_ALL_DESCENDANTS || 1 | 1 + 'No condition no descendants' | '/shops/shop[@id=1]/categories' | OMIT_DESCENDANTS || 3 | 0 + 'Integer and level 1 descendants' | '/shops' | new FetchDescendantsOption(1) || 1 | 5 + 'Integer and level 2 descendants' | '/shops/shop[@id=1]' | new FetchDescendantsOption(2) || 1 | 3 } @Sql([CLEAR_DATA, SET_DATA]) diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy index cc2369d50..5f48469c0 100755 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceIntegrationSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2021-2022 Bell Canada. * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -20,6 +20,7 @@ * SPDX-License-Identifier: Apache-2.0 * ============LICENSE_END========================================================= */ + package org.onap.cps.spi.impl import com.fasterxml.jackson.databind.ObjectMapper @@ -295,6 +296,44 @@ class CpsDataPersistenceServiceIntegrationSpec extends CpsPersistenceSpecBase { 'invalid xpath' | DATASPACE_NAME | ANCHOR_FOR_DATA_NODES_WITH_LEAVES | 'INVALID XPATH' || CpsPathException } + @Sql([CLEAR_DATA, SET_DATA]) + def 'Get multiple data nodes by xpath.'() { + when: 'fetch #scenario.' + def results = objectUnderTest.getDataNodes(DATASPACE_NAME, ANCHOR_NAME3, inputXpaths, OMIT_DESCENDANTS) + then: 'the expected number of data nodes are returned' + assert results.size() == expectedResultSize + where: 'following parameters were used' + scenario | inputXpaths || expectedResultSize + '0 nodes' | [] || 0 + '1 node' | ["/parent-200"] || 1 + '2 unique nodes' | ["/parent-200", "/parent-201"] || 2 + '3 unique nodes' | ["/parent-200", "/parent-201", "/parent-202"] || 3 + '1 unique node with duplicate xpath' | ["/parent-200", "/parent-200"] || 1 + '2 unique nodes with duplicate xpath' | ["/parent-200", "/parent-202", "/parent-200"] || 2 + 'list element with key (single quote)' | ["/parent-201/child-204[@key='A']"] || 1 + 'list element with key (double quote)' | ['/parent-201/child-204[@key="A"]'] || 1 + 'non-existing xpath' | ["/NO-XPATH"] || 0 + 'existing and non-existing xpaths' | ["/parent-200", "/NO-XPATH", "/parent-201"] || 2 + 'invalid xpath' | ["INVALID XPATH"] || 0 + 'valid and invalid xpaths' | ["/parent-200", "INVALID XPATH", "/parent-201"] || 2 + 'root xpath' | ["/"] || 7 + 'empty (root) xpath' | [""] || 7 + 'root and top-level xpaths' | ["/", "/parent-200", "/parent-201"] || 7 + 'root and child xpaths' | ["/", "/parent-200/child-201"] || 8 + } + + @Sql([CLEAR_DATA, SET_DATA]) + def 'Get multiple data nodes error scenario: #scenario.'() { + when: 'attempt to get data nodes with #scenario' + objectUnderTest.getDataNodes(dataspaceName, anchorName, ['/not-relevant'], OMIT_DESCENDANTS) + then: 'a #expectedException is thrown' + thrown(expectedException) + where: 'the following data is used' + scenario | dataspaceName | anchorName || expectedException + 'non-existing dataspace' | 'NO DATASPACE' | 'not relevant' || DataspaceNotFoundException + 'non-existing anchor' | DATASPACE_NAME | 'NO ANCHOR' || AnchorNotFoundException + } + @Sql([CLEAR_DATA, SET_DATA]) def 'Update data node leaves.'() { when: 'update is performed for leaves' diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy index 01c1dc70e..5dab87eec 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy @@ -1,8 +1,8 @@ /* * ============LICENSE_START======================================================= * Copyright (c) 2021 Bell Canada. - * Modifications Copyright (C) 2021-2022 Nordix Foundation - * Modifications Copyright (C) 2022 TechMahindra Ltd. + * Modifications Copyright (C) 2021-2023 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. @@ -32,6 +32,7 @@ import org.onap.cps.spi.model.DataNode import org.onap.cps.spi.model.DataNodeBuilder import org.onap.cps.spi.repository.AnchorRepository import org.onap.cps.spi.repository.DataspaceRepository +import org.onap.cps.spi.repository.FragmentNativeRepository import org.onap.cps.spi.repository.FragmentRepository import org.onap.cps.spi.utils.SessionManager import org.onap.cps.utils.JsonObjectMapper @@ -45,8 +46,10 @@ class CpsDataPersistenceServiceSpec extends Specification { def mockFragmentRepository = Mock(FragmentRepository) def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) def mockSessionManager = Mock(SessionManager) + def stubFragmentNativeRepository = Stub(FragmentNativeRepository) - def objectUnderTest = Spy(new CpsDataPersistenceServiceImpl(mockDataspaceRepository, mockAnchorRepository, mockFragmentRepository, jsonObjectMapper, mockSessionManager)) + def objectUnderTest = Spy(new CpsDataPersistenceServiceImpl(mockDataspaceRepository, mockAnchorRepository, + mockFragmentRepository, jsonObjectMapper, mockSessionManager, stubFragmentNativeRepository)) def 'Storing data nodes individually when batch operation fails'(){ given: 'two data nodes and supporting repository mock behavior' @@ -146,11 +149,11 @@ class CpsDataPersistenceServiceSpec extends Specification { def anchorEntity = new AnchorEntity(id:123) mockAnchorRepository.getByDataspaceAndName(*_) >> anchorEntity and: 'fragment repository returns a collection of fragments' - def fragmentEntity1 = new FragmentEntity(xpath: 'xpath1', childFragments: []) - def fragmentEntity2 = new FragmentEntity(xpath: 'xpath2', childFragments: []) - mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['xpath1','xpath2']) >> [ fragmentEntity1, fragmentEntity2 ] + def fragmentEntity1 = new FragmentEntity(xpath: '/xpath1', childFragments: []) + def fragmentEntity2 = new FragmentEntity(xpath: '/xpath2', childFragments: []) + mockFragmentRepository.findByAnchorAndMultipleCpsPaths(123, ['/xpath1', '/xpath2'] as Set) >> [fragmentEntity1, fragmentEntity2] when: 'getting data nodes for 2 xpaths' - def result = objectUnderTest.getDataNodes('some-dataspace', 'some-anchor', ['xpath1','xpath2'],FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) + def result = objectUnderTest.getDataNodes('some-dataspace', 'some-anchor', ['/xpath1', '/xpath2'], FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) then: '2 data nodes are returned' assert result.size() == 2 } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy index 5aae285d7..4dd4823c9 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServiceDeletePerfTest.groovy @@ -61,8 +61,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase } stopWatch.stop() def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 6000 milliseconds' - assert deleteDurationInMillis < 6000 + then: 'delete duration is under 300 milliseconds' + assert deleteDurationInMillis < 300 } def 'Delete 50 grandchildren (that have no descendants)'() { @@ -74,8 +74,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase } stopWatch.stop() def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 500 milliseconds' - assert deleteDurationInMillis < 500 + then: 'delete duration is under 350 milliseconds' + assert deleteDurationInMillis < 350 } def 'Delete 1 large data node with many descendants'() { @@ -84,8 +84,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase objectUnderTest.deleteDataNode(PERF_DATASPACE, PERF_ANCHOR, PERF_TEST_PARENT) stopWatch.stop() def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 2500 milliseconds' - assert deleteDurationInMillis < 2500 + then: 'delete duration is under 250 milliseconds' + assert deleteDurationInMillis < 250 } @Sql([CLEAR_DATA, PERF_TEST_DATA]) @@ -108,8 +108,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase } stopWatch.stop() def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 4000 milliseconds' - assert deleteDurationInMillis < 4000 + then: 'delete duration is under 1000 milliseconds' + assert deleteDurationInMillis < 1000 } def 'Delete 10 list elements with keys'() { @@ -122,8 +122,8 @@ class CpsDataPersistenceServiceDeletePerfTest extends CpsPersistencePerfSpecBase } stopWatch.stop() def deleteDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'delete duration is under 6000 milliseconds' - assert deleteDurationInMillis < 6000 + then: 'delete duration is under 1200 milliseconds' + assert deleteDurationInMillis < 1200 } @Sql([CLEAR_DATA, PERF_TEST_DATA]) diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy index 28363d74b..040749027 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/performance/CpsDataPersistenceServicePerfTest.groovy @@ -29,8 +29,6 @@ import org.onap.cps.spi.repository.FragmentRepository import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.jdbc.Sql -import java.util.concurrent.TimeUnit - import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS @@ -51,8 +49,6 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase { static def NUMBER_OF_CHILDREN = 200 static def NUMBER_OF_GRAND_CHILDREN = 50 static def TOTAL_NUMBER_OF_NODES = 1 + NUMBER_OF_CHILDREN + (NUMBER_OF_CHILDREN * NUMBER_OF_GRAND_CHILDREN) // Parent + Children + Grand-children - static def ALLOWED_SETUP_TIME_MS = TimeUnit.SECONDS.toMillis(10) - static def ALLOWED_READ_TIME_AL_NODES_MS = 500 def stopWatch = new StopWatch() def readStopWatch = new StopWatch() @@ -64,8 +60,8 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase { createLineage(objectUnderTest, NUMBER_OF_CHILDREN, NUMBER_OF_GRAND_CHILDREN, false) stopWatch.stop() def setupDurationInMillis = stopWatch.getTotalTimeMillis() - and: 'setup duration is under #ALLOWED_SETUP_TIME_MS milliseconds' - assert setupDurationInMillis < ALLOWED_SETUP_TIME_MS + and: 'setup duration is under 10 seconds' + assert setupDurationInMillis < 10000 } def 'Get data node with many descendants by xpath #scenario'() { @@ -75,7 +71,7 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase { stopWatch.stop() def readDurationInMillis = stopWatch.getTotalTimeMillis() then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS + assert readDurationInMillis < 500 and: 'data node is returned with all the descendants populated' assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES where: 'the following xPaths are used' @@ -91,7 +87,7 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase { stopWatch.stop() def readDurationInMillis = stopWatch.getTotalTimeMillis() then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < ALLOWED_READ_TIME_AL_NODES_MS + assert readDurationInMillis < 500 and: 'data node is returned with all the descendants populated' assert countDataNodes(result) == TOTAL_NUMBER_OF_NODES } @@ -115,12 +111,12 @@ class CpsDataPersistenceServicePerfTest extends CpsPersistencePerfSpecBase { def result = objectUnderTest.queryDataNodes(PERF_DATASPACE, PERF_ANCHOR, '//perf-test-grand-child-1', descendantsOption) stopWatch.stop() def readDurationInMillis = stopWatch.getTotalTimeMillis() - then: 'read duration is under 500 milliseconds' - assert readDurationInMillis < alowedDuration + then: 'read duration is under #allowedDuration milliseconds' + assert readDurationInMillis < allowedDuration and: 'data node is returned with all the descendants populated' assert result.size() == NUMBER_OF_CHILDREN where: 'the following options are used' - scenario | descendantsOption || alowedDuration + scenario | descendantsOption || allowedDuration 'omit descendants ' | OMIT_DESCENDANTS || 150 'include descendants (although there are none)' | INCLUDE_ALL_DESCENDANTS || 150 } diff --git a/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java b/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java index b80054ac3..0c8cddcd7 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java +++ b/cps-service/src/main/java/org/onap/cps/spi/FetchDescendantsOption.java @@ -2,6 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2021 Pantheon.tech * Copyright (C) 2022 Nordix Foundation + * 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. @@ -20,7 +21,11 @@ package org.onap.cps.spi; +import com.google.common.base.Strings; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; +import org.onap.cps.spi.exceptions.DataValidationException; @RequiredArgsConstructor public class FetchDescendantsOption { @@ -29,6 +34,9 @@ public class FetchDescendantsOption { public static final FetchDescendantsOption OMIT_DESCENDANTS = new FetchDescendantsOption(0); public static final FetchDescendantsOption INCLUDE_ALL_DESCENDANTS = new FetchDescendantsOption(-1); + private static final Pattern FETCH_DESCENDANTS_OPTION_PATTERN = + Pattern.compile("^$|^all$|^none$|^[0-9]+$|^-1$"); + private final int depth; /** @@ -58,6 +66,36 @@ public class FetchDescendantsOption { return nextDescendantsOption; } + /** + * get fetch descendants option for given descendant. + * + * @param fetchDescendantsOptionAsString fetch descendants option string + * @return fetch descendants option for given descendant + */ + public static FetchDescendantsOption getFetchDescendantsOption(final String fetchDescendantsOptionAsString) { + validateFetchDescendantsOption(fetchDescendantsOptionAsString); + if (Strings.isNullOrEmpty(fetchDescendantsOptionAsString) + || "0".equals(fetchDescendantsOptionAsString) || "none".equals(fetchDescendantsOptionAsString)) { + return FetchDescendantsOption.OMIT_DESCENDANTS; + } else if ("-1".equals(fetchDescendantsOptionAsString) || "all".equals(fetchDescendantsOptionAsString)) { + return FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS; + } else { + final Integer depth = Integer.valueOf(fetchDescendantsOptionAsString); + return new FetchDescendantsOption(depth); + } + } + + private static void validateFetchDescendantsOption(final String fetchDescendantsOptionAsString) { + if (Strings.isNullOrEmpty(fetchDescendantsOptionAsString)) { + return; + } + final Matcher matcher = FETCH_DESCENDANTS_OPTION_PATTERN.matcher(fetchDescendantsOptionAsString); + if (!matcher.matches()) { + throw new DataValidationException("FetchDescendantsOption validation error.", + fetchDescendantsOptionAsString + " is not valid fetch descendants option"); + } + } + private static void validateDepth(final int depth) { if (depth < -1) { throw new IllegalArgumentException("A depth of less than minus one is not allowed"); diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy index 8b232b420..60286b664 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation + * 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. @@ -43,7 +44,8 @@ class CpsQueryServiceImplSpec extends Specification { and: 'the CpsValidator is called on the dataspaceName, schemaSetName and anchorName' 1 * mockCpsValidator.validateNameCharacters(dataspaceName, anchorName) where: 'all fetch descendants options are supported' - fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS] + fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS, + FetchDescendantsOption.FETCH_DIRECT_CHILDREN_ONLY, new FetchDescendantsOption(10)] } } diff --git a/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy index 627383561..c4d3dd8b7 100644 --- a/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/spi/FetchDescendantsOptionSpec.groovy @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Nordix Foundation + * 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. @@ -20,7 +21,7 @@ package org.onap.cps.spi - +import org.onap.cps.spi.exceptions.DataValidationException import spock.lang.Specification class FetchDescendantsOptionSpec extends Specification { @@ -72,4 +73,18 @@ class FetchDescendantsOptionSpec extends Specification { then: 'exception thrown' thrown IllegalArgumentException } + + def 'Create fetch descendant option with descendant using #scenario'() { + when: 'the next level of depth is not allowed' + def FetchDescendantsOption fetchDescendantsOption = FetchDescendantsOption.getFetchDescendantsOption(fetchDescendantsOptionAsString) + then: 'fetch descendant object created' + assert fetchDescendantsOption.depth == expectedDepth + where: 'following parameters are used' + scenario | fetchDescendantsOptionAsString || expectedDepth + 'all descendants using number' | '-1' || -1 + 'all descendants using all' | 'all' || -1 + 'No descendants by default' | '' || 0 + 'No descendants using none' | 'none' || 0 + 'til 10th descendants using number' | '10' || 10 + } } diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml index ec7d29524..53c72f559 100644 --- a/docs/api/swagger/cps/openapi.yaml +++ b/docs/api/swagger/cps/openapi.yaml @@ -15,29 +15,30 @@ info: x-logo: url: cps_logo.png servers: -- url: /cps/api + - url: /cps/api +security: + - basicAuth: [] tags: -- name: cps-admin - description: cps Admin -- name: cps-data - description: cps Data + - name: cps-admin + description: cps Admin + - name: cps-data + description: cps Data paths: /v1/dataspaces: post: tags: - - cps-admin + - cps-admin summary: Create a dataspace description: Create a new dataspace operationId: createDataspace - deprecated: true parameters: - - name: dataspace-name - in: query - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace + - name: dataspace-name + in: query + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace responses: "201": description: Created @@ -96,24 +97,36 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred - /v2/dataspaces: - post: + deprecated: true + /{apiVersion}/dataspaces: + delete: tags: - - cps-admin - summary: Create a dataspace - description: Create a new dataspace - operationId: createDataspaceV2 + - cps-admin + summary: Delete a dataspace + description: Delete a dataspace + operationId: deleteDataspace parameters: - - name: dataspace-name - in: query - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: query + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace responses: - "201": - description: Created + "204": + description: No Content + content: {} "400": description: Bad Request content: @@ -164,26 +177,24 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred - /{apiVersion}/dataspaces: - delete: + /v2/dataspaces: + post: tags: - - cps-admin - summary: Delete a dataspace - description: Delete a dataspace - operationId: deleteDataspace + - cps-admin + summary: Create a dataspace + description: Create a new dataspace + operationId: createDataspaceV2 parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: query - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace + - name: dataspace-name + in: query + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace responses: - "204": - description: No Content - content: {} + "201": + description: Created without response body "400": description: Bad Request content: @@ -237,12 +248,21 @@ paths: /{apiVersion}/admin/dataspaces: get: tags: - - cps-admin - summary: Get dataspaces - description: "Read all dataspaces" + - cps-admin + summary: Get all dataspaces + description: Read all dataspaces operationId: getAllDataspaces parameters: - - $ref: '#/components/parameters/apiVersionInPath' + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 responses: "200": description: OK @@ -295,19 +315,28 @@ paths: /{apiVersion}/admin/dataspaces/{dataspace-name}: get: tags: - - cps-admin + - cps-admin summary: Get a dataspace - description: Read an dataspace given a dataspace name + description: Read a dataspace given a dataspace name operationId: getDataspace parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace responses: "200": description: OK @@ -355,31 +384,43 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred - /{apiVersion}/dataspaces/{dataspace-name}/anchors: - get: + /v1/dataspaces/{dataspace-name}/anchors: + post: tags: - - cps-admin - summary: Get anchors - description: "Read all anchors, given a dataspace" - operationId: getAnchors + - cps-admin + summary: Create an anchor + description: Create a new anchor in the given dataspace + operationId: createAnchor parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: schema-set-name + in: query + description: schema-set-name + required: true + schema: + type: string + example: my-schema-set + - name: anchor-name + in: query + description: anchor-name + required: true + schema: + type: string + example: my-anchor responses: - "200": - description: OK + "201": + description: Created content: - application/json: + text/plain: schema: - type: array - items: - $ref: '#/components/schemas/AnchorDetails' + type: string + example: my-resource "400": description: Bad Request content: @@ -410,6 +451,16 @@ paths: status: 403 message: Request Forbidden details: This request is forbidden + "409": + 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. "500": description: Internal Server Error content: @@ -420,44 +471,39 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred - /v1/dataspaces/{dataspace-name}/anchors: + deprecated: true + /v2/dataspaces/{dataspace-name}/anchors: post: tags: - - cps-admin + - cps-admin summary: Create an anchor - deprecated: true description: Create a new anchor in the given dataspace - operationId: createAnchor + operationId: createAnchorV2 parameters: - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: schema-set-name - in: query - description: schema-set-name - required: true - schema: - type: string - example: my-schema-set - - name: anchor-name - in: query - description: anchor-name - required: true - schema: - type: string - example: my-anchor + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: schema-set-name + in: query + description: schema-set-name + required: true + schema: + type: string + example: my-schema-set + - name: anchor-name + in: query + description: anchor-name + required: true + schema: + type: string + example: my-anchor responses: "201": - description: Created - content: - text/plain: - schema: - type: string - example: my-resource + description: Created without response body "400": description: Bad Request content: @@ -508,38 +554,40 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred - /v2/dataspaces/{dataspace-name}/anchors: - post: + /{apiVersion}/dataspaces/{dataspace-name}/anchors: + get: tags: - - cps-admin - summary: Create an anchor - description: Create a new anchor in the given dataspace - operationId: createAnchorV2 + - cps-admin + summary: Get anchors + description: "Read all anchors, given a dataspace" + operationId: getAnchors parameters: - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: schema-set-name - in: query - description: schema-set-name - required: true - schema: - type: string - example: my-schema-set - - name: anchor-name - in: query - description: anchor-name - required: true - schema: - type: string - example: my-anchor + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace responses: - "201": - description: Created + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/AnchorDetails' "400": description: Bad Request content: @@ -570,16 +618,6 @@ paths: status: 403 message: Request Forbidden details: This request is forbidden - "409": - 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. "500": description: Internal Server Error content: @@ -593,26 +631,35 @@ paths: /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}: get: tags: - - cps-admin + - cps-admin summary: Get an anchor description: Read an anchor given an anchor name and a dataspace operationId: getAnchor parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor responses: "200": description: OK @@ -662,26 +709,35 @@ paths: details: Internal Server Error occurred delete: tags: - - cps-admin + - cps-admin summary: Delete an anchor description: Delete an anchor given an anchor name and a dataspace operationId: deleteAnchor parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor responses: "204": description: No Content @@ -729,25 +785,25 @@ paths: /v1/dataspaces/{dataspace-name}/schema-sets: post: tags: - - cps-admin + - cps-admin summary: Create a schema set description: Create a new schema set in the given dataspace operationId: createSchemaSet parameters: - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: schema-set-name - in: query - description: schema-set-name - required: true - schema: - type: string - example: my-schema-set + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: schema-set-name + in: query + description: schema-set-name + required: true + schema: + type: string + example: my-schema-set requestBody: content: multipart/form-data: @@ -812,28 +868,29 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred + deprecated: true /v2/dataspaces/{dataspace-name}/schema-sets: post: tags: - - cps-admin + - cps-admin summary: Create a schema set description: Create a new schema set in the given dataspace operationId: createSchemaSetV2 parameters: - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: schema-set-name - in: query - description: schema-set-name - required: true - schema: - type: string - example: my-schema-set + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: schema-set-name + in: query + description: schema-set-name + required: true + schema: + type: string + example: my-schema-set requestBody: content: multipart/form-data: @@ -842,7 +899,7 @@ paths: required: true responses: "201": - description: Created + description: Created without response body "400": description: Bad Request content: @@ -896,19 +953,28 @@ paths: /{apiVersion}/dataspaces/{dataspace-name}/schema-sets: get: tags: - - cps-admin - summary: Get schema sets for a given dataspace - description: "Read schema sets for a given dataspace" + - cps-admin + summary: Get schema sets + description: "Read all schema sets, given a dataspace" operationId: getSchemaSets parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace responses: "200": description: OK @@ -961,26 +1027,35 @@ paths: /{apiVersion}/dataspaces/{dataspace-name}/schema-sets/{schema-set-name}: get: tags: - - cps-admin + - cps-admin summary: Get a schema set description: Read a schema set given a schema set name and a dataspace operationId: getSchemaSet parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: schema-set-name - in: path - description: schema-set-name - required: true - schema: - type: string - example: my-schema-set + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: schema-set-name + in: path + description: schema-set-name + required: true + schema: + type: string + example: my-schema-set responses: "200": description: OK @@ -1030,26 +1105,35 @@ paths: details: Internal Server Error occurred delete: tags: - - cps-admin + - cps-admin summary: Delete a schema set description: Delete a schema set given a schema set name and a dataspace operationId: deleteSchemaSet parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: schema-set-name - in: path - description: schema-set-name - required: true - schema: - type: string - example: my-schema-set + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: schema-set-name + in: path + description: schema-set-name + required: true + schema: + type: string + example: my-schema-set responses: "204": description: No Content @@ -1104,50 +1188,145 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred - /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/node: + /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/node: get: tags: - - cps-data + - cps-data summary: Get a node description: Get a node with an option to retrieve all the children for a given anchor and dataspace operationId: getNodeByDataspaceAndAnchor parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: false - schema: - type: string - default: / - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: include-descendants - in: query - description: include-descendants - required: false - schema: - type: boolean - example: false - default: false + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: false + schema: + type: string + default: / + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: include-descendants + in: query + description: include-descendants + required: false + schema: + type: boolean + example: false + default: false + responses: + "200": + description: OK + content: + application/json: + schema: + type: object + examples: + dataSample: + $ref: '#/components/examples/dataSample' + "400": + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 400 + message: Bad Request + details: The provided request is not valid + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 401 + message: Unauthorized request + details: This request is unauthorized + "403": + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 403 + message: Request Forbidden + details: This request is forbidden + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 500 + message: Internal Server Error + details: Internal Server Error occurred + deprecated: true + x-codegen-request-body-name: xpath + /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/node: + get: + tags: + - cps-data + summary: Get a node + description: Get a node with an option to retrieve all the children for a given + anchor and dataspace + operationId: getNodeByDataspaceAndAnchorV2 + parameters: + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: false + schema: + type: string + default: / + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: descendants + in: query + description: "descendents to query depth of children. allowed values are none,\ + \ all, any number starting from -1" + required: false + schema: + type: string + example: "3" + default: none responses: "200": description: OK @@ -1202,46 +1381,55 @@ paths: /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes: put: tags: - - cps-data + - cps-data summary: Replace a node with descendants description: "Replace a node with descendants for a given dataspace, anchor\ \ and a parent node xpath" operationId: replaceNode parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: false - schema: - type: string - default: / - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: observed-timestamp - in: query - description: observed-timestamp - required: false - schema: - type: string - example: 2021-03-21T00:10:34.030-0100 + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: false + schema: + type: string + default: / + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: 2021-03-21T00:10:34.030-0100 requestBody: content: application/json: @@ -1303,53 +1491,77 @@ paths: details: Internal Server Error occurred post: tags: - - cps-data + - cps-data summary: Create a node description: Create a node for a given anchor and dataspace operationId: createNode parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: false - schema: - type: string - default: / - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: observed-timestamp - in: query - description: observed-timestamp - required: false - schema: - type: string - example: 2021-03-21T00:10:34.030-0100 + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: false + schema: + type: string + default: / + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: 2021-03-21T00:10:34.030-0100 + - name: Content-Type + in: header + description: Content type header + required: true + schema: + type: string + example: application/json requestBody: content: application/json: schema: - type: object + type: string examples: dataSample: $ref: '#/components/examples/dataSample' + application/xml: + schema: + type: object + xml: + name: stores + examples: + dataSample: + $ref: '#/components/examples/dataSampleXml' required: true responses: "201": @@ -1411,46 +1623,55 @@ paths: details: Internal Server Error occurred delete: tags: - - cps-data + - cps-data summary: Delete a data node description: Delete a datanode for a given dataspace and anchor given a node xpath. operationId: deleteDataNode parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: false - schema: - type: string - default: / - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: observed-timestamp - in: query - description: observed-timestamp - required: false - schema: - type: string - example: 2021-03-21T00:10:34.030-0100 + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: false + schema: + type: string + default: / + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: 2021-03-21T00:10:34.030-0100 responses: "204": description: No Content @@ -1497,46 +1718,55 @@ paths: details: Internal Server Error occurred patch: tags: - - cps-data + - cps-data summary: Update node leaves description: Update a data node leaves for a given dataspace and anchor and a parent node xpath operationId: updateNodeLeaves parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: false - schema: - type: string - default: / - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: observed-timestamp - in: query - description: observed-timestamp - required: false - schema: - type: string - example: 2021-03-21T00:10:34.030-0100 + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: false + schema: + type: string + default: / + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: 2021-03-21T00:10:34.030-0100 requestBody: content: application/json: @@ -1596,47 +1826,141 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred + /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes: + delete: + tags: + - cps-data + summary: Delete one or all list element(s) + description: Delete one or all list element(s) for a given anchor and dataspace + operationId: deleteListOrListElement + parameters: + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: true + schema: + type: string + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: 2021-03-21T00:10:34.030-0100 + responses: + "204": + description: No Content + content: {} + "400": + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 400 + message: Bad Request + details: The provided request is not valid + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 401 + message: Unauthorized request + details: This request is unauthorized + "403": + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 403 + message: Request Forbidden + details: This request is forbidden + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 500 + message: Internal Server Error + details: Internal Server Error occurred + deprecated: true /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/list-nodes: put: tags: - - cps-data + - cps-data summary: Replace list content description: "Replace list content under a given parent, anchor and dataspace" operationId: replaceListContent parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: true - schema: - type: string - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: observed-timestamp - in: query - description: observed-timestamp - required: false - schema: - type: string - example: 2021-03-21T00:10:34.030-0100 + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: true + schema: + type: string + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: 2021-03-21T00:10:34.030-0100 requestBody: content: application/json: @@ -1698,44 +2022,53 @@ paths: details: Internal Server Error occurred post: tags: - - cps-data + - cps-data summary: Add list element(s) description: Add list element(s) to a list for a given anchor and dataspace operationId: addListElements parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: true - schema: - type: string - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: observed-timestamp - in: query - description: observed-timestamp - required: false - schema: - type: string - example: 2021-03-21T00:10:34.030-0100 + - name: apiVersion + in: path + description: apiVersion + required: true + schema: + type: string + default: v2 + enum: + - v1 + - v2 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - name: xpath + in: query + description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" + required: true + schema: + type: string + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: "/shops/bookstore/categories[@code=1]" + - name: observed-timestamp + in: query + description: observed-timestamp + required: false + schema: + type: string + example: 2021-03-21T00:10:34.030-0100 requestBody: content: application/json: @@ -1793,50 +2126,58 @@ paths: status: 500 message: Internal Server Error details: Internal Server Error occurred - delete: + /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query: + get: tags: - - cps-data - summary: Delete one or all list element(s) - description: Delete one or all list element(s) for a given anchor and dataspace - operationId: deleteListOrListElement + - cps-query + summary: Query data nodes + description: Query data nodes for the given dataspace and anchor using CPS path + operationId: getNodesByDataspaceAndAnchorAndCpsPath parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - name: xpath - in: query - description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html" - required: true - schema: - type: string - examples: - container xpath: - value: /shops/bookstore - list attributes xpath: - value: "/shops/bookstore/categories[@code=1]" - - name: observed-timestamp - in: query - description: observed-timestamp - required: false - schema: - type: string - example: 2021-03-21T00:10:34.030-0100 + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - 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]" + - name: include-descendants + in: query + description: include-descendants + required: false + schema: + type: boolean + example: false + default: false responses: - "204": - description: No Content - content: {} + "200": + description: OK + content: + application/json: + schema: + type: object + examples: + dataSample: + $ref: '#/components/examples/dataSample' "400": description: Bad Request content: @@ -1878,49 +2219,50 @@ paths: message: Internal Server Error details: Internal Server Error occurred deprecated: true - /{apiVersion}/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query: + x-codegen-request-body-name: xpath + /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query: get: tags: - - cps-query + - cps-query summary: Query data nodes description: Query data nodes for the given dataspace and anchor using CPS path - operationId: getNodesByDataspaceAndAnchorAndCpsPath + operationId: getNodesByDataspaceAndAnchorAndCpsPathV2 parameters: - - $ref: '#/components/parameters/apiVersionInPath' - - name: dataspace-name - in: path - description: dataspace-name - required: true - schema: - type: string - example: my-dataspace - - name: anchor-name - in: path - description: anchor-name - required: true - schema: - type: string - example: my-anchor - - 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]" - - name: include-descendants - in: query - description: include-descendants - required: false - schema: - type: boolean - example: false - default: false + - name: dataspace-name + in: path + description: dataspace-name + required: true + schema: + type: string + example: my-dataspace + - name: anchor-name + in: path + description: anchor-name + required: true + schema: + type: string + example: my-anchor + - 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]" + - name: descendants + in: query + description: "descendents to query depth of children. allowed values are none,\ + \ all, any number starting from -1" + required: false + schema: + type: string + example: "3" + default: none responses: "200": description: OK @@ -1973,20 +2315,6 @@ paths: details: Internal Server Error occurred x-codegen-request-body-name: xpath components: - parameters: - apiVersionInPath: - name: apiVersion - in: path - description: apiVersion - required: true - schema: - type: string - enum: [v1, v2] - default: v2 - securitySchemes: - basicAuth: - type: http - scheme: basic schemas: ErrorMessage: title: Error @@ -1998,6 +2326,13 @@ components: type: string details: type: string + DataspaceDetails: + title: Dataspace details by dataspace Name + type: object + properties: + name: + type: string + example: my-dataspace AnchorDetails: title: Anchor details by anchor Name type: object @@ -2011,16 +2346,9 @@ components: schemaSetName: type: string example: my-schema-set - DataspaceDetails: - title: Dataspace details by dataspace Name - type: object - properties: - name: - type: string - example: my-dataspace MultipartFile: required: - - file + - file type: object properties: file: @@ -2030,7 +2358,7 @@ components: SchemaSetDetails: title: Schema set details by dataspace and schemasetName required: - - moduleReferences + - moduleReferences type: object properties: dataspaceName: @@ -2062,10 +2390,15 @@ components: test:bookstore: bookstore-name: Chapters categories: - - code: 1 - name: SciFi - - code: 2 - name: kids - -security: - - basicAuth: [] + - code: 1 + name: SciFi + - code: 2 + name: kids + dataSampleXml: + value: + Chapters 1 SciFi + + securitySchemes: + basicAuth: + type: http + scheme: basic diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml index 9e84f3a19..3bf93a1e5 100644 --- a/docs/api/swagger/ncmp/openapi-inventory.yaml +++ b/docs/api/swagger/ncmp/openapi-inventory.yaml @@ -4,12 +4,14 @@ info: description: NCMP Inventory API version: "1.0" servers: -- url: /ncmpInventory + - url: /ncmpInventory +security: + - basicAuth: [] paths: /v1/ch: post: tags: - - network-cm-proxy-inventory + - network-cm-proxy-inventory summary: DMI notifies NCMP of new CM Handles description: "Register a DMI Plugin with any new, updated or removed CM Handles." operationId: updateDmiPluginRegistration @@ -63,51 +65,104 @@ paths: $ref: '#/components/schemas/DmiPluginRegistrationErrorResponse' example: failedCreatedCmHandles: - - cmHandle: my-cm-handle-01 - errorCode: "00" - errorText: Unknown error. - - cmHandle: my-cm-handle-02 - errorCode: "01" - errorText: cm-handle already exists - - cmHandle: my-cm-handle-03 - errorCode: "03" - errorText: cm-handle has an invalid character(s) in id + - cmHandle: my-cm-handle-01 + errorCode: "00" + errorText: Unknown error. + - cmHandle: my-cm-handle-02 + errorCode: "01" + errorText: cm-handle already exists + - cmHandle: my-cm-handle-03 + errorCode: "03" + errorText: cm-handle has an invalid character(s) in id failedUpdatedCmHandles: - - cmHandle: my-cm-handle-01 - errorCode: "00" - errorText: Unknown error. - - cmHandle: my-cm-handle-02 - errorCode: "02" - errorText: cm-handle does not exist - - cmHandle: my-cm-handle-03 - errorCode: "03" - errorText: cm-handle has an invalid character(s) in id + - cmHandle: my-cm-handle-01 + errorCode: "00" + errorText: Unknown error. + - cmHandle: my-cm-handle-02 + errorCode: "02" + errorText: cm-handle does not exist + - cmHandle: my-cm-handle-03 + errorCode: "03" + errorText: cm-handle has an invalid character(s) in id failedRemovedCmHandles: - - cmHandle: my-cm-handle-01 - errorCode: "00" - errorText: Unknown error. - - cmHandle: my-cm-handle-02 - errorCode: "02" - errorText: cm-handle does not exists - - cmHandle: my-cm-handle-03 - errorCode: "03" - errorText: cm-handle has an invalid character(s) in id + - cmHandle: my-cm-handle-01 + errorCode: "00" + errorText: Unknown error. + - cmHandle: my-cm-handle-02 + errorCode: "02" + errorText: cm-handle does not exists + - cmHandle: my-cm-handle-03 + errorCode: "03" + errorText: cm-handle has an invalid character(s) in id /v1/ch/cmHandles: get: tags: - - network-cm-proxy-inventory + - network-cm-proxy-inventory summary: "Get all cm handle IDs for a registered DMI plugin (DMI plugin, DMI\ \ data plugin, DMI model plugin)" description: Get all cm handle IDs for a registered DMI plugin operationId: getAllCmHandleIdsForRegisteredDmi parameters: - - name: dmi-plugin-identifier - in: query - description: dmi-plugin-identifier + - name: dmi-plugin-identifier + in: query + description: dmi-plugin-identifier + required: true + schema: + type: string + example: my-dmi-plugin + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + type: string + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 401 + message: Unauthorized error message + details: Unauthorized error details + "403": + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 403 + message: Forbidden error message + details: Forbidden error details + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 500 + message: Internal Server Error + details: Internal Server Error occurred + /v1/ch/searches: + post: + tags: + - network-cm-proxy-inventory + summary: Query for CM Handle IDs + description: "Query and get CMHandleIds for additional properties, public properties\ + \ and registered DMI plugin (DMI plugin, DMI data plugin, DMI model plugin)." + operationId: searchCmHandleIds + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CmHandleQueryParameters' required: true - schema: - type: string - example: my-dmi-plugin responses: "200": description: OK @@ -148,10 +203,6 @@ paths: message: Internal Server Error details: Internal Server Error occurred components: - securitySchemes: - basicAuth: - type: http - scheme: basic schemas: RestDmiPluginRegistration: type: object @@ -179,14 +230,14 @@ components: removedCmHandles: type: array example: - - my-cm-handle1 - - my-cm-handle2 - - my-cm-handle3 + - my-cm-handle1 + - my-cm-handle2 + - my-cm-handle3 items: type: string RestInputCmHandle: required: - - cmHandle + - cmHandle type: object properties: cmHandle: @@ -238,6 +289,45 @@ components: errorText: type: string example: Unknown error. - -security: - - basicAuth: [] \ No newline at end of file + CmHandleQueryParameters: + title: Cm Handle query parameters for executing cm handle search + type: object + properties: + cmHandleQueryParameters: + type: array + items: + $ref: '#/components/schemas/ConditionProperties' + conditions: + type: array + description: "not necessary, it is just for backward compatibility" + deprecated: true + items: + $ref: '#/components/schemas/OldConditionProperties' + ConditionProperties: + properties: + conditionName: + type: string + conditionParameters: + type: array + items: + type: object + additionalProperties: + type: string + OldConditionProperties: + properties: + name: + type: string + conditionParameters: + type: array + items: + $ref: '#/components/schemas/ModuleNameAsJsonObject' + deprecated: true + ModuleNameAsJsonObject: + properties: + moduleName: + type: string + example: my-module + securitySchemes: + basicAuth: + type: http + scheme: basic diff --git a/docs/api/swagger/ncmp/openapi.yaml b/docs/api/swagger/ncmp/openapi.yaml index 44c4788cf..18839664a 100644 --- a/docs/api/swagger/ncmp/openapi.yaml +++ b/docs/api/swagger/ncmp/openapi.yaml @@ -4,87 +4,89 @@ info: description: NCMP to CPS Proxy API version: "1.0" servers: -- url: /ncmp + - url: /ncmp +security: + - basicAuth: [] paths: /v1/ch/{cm-handle}/data/ds/{datastore-name}: get: tags: - - network-cm-proxy + - network-cm-proxy summary: Get resource data for cm handle description: Get resource data for given cm handle operationId: getResourceDataForCmHandle parameters: - - name: datastore-name - in: path - description: The type of the requested data - required: true - schema: - type: string - example: ncmp-datastore:operational - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: datastore-name + in: path + description: The type of the requested data + required: true + schema: + type: string + example: ncmp-datastore:operational + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle - - name: resourceIdentifier - in: query - description: The format of resource identifier depend on the associated DMI - Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but - it can really be anything. - required: true - allowReserved: true - schema: - type: string - examples: - sample 1: - value: - resourceIdentifier: \shops\bookstore - sample 2: - value: - resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" - sample 3: - value: - resourceIdentifier: "parent=shops,child=bookstore" - - name: options - in: query - description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\ + required: true + schema: + type: string + example: my-cm-handle + - name: resourceIdentifier + in: query + description: The format of resource identifier depend on the associated DMI + Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but + it can really be anything. + required: true + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + resourceIdentifier: \shops\bookstore + sample 2: + value: + resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" + sample 3: + value: + resourceIdentifier: "parent=shops,child=bookstore" + - name: options + in: query + description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\ \ in parenthesis'()'. The format of options parameter depend on the associated\ \ DMI Plugin implementation." - required: false - allowReserved: true - schema: - type: string - examples: - sample 1: - value: - options: (depth=3) - sample 2: - value: - options: (fields=book) - sample 3: - value: - options: "(depth=2,fields=book/authors)" - - name: topic - in: query - description: topic parameter in query. - required: false - allowReserved: true - schema: - type: string - examples: - sample 1: - value: - topic: my-topic-name - - name: include-descendants - in: query - description: Determines if descendants are included in response - required: false - schema: - type: boolean - default: false + required: false + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + options: (depth=3) + sample 2: + value: + options: (fields=book) + sample 3: + value: + options: "(depth=2,fields=book/authors)" + - name: topic + in: query + description: topic parameter in query. + required: false + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + topic: my-topic-name + - name: include-descendants + in: query + description: Determines if descendants are included in response + required: false + schema: + type: boolean + default: false responses: "200": description: OK @@ -148,55 +150,55 @@ paths: body: Bad Request put: tags: - - network-cm-proxy + - network-cm-proxy summary: Update resource data from pass-through running for a cm handle description: Update resource data from pass-through running for the given cm handle operationId: updateResourceDataRunningForCmHandle parameters: - - name: datastore-name - in: path - description: The type of the requested data - required: true - schema: - type: string - example: ncmp-datastore:operational - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: datastore-name + in: path + description: The type of the requested data + required: true + schema: + type: string + example: ncmp-datastore:operational + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle - - name: resourceIdentifier - in: query - description: The format of resource identifier depend on the associated DMI - Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but - it can really be anything. - required: true - allowReserved: true - schema: - type: string - examples: - sample 1: - value: - resourceIdentifier: \shops\bookstore - sample 2: - value: - resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" - sample 3: - value: - resourceIdentifier: "parent=shops,child=bookstore" - - name: Content-Type - in: header - description: "Content parameter for request, if content parameter is null,\ + required: true + schema: + type: string + example: my-cm-handle + - name: resourceIdentifier + in: query + description: The format of resource identifier depend on the associated DMI + Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but + it can really be anything. + required: true + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + resourceIdentifier: \shops\bookstore + sample 2: + value: + resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" + sample 3: + value: + resourceIdentifier: "parent=shops,child=bookstore" + - name: Content-Type + in: header + description: "Content parameter for request, if content parameter is null,\ \ default value is application/json." - required: false - schema: - type: string - example: application/yang-data+json - default: application/json + required: false + schema: + type: string + example: application/yang-data+json + default: application/json requestBody: content: application/json: @@ -272,54 +274,54 @@ paths: body: Bad Request post: tags: - - network-cm-proxy + - network-cm-proxy summary: create resource data from pass-through running for cm handle description: create resource data from pass-through running for given cm handle operationId: createResourceDataRunningForCmHandle parameters: - - name: datastore-name - in: path - description: The type of the requested data - required: true - schema: - type: string - example: ncmp-datastore:operational - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: datastore-name + in: path + description: The type of the requested data + required: true + schema: + type: string + example: ncmp-datastore:operational + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle - - name: resourceIdentifier - in: query - description: The format of resource identifier depend on the associated DMI - Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but - it can really be anything. - required: true - allowReserved: true - schema: - type: string - examples: - sample 1: - value: - resourceIdentifier: \shops\bookstore - sample 2: - value: - resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" - sample 3: - value: - resourceIdentifier: "parent=shops,child=bookstore" - - name: Content-Type - in: header - description: "Content parameter for request, if content parameter is null,\ + required: true + schema: + type: string + example: my-cm-handle + - name: resourceIdentifier + in: query + description: The format of resource identifier depend on the associated DMI + Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but + it can really be anything. + required: true + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + resourceIdentifier: \shops\bookstore + sample 2: + value: + resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" + sample 3: + value: + resourceIdentifier: "parent=shops,child=bookstore" + - name: Content-Type + in: header + description: "Content parameter for request, if content parameter is null,\ \ default value is application/json." - required: false - schema: - type: string - example: application/yang-data+json - default: application/json + required: false + schema: + type: string + example: application/yang-data+json + default: application/json requestBody: content: application/json: @@ -392,54 +394,54 @@ paths: body: Bad Request delete: tags: - - network-cm-proxy + - network-cm-proxy summary: Delete resource data description: Delete resource data from pass-through running for a given cm handle operationId: deleteResourceDataRunningForCmHandle parameters: - - name: datastore-name - in: path - description: The type of the requested data - required: true - schema: - type: string - example: ncmp-datastore:operational - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: datastore-name + in: path + description: The type of the requested data + required: true + schema: + type: string + example: ncmp-datastore:operational + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle - - name: resourceIdentifier - in: query - description: The format of resource identifier depend on the associated DMI - Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but - it can really be anything. - required: true - allowReserved: true - schema: - type: string - examples: - sample 1: - value: - resourceIdentifier: \shops\bookstore - sample 2: - value: - resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" - sample 3: - value: - resourceIdentifier: "parent=shops,child=bookstore" - - name: Content-Type - in: header - description: "Content parameter for request, if content parameter is null,\ + required: true + schema: + type: string + example: my-cm-handle + - name: resourceIdentifier + in: query + description: The format of resource identifier depend on the associated DMI + Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but + it can really be anything. + required: true + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + resourceIdentifier: \shops\bookstore + sample 2: + value: + resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" + sample 3: + value: + resourceIdentifier: "parent=shops,child=bookstore" + - name: Content-Type + in: header + description: "Content parameter for request, if content parameter is null,\ \ default value is application/json." - required: false - schema: - type: string - example: application/yang-data+json - default: application/json + required: false + schema: + type: string + example: application/yang-data+json + default: application/json responses: "204": description: No Content @@ -507,55 +509,55 @@ paths: body: Bad Request patch: tags: - - network-cm-proxy + - network-cm-proxy summary: Patch resource data from pass-through running description: Patch resource data from pass-through running for the given cm handle operationId: patchResourceDataRunningForCmHandle parameters: - - name: datastore-name - in: path - description: The type of the requested data - required: true - schema: - type: string - example: ncmp-datastore:operational - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: datastore-name + in: path + description: The type of the requested data + required: true + schema: + type: string + example: ncmp-datastore:operational + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle - - name: resourceIdentifier - in: query - description: The format of resource identifier depend on the associated DMI - Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but - it can really be anything. - required: true - allowReserved: true - schema: - type: string - examples: - sample 1: - value: - resourceIdentifier: \shops\bookstore - sample 2: - value: - resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" - sample 3: - value: - resourceIdentifier: "parent=shops,child=bookstore" - - name: Content-Type - in: header - description: "Content parameter for request, if content parameter is null,\ + required: true + schema: + type: string + example: my-cm-handle + - name: resourceIdentifier + in: query + description: The format of resource identifier depend on the associated DMI + Plugin implementation. For ONAP DMI Plugin it will be RESTConf paths but + it can really be anything. + required: true + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + resourceIdentifier: \shops\bookstore + sample 2: + value: + resourceIdentifier: "\\shops\\bookstore\\categories[@code=1]" + sample 3: + value: + resourceIdentifier: "parent=shops,child=bookstore" + - name: Content-Type + in: header + description: "Content parameter for request, if content parameter is null,\ \ default value is application/json." - required: false - schema: - type: string - example: application/yang-data+json - default: application/json + required: false + schema: + type: string + example: application/yang-data+json + default: application/json requestBody: content: '*/*': @@ -623,23 +625,156 @@ paths: dmi-response: http-code: 400 body: Bad Request + /v1/ch/{cm-handle}/data/ds/{datastore-name}/query: + get: + tags: + - network-cm-proxy + summary: Query resource data for a given cm handle + description: Query resource data for a given cm handle + operationId: queryResourceDataForCmHandle + parameters: + - name: datastore-name + in: path + description: The type of the requested data + required: true + schema: + type: string + example: ncmp-datastore:operational + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ + \ or any other cm object by managed Network CM Proxy" + required: true + schema: + type: string + example: my-cm-handle + - 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]" + - name: options + in: query + description: "options parameter in query, it is mandatory to wrap key(s)=value(s)\ + \ in parenthesis'()'. The format of options parameter depend on the associated\ + \ DMI Plugin implementation." + required: false + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + options: (depth=3) + sample 2: + value: + options: (fields=book) + sample 3: + value: + options: "(depth=2,fields=book/authors)" + - name: topic + in: query + description: topic parameter in query. + required: false + allowReserved: true + schema: + type: string + examples: + sample 1: + value: + topic: my-topic-name + - name: include-descendants + in: query + description: Determines if descendants are included in response + required: false + schema: + type: boolean + default: false + responses: + "200": + description: OK + content: + application/json: + schema: + type: object + examples: + dataSampleResponse: + $ref: '#/components/examples/dataSampleResponse' + "400": + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 400 BAD_REQUEST + message: Bad request error message + details: Bad request error details + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 401 + message: Unauthorized error message + details: Unauthorized error details + "403": + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 403 + message: Forbidden error message + details: Forbidden error details + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorMessage' + example: + status: 500 + message: Internal Server Error + details: Internal Server Error occurred + "502": + description: Bad Gateway + content: + application/json: + schema: + $ref: '#/components/schemas/DmiErrorMessage' + example: + message: Bad Gateway Error Message NCMP + dmi-response: + http-code: 400 + body: Bad Request /v1/ch/{cm-handle}/modules: get: tags: - - network-cm-proxy + - network-cm-proxy summary: Fetch all module references (name and revision) for a given cm handle description: fetch all module references (name and revision) for a given cm handle operationId: getModuleReferencesByCmHandle parameters: - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle + required: true + schema: + type: string + example: my-cm-handle responses: "200": description: OK @@ -692,21 +827,21 @@ paths: /v1/ch/{cm-handle}/modules/definitions: get: tags: - - network-cm-proxy + - network-cm-proxy summary: "Fetch all module definitions (name, revision, yang resource) for a\ \ given cm handle" description: "Fetch all module definitions (name, revision, yang resource) for\ \ a given cm handle" operationId: getModuleDefinitionsByCmHandleId parameters: - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle + required: true + schema: + type: string + example: my-cm-handle responses: "200": description: OK @@ -749,7 +884,7 @@ paths: /v1/ch/searches: post: tags: - - network-cm-proxy + - network-cm-proxy summary: Execute cm handle search using the available conditions description: Execute cm handle query search and return a list of cm handle details. Any number of conditions can be applied. To be included in the result a cm-handle @@ -831,19 +966,19 @@ paths: /v1/ch/{cm-handle}: get: tags: - - network-cm-proxy + - network-cm-proxy summary: Retrieve CM handle details description: Retrieve CM handle details and properties by cm handle id operationId: retrieveCmHandleDetailsById parameters: - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle + required: true + schema: + type: string + example: my-cm-handle responses: "200": description: OK @@ -894,19 +1029,19 @@ paths: /v1/ch/{cm-handle}/properties: get: tags: - - network-cm-proxy + - network-cm-proxy summary: Get CM handle properties description: Get CM handle properties by cm handle id operationId: getCmHandlePublicPropertiesByCmHandleId parameters: - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle + required: true + schema: + type: string + example: my-cm-handle responses: "200": description: OK @@ -957,7 +1092,7 @@ paths: /v1/ch/id-searches: post: tags: - - network-cm-proxy + - network-cm-proxy summary: Execute cm handle query upon a given set of query parameters description: Execute cm handle query search and return a list of cm handle ids. Any number of conditions can be applied. To be included in the result a cm-handle @@ -1049,19 +1184,19 @@ paths: /v1/ch/{cm-handle}/state: get: tags: - - network-cm-proxy + - network-cm-proxy summary: Get CM handle state description: Get CM handle state by cm handle id operationId: getCmHandleStateByCmHandleId parameters: - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle + required: true + schema: + type: string + example: my-cm-handle responses: "200": description: OK @@ -1112,28 +1247,28 @@ paths: /v1/ch/{cm-handle}/data-sync: put: tags: - - network-cm-proxy + - network-cm-proxy summary: Set the Data Sync Enabled Flag description: Set the data sync enabled flag to true or false for a specified Cm-Handle. This will in turn set the data sync state to UNSYNCHRONIZED and NONE_REQUESTED respectfully. operationId: setDataSyncEnabledFlagForCmHandle parameters: - - name: cm-handle - in: path - description: "The identifier for a network function, network element, subnetwork\ + - name: cm-handle + in: path + description: "The identifier for a network function, network element, subnetwork\ \ or any other cm object by managed Network CM Proxy" - required: true - schema: - type: string - example: my-cm-handle - - name: dataSyncEnabled - in: query - description: Is used to enable or disable the data synchronization flag - required: true - schema: - type: boolean - example: true + required: true + schema: + type: string + example: my-cm-handle + - name: dataSyncEnabled + in: query + description: Is used to enable or disable the data synchronization flag + required: true + schema: + type: boolean + example: true responses: "200": description: OK @@ -1193,10 +1328,6 @@ paths: http-code: 400 body: Bad Request components: - securitySchemes: - basicAuth: - type: http - scheme: basic schemas: ErrorMessage: title: Error @@ -1365,17 +1496,17 @@ components: value: bookstore: categories: - - code: "01" - books: - - authors: - - Iain M. Banks - - Ursula K. Le Guin - name: SciFi - - code: "02" - books: - - authors: - - Philip Pullman - name: kids + - code: "01" + books: + - authors: + - Iain M. Banks + - Ursula K. Le Guin + name: SciFi + - code: "02" + books: + - authors: + - Philip Pullman + name: kids dataSampleRequest: summary: Sample request description: Sample request body @@ -1383,17 +1514,17 @@ components: test:bookstore: bookstore-name: Chapters categories: - - code: "01" - name: SciFi - books: - - authors: - - Iain M. Banks - - Ursula K. Le Guin - - code: "02" - name: kids - books: - - authors: - - Philip Pullman + - code: "01" + name: SciFi + books: + - authors: + - Iain M. Banks + - Ursula K. Le Guin + - code: "02" + name: kids + books: + - authors: + - Philip Pullman dataSamplePatchRequest: summary: Sample patch request description: Sample patch request body @@ -1401,86 +1532,87 @@ components: ietf-restconf:yang-patch: patch-id: patch-1 edit: - - edit-id: edit1 - operation: merge - target: / - value: - test:bookstore: - bookstore-name: Chapters - categories: - - code: "01" - name: Science - books: - - authors: - - Author1 - - Author2 - - code: "02" - name: Arts - books: - - authors: - - Author3 - - edit-id: edit2 - operation: merge - target: / - value: - test:bookstore: - bookstore-name: Novels - categories: - - code: "03" - name: History - books: - - authors: - - Iain M. Banks - - Ursula K. Le Guin - - code: "04" - name: Fiction - books: - - authors: - - Philip Pullman + - edit-id: edit1 + operation: merge + target: / + value: + test:bookstore: + bookstore-name: Chapters + categories: + - code: "01" + name: Science + books: + - authors: + - Author1 + - Author2 + - code: "02" + name: Arts + books: + - authors: + - Author3 + - edit-id: edit2 + operation: merge + target: / + value: + test:bookstore: + bookstore-name: Novels + categories: + - code: "03" + name: History + books: + - authors: + - Iain M. Banks + - Ursula K. Le Guin + - code: "04" + name: Fiction + books: + - authors: + - Philip Pullman pubPropCmHandleQueryParameters: value: cmHandleQueryParameters: - - conditionName: hasAllProperties - conditionParameters: - - Color: yellow - - Shape: circle - - Size: small + - conditionName: hasAllProperties + conditionParameters: + - Color: yellow + - Shape: circle + - Size: small modulesCmHandleQueryParameters: value: cmHandleQueryParameters: - - conditionName: hasAllModules - conditionParameters: - - moduleName: my-module-1 - - moduleName: my-module-2 - - moduleName: my-module-3 + - conditionName: hasAllModules + conditionParameters: + - moduleName: my-module-1 + - moduleName: my-module-2 + - moduleName: my-module-3 allCmHandleQueryParameters: value: cmHandleQueryParameters: - - conditionName: hasAllModules - conditionParameters: - - moduleName: my-module-1 - - moduleName: my-module-2 - - moduleName: my-module-3 - - conditionName: hasAllProperties - conditionParameters: - - Color: yellow - - Shape: circle - - Size: small - - conditionName: cmHandleWithCpsPath - conditionParameters: - - cpsPath: "//state[@cm-handle-state='ADVISED']" + - conditionName: hasAllModules + conditionParameters: + - moduleName: my-module-1 + - moduleName: my-module-2 + - moduleName: my-module-3 + - conditionName: hasAllProperties + conditionParameters: + - Color: yellow + - Shape: circle + - Size: small + - conditionName: cmHandleWithCpsPath + conditionParameters: + - cpsPath: "//state[@cm-handle-state='ADVISED']" cpsPathCmHandleStateQueryParameters: value: cmHandleQueryParameters: - - conditionName: cmHandleWithCpsPath - conditionParameters: - - cpsPath: "//state[@cm-handle-state='LOCKED']" + - conditionName: cmHandleWithCpsPath + conditionParameters: + - cpsPath: "//state[@cm-handle-state='LOCKED']" cpsPathCmHandleDataSyncQueryParameters: value: cmHandleQueryParameters: - - conditionName: cmHandleWithCpsPath - conditionParameters: - - cpsPath: "//state[@data-sync-enabled='true']" - -security: - - basicAuth: [] + - conditionName: cmHandleWithCpsPath + conditionParameters: + - cpsPath: "//state[@data-sync-enabled='true']" + securitySchemes: + basicAuth: + type: http + scheme: basic