import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
RestTemplate restTemplate = new RestTemplate();
private static com.google.gson.Gson gson = new GsonBuilder() //
- .serializeNulls() //
- .create(); //
+ .serializeNulls() //
+ .create(); //
private final String urlPrefix;
@Autowired
public PolicyAgentApiImpl(
- @org.springframework.beans.factory.annotation.Value("${policycontroller.url.prefix}") final String urlPrefix) {
+ @org.springframework.beans.factory.annotation.Value("${policycontroller.url.prefix}") final String urlPrefix) {
logger.debug("ctor prefix '{}'", urlPrefix);
this.urlPrefix = urlPrefix;
}
@Override
public ResponseEntity<String> getAllPolicyTypes() {
- String url = baseUrl() + "/policy_schemas";
- ResponseEntity<String> rsp = this.restTemplate.getForEntity(url, String.class);
- if (!rsp.getStatusCode().is2xxSuccessful()) {
- return rsp;
- }
-
- PolicyTypes result = new PolicyTypes();
- JsonParser jsonParser = new JsonParser();
try {
+ String url = baseUrl() + "/policy_schemas";
+ ResponseEntity<String> rsp = this.restTemplate.getForEntity(url, String.class);
+ if (!rsp.getStatusCode().is2xxSuccessful()) {
+ return rsp;
+ }
+
+ PolicyTypes result = new PolicyTypes();
+ JsonParser jsonParser = new JsonParser();
+
JsonArray schemas = jsonParser.parse(rsp.getBody()).getAsJsonArray();
for (JsonElement schema : schemas) {
JsonObject schemaObj = schema.getAsJsonObject();
}
try {
- Type listType = new TypeToken<List<ImmutablePolicyInfo>>() {
- }.getType();
+ Type listType = new TypeToken<List<ImmutablePolicyInfo>>() {}.getType();
List<PolicyInfo> rspParsed = gson.fromJson(rsp.getBody(), listType);
PolicyInstances result = new PolicyInstances();
for (PolicyInfo p : rspParsed) {
@Override
public ResponseEntity<String> putPolicy(String policyTypeIdString, String policyInstanceId, String json,
- String ric) {
+ String ric) {
String url = baseUrl() + "/policy?type={type}&instance={instance}&ric={ric}&service={service}";
Map<String, ?> uriVariables = Map.of( //
- "type", policyTypeIdString, //
- "instance", policyInstanceId, //
- "ric", ric, //
- "service", "dashboard");
+ "type", policyTypeIdString, //
+ "instance", policyInstanceId, //
+ "ric", ric, //
+ "service", "dashboard");
try {
- this.restTemplate.put(url, json, uriVariables);
+ this.restTemplate.put(url, createJsonHttpEntity(json), uriVariables);
return new ResponseEntity<>(HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
String rsp = this.restTemplate.getForObject(url, String.class, uriVariables);
try {
- Type listType = new TypeToken<List<ImmutableRicInfo>>() {
- }.getType();
+ Type listType = new TypeToken<List<ImmutableRicInfo>>() {}.getType();
List<RicInfo> rspParsed = gson.fromJson(rsp, listType);
Collection<String> result = new Vector<>(rspParsed.size());
for (RicInfo ric : rspParsed) {
}
}
+ private HttpEntity<String> createJsonHttpEntity(String content) {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ return new HttpEntity<String>(content, headers);
+ }
+
}
import java.lang.invoke.MethodHandles;
import java.net.URI;
+
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.onap.portalsdk.core.onboarding.util.PortalApiConstants;
mvn -Dtest=MockPolicyAgent test
The backend server publishes live API documentation at the
-URL `http://your-host-name-here:8080/swagger-ui.html`
+URL `http://your-host-name-here:8081/swagger-ui.html`
## License
]
}
]
- },
- "streams_subscribes": {
- "dmaap_subscriber": {
- "dmaap_info": {
- "topic_url": "http://dradmin:dradmin@localhost:2222/events/A1-P/users/sdnc1"
- },
- "type": "message_router"
- }
}
}
\ No newline at end of file
--- /dev/null
+swagger: '2.0'
+info:
+ description: Api Documentation
+ version: '1.0'
+ title: Api Documentation
+ termsOfService: 'urn:tos'
+ contact: {}
+ license:
+ name: Apache 2.0
+ url: 'http://www.apache.org/licenses/LICENSE-2.0'
+host: 'localhost:8081'
+basePath: /
+tags:
+ - name: policy-controller
+ description: Policy Controller
+ - name: ric-repository-controller
+ description: Ric Repository Controller
+ - name: service-controller
+ description: Service Controller
+ - name: status-controller
+ description: Status Controller
+paths:
+ /policies:
+ get:
+ tags:
+ - policy-controller
+ summary: Returns the policies
+ operationId: getPoliciesUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: type
+ in: query
+ description: type
+ required: false
+ type: string
+ - name: ric
+ in: query
+ description: ric
+ required: false
+ type: string
+ - name: service
+ in: query
+ description: service
+ required: false
+ type: string
+ responses:
+ '200':
+ description: Policies
+ schema:
+ type: array
+ items:
+ $ref: '#/definitions/PolicyInfo'
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ /policy:
+ get:
+ tags:
+ - policy-controller
+ summary: Returns a policy configuration
+ operationId: getPolicyUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: instance
+ in: query
+ description: instance
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Policy found
+ schema:
+ type: object
+ '204':
+ description: Policy is not found
+ schema:
+ type: string
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ put:
+ tags:
+ - policy-controller
+ summary: Put a policy
+ operationId: putPolicyUsingPUT
+ consumes:
+ - application/json
+ produces:
+ - '*/*'
+ parameters:
+ - name: type
+ in: query
+ description: type
+ required: true
+ type: string
+ - name: instance
+ in: query
+ description: instance
+ required: true
+ type: string
+ - name: ric
+ in: query
+ description: ric
+ required: true
+ type: string
+ - name: service
+ in: query
+ description: service
+ required: true
+ type: string
+ - in: body
+ name: jsonBody
+ description: jsonBody
+ required: true
+ schema:
+ type: object
+ responses:
+ '200':
+ description: Policy created or updated
+ schema:
+ type: string
+ '201':
+ description: Created
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ delete:
+ tags:
+ - policy-controller
+ summary: Deletes the policy
+ operationId: deletePolicyUsingDELETE
+ produces:
+ - '*/*'
+ parameters:
+ - name: instance
+ in: query
+ description: instance
+ required: true
+ type: string
+ responses:
+ '200':
+ description: OK
+ schema:
+ $ref: '#/definitions/Mono«ResponseEntity«Void»»'
+ '204':
+ description: Policy deleted
+ schema:
+ $ref: '#/definitions/Mono«ResponseEntity«Void»»'
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ /policy_schema:
+ get:
+ tags:
+ - policy-controller
+ summary: Returns one policy type schema definition
+ operationId: getPolicySchemaUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: id
+ in: query
+ description: id
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Policy schema
+ schema:
+ type: object
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ /policy_schemas:
+ get:
+ tags:
+ - policy-controller
+ summary: Returns policy type schema definitions
+ operationId: getPolicySchemasUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: ric
+ in: query
+ description: ric
+ required: false
+ type: string
+ responses:
+ '200':
+ description: Policy schemas
+ schema:
+ type: array
+ items:
+ type: string
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ /policy_types:
+ get:
+ tags:
+ - policy-controller
+ summary: Returns policy types
+ operationId: getPolicyTypesUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: ric
+ in: query
+ description: ric
+ required: false
+ type: string
+ responses:
+ '200':
+ description: Policy type names
+ schema:
+ type: array
+ items:
+ type: string
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ /ric:
+ get:
+ tags:
+ - ric-repository-controller
+ summary: Returns the name of a RIC managing one Mananged Element
+ operationId: getRicUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: managedElementId
+ in: query
+ description: managedElementId
+ required: false
+ type: string
+ responses:
+ '200':
+ description: RIC is fond
+ schema:
+ type: string
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: RIC is not fond
+ schema:
+ type: string
+ /rics:
+ get:
+ tags:
+ - ric-repository-controller
+ summary: Returns NearRT RIC information
+ operationId: getRicsUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: policyType
+ in: query
+ description: policyType
+ required: false
+ type: string
+ responses:
+ '200':
+ description: OK
+ schema:
+ type: array
+ items:
+ $ref: '#/definitions/RicInfo'
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ /service:
+ put:
+ tags:
+ - service-controller
+ summary: Register a service
+ operationId: putServiceUsingPUT
+ consumes:
+ - application/json
+ produces:
+ - '*/*'
+ parameters:
+ - in: body
+ name: registrationInfo
+ description: registrationInfo
+ required: true
+ schema:
+ $ref: '#/definitions/ServiceRegistrationInfo'
+ responses:
+ '200':
+ description: OK
+ schema:
+ type: string
+ '201':
+ description: Created
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ /services:
+ get:
+ tags:
+ - service-controller
+ summary: Returns service information
+ operationId: getServicesUsingGET
+ produces:
+ - '*/*'
+ parameters:
+ - name: name
+ in: query
+ description: name
+ required: false
+ type: string
+ responses:
+ '200':
+ description: OK
+ schema:
+ type: array
+ items:
+ $ref: '#/definitions/ServiceStatus'
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ delete:
+ tags:
+ - service-controller
+ summary: Delete a service
+ operationId: deleteServiceUsingDELETE
+ produces:
+ - '*/*'
+ parameters:
+ - name: name
+ in: query
+ description: name
+ required: true
+ type: string
+ responses:
+ '200':
+ description: OK
+ schema:
+ type: string
+ '204':
+ description: No Content
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ /services/keepalive:
+ post:
+ tags:
+ - service-controller
+ summary: Keep the poilicies alive for a service
+ operationId: keepAliveServiceUsingPOST
+ consumes:
+ - application/json
+ produces:
+ - '*/*'
+ parameters:
+ - name: name
+ in: query
+ description: name
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Policies timeout supervision refreshed
+ schema:
+ type: string
+ '201':
+ description: Created
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: 'The service is not found, needs re-registration'
+ /status:
+ get:
+ tags:
+ - status-controller
+ summary: Returns status and statistics of the service
+ operationId: getStatusUsingGET
+ produces:
+ - '*/*'
+ responses:
+ '200':
+ description: Service is living
+ schema:
+ type: string
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+definitions:
+ Mono«ResponseEntity«Void»»:
+ type: object
+ title: Mono«ResponseEntity«Void»»
+ Mono«ResponseEntity«string»»:
+ type: object
+ title: Mono«ResponseEntity«string»»
+ PolicyInfo:
+ type: object
+ properties:
+ id:
+ type: string
+ description: identity of the policy
+ allowEmptyValue: false
+ json:
+ type: string
+ description: the configuration of the policy
+ allowEmptyValue: false
+ lastModified:
+ type: string
+ description: 'timestamp, last modification time'
+ allowEmptyValue: false
+ ric:
+ type: string
+ description: identity the target NearRT RIC
+ allowEmptyValue: false
+ service:
+ type: string
+ description: the name of the service owning the policy
+ allowEmptyValue: false
+ type:
+ type: string
+ description: name of the policy type
+ allowEmptyValue: false
+ title: PolicyInfo
+ RicInfo:
+ type: object
+ properties:
+ managedElementIds:
+ type: array
+ description: O1 identities for managed entities
+ allowEmptyValue: false
+ items:
+ type: string
+ name:
+ type: string
+ description: identity of the ric
+ allowEmptyValue: false
+ policyTypes:
+ type: array
+ description: supported policy types
+ allowEmptyValue: false
+ items:
+ type: string
+ title: RicInfo
+ ServiceRegistrationInfo:
+ type: object
+ properties:
+ callbackUrl:
+ type: string
+ description: callback for notifying of RIC recovery
+ allowEmptyValue: false
+ keepAliveIntervalSeconds:
+ type: integer
+ format: int64
+ description: keep alive interval for policies owned by the service. 0 means no timeout supervision. Polcies that are not refreshed within this time are removed
+ allowEmptyValue: false
+ name:
+ type: string
+ description: identity of the service
+ allowEmptyValue: false
+ title: ServiceRegistrationInfo
+ ServiceStatus:
+ type: object
+ properties:
+ keepAliveIntervalSeconds:
+ type: integer
+ format: int64
+ description: policy keep alive timeout
+ allowEmptyValue: false
+ name:
+ type: string
+ description: identity of the service
+ allowEmptyValue: false
+ timeSincePingSeconds:
+ type: integer
+ format: int64
+ description: time since last invocation by the service
+ allowEmptyValue: false
+ title: ServiceStatus
+
--- /dev/null
+
+#description: Docker application of policy agent managing policies
+#blueprint_version: 1.0.0
+---
+tosca_definitions_version: cloudify_dsl_1_3
+description: Docker application to collect log file from PNF
+imports:
+ - http://www.getcloudify.org/spec/cloudify/4.3.1/types.yaml
+ - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R5/k8splugin/1.6.0/k8splugin_types.yaml
+ - https://nexus.onap.org/service/local/repositories/raw/content/org.onap.ccsdk.platform.plugins/type_files/dmaap/dmaap.yaml
+inputs:
+ policy-agent_cpu_limit:
+ type: string
+ default: "250m"
+ policy-agent_cpu_request:
+ type: string
+ default: "250m"
+ policy-agent_memory_limit:
+ type: string
+ default: "256Mi"
+ policy-agent_memory_request:
+ type: string
+ default: "256Mi"
+ envs:
+ default: {}
+ external_port:
+ type: string
+ default: ":0"
+ publish_topic_name:
+ type: string
+ default: "A1-POLICY-AGENT-WRITE"
+ subscribe_topic_name:
+ type: string
+ default: "A1-POLICY-AGENT-READ"
+ consumer_group:
+ type: string
+ default: "users"
+ consumer_id:
+ type: string
+ default: "policy-agent"
+ log_directory:
+ type: string
+ default: "/var/log/policy-agent"
+ replicas:
+ type: integer
+ description: number of instances
+ default: 1
+ tag_version:
+ type: string
+ default: "nexus3.o-ran-sc.org:10004/o-ran-sc/nonrtric-policy-agent:1.0.0"
+node_templates:
+ policy-agent:
+ type: dcae.nodes.ContainerizedServiceComponentUsingDmaap
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ inputs:
+ envs:
+ get_input: envs
+ properties:
+ application_config:
+ streams_publishes:
+ dmaap_publisher:
+ dmaap_info:
+ topic_url: { concat: ['https://message-router:3905/events/',{ get_input: publish_topic_name }] }
+ type: message_router
+ streams_subscribes:
+ dmaap_subscriber:
+ dmaap_info:
+ topic_url: { concat: ['https://message-router:3905/events/',{ get_input: subscribe_topic_name }, '/', { get_input: consumer_group }, "/", { get_input: consumer_id }] }
+ type: message_router
+ ric:
+ - name: ric1
+ baseUrl: http://localhost:8083/
+ managedElementIds:
+ - kista_1
+ - kista_2
+ - name: ric2
+ baseUrl: http://localhost:8085/
+ managedElementIds:
+ - kista_3
+ - kista_4
+ docker_config:
+ healthcheck:
+ interval: 15s
+ timeout: 1s
+ type: http
+ endpoint: /status
+ ports:
+ - concat: ["8081", {get_input: external_port}]
+ image:
+ get_input: tag_version
+ service_component_type: policy-agent
+ log_info:
+ log_directory:
+ get_input: log_directory
+ replicas:
+ get_input: replicas
+ resource_config:
+ limits:
+ cpu:
+ get_input: policy-agent_cpu_limit
+ memory:
+ get_input: policy-agent_memory_limit
+ requests:
+ cpu:
+ get_input: policy-agent_cpu_request
+ memory:
+ get_input: policy-agent_memory_request
+
+
public interface A1Client {
public static enum A1ProtocolType {
- UNKNOWN, STD_V1, OSC_V1, CONTROLLER
+ UNKNOWN, STD_V1, OSC_V1, SDNC_OSC, SDNR_ONAP
}
public Mono<A1ProtocolType> getProtocolVersion();
return Mono.just(createStdA1ClientImpl(ric));
} else if (version == A1ProtocolType.OSC_V1) {
return Mono.just(new OscA1Client(ric.getConfig()));
- } else if (version == A1ProtocolType.CONTROLLER) {
- return Mono.just(createControllerA1Client(ric));
+ } else if (version == A1ProtocolType.SDNC_OSC) {
+ return Mono.just(createSdncOscA1Client(ric));
+ } else if (version == A1ProtocolType.SDNR_ONAP) {
+ return Mono.just(createSdnrOnapA1Client(ric));
}
return Mono.error(new ServiceException("Not supported protocoltype: " + version));
}
private Mono<A1Client.A1ProtocolType> getProtocolVersion(Ric ric) {
if (ric.getProtocolVersion() == A1ProtocolType.UNKNOWN) {
- return fetchVersion(ric, createControllerA1Client(ric)) //
+ return fetchVersion(ric, createSdnrOnapA1Client(ric)) //
+ .onErrorResume(err -> fetchVersion(ric, createSdncOscA1Client(ric)))
.onErrorResume(err -> fetchVersion(ric, new OscA1Client(ric.getConfig())))
.onErrorResume(err -> fetchVersion(ric, createStdA1ClientImpl(ric)))
.doOnNext(version -> ric.setProtocolVersion(version))
return new StdA1Client(ric.getConfig());
}
- protected A1Client createControllerA1Client(Ric ric) {
- return new ControllerA1Client(ric.getConfig());
+ protected A1Client createSdncOscA1Client(Ric ric) {
+ return new SdncOscA1Client(ric.getConfig());
+ }
+
+ protected A1Client createSdnrOnapA1Client(Ric ric) {
+ return new SdnrOnapA1Client(ric.getConfig());
}
private Mono<A1Client.A1ProtocolType> fetchVersion(Ric ric, A1Client a1Client) {
return client.post() //
.uri(uri) //
.contentType(MediaType.APPLICATION_JSON) //
- .syncBody(body) //
+ .bodyValue(body) //
+ .retrieve() //
+ .onStatus(HttpStatus::isError,
+ response -> Mono.error(new AsyncRestClientException(response.statusCode().toString()))) //
+ .bodyToMono(String.class);
+ }
+
+ public Mono<String> postWithAuthHeader(String uri, String body, String username, String password) {
+ return client.post() //
+ .uri(uri) //
+ .headers(headers -> headers.setBasicAuth(username, password)) //
+ .contentType(MediaType.APPLICATION_JSON) //
+ .bodyValue(body) //
.retrieve() //
.onStatus(HttpStatus::isError,
response -> Mono.error(new AsyncRestClientException(response.statusCode().toString()))) //
return client.put() //
.uri(uri) //
.contentType(MediaType.APPLICATION_JSON) //
- .syncBody(body) //
+ .bodyValue(body) //
.retrieve() //
.onStatus(HttpStatus::isError,
response -> Mono.error(new AsyncRestClientException(response.statusCode().toString()))) //
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-public class ControllerA1Client implements A1Client {
+public class SdncOscA1Client implements A1Client {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private static final String A1_CONTROLLER_URL =
- "http://admin:Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U@a1-controller-container:8181/restconf/operations";
+ private static final String A1_CONTROLLER_URL = "http://a1-controller-container:8181/restconf/operations";
+ private static final String A1_CONTROLLER_USERNAME = "admin";
+ private static final String A1_CONTROLLER_PASSWORD = "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U";
private final RicConfig ricConfig;
private final AsyncRestClient restClient;
- public ControllerA1Client(RicConfig ricConfig) {
+ public SdncOscA1Client(RicConfig ricConfig) {
this.ricConfig = ricConfig;
this.restClient = new AsyncRestClient(A1_CONTROLLER_URL);
- logger.debug("ControllerA1Client for ric: {}", this.ricConfig.name());
+ logger.debug("SdncOscA1Client for ric: {}", this.ricConfig.name());
}
@Override
String inputJsonString = createInputJsonString(paramsJson);
logger.debug("POST getPolicyTypeIdentities inputJsonString = {}", inputJsonString);
- return restClient.post("/A1-ADAPTER-API:getPolicyTypeIdentities", inputJsonString) //
+ return restClient
+ .postWithAuthHeader("/A1-ADAPTER-API:getPolicyTypeIdentities", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD) //
.flatMap(response -> getValueFromResponse(response, "policy-type-id-list")) //
.flatMap(this::parseJsonArrayOfString);
}
String inputJsonString = createInputJsonString(paramsJson);
logger.debug("POST getPolicyIdentities inputJsonString = {}", inputJsonString);
- return restClient.post("/A1-ADAPTER-API:getPolicyIdentities", inputJsonString) //
+ return restClient
+ .postWithAuthHeader("/A1-ADAPTER-API:getPolicyIdentities", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD) //
.flatMap(response -> getValueFromResponse(response, "policy-id-list")) //
.flatMap(this::parseJsonArrayOfString);
}
String inputJsonString = createInputJsonString(paramsJson);
logger.debug("POST getPolicyType inputJsonString = {}", inputJsonString);
- return restClient.post("/A1-ADAPTER-API:getPolicyType", inputJsonString) //
+ return restClient
+ .postWithAuthHeader("/A1-ADAPTER-API:getPolicyType", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD) //
.flatMap(response -> getValueFromResponse(response, "policy-type")) //
.flatMap(this::extractPolicySchema);
}
String inputJsonString = createInputJsonString(paramsJson);
logger.debug("POST putPolicy inputJsonString = {}", inputJsonString);
- return restClient.post("/A1-ADAPTER-API:putPolicy", inputJsonString) //
+ return restClient
+ .postWithAuthHeader("/A1-ADAPTER-API:putPolicy", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD) //
.flatMap(response -> getValueFromResponse(response, "returned-policy")) //
.flatMap(this::validateJson);
}
String inputJsonString = createInputJsonString(paramsJson);
logger.debug("POST deletePolicy inputJsonString = {}", inputJsonString);
- return restClient.post("/A1-ADAPTER-API:deletePolicy", inputJsonString);
+ return restClient.postWithAuthHeader("/A1-ADAPTER-API:deletePolicy", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD);
}
@Override
public Mono<A1ProtocolType> getProtocolVersion() {
return getPolicyTypeIdentities() //
- .flatMap(x -> Mono.just(A1ProtocolType.CONTROLLER));
+ .flatMap(x -> Mono.just(A1ProtocolType.SDNC_OSC));
}
private String createInputJsonString(JSONObject paramsJson) {
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 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.oransc.policyagent.clients;
+
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.oransc.policyagent.configuration.RicConfig;
+import org.oransc.policyagent.repository.Policy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class SdnrOnapA1Client implements A1Client {
+ private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private static final String A1_CONTROLLER_URL = "http://sdnc_controller_container:8181/restconf/operations";
+ private static final String A1_CONTROLLER_USERNAME = "admin";
+ private static final String A1_CONTROLLER_PASSWORD = "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U";
+
+ private final RicConfig ricConfig;
+ private final AsyncRestClient restClient;
+
+ public SdnrOnapA1Client(RicConfig ricConfig) {
+ this.ricConfig = ricConfig;
+ this.restClient = new AsyncRestClient(A1_CONTROLLER_URL);
+ logger.debug("SdnrOnapA1Client for ric: {}", this.ricConfig.name());
+ }
+
+ @Override
+ public Mono<List<String>> getPolicyTypeIdentities() {
+ JSONObject paramsJson = new JSONObject();
+ paramsJson.put("near-rt-ric-id", ricConfig.baseUrl());
+ String inputJsonString = createInputJsonString(paramsJson);
+ logger.debug("POST getPolicyTypeIdentities inputJsonString = {}", inputJsonString);
+
+ return restClient
+ .postWithAuthHeader("/A1-ADAPTER-API:getPolicyTypes", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD) //
+ .flatMap(response -> getValueFromResponse(response, "policy-type-id-list")) //
+ .flatMap(this::parseJsonArrayOfString);
+ }
+
+ @Override
+ public Mono<List<String>> getPolicyIdentities() {
+ return getPolicyTypeIdentities() //
+ .flatMapMany(types -> Flux.fromIterable(types)) //
+ .flatMap(type -> getPolicyIdentities(type)) //
+ .flatMap(policyIds -> Flux.fromIterable(policyIds)) //
+ .collectList();
+ }
+
+ public Mono<List<String>> getPolicyIdentities(String policyTypeId) {
+ JSONObject paramsJson = new JSONObject();
+ paramsJson.put("near-rt-ric-id", ricConfig.baseUrl());
+ paramsJson.put("policy-type-id", policyTypeId);
+ String inputJsonString = createInputJsonString(paramsJson);
+ logger.debug("POST getPolicyIdentities inputJsonString = {}", inputJsonString);
+
+ return restClient
+ .postWithAuthHeader("/A1-ADAPTER-API:getPolicyInstances", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD) //
+ .flatMap(response -> getValueFromResponse(response, "policy-instance-id-list")) //
+ .flatMap(this::parseJsonArrayOfString);
+ }
+
+ @Override
+ public Mono<String> getPolicyTypeSchema(String policyTypeId) {
+ JSONObject paramsJson = new JSONObject();
+ paramsJson.put("near-rt-ric-id", ricConfig.baseUrl());
+ paramsJson.put("policy-type-id", policyTypeId);
+ String inputJsonString = createInputJsonString(paramsJson);
+ logger.debug("POST getPolicyType inputJsonString = {}", inputJsonString);
+
+ return restClient
+ .postWithAuthHeader("/A1-ADAPTER-API:getPolicyType", inputJsonString, A1_CONTROLLER_USERNAME,
+ A1_CONTROLLER_PASSWORD) //
+ .flatMap(response -> getValueFromResponse(response, "policy-type")) //
+ .flatMap(this::extractPolicySchema);
+ }
+
+ @Override
+ public Mono<String> putPolicy(Policy policy) {
+ JSONObject paramsJson = new JSONObject();
+ paramsJson.put("near-rt-ric-id", ricConfig.baseUrl());
+ paramsJson.put("policy-instance-id", policy.id());
+ paramsJson.put("policy-type-id", policy.type().name());
+ paramsJson.put("policy-instance", policy.json());
+ paramsJson.put("properties", new JSONArray());
+ String inputJsonString = createInputJsonString(paramsJson);
+ logger.debug("POST putPolicy inputJsonString = {}", inputJsonString);
+
+ return restClient.postWithAuthHeader("/A1-ADAPTER-API:createPolicyInstance", inputJsonString,
+ A1_CONTROLLER_USERNAME, A1_CONTROLLER_PASSWORD);
+ }
+
+ public Mono<String> deletePolicy(String policyTypeId, String policyId) {
+ JSONObject paramsJson = new JSONObject();
+ paramsJson.put("near-rt-ric-id", ricConfig.baseUrl());
+ paramsJson.put("policy-instance-id", policyId);
+ paramsJson.put("policy-type-id", policyTypeId);
+ String inputJsonString = createInputJsonString(paramsJson);
+ logger.debug("POST deletePolicy inputJsonString = {}", inputJsonString);
+
+ return restClient.postWithAuthHeader("/A1-ADAPTER-API:deletePolicyInstance", inputJsonString,
+ A1_CONTROLLER_USERNAME, A1_CONTROLLER_PASSWORD);
+ }
+
+ @Override
+ public Mono<String> deletePolicy(Policy policy) {
+ return deletePolicy(policy.type().name(), policy.id());
+ }
+
+ @Override
+ public Flux<String> deleteAllPolicies() {
+ return getPolicyTypeIdentities() //
+ .flatMapMany(types -> Flux.fromIterable(types)) //
+ .flatMap(typeId -> deletePoliciesForType(typeId)); //
+ }
+
+ private Flux<String> deletePoliciesForType(String typeId) {
+ return getPolicyIdentities(typeId) //
+ .flatMapMany(policyIds -> Flux.fromIterable(policyIds)) //
+ .flatMap(policyId -> deletePolicy(typeId, policyId)); //
+ }
+
+ @Override
+ public Mono<A1ProtocolType> getProtocolVersion() {
+ return getPolicyTypeIdentities() //
+ .flatMap(x -> Mono.just(A1ProtocolType.SDNR_ONAP));
+ }
+
+ private String createInputJsonString(JSONObject paramsJson) {
+ JSONObject inputJson = new JSONObject();
+ inputJson.put("input", paramsJson);
+ return inputJson.toString();
+ }
+
+ private Mono<String> getValueFromResponse(String response, String key) {
+ logger.debug("A1 client: response = {}", response);
+ try {
+ JSONObject outputJson = new JSONObject(response);
+ JSONObject responseParams = outputJson.getJSONObject("output");
+ String value = responseParams.get(key).toString();
+ return Mono.just(value);
+ } catch (JSONException ex) { // invalid json
+ return Mono.error(ex);
+ }
+ }
+
+ private Mono<List<String>> parseJsonArrayOfString(String inputString) {
+ try {
+ List<String> arrayList = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(inputString);
+ for (int i = 0; i < jsonArray.length(); i++) {
+ arrayList.add(jsonArray.getString(i));
+ }
+ logger.debug("A1 client: received list = {}", arrayList);
+ return Mono.just(arrayList);
+ } catch (JSONException ex) { // invalid json
+ return Mono.error(ex);
+ }
+ }
+
+ private Mono<String> extractPolicySchema(String inputString) {
+ try {
+ JSONObject jsonObject = new JSONObject(inputString);
+ JSONObject schemaObject = jsonObject.getJSONObject("policySchema");
+ String schemaString = schemaObject.toString();
+ return Mono.just(schemaString);
+ } catch (JSONException ex) { // invalid json
+ return Mono.error(ex);
+ }
+ }
+}
@GetMapping("/policy_schemas")
@ApiOperation(value = "Returns policy type schema definitions")
- @ApiResponses(value = {@ApiResponse(code = 200, message = "Policy Types found")})
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = 200, message = "Policy schemas", response = String.class, responseContainer = "List")})
public ResponseEntity<String> getPolicySchemas(@RequestParam(name = "ric", required = false) String ricName) {
synchronized (this.policyTypes) {
if (ricName == null) {
@GetMapping("/policy_schema")
@ApiOperation(value = "Returns one policy type schema definition")
- @ApiResponses(value = {@ApiResponse(code = 200, message = "Policy Type found")})
+ @ApiResponses(value = {@ApiResponse(code = 200, message = "Policy schema", response = Object.class)})
public ResponseEntity<String> getPolicySchema(@RequestParam(name = "id", required = true) String id) {
try {
PolicyType type = policyTypes.getType(id);
@GetMapping("/policy_types")
@ApiOperation(value = "Returns policy types")
- @ApiResponses(value = {@ApiResponse(code = 200, message = "Policy Types found")})
+ @ApiResponses(
+ value = {@ApiResponse(
+ code = 200,
+ message = "Policy type names",
+ response = String.class,
+ responseContainer = "List")})
public ResponseEntity<String> getPolicyTypes(@RequestParam(name = "ric", required = false) String ricName) {
synchronized (this.policyTypes) {
if (ricName == null) {
}
@GetMapping("/policy")
- @ApiOperation(value = "Returns the policy")
+ @ApiOperation(value = "Returns a policy configuration") //
@ApiResponses(
- value = {@ApiResponse(code = 200, message = "Policy found"),
- @ApiResponse(code = 204, message = "Policy is not found")})
+ value = { //
+ @ApiResponse(code = 200, message = "Policy found", response = Object.class), //
+ @ApiResponse(code = 204, message = "Policy is not found")} //
+ )
+
public ResponseEntity<String> getPolicy( //
@RequestParam(name = "instance", required = true) String instance) {
try {
}
@DeleteMapping("/policy")
- @ApiOperation(value = "Deletes the policy")
- @ApiResponses(value = {@ApiResponse(code = 204, message = "Policy deleted")})
+ @ApiOperation(value = "Deletes the policy", response = Object.class)
+ @ApiResponses(value = {@ApiResponse(code = 204, message = "Policy deleted", response = Object.class)})
public Mono<ResponseEntity<Void>> deletePolicy( //
@RequestParam(name = "instance", required = true) String id) {
Policy policy = policies.get(id);
}
@PutMapping(path = "/policy")
- @ApiOperation(value = "Create the policy")
- @ApiResponses(value = {@ApiResponse(code = 201, message = "Policy created")})
+ @ApiOperation(value = "Put a policy", response = String.class)
+ @ApiResponses(value = {@ApiResponse(code = 200, message = "Policy created or updated")})
public Mono<ResponseEntity<String>> putPolicy( //
@RequestParam(name = "type", required = true) String typeName, //
@RequestParam(name = "instance", required = true) String instanceId, //
@RequestParam(name = "ric", required = true) String ricName, //
@RequestParam(name = "service", required = true) String service, //
- @RequestBody String jsonBody) {
+ @RequestBody Object jsonBody) {
+
+ String jsonString = gson.toJson(jsonBody);
Ric ric = rics.get(ricName);
PolicyType type = policyTypes.get(typeName);
if (ric != null && type != null && ric.getState() == Ric.RicState.IDLE) {
Policy policy = ImmutablePolicy.builder() //
.id(instanceId) //
- .json(jsonBody) //
+ .json(jsonString) //
.type(type) //
.ric(ric) //
.ownerServiceName(service) //
.flatMap(client -> client.putPolicy(policy)) //
.doOnNext(notUsed -> policies.put(policy)) //
.flatMap(notUsed -> {
- return Mono.just(new ResponseEntity<>(HttpStatus.CREATED));
+ return Mono.just(new ResponseEntity<>(HttpStatus.OK));
});
}
return Mono.just(new ResponseEntity<>(HttpStatus.NOT_FOUND));
@GetMapping("/policies")
@ApiOperation(value = "Returns the policies")
- @ApiResponses(value = {@ApiResponse(code = 200, message = "Policies found")})
+ @ApiResponses(
+ value = {
+ @ApiResponse(code = 200, message = "Policies", response = PolicyInfo.class, responseContainer = "List")})
public ResponseEntity<String> getPolicies( //
@RequestParam(name = "type", required = false) String type, //
@RequestParam(name = "ric", required = false) String ric, //
private String policiesToJson(Collection<Policy> policies) {
Vector<PolicyInfo> v = new Vector<>(policies.size());
for (Policy p : policies) {
- PolicyInfo policyInfo = ImmutablePolicyInfo.builder() //
- .json(p.json()) //
- .id(p.id()) //
- .ric(p.ric().name()) //
- .type(p.type().name()) //
- .service(p.ownerServiceName()) //
- .lastModified(p.lastModified()) //
- .build();
+ PolicyInfo policyInfo = new PolicyInfo();
+ policyInfo.id = p.id();
+ policyInfo.json = p.json();
+ policyInfo.ric = p.ric().name();
+ policyInfo.type = p.type().name();
+ policyInfo.service = p.ownerServiceName();
+ policyInfo.lastModified = p.lastModified();
+ if (!policyInfo.validate()) {
+ throw new RuntimeException("BUG, all fields must be set");
+ }
v.add(policyInfo);
}
return gson.toJson(v);
package org.oransc.policyagent.controllers;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
import org.immutables.gson.Gson;
-import org.immutables.value.Value;
-@Value.Immutable
@Gson.TypeAdapters
-interface PolicyInfo {
+@ApiModel(value = "PolicyInfo")
+public class PolicyInfo {
+
+ @ApiModelProperty(value = "identity of the policy")
+ public String id;
+
+ @ApiModelProperty(value = "name of the policy type")
+ public String type;
- public String id();
+ @ApiModelProperty(value = "identity the target NearRT RIC")
+ public String ric;
- public String type();
+ @ApiModelProperty(value = "the configuration of the policy")
+ public String json;
- public String ric();
+ @ApiModelProperty(value = "the name of the service owning the policy")
+ public String service;
- public String json();
+ @ApiModelProperty(value = "timestamp, last modification time")
+ public String lastModified;
- public String service();
+ PolicyInfo() {
+ }
- public String lastModified();
+ public boolean validate() {
+ return id != null && type != null && ric != null && json != null && service != null && lastModified != null;
+ }
}
package org.oransc.policyagent.controllers;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
import java.util.Collection;
import org.immutables.gson.Gson;
-import org.immutables.value.Value;
-@Value.Immutable
@Gson.TypeAdapters
-interface RicInfo {
+@ApiModel(value = "RicInfo")
+class RicInfo {
+ @ApiModelProperty(value = "identity of the ric")
+ public final String name;
- public String name();
+ @ApiModelProperty(value = "O1 identities for managed entities")
+ public final Collection<String> managedElementIds;
- public Collection<String> managedElementIds();
+ @ApiModelProperty(value = "supported policy types")
+ public final Collection<String> policyTypes;
- public Collection<String> policyTypes();
+ RicInfo(String name, Collection<String> managedElementIds, Collection<String> policyTypes) {
+ this.name = name;
+ this.managedElementIds = managedElementIds;
+ this.policyTypes = policyTypes;
+ }
}
* Example: http://localhost:8080/rics?managedElementId=kista_1
*/
@GetMapping("/ric")
- @ApiOperation(value = "Returns the name of a RIC managing one Mananged Element", response = String.class)
+ @ApiOperation(value = "Returns the name of a RIC managing one Mananged Element")
@ApiResponses(
value = { //
- @ApiResponse(code = 200, message = "RIC is fond"), //
- @ApiResponse(code = 404, message = "RIC is not fond") //
+ @ApiResponse(code = 200, message = "RIC is fond", response = String.class), //
+ @ApiResponse(code = 404, message = "RIC is not fond", response = String.class) //
})
public ResponseEntity<String> getRic(
@RequestParam(name = "managedElementId", required = false, defaultValue = "") String managedElementId) {
* Example: http://localhost:8080/ric
*/
@GetMapping("/rics")
- @ApiOperation(value = "Returns defined NearRT RIC:s as Json", response = RicInfo.class)
+ @ApiOperation(value = "Returns NearRT RIC information")
@ApiResponses(
value = { //
- @ApiResponse(code = 200, message = "OK", response = RicInfo.class) //
+ @ApiResponse(code = 200, message = "OK", response = RicInfo.class, responseContainer = "List") //
})
public ResponseEntity<String> getRics(
@RequestParam(name = "policyType", required = false) String supportingPolicyType) {
synchronized (rics) {
for (Ric ric : rics.getRics()) {
if (supportingPolicyType == null || ric.isSupportingType(supportingPolicyType)) {
- result.add(ImmutableRicInfo.builder() //
- .name(ric.name()) //
- .managedElementIds(ric.getManagedElementIds()) //
- .policyTypes(ric.getSupportedPolicyTypeNames()) //
- .build());
+ result.add(new RicInfo(ric.name(), ric.getManagedElementIds(), ric.getSupportedPolicyTypeNames()));
}
}
}
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
}
@GetMapping("/services")
- @ApiOperation(value = "Returns service information", response = ServiceStatus.class)
- @ApiResponses(value = {@ApiResponse(code = 200, message = "OK")})
+ @ApiOperation(value = "Returns service information")
+ @ApiResponses(
+ value = {@ApiResponse(code = 200, message = "OK", response = ServiceStatus.class, responseContainer = "List")})
public ResponseEntity<String> getServices( //
@RequestParam(name = "name", required = false) String name) {
}
private ServiceStatus toServiceStatus(Service s) {
- return ImmutableServiceStatus.builder() //
- .name(s.getName()) //
- .keepAliveInterval(s.getKeepAliveInterval().toSeconds()) //
- .timeSincePing(s.timeSinceLastPing().toSeconds()) //
- .build();
+ return new ServiceStatus(s.getName(), s.getKeepAliveInterval().toSeconds(), s.timeSinceLastPing().toSeconds());
}
+ @ApiOperation(value = "Register a service")
+ @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = String.class)})
@PutMapping("/service")
public ResponseEntity<String> putService( //
- @RequestBody String jsonBody) {
+ @RequestBody ServiceRegistrationInfo registrationInfo) {
try {
- ServiceRegistrationInfo s = gson.fromJson(jsonBody, ImmutableServiceRegistrationInfo.class);
- this.services.put(toService(s));
+ this.services.put(toService(registrationInfo));
return new ResponseEntity<String>("OK", HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<String>(e.getMessage(), HttpStatus.NO_CONTENT);
}
}
+ @ApiOperation(value = "Delete a service")
+ @ApiResponses(value = {@ApiResponse(code = 200, message = "OK")})
@DeleteMapping("/services")
public ResponseEntity<String> deleteService( //
@RequestParam(name = "name", required = true) String name) {
}
}
+ @ApiOperation(value = "Keep the poilicies alive for a service")
+ @ApiResponses(
+ value = {@ApiResponse(code = 200, message = "Policies timeout supervision refreshed"),
+ @ApiResponse(code = 404, message = "The service is not found, needs re-registration")})
+ @PostMapping("/services/keepalive")
+ public ResponseEntity<String> keepAliveService( //
+ @RequestParam(name = "name", required = true) String name) {
+ try {
+ services.getService(name).ping();
+ return new ResponseEntity<String>("OK", HttpStatus.OK);
+ } catch (Exception e) {
+ return new ResponseEntity<String>(e.getMessage(), HttpStatus.NOT_FOUND);
+ }
+ }
+
private Service removeService(String name) throws ServiceException {
synchronized (this.services) {
Service service = this.services.getService(name);
}
private Service toService(ServiceRegistrationInfo s) {
- return new Service(s.name(), Duration.ofSeconds(s.keepAliveInterval()), s.callbackUrl());
+ return new Service(s.name, Duration.ofSeconds(s.keepAliveIntervalSeconds), s.callbackUrl);
}
}
package org.oransc.policyagent.controllers;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
import org.immutables.gson.Gson;
-import org.immutables.value.Value;
-@Value.Immutable
@Gson.TypeAdapters
-public interface ServiceRegistrationInfo {
+@ApiModel(value = "ServiceRegistrationInfo")
+public class ServiceRegistrationInfo {
+
+ @ApiModelProperty(value = "identity of the service")
+ public String name;
+
+ @ApiModelProperty(
+ value = "keep alive interval for policies owned by the service. 0 means no timeout supervision."
+ + " Polcies that are not refreshed within this time are removed")
+ public long keepAliveIntervalSeconds;
- public String name();
+ @ApiModelProperty(value = "callback for notifying of RIC recovery")
+ public String callbackUrl;
- public long keepAliveInterval();
+ public ServiceRegistrationInfo() {
+ }
- public String callbackUrl();
+ public ServiceRegistrationInfo(String name, long keepAliveIntervalSeconds, String callbackUrl) {
+ this.name = name;
+ this.keepAliveIntervalSeconds = keepAliveIntervalSeconds;
+ this.callbackUrl = callbackUrl;
+ }
}
package org.oransc.policyagent.controllers;
-import com.google.gson.annotations.SerializedName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import org.immutables.gson.Gson;
-import org.immutables.value.Value;
-@Value.Immutable
@Gson.TypeAdapters
-public interface ServiceStatus {
+@ApiModel(value = "ServiceStatus")
+public class ServiceStatus {
- @SerializedName("name")
- public String name();
+ @ApiModelProperty(value = "identity of the service")
+ public final String name;
- @SerializedName("keepAlive")
- public long keepAliveInterval();
+ @ApiModelProperty(value = "policy keep alive timeout")
+ public final long keepAliveIntervalSeconds;
- @SerializedName("timeSincePing")
- public long timeSincePing();
+ @ApiModelProperty(value = "time since last invocation by the service")
+ public final long timeSincePingSeconds;
+
+ ServiceStatus(String name, long keepAliveIntervalSeconds, long timeSincePingSeconds) {
+ this.name = name;
+ this.keepAliveIntervalSeconds = keepAliveIntervalSeconds;
+ this.timeSincePingSeconds = timeSincePingSeconds;
+ }
}
@ApiOperation(value = "Returns status and statistics of the service")
@ApiResponses(
value = { //
- @ApiResponse(code = 200, message = "Service is living") //
+ @ApiResponse(code = 200, message = "Service is living", response = String.class) //
})
public Mono<ResponseEntity<String>> getStatus() {
Mono<ResponseEntity<String>> response = Mono.just(new ResponseEntity<>("hunky dory", HttpStatus.OK));
return this.keepAliveInterval;
}
- private synchronized void ping() {
+ public synchronized void ping() {
this.lastPing = Instant.now();
}
public synchronized boolean isExpired() {
- return timeSinceLastPing().compareTo(this.keepAliveInterval) > 0;
+ return this.keepAliveInterval.getSeconds() > 0 && timeSinceLastPing().compareTo(this.keepAliveInterval) > 0;
}
public synchronized Duration timeSinceLastPing() {
package org.oransc.policyagent;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.oransc.policyagent.configuration.ApplicationConfig;
import org.oransc.policyagent.configuration.ImmutableRicConfig;
import org.oransc.policyagent.configuration.RicConfig;
-import org.oransc.policyagent.controllers.ImmutableServiceRegistrationInfo;
-import org.oransc.policyagent.controllers.ImmutableServiceStatus;
+import org.oransc.policyagent.controllers.PolicyInfo;
import org.oransc.policyagent.controllers.ServiceRegistrationInfo;
import org.oransc.policyagent.controllers.ServiceStatus;
import org.oransc.policyagent.exceptions.ServiceException;
import org.oransc.policyagent.repository.PolicyType;
import org.oransc.policyagent.repository.PolicyTypes;
import org.oransc.policyagent.repository.Ric;
+import org.oransc.policyagent.repository.Ric.RicState;
import org.oransc.policyagent.repository.Rics;
import org.oransc.policyagent.repository.Services;
import org.oransc.policyagent.tasks.RepositorySupervision;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatus.Series;
+import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.ClientHttpResponse;
import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
@ExtendWith(SpringExtension.class)
private final RestTemplate restTemplate = new RestTemplate();
+ public class RestTemplateResponseErrorHandler implements ResponseErrorHandler {
+
+ @Override
+ public boolean hasError(ClientHttpResponse httpResponse) throws IOException {
+ return (httpResponse.getStatusCode().series() == Series.CLIENT_ERROR
+ || httpResponse.getStatusCode().series() == Series.SERVER_ERROR);
+ }
+
+ @Override
+ public void handleError(ClientHttpResponse httpResponse) throws IOException {
+ System.out.println("Error " + httpResponse.toString());
+ }
+ }
+
private void reset() {
rics.clear();
policies.clear();
policyTypes.clear();
assertThat(policies.size()).isEqualTo(0);
+ restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
}
@Test
Policy policy = addPolicy("policyId", "typeName", "service", "ric"); // This should be created in the RIC
supervision.checkAllRics(); // The created policy should be put in the RIC
+ await().untilAsserted(() -> RicState.IDLE.equals(rics.getRic("ric").getState()));
+
Policies ricPolicies = getA1Client("ric").getPolicies();
assertThat(ricPolicies.size()).isEqualTo(1);
Policy ricPolicy = ricPolicies.get("policyId");
String rsp = this.restTemplate.getForObject(url, String.class);
System.out.println(rsp);
-
assertThat(rsp).isEqualTo("ric1");
}
@Test
public void testPutPolicy() throws Exception {
+ reset();
putService("service1");
+ addPolicyType("type1", "ric1");
String url = baseUrl() + "/policy?type=type1&instance=instance1&ric=ric1&service=service1";
- String json = "{}";
- addPolicyType("type1", "ric1");
+ final String json = jsonString();
this.rics.getRic("ric1").setState(Ric.RicState.IDLE);
- this.restTemplate.put(url, json);
-
+ this.restTemplate.put(url, createJsonHttpEntity(json));
Policy policy = policies.getPolicy("instance1");
assertThat(policy).isNotNull();
return ric;
}
+ private String createServiceJson(String name) {
+ ServiceRegistrationInfo service = new ServiceRegistrationInfo(name, 1, "callbackUrl");
+
+ String json = gson.toJson(service);
+ return json;
+ }
+
+ HttpEntity<String> createJsonHttpEntity(String content) {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ return new HttpEntity<String>(content, headers);
+ }
+
+ private void putService(String name) {
+ String url = baseUrl() + "/service";
+ HttpEntity<String> entity = createJsonHttpEntity(createServiceJson(name));
+ this.restTemplate.put(url, entity);
+ }
+
+ private String jsonString() {
+ return "{\n \"servingCellNrcgi\": \"1\"\n }";
+ }
+
private Policy addPolicy(String id, String typeName, String service, String ric) throws ServiceException {
addRic(ric);
Policy p = ImmutablePolicy.builder().id(id) //
- .json("{}") //
+ .json(jsonString()) //
.ownerServiceName(service) //
.ric(rics.getRic(ric)) //
.type(addPolicyType(typeName, ric)) //
public void testGetPolicies() throws Exception {
String url = baseUrl() + "/policies";
addPolicy("id1", "type1", "service1");
- addPolicy("id2", "type2", "service2");
String rsp = this.restTemplate.getForObject(url, String.class);
System.out.println(rsp);
- assertThat(rsp).contains("id1");
- assertThat(rsp).contains("id2");
+ List<PolicyInfo> info = parseList(rsp, PolicyInfo.class);
+ assertThat(info).size().isEqualTo(1);
+ PolicyInfo policyInfo = info.get(0);
+ assert (policyInfo.validate());
+ assertThat(policyInfo.id).isEqualTo("id1");
+ assertThat(policyInfo.type).isEqualTo("type1");
+ assertThat(policyInfo.service).isEqualTo("service1");
}
@Test
assertFalse(rsp.contains("id3"));
}
- private String createServiceJson(String name) {
- ServiceRegistrationInfo service = ImmutableServiceRegistrationInfo.builder() //
- .keepAliveInterval(1) //
- .name(name) //
- .callbackUrl("callbackUrl") //
- .build();
- String json = gson.toJson(service);
- return json;
- }
-
- private void putService(String name) {
- String url = baseUrl() + "/service";
- this.restTemplate.put(url, createServiceJson(name));
- }
-
@Test
public void testPutAndGetService() throws Exception {
+ reset();
// PUT
putService("name");
// GET
String url = baseUrl() + "/services?name=name";
String rsp = this.restTemplate.getForObject(url, String.class);
- List<ImmutableServiceStatus> info = parseList(rsp, ImmutableServiceStatus.class);
+ List<ServiceStatus> info = parseList(rsp, ServiceStatus.class);
assertThat(info.size() == 1);
ServiceStatus status = info.iterator().next();
- assertThat(status.keepAliveInterval() == 1);
- assertThat(status.name().equals("name"));
+ assertThat(status.keepAliveIntervalSeconds == 1);
+ assertThat(status.name.equals("name"));
// GET (all)
url = baseUrl() + "/services";
assertThat(rsp.contains("name"));
System.out.println(rsp);
+ // Keep alive
+ url = baseUrl() + "/services/keepalive?name=name";
+ rsp = this.restTemplate.postForObject(url, null, String.class);
+ assertThat(rsp.contains("OK"));
+
// DELETE
assertThat(services.size() == 1);
url = baseUrl() + "/services?name=name";
this.restTemplate.delete(url);
assertThat(services.size() == 0);
+
+ // Keep alive, no registerred service
+ url = baseUrl() + "/services/keepalive?name=nameXXX";
+ ResponseEntity<String> entity = this.restTemplate.postForEntity(url, null, String.class);
+ assertThat(entity.getStatusCode().equals(HttpStatus.NOT_FOUND));
}
private static <T> List<T> parseList(String jsonString, Class<T> clazz) {
return getOrCreateA1Client(ric.name());
}
- @Override
- protected A1Client createControllerA1Client(Ric ric) {
- return getOrCreateA1Client(ric.name());
- }
-
public MockA1Client getOrCreateA1Client(String ricName) {
if (!clients.containsKey(ricName)) {
logger.debug("Creating client for RIC: {}", ricName);