diff options
18 files changed, 418 insertions, 171 deletions
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java index 0ca3a45d..642385aa 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java @@ -79,7 +79,8 @@ public class A1ClientFactory { } else if (version == A1ProtocolType.OSC_V1) { assertNoControllerConfig(ric, version); return new OscA1Client(ric.getConfig(), this.restClientFactory); - } else if (version == A1ProtocolType.CCSDK_A1_ADAPTER_STD_V1_1 || version == A1ProtocolType.CCSDK_A1_ADAPTER_OSC_V1 + } else if (version == A1ProtocolType.CCSDK_A1_ADAPTER_STD_V1_1 + || version == A1ProtocolType.CCSDK_A1_ADAPTER_OSC_V1 || version == A1ProtocolType.CCSDK_A1_ADAPTER_STD_V2_0_0) { return new CcsdkA1AdapterClient(version, ric.getConfig(), getControllerConfig(ric), this.restClientFactory); } else { diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbackInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbackInfo.java new file mode 100644 index 00000000..7d5f003a --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbackInfo.java @@ -0,0 +1,61 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2020 Nordix Foundation. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.controllers; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import org.immutables.gson.Gson; + +@Gson.TypeAdapters +@ApiModel(value = "service_callback_info_v2", + description = "Information transferred as in Service callbacks (callback_url)") +public class ServiceCallbackInfo { + + private static final String EVENT_TYPE_DESCRIPTION = "values:\n" // + + "AVAILABLE: the Near-RT RIC has become available for A1 Policy management"; + + @Gson.TypeAdapters + @ApiModel(value = "event_type_v2", description = EVENT_TYPE_DESCRIPTION) + public enum EventType { + AVAILABLE + } + + @ApiModelProperty(value = "identity of a Near-RT RIC", required = true) + @SerializedName("ric_id") + @JsonProperty(value = "ric_id", required = true) + public String ricId; + + @ApiModelProperty(value = EVENT_TYPE_DESCRIPTION, required = true) + @SerializedName("event_type") + @JsonProperty(value = "event_type", required = true) + public EventType eventType; + + public ServiceCallbackInfo(String ricId, EventType eventType) { + this.ricId = ricId; + this.eventType = eventType; + } + + public ServiceCallbackInfo() {} +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbacks.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbacks.java new file mode 100644 index 00000000..d6286eed --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/ServiceCallbacks.java @@ -0,0 +1,85 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2020 Nordix Foundation. All rights reserved. + * ====================================================================== + * 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.controllers; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.lang.invoke.MethodHandles; + +import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient; +import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * Callbacks to the Service + */ +@SuppressWarnings("java:S3457") // No need to call "toString()" method as formatting and string .. +public class ServiceCallbacks { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private static Gson gson = new GsonBuilder().create(); + + private final AsyncRestClient restClient; + + public ServiceCallbacks(AsyncRestClientFactory restClientFactory) { + this.restClient = restClientFactory.createRestClient(""); + } + + public void notifyServicesRicSynchronized(Ric ric, Services services) { + createTask(ric, services).subscribe(numberOfServices -> logger.debug("Services {} notified", numberOfServices), + throwable -> logger.error("Service notification failed, cause: {}", throwable.getMessage()), + () -> logger.debug("All services notified")); + + } + + private Mono<Integer> createTask(Ric ric, Services services) { + return Flux.fromIterable(services.getAll()) // + .flatMap(service -> notifyServiceRicSynchronized(ric, service)) // + .collectList() // + .flatMap(okResponses -> Mono.just(Integer.valueOf(okResponses.size()))); // + } + + private Mono<String> notifyServiceRicSynchronized(Ric ric, Service service) { + if (service.getCallbackUrl().isEmpty()) { + return Mono.empty(); + } + + ServiceCallbackInfo request = new ServiceCallbackInfo(ric.id(), ServiceCallbackInfo.EventType.AVAILABLE); + String body = gson.toJson(request); + + return restClient.post(service.getCallbackUrl(), body) + .doOnNext(resp -> logger.debug("Invoking service {} callback, ric: {}", service.getName(), ric.id())) + .onErrorResume(throwable -> { + logger.error("Service: {}, callback: {} failed: {}", service.getName(), service.getCallbackUrl(), + throwable.toString()); + return Mono.empty(); + }); + } + +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java index e9a95e1a..548f4fe1 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java @@ -100,7 +100,7 @@ public class ServiceController { throw new ServiceException("Missing mandatory parameter 'serviceName'"); } if (registrationInfo.keepAliveIntervalSeconds < 0) { - throw new ServiceException("Keepalive interval shoul be greater or equal to 0"); + throw new ServiceException("Keepalive interval should be greater or equal to 0"); } if (!registrationInfo.callbackUrl.isEmpty()) { new URL(registrationInfo.callbackUrl); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java index 13568dbc..256b4782 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java @@ -283,7 +283,7 @@ public class PolicyController { "Returns a list of A1 policies matching given search criteria. <br>" // + "If several query parameters are defined, the policies matching all conditions are returned."; - @GetMapping(path = Consts.V2_API_ROOT + "/policy_instances", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(path = Consts.V2_API_ROOT + "/policy-instances", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Query for A1 policy instances", notes = GET_POLICIES_QUERY_DETAILS) @ApiResponses(value = { // @ApiResponse(code = 200, message = "Policies", response = PolicyInfoList.class), diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java index 594cf786..c032e3ad 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java @@ -38,8 +38,8 @@ public class PolicyInfo { public String policyId; @ApiModelProperty(value = "identity of the policy type", required = true) - @JsonProperty(value = "policy_type_id", required = true) - @SerializedName("policy_type_id") + @JsonProperty(value = "policytype_id", required = true) + @SerializedName("policytype_id") public String policyTypeId; @ApiModelProperty(value = "identity of the target Near-RT RIC", required = true) diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java index 5ecc7277..ede69d5d 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeIdList.java @@ -31,12 +31,12 @@ import java.util.Collection; import org.immutables.gson.Gson; @Gson.TypeAdapters -@ApiModel(value = "policy_type_id_list_v2", description = "Information about policy types") +@ApiModel(value = "policytype_id_list_v2", description = "Information about policy types") public class PolicyTypeIdList { @ApiModelProperty(value = "Policy type identities") - @SerializedName("policy_type_ids") - @JsonProperty("policy_type_ids") + @SerializedName("policytype_ids") + @JsonProperty("policytype_ids") public final Collection<String> policyTypesIds; public PolicyTypeIdList(Collection<String> ids) { diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeInfo.java index ff979650..b97730e6 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeInfo.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeInfo.java @@ -31,7 +31,7 @@ import io.swagger.annotations.ApiModelProperty; import org.immutables.gson.Gson; @Gson.TypeAdapters -@ApiModel(value = "policy_type_v2", description = "Policy type") +@ApiModel(value = "policytype_v2", description = "Policy type") public class PolicyTypeInfo { @ApiModelProperty( diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java index 938d5106..85983080 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicInfo.java @@ -57,8 +57,8 @@ public class RicInfo { public final Collection<String> managedElementIds; @ApiModelProperty(value = "supported policy types") - @SerializedName("policy_type_ids") - @JsonProperty("policy_type_ids") + @SerializedName("policytype_ids") + @JsonProperty("policytype_ids") public final Collection<String> policyTypeIds; @ApiModelProperty(value = STATE_DESCRIPTION, name = "state") diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java index 68afc384..88711164 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceRegistrationInfo.java @@ -46,7 +46,8 @@ public class ServiceRegistrationInfo { @JsonProperty("keep_alive_interval_seconds") public long keepAliveIntervalSeconds = 0; - @ApiModelProperty(value = "callback for notifying of RIC synchronization", required = false, allowEmptyValue = true) + @ApiModelProperty(value = "callback for notifying of Near-RT RIC state changes", required = false, + allowEmptyValue = true) @SerializedName("callback_url") @JsonProperty("callback_url") public String callbackUrl = ""; diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Service.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Service.java index 823490ce..3c7c53a1 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Service.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Service.java @@ -24,13 +24,20 @@ import java.time.Duration; import java.time.Instant; import lombok.Getter; +import lombok.Setter; public class Service { @Getter private final String name; + + @Getter private final Duration keepAliveInterval; + private Instant lastPing; - private final String callbackUrl; + + @Getter + @Setter // For test + private String callbackUrl; public Service(String name, Duration keepAliveInterval, String callbackUrl) { this.name = name; @@ -39,10 +46,6 @@ public class Service { keepAlive(); } - public synchronized Duration getKeepAliveInterval() { - return this.keepAliveInterval; - } - public synchronized void keepAlive() { this.lastPing = Instant.now(); } @@ -55,8 +58,4 @@ public class Service { return Duration.between(this.lastPing, Instant.now()); } - public synchronized String getCallbackUrl() { - return this.callbackUrl; - } - } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTask.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTask.java index 88d99232..825418b5 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTask.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTask.java @@ -24,8 +24,8 @@ import static org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicSt import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory; -import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient; import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceCallbacks; import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies; @@ -33,7 +33,6 @@ import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy; import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType; import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric; -import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -132,22 +131,7 @@ public class RicSynchronizationTask { private void onSynchronizationComplete(Ric ric) { logger.debug("Synchronization completed for: {}", ric.id()); ric.setState(RicState.AVAILABLE); - notifyAllServices("Synchronization completed for:" + ric.id()); - } - - private void notifyAllServices(String body) { - for (Service service : services.getAll()) { - String url = service.getCallbackUrl(); - if (url.length() > 0) { - createNotificationClient(url) // - .put("", body) // - .subscribe( // - notUsed -> logger.debug("Service {} notified", service.getName()), - throwable -> logger.warn("Service notification failed for service: {}. Cause: {}", - service.getName(), throwable.getMessage()), - () -> logger.debug("All services notified")); - } - } + notifyServices(ric); } private Flux<Object> deleteAllPolicyInstances(Ric ric, Throwable t) { @@ -163,8 +147,9 @@ public class RicSynchronizationTask { return Flux.concat(synchronizedTypes, deletePoliciesInRic); } - AsyncRestClient createNotificationClient(final String url) { - return restClientFactory.createRestClient(url); + void notifyServices(Ric ric) { + ServiceCallbacks callbacks = new ServiceCallbacks(this.restClientFactory); + callbacks.notifyServicesRicSynchronized(ric, services); } private Flux<PolicyType> synchronizePolicyTypes(Ric ric, A1Client a1Client) { diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClientTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClientTest.java index 87615f68..aad1ed02 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClientTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/CcsdkA1AdapterClientTest.java @@ -43,9 +43,9 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.OngoingStubbing; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType; -import org.onap.ccsdk.oran.a1policymanagementservice.clients.ImmutableAdapterOutput.Builder; import org.onap.ccsdk.oran.a1policymanagementservice.clients.CcsdkA1AdapterClient.AdapterOutput; import org.onap.ccsdk.oran.a1policymanagementservice.clients.CcsdkA1AdapterClient.AdapterRequest; +import org.onap.ccsdk.oran.a1policymanagementservice.clients.ImmutableAdapterOutput.Builder; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableControllerConfig; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy; @@ -171,7 +171,8 @@ class CcsdkA1AdapterClientTest { @Test void getTypeSchema_OSC() throws IOException { String expUrl = RIC_1_URL + "/a1-p/policytypes/policyTypeId"; - testGetTypeSchema(A1ProtocolType.CCSDK_A1_ADAPTER_OSC_V1, expUrl, "policyTypeId", "test_osc_get_schema_response.json"); + testGetTypeSchema(A1ProtocolType.CCSDK_A1_ADAPTER_OSC_V1, expUrl, "policyTypeId", + "test_osc_get_schema_response.json"); } @Test diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java index 0fc252d8..02fdaf9c 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java @@ -52,6 +52,7 @@ import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicC import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableWebClientConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceCallbackInfo; import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException; import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy; import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType; @@ -63,6 +64,7 @@ import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics; +import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services; import org.onap.ccsdk.oran.a1policymanagementservice.tasks.RicSupervision; import org.onap.ccsdk.oran.a1policymanagementservice.tasks.ServiceSupervision; @@ -122,6 +124,9 @@ class ApplicationTest { @Autowired Services services; + @Autowired + RappSimulatorController rAppSimulator; + private static Gson gson = new GsonBuilder().create(); public static class MockApplicationConfig extends ApplicationConfig { @@ -192,6 +197,7 @@ class ApplicationTest { policyTypes.clear(); services.clear(); a1ClientFactory.reset(); + this.rAppSimulator.getTestResults().clear(); } @AfterEach @@ -355,7 +361,7 @@ class ApplicationTest { policy = policies.getPolicy(policyInstanceId); assertThat(policy.isTransient()).isFalse(); - url = "/policy_instances"; + url = "/policy-instances"; String rsp = restClient().get(url).block(); assertThat(rsp).as("Response contains policy instance ID.").contains(policyInstanceId); @@ -417,7 +423,7 @@ class ApplicationTest { String body = putPolicyBody("service1", "ric1", "", "id1"); restClient().put("/policies", body).block(); - String rsp = restClient().get("/policy_instances").block(); + String rsp = restClient().get("/policy-instances").block(); PolicyInfoList info = gson.fromJson(rsp, PolicyInfoList.class); assertThat(info.policies).hasSize(1); PolicyInfo policyInfo = info.policies.iterator().next(); @@ -518,7 +524,7 @@ class ApplicationTest { void testGetPolicyInstances() throws Exception { addPolicy("id1", "type1", "service1"); - String url = "/policy_instances"; + String url = "/policy-instances"; String rsp = restClient().get(url).block(); logger.info(rsp); PolicyInfoList info = gson.fromJson(rsp, PolicyInfoList.class); @@ -536,14 +542,14 @@ class ApplicationTest { addPolicy("id2", "type1", "service2"); addPolicy("id3", "type2", "service1"); - String url = "/policy_instances?policytype_id=type1"; + String url = "/policy-instances?policytype_id=type1"; String rsp = restClient().get(url).block(); logger.info(rsp); assertThat(rsp).contains("id1") // .contains("id2") // .doesNotContain("id3"); - url = "/policy_instances?policytype_id=type1&service_id=service2"; + url = "/policy-instances?policytype_id=type1&service_id=service2"; rsp = restClient().get(url).block(); logger.info(rsp); assertThat(rsp).doesNotContain("id1") // @@ -551,11 +557,11 @@ class ApplicationTest { .doesNotContain("id3"); // Test get policies for non existing type - url = "/policy_instances?policytype_id=type1XXX"; + url = "/policy-instances?policytype_id=type1XXX"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); // Test get policies for non existing RIC - url = "/policy_instances?ric_id=XXX"; + url = "/policy-instances?ric_id=XXX"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); } @@ -672,7 +678,25 @@ class ApplicationTest { rsp = restClient().get(url).block(); info = gson.fromJson(rsp, PolicyStatusInfo.class); assertThat(info.status.toString()).isEqualTo("{}"); + } + + @Test + void testServiceNotification() throws ServiceException { + putService("junkService"); + Service junkService = this.services.get("junkService"); + junkService.setCallbackUrl("https://junk"); + putService("service"); + + Ric ric = addRic("ric1"); + ric.setState(Ric.RicState.UNAVAILABLE); + supervision.checkAllRics(); + waitForRicState("ric1", RicState.AVAILABLE); + RappSimulatorController.TestResults receivedCallbacks = rAppSimulator.getTestResults(); + assertThat(receivedCallbacks.getReceivedInfo().size()).isEqualTo(1); + ServiceCallbackInfo callbackInfo = receivedCallbacks.getReceivedInfo().get(0); + assertThat(callbackInfo.ricId).isEqualTo("ric1"); + assertThat(callbackInfo.eventType).isEqualTo(ServiceCallbackInfo.EventType.AVAILABLE); } private Policy addPolicy(String id, String typeName, String service, String ric) throws ServiceException { @@ -685,7 +709,7 @@ class ApplicationTest { .type(addPolicyType(typeName, ric)) // .lastModified(Instant.now()) // .isTransient(false) // - .statusNotificationUri("/policy_status?id=XXX") // + .statusNotificationUri("/policy-status?id=XXX") // .build(); policies.put(policy); return policy; @@ -696,7 +720,8 @@ class ApplicationTest { } private String createServiceJson(String name, long keepAliveIntervalSeconds) { - return createServiceJson(name, keepAliveIntervalSeconds, "https://examples.javacodegeeks.com/core-java/"); + String callbackUrl = baseUrl() + RappSimulatorController.SERVICE_CALLBACK_URL; + return createServiceJson(name, keepAliveIntervalSeconds, callbackUrl); } private String createServiceJson(String name, long keepAliveIntervalSeconds, String url) { @@ -769,6 +794,10 @@ class ApplicationTest { } + private String baseUrl() { + return "https://localhost:" + port; + } + private AsyncRestClient restClient(boolean useTrustValidation) { String baseUrl = "https://localhost:" + port + Consts.V2_API_ROOT; return restClient(baseUrl, useTrustValidation); diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java index f8369610..ded864f7 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java @@ -131,7 +131,7 @@ class ConcurrencyTestRunnable implements Runnable { } private void listPolicies() { - String uri = "/policy_instances"; + String uri = "/policy-instances"; webClient.getForEntity(uri).block(); } diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RappSimulatorController.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RappSimulatorController.java new file mode 100644 index 00000000..0a679201 --- /dev/null +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RappSimulatorController.java @@ -0,0 +1,81 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2020 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. + * ========================LICENSE_END=================================== + */ + +package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +import java.lang.invoke.MethodHandles; +import java.util.Vector; + +import lombok.Getter; + +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceCallbackInfo; +import org.onap.ccsdk.oran.a1policymanagementservice.controllers.VoidResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController("RappCallbacksController") +@Api(tags = {"R-App Callbacks"}) +public class RappSimulatorController { + + private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static final String SERVICE_CALLBACK_URL = "/r-app/pms-callback"; + private static Gson gson = new GsonBuilder().create(); + + public static class TestResults { + @Getter + private Vector<ServiceCallbackInfo> receivedInfo = new Vector<>(); + + public void clear() { + receivedInfo.clear(); + } + } + + @Getter + private TestResults testResults = new TestResults(); + + private static final String CALLBACK_DESCRIPTION = "The URL to this call is registerred at Service registration."; + + @PostMapping(path = SERVICE_CALLBACK_URL, produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Callback for Near-RT RIC status", notes = CALLBACK_DESCRIPTION) + @ApiResponses(value = { // + @ApiResponse(code = 200, message = "OK", response = VoidResponse.class)} // + ) + public ResponseEntity<Object> jobStatusCallback( // + @RequestBody ServiceCallbackInfo body) { + logger.info("R-App callback body: {}", gson.toJson(body)); + this.testResults.receivedInfo.add(body); + return new ResponseEntity<>(HttpStatus.OK); + } + +} diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java index a50d4ab7..8029741e 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java @@ -23,9 +23,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.tasks; import static ch.qos.logback.classic.Level.WARN; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -48,7 +46,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory; -import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient; import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig; @@ -162,21 +159,15 @@ class RicSynchronizationTaskTest { RicSynchronizationTask synchronizerUnderTest = spy(createTask()); - AsyncRestClient restClientMock = setUpCreationOfAsyncRestClient(synchronizerUnderTest); - when(restClientMock.put(anyString(), anyString())).thenReturn(Mono.just("Ok")); - synchronizerUnderTest.run(RIC_1); verify(a1ClientMock, times(1)).getPolicyTypeIdentities(); verifyNoMoreInteractions(a1ClientMock); verify(synchronizerUnderTest).run(RIC_1); - verify(synchronizerUnderTest).createNotificationClient(SERVICE_1_CALLBACK_URL); + verify(synchronizerUnderTest).notifyServices(any()); verifyNoMoreInteractions(synchronizerUnderTest); - verify(restClientMock).put("", "Synchronization completed for:" + RIC_1_NAME); - verifyNoMoreInteractions(restClientMock); - assertThat(policyTypes.size()).isEqualTo(1); assertThat(policies.size()).isZero(); assertThat(RIC_1.getState()).isEqualTo(RicState.AVAILABLE); @@ -287,45 +278,11 @@ class RicSynchronizationTaskTest { assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE); } - @Test - void ricIdlePolicyTypeInRepo_thenSynchronizationWithErrorOnServiceNotificationErrorLogged() { - RIC_1.setState(RicState.AVAILABLE); - - policyTypes.put(POLICY_TYPE_1); - - services.put(SERVICE_1); - - setUpCreationOfA1Client(); - simulateRicWithOnePolicyType(); - - final ListAppender<ILoggingEvent> logAppender = - LoggingUtils.getLogListAppender(RicSynchronizationTask.class, WARN); - - RicSynchronizationTask synchronizerUnderTest = spy(createTask()); - - AsyncRestClient restClientMock = setUpCreationOfAsyncRestClient(synchronizerUnderTest); - String originalErrorMessage = "Exception"; - when(restClientMock.put(anyString(), anyString())).thenReturn(Mono.error(new Exception(originalErrorMessage))); - - synchronizerUnderTest.run(RIC_1); - - ILoggingEvent loggingEvent = logAppender.list.get(0); - assertThat(loggingEvent.getLevel()).isEqualTo(WARN); - verifyCorrectLogMessage(0, logAppender, - "Service notification failed for service: " + SERVICE_1_NAME + ". Cause: " + originalErrorMessage); - } - private void setUpCreationOfA1Client() { when(a1ClientFactoryMock.createA1Client(any(Ric.class))).thenReturn(Mono.just(a1ClientMock)); doReturn(Flux.empty()).when(a1ClientMock).deleteAllPolicies(); } - private AsyncRestClient setUpCreationOfAsyncRestClient(RicSynchronizationTask synchronizerUnderTest) { - AsyncRestClient restClientMock = mock(AsyncRestClient.class); - doReturn(restClientMock).when(synchronizerUnderTest).createNotificationClient(anyString()); - return restClientMock; - } - private void simulateRicWithOnePolicyType() { when(a1ClientMock.getPolicyTypeIdentities()).thenReturn(Mono.just(Arrays.asList(POLICY_TYPE_1_NAME))); } diff --git a/docs/offeredapis/swagger/pms-api.json b/docs/offeredapis/swagger/pms-api.json index 1495c0f8..3f684b8b 100644 --- a/docs/offeredapis/swagger/pms-api.json +++ b/docs/offeredapis/swagger/pms-api.json @@ -54,7 +54,7 @@ "operationId": "getPolicyTypesUsingGET", "responses": { "200": { - "schema": {"$ref": "#/definitions/policy_type_id_list_v2"}, + "schema": {"$ref": "#/definitions/policytype_id_list_v2"}, "description": "Policy type IDs" }, "401": {"description": "Unauthorized"}, @@ -269,7 +269,7 @@ "summary": "Query policies", "deprecated": false, "produces": ["*/*"], - "operationId": "getPoliciesUsingGET_1", + "operationId": "getPoliciesUsingGET", "responses": { "200": { "schema": { @@ -400,7 +400,7 @@ "summary": "Query Near-RT RIC information", "deprecated": false, "produces": ["*/*"], - "operationId": "getRicsUsingGET", + "operationId": "getRicsUsingGET_1", "responses": { "200": { "schema": { @@ -484,7 +484,7 @@ "deprecated": false, "produces": ["application/json"], "description": "The call returns all Near-RT RICs that supports a given policy type identity", - "operationId": "getRicsUsingGET_1", + "operationId": "getRicsUsingGET", "responses": { "200": { "schema": {"$ref": "#/definitions/ric_info_list_v2"}, @@ -585,6 +585,52 @@ }], "tags": ["A1 Policy Management Version 1.0"] }}, + "/v2/policy-instances": {"get": { + "summary": "Query for A1 policy instances", + "deprecated": false, + "produces": ["application/json"], + "description": "Returns a list of A1 policies matching given search criteria. <br>If several query parameters are defined, the policies matching all conditions are returned.", + "operationId": "getPolicyInstancesUsingGET", + "responses": { + "200": { + "schema": {"$ref": "#/definitions/policy_info_list_v2"}, + "description": "Policies" + }, + "401": {"description": "Unauthorized"}, + "403": {"description": "Forbidden"}, + "404": { + "schema": {"$ref": "#/definitions/error_information"}, + "description": "Near-RT RIC, policy type or service not found" + } + }, + "parameters": [ + { + "in": "query", + "allowEmptyValue": false, + "name": "policytype_id", + "description": "The identity of the policy type to get policies for.", + "type": "string", + "required": false + }, + { + "in": "query", + "allowEmptyValue": false, + "name": "ric_id", + "description": "The identity of the Near-RT RIC to get policies for.", + "type": "string", + "required": false + }, + { + "in": "query", + "allowEmptyValue": false, + "name": "service_id", + "description": "The identity of the service to get policies for.", + "type": "string", + "required": false + } + ], + "tags": ["A1 Policy Management Version 2.0 (in progress)"] + }}, "/v2/services": { "get": { "summary": "Returns service information", @@ -652,7 +698,7 @@ "summary": "Returns the name of a RIC managing one Mananged Element", "deprecated": false, "produces": ["*/*"], - "operationId": "getRicUsingGET", + "operationId": "getRicUsingGET_1", "responses": { "200": { "schema": {"type": "string"}, @@ -701,52 +747,6 @@ "tags": ["A1 Policy Management Version 1.0"], "consumes": ["application/json"] }}, - "/v2/policy_instances": {"get": { - "summary": "Query for A1 policy instances", - "deprecated": false, - "produces": ["application/json"], - "description": "Returns a list of A1 policies matching given search criteria. <br>If several query parameters are defined, the policies matching all conditions are returned.", - "operationId": "getPoliciesUsingGET", - "responses": { - "200": { - "schema": {"$ref": "#/definitions/policy_info_list_v2"}, - "description": "Policies" - }, - "401": {"description": "Unauthorized"}, - "403": {"description": "Forbidden"}, - "404": { - "schema": {"$ref": "#/definitions/error_information"}, - "description": "Near-RT RIC, policy type or service not found" - } - }, - "parameters": [ - { - "in": "query", - "allowEmptyValue": false, - "name": "policytype_id", - "description": "The identity of the policy type to get policies for.", - "type": "string", - "required": false - }, - { - "in": "query", - "allowEmptyValue": false, - "name": "ric_id", - "description": "The identity of the Near-RT RIC to get policies for.", - "type": "string", - "required": false - }, - { - "in": "query", - "allowEmptyValue": false, - "name": "service_id", - "description": "The identity of the service to get policies for.", - "type": "string", - "required": false - } - ], - "tags": ["A1 Policy Management Version 2.0 (in progress)"] - }}, "/v2/services/{service_id}/keepalive": {"put": { "summary": "Heartbeat indicates that the service is running", "deprecated": false, @@ -782,7 +782,7 @@ "operationId": "getPolicyTypeUsingGET", "responses": { "200": { - "schema": {"$ref": "#/definitions/policy_type_v2"}, + "schema": {"$ref": "#/definitions/policytype_v2"}, "description": "Policy type" }, "401": {"description": "Unauthorized"}, @@ -822,7 +822,7 @@ "deprecated": false, "produces": ["application/json"], "description": "Either a Near-RT RIC identity or a Mananged Element identity can be specified.<br>The intention with Mananged Element identity is the ID used in O1 for accessing the traffical element (such as the ID of CU).", - "operationId": "getRicUsingGET_1", + "operationId": "getRicUsingGET", "responses": { "200": { "schema": {"$ref": "#/definitions/ric_info_v2"}, @@ -882,6 +882,29 @@ }], "tags": ["A1 Policy Management Version 2.0 (in progress)"] }}, + "/r-app/pms-callback": {"post": { + "summary": "Callback for Near-RT RIC status", + "deprecated": false, + "produces": ["application/json"], + "description": "The URL to this call is registerred at Service registration.", + "operationId": "jobStatusCallbackUsingPOST", + "responses": { + "200": {"description": "OK"}, + "201": {"description": "Created"}, + "401": {"description": "Unauthorized"}, + "403": {"description": "Forbidden"}, + "404": {"description": "Not Found"} + }, + "parameters": [{ + "schema": {"$ref": "#/definitions/service_callback_info_v2"}, + "in": "body", + "name": "body", + "description": "body", + "required": true + }], + "tags": ["R-App Callbacks"], + "consumes": ["application/json"] + }}, "/service": {"put": { "summary": "Register a service", "deprecated": false, @@ -992,7 +1015,7 @@ } } }, - "host": "localhost:43287", + "host": "localhost:38593", "definitions": { "error_information": { "description": "Problem as defined in https://tools.ietf.org/html/rfc7807", @@ -1083,7 +1106,7 @@ "CONSISTENCY_CHECK" ] }, - "policy_type_ids": { + "policytype_ids": { "description": "supported policy types", "type": "array", "items": {"type": "string"} @@ -1123,7 +1146,7 @@ "required": ["service_id"], "properties": { "callback_url": { - "description": "callback for notifying of RIC synchronization", + "description": "callback for notifying of Near-RT RIC state changes", "type": "string" }, "service_id": { @@ -1176,16 +1199,6 @@ } } }, - "policy_type_id_list_v2": { - "description": "Information about policy types", - "type": "object", - "title": "policy_type_id_list_v2", - "properties": {"policy_type_ids": { - "description": "Policy type identities", - "type": "array", - "items": {"type": "string"} - }} - }, "service_status_v1": { "type": "object", "title": "service_status_v1", @@ -1234,6 +1247,15 @@ } } }, + "policytype_v2": { + "description": "Policy type", + "type": "object", + "title": "policytype_v2", + "properties": {"policy_schema": { + "description": "Policy type json scema. The schema is a json object following http://json-schema.org/draft-07/schema", + "type": "object" + }} + }, "ric_info_list_v2": { "description": "List of Near-RT RIC information", "type": "object", @@ -1244,13 +1266,14 @@ "items": {"$ref": "#/definitions/ric_info_v2"} }} }, - "policy_type_v2": { - "description": "Policy type", + "policytype_id_list_v2": { + "description": "Information about policy types", "type": "object", - "title": "policy_type_v2", - "properties": {"policy_schema": { - "description": "Policy type json scema. The schema is a json object following http://json-schema.org/draft-07/schema", - "type": "object" + "title": "policytype_id_list_v2", + "properties": {"policytype_ids": { + "description": "Policy type identities", + "type": "array", + "items": {"type": "string"} }} }, "policy_id_list_v2": { @@ -1270,7 +1293,7 @@ "required": [ "policy_data", "policy_id", - "policy_type_id", + "policytype_id", "ric_id", "service_id" ], @@ -1299,7 +1322,7 @@ "description": "Callback URI for policy status updates", "type": "string" }, - "policy_type_id": { + "policytype_id": { "description": "identity of the policy type", "type": "string" } @@ -1315,6 +1338,26 @@ "items": {"$ref": "#/definitions/service_status_v2"} }} }, + "service_callback_info_v2": { + "description": "Information transferred as in Service callbacks (callback_url)", + "type": "object", + "title": "service_callback_info_v2", + "required": [ + "event_type", + "ric_id" + ], + "properties": { + "ric_id": { + "description": "identity of a Near-RT RIC", + "type": "string" + }, + "event_type": { + "description": "values:\nAVAILABLE: the Near-RT RIC has become available for A1 Policy management", + "type": "string", + "enum": ["AVAILABLE"] + } + } + }, "Mono«ResponseEntity«string»»": { "type": "object", "title": "Mono«ResponseEntity«string»»" @@ -1340,6 +1383,10 @@ { "name": "A1 Policy Management Version 2.0 (in progress)", "description": "Policy Controller" + }, + { + "name": "R-App Callbacks", + "description": "Rapp Simulator Controller" } ] }
\ No newline at end of file |