Added status controller
Change-Id: I6ee63a6d9a0cb5b0003a8f2b907abdcc14374faf
Issue-ID: NONRTRIC-173
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
diff --git a/enrichment-coordinator-service/docs/api.json b/enrichment-coordinator-service/docs/api.json
index e4f7660..76be3a4 100644
--- a/enrichment-coordinator-service/docs/api.json
+++ b/enrichment-coordinator-service/docs/api.json
@@ -285,6 +285,22 @@
}],
"tags": ["Enrichment Data Producer API"]
}},
+ "/status": {"get": {
+ "summary": "Returns status and statistics of this service",
+ "deprecated": false,
+ "produces": ["application/json"],
+ "operationId": "getStatusUsingGET",
+ "responses": {
+ "200": {
+ "schema": {"$ref": "#/definitions/status_info"},
+ "description": "Service is living"
+ },
+ "401": {"description": "Unauthorized"},
+ "403": {"description": "Forbidden"},
+ "404": {"description": "Not Found"}
+ },
+ "tags": ["Service status"]
+ }},
"/producer_simulator/job_created_error": {"post": {
"summary": "Callback for EI job creation, returns error",
"deprecated": false,
@@ -554,7 +570,7 @@
"consumes": ["application/json"]
}}
},
- "host": "localhost:43453",
+ "host": "localhost:40973",
"definitions": {
"EiType": {
"description": "Information for an EI type",
@@ -652,6 +668,31 @@
}
}
},
+ "status_info": {
+ "type": "object",
+ "title": "status_info",
+ "properties": {
+ "no_of_producers": {
+ "format": "int32",
+ "description": "Number of EI producers",
+ "type": "integer"
+ },
+ "no_of_jobs": {
+ "format": "int32",
+ "description": "Number of EI jobs",
+ "type": "integer"
+ },
+ "no_of_types": {
+ "format": "int32",
+ "description": "Number of EI types",
+ "type": "integer"
+ },
+ "status": {
+ "description": "status text",
+ "type": "string"
+ }
+ }
+ },
"EiJobStatus": {
"description": "Status for an EI Job",
"type": "object",
@@ -749,6 +790,10 @@
{
"name": "Producer Simulator",
"description": "Producer Simulator Controller"
+ },
+ {
+ "name": "Service status",
+ "description": "Status Controller"
}
]
}
\ No newline at end of file
diff --git a/enrichment-coordinator-service/docs/api.yaml b/enrichment-coordinator-service/docs/api.yaml
index f3fa767..48a65dd 100644
--- a/enrichment-coordinator-service/docs/api.yaml
+++ b/enrichment-coordinator-service/docs/api.yaml
@@ -317,6 +317,26 @@
required: true
tags:
- Enrichment Data Producer API
+ /status:
+ get:
+ summary: Returns status and statistics of this service
+ deprecated: false
+ produces:
+ - application/json
+ operationId: getStatusUsingGET
+ responses:
+ '200':
+ schema:
+ $ref: '#/definitions/status_info'
+ description: Service is living
+ '401':
+ description: Unauthorized
+ '403':
+ description: Forbidden
+ '404':
+ description: Not Found
+ tags:
+ - Service status
/producer_simulator/job_created_error:
post:
summary: 'Callback for EI job creation, returns error'
@@ -599,7 +619,7 @@
- Producer Simulator
consumes:
- application/json
-host: 'localhost:43453'
+host: 'localhost:40973'
definitions:
EiType:
description: Information for an EI type
@@ -677,6 +697,25 @@
ei_job_data_schema:
description: Json schema for the job data
type: object
+ status_info:
+ type: object
+ title: status_info
+ properties:
+ no_of_producers:
+ format: int32
+ description: Number of EI producers
+ type: integer
+ no_of_jobs:
+ format: int32
+ description: Number of EI jobs
+ type: integer
+ no_of_types:
+ format: int32
+ description: Number of EI types
+ type: integer
+ status:
+ description: status text
+ type: string
EiJobStatus:
description: Status for an EI Job
type: object
@@ -761,4 +800,6 @@
description: Producer Controller
- name: Producer Simulator
description: Producer Simulator Controller
+ - name: Service status
+ description: Status Controller
diff --git a/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/StatusController.java b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/StatusController.java
new file mode 100644
index 0000000..a210aa5
--- /dev/null
+++ b/enrichment-coordinator-service/src/main/java/org/oransc/enrichment/controllers/StatusController.java
@@ -0,0 +1,99 @@
+/*-
+ * ========================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.oransc.enrichment.controllers;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import org.immutables.gson.Gson;
+import org.oransc.enrichment.repository.EiJobs;
+import org.oransc.enrichment.repository.EiProducers;
+import org.oransc.enrichment.repository.EiTypes;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+
+@RestController("StatusController")
+@Api(tags = "Service status")
+public class StatusController {
+
+ @Autowired
+ private EiJobs eiJobs;
+
+ @Autowired
+ private EiTypes eiTypes;
+
+ @Autowired
+ private EiProducers eiProducers;
+
+ @Gson.TypeAdapters
+ @ApiModel(value = "status_info")
+ public static class StatusInfo {
+ @ApiModelProperty(value = "status text")
+ @SerializedName("status")
+ @JsonProperty(value = "status", required = true)
+ public final String status;
+
+ @ApiModelProperty(value = "Number of EI producers")
+ @SerializedName("no_of_producers")
+ @JsonProperty(value = "no_of_producers", required = true)
+ public final int noOfProducers;
+
+ @ApiModelProperty(value = "Number of EI types")
+ @SerializedName("no_of_types")
+ @JsonProperty(value = "no_of_types", required = true)
+ public final int noOfTypes;
+
+ @ApiModelProperty(value = "Number of EI jobs")
+ @SerializedName("no_of_jobs")
+ @JsonProperty(value = "no_of_jobs", required = true)
+ public final int noOfJobs;
+
+ public StatusInfo(String status, EiProducers producers, EiTypes types, EiJobs jobs) {
+ this.status = status;
+ this.noOfJobs = jobs.size();
+ this.noOfProducers = producers.size();
+ this.noOfTypes = types.size();
+ }
+ }
+
+ @GetMapping(path = "/status", produces = MediaType.APPLICATION_JSON_VALUE)
+ @ApiOperation(value = "Returns status and statistics of this service")
+ @ApiResponses(value = { //
+ @ApiResponse(code = 200, message = "Service is living", response = StatusInfo.class) //
+ })
+ public Mono<ResponseEntity<Object>> getStatus() {
+ StatusInfo info = new StatusInfo("hunky dory", this.eiProducers, this.eiTypes, this.eiJobs);
+ return Mono.just(new ResponseEntity<>(info, HttpStatus.OK));
+ }
+
+}
diff --git a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java
index 67b0d8a..d8a0b32 100644
--- a/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java
+++ b/enrichment-coordinator-service/src/test/java/org/oransc/enrichment/ApplicationTest.java
@@ -82,10 +82,9 @@
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
-@TestPropertySource(
- properties = { //
+@TestPropertySource(properties = { //
"server.ssl.key-store=./config/keystore.jks", //
- "app.webclient.trust-store=./config/truststore.jks"})
+ "app.webclient.trust-store=./config/truststore.jks" })
class ApplicationTest {
private final String EI_TYPE_ID = "typeId";
private final String EI_PRODUCER_ID = "producerId";
@@ -113,8 +112,8 @@
ProducerSupervision producerSupervision;
private static Gson gson = new GsonBuilder() //
- .serializeNulls() //
- .create(); //
+ .serializeNulls() //
+ .create(); //
/**
* Overrides the BeanFactory.
@@ -284,8 +283,8 @@
String url = ConsumerConsts.API_ROOT + "/eitypes/typeId/eijobs/jobId";
// The element with name "property1" is mandatory in the schema
- ConsumerEiJobInfo jobInfo =
- new ConsumerEiJobInfo(jsonObject("{ \"XXstring\" : \"value\" }"), "owner", "targetUri");
+ ConsumerEiJobInfo jobInfo = new ConsumerEiJobInfo(jsonObject("{ \"XXstring\" : \"value\" }"), "owner",
+ "targetUri");
String body = gson.toJson(jobInfo);
testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT, "Json validation failure");
@@ -329,7 +328,7 @@
String url = ConsumerConsts.API_ROOT + "/eitypes/typeId2/eijobs/jobId";
String body = gson.toJson(eiJobInfo());
testErrorCode(restClient().put(url, body), HttpStatus.CONFLICT,
- "Not allowed to change type for existing EI job");
+ "Not allowed to change type for existing EI job");
}
@Test
@@ -448,7 +447,7 @@
}
private void assertProducerOpState(String producerId,
- ProducerStatusInfo.OperationalState expectedOperationalState) {
+ ProducerStatusInfo.OperationalState expectedOperationalState) {
String statusUrl = ProducerConsts.API_ROOT + "/eiproducers/" + producerId + "/status";
ResponseEntity<String> resp = restClient().getForEntity(statusUrl).block();
ProducerStatusInfo statusInfo = gson.fromJson(resp.getBody(), ProducerStatusInfo.class);
@@ -474,29 +473,39 @@
assertThat(this.eiTypes.size()).isEqualTo(0);
}
+ @Test
+ void testGetStatus() throws JsonMappingException, JsonProcessingException, ServiceException {
+ putEiProducerWithOneTypeRejecting("simulateProducerError", EI_TYPE_ID);
+ putEiProducerWithOneTypeRejecting("simulateProducerError2", EI_TYPE_ID);
+
+ String url = "/status";
+ ResponseEntity<String> resp = restClient().getForEntity(url).block();
+ assertThat(resp.getBody()).contains("hunky dory");
+ }
+
ProducerEiTypeRegistrationInfo producerEiTypeRegistrationInfo(String typeId)
- throws JsonMappingException, JsonProcessingException {
+ throws JsonMappingException, JsonProcessingException {
return new ProducerEiTypeRegistrationInfo(jsonSchemaObject(), typeId);
}
ProducerRegistrationInfo producerEiRegistratioInfoRejecting(String typeId)
- throws JsonMappingException, JsonProcessingException {
+ throws JsonMappingException, JsonProcessingException {
Collection<ProducerEiTypeRegistrationInfo> types = new ArrayList<>();
types.add(producerEiTypeRegistrationInfo(typeId));
return new ProducerRegistrationInfo(types, //
- baseUrl() + ProducerSimulatorController.JOB_CREATED_ERROR_URL,
- baseUrl() + ProducerSimulatorController.JOB_DELETED_ERROR_URL,
- baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL);
+ baseUrl() + ProducerSimulatorController.JOB_CREATED_ERROR_URL,
+ baseUrl() + ProducerSimulatorController.JOB_DELETED_ERROR_URL,
+ baseUrl() + ProducerSimulatorController.SUPERVISION_ERROR_URL);
}
ProducerRegistrationInfo producerEiRegistratioInfo(String typeId)
- throws JsonMappingException, JsonProcessingException {
+ throws JsonMappingException, JsonProcessingException {
Collection<ProducerEiTypeRegistrationInfo> types = new ArrayList<>();
types.add(producerEiTypeRegistrationInfo(typeId));
return new ProducerRegistrationInfo(types, //
- baseUrl() + ProducerSimulatorController.JOB_CREATED_URL,
- baseUrl() + ProducerSimulatorController.JOB_DELETED_URL,
- baseUrl() + ProducerSimulatorController.SUPERVISION_URL);
+ baseUrl() + ProducerSimulatorController.JOB_CREATED_URL,
+ baseUrl() + ProducerSimulatorController.JOB_DELETED_URL,
+ baseUrl() + ProducerSimulatorController.SUPERVISION_URL);
}
ConsumerEiJobInfo eiJobInfo() throws JsonMappingException, JsonProcessingException {
@@ -514,17 +523,17 @@
Object jsonSchemaObject() {
// a json schema with one mandatory property named "string"
String schemaStr = "{" //
- + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," //
- + "\"type\": \"object\"," //
- + "\"properties\": {" //
- + EI_JOB_PROPERTY + " : {" //
- + " \"type\": \"string\"" //
- + " }" //
- + "}," //
- + "\"required\": [" //
- + EI_JOB_PROPERTY //
- + "]" //
- + "}"; //
+ + "\"$schema\": \"http://json-schema.org/draft-04/schema#\"," //
+ + "\"type\": \"object\"," //
+ + "\"properties\": {" //
+ + EI_JOB_PROPERTY + " : {" //
+ + " \"type\": \"string\"" //
+ + " }" //
+ + "}," //
+ + "\"required\": [" //
+ + EI_JOB_PROPERTY //
+ + "]" //
+ + "}"; //
return jsonObject(schemaStr);
}
@@ -533,7 +542,7 @@
}
private EiJob putEiJob(String eiTypeId, String jobId)
- throws JsonMappingException, JsonProcessingException, ServiceException {
+ throws JsonMappingException, JsonProcessingException, ServiceException {
String url = ConsumerConsts.API_ROOT + "/eitypes/" + eiTypeId + "/eijobs/" + jobId;
String body = gson.toJson(eiJobInfo());
@@ -543,7 +552,7 @@
}
private EiType putEiProducerWithOneTypeRejecting(String producerId, String eiTypeId)
- throws JsonMappingException, JsonProcessingException, ServiceException {
+ throws JsonMappingException, JsonProcessingException, ServiceException {
String url = ProducerConsts.API_ROOT + "/eiproducers/" + producerId;
String body = gson.toJson(producerEiRegistratioInfoRejecting(eiTypeId));
@@ -552,7 +561,7 @@
}
private EiType putEiProducerWithOneType(String producerId, String eiTypeId)
- throws JsonMappingException, JsonProcessingException, ServiceException {
+ throws JsonMappingException, JsonProcessingException, ServiceException {
String url = ProducerConsts.API_ROOT + "/eiproducers/" + producerId;
String body = gson.toJson(producerEiRegistratioInfo(eiTypeId));
@@ -567,14 +576,14 @@
private AsyncRestClient restClient(boolean useTrustValidation) {
WebClientConfig config = this.applicationConfig.getWebClientConfig();
config = ImmutableWebClientConfig.builder() //
- .keyStoreType(config.keyStoreType()) //
- .keyStorePassword(config.keyStorePassword()) //
- .keyStore(config.keyStore()) //
- .keyPassword(config.keyPassword()) //
- .isTrustStoreUsed(useTrustValidation) //
- .trustStore(config.trustStore()) //
- .trustStorePassword(config.trustStorePassword()) //
- .build();
+ .keyStoreType(config.keyStoreType()) //
+ .keyStorePassword(config.keyStorePassword()) //
+ .keyStore(config.keyStore()) //
+ .keyPassword(config.keyPassword()) //
+ .isTrustStoreUsed(useTrustValidation) //
+ .trustStore(config.trustStore()) //
+ .trustStorePassword(config.trustStorePassword()) //
+ .build();
return new AsyncRestClient(baseUrl(), config);
}
@@ -588,16 +597,16 @@
}
private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains,
- boolean expectApplicationProblemJsonMediaType) {
+ boolean expectApplicationProblemJsonMediaType) {
StepVerifier.create(request) //
- .expectSubscription() //
- .expectErrorMatches(
- t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) //
- .verify();
+ .expectSubscription() //
+ .expectErrorMatches(
+ t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType)) //
+ .verify();
}
private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains,
- boolean expectApplicationProblemJsonMediaType) {
+ boolean expectApplicationProblemJsonMediaType) {
assertTrue(throwable instanceof WebClientResponseException);
WebClientResponseException responseException = (WebClientResponseException) throwable;
assertThat(responseException.getStatusCode()).isEqualTo(expStatus);