A1-PMS, graceful shutdown 94/132894/2
authorPatrikBuhr <patrik.buhr@est.tech>
Mon, 28 Nov 2022 08:40:36 +0000 (09:40 +0100)
committerPatrikBuhr <patrik.buhr@est.tech>
Wed, 11 Jan 2023 10:10:35 +0000 (11:10 +0100)
Support for granceful shutdown via signal "SIGTERM"
and via calling REST POST /actuator/shutdown

Issue-ID: CCSDK-3830
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
Change-Id: Ibc71cd8a2c9f44ec844ab49c8f225ae128549776

24 files changed:
a1-policy-management/api/pms-api.json
a1-policy-management/api/pms-api.yaml
a1-policy-management/config/application.yaml
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/Application.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/SwaggerConfig.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/aspect/LogAspect.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ConfigurationFile.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/datastore/S3ObjectStore.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageHandler.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/exceptions/GlobalExceptionHandler.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Lock.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Ric.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Services.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervision.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTask.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/ServiceSupervision.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/MockPolicyManagementService.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java
docs/offeredapis/swagger/pms-api.json
docs/offeredapis/swagger/pms-api.yaml

index ce2d9aa..b8a9b95 100644 (file)
             ],
             "tags": ["NearRT-RIC Repository"]
         }},
+        "/actuator/shutdown": {"post": {
+            "summary": "Actuator web endpoint 'shutdown'",
+            "operationId": "shutdown",
+            "responses": {"200": {
+                "description": "OK",
+                "content": {"*/*": {
+                    "schema": {
+                        "type": "object",
+                        "example": null
+                    },
+                    "example": null
+                }}
+            }},
+            "tags": ["Actuator"]
+        }},
         "/a1-policy/v2/policy-types": {"get": {
             "summary": "Query policy type identities",
             "operationId": "getPolicyTypes",
     },
     "info": {
         "license": {
-            "name": "Copyright (C) 2020-2022 Nordix Foundation. Licensed under the Apache License.",
+            "name": "Copyright (C) 2020-2023 Nordix Foundation. Licensed under the Apache License.",
             "url": "http://www.apache.org/licenses/LICENSE-2.0"
         },
-        "description": "<h2>General<\/h2><p>The O-RAN Non-RT RIC Policy Management Service provides a REST API for management of A1 policies. <br/>The main tasks of the service are:<\/p><ul><li>A1 Policy creation, modification and deletion.<\/li><li>Monitoring and maintaining consistency of the SMO view of A1 policies and the Near-RT RICs<\/li><li>Maintaining a view of supported Near-RT RIC policy types<\/li><li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.<\/li><\/ul><h2>APIs provided by the service<\/h2><h3>A1 Policy Management<\/h3><p>This is an API for management of A1 Policies.<\/p><ul><li>A1 Policy retrieval, creation, modification and deletion.<\/li><li>Retrieval of supported A1 Policy types for a Near-RT RIC<\/li><li>Retrieval of status for existing A1 policies<\/li><\/ul><h3>Management of configuration<\/h3><p>API for updating and retrieval of the component configuration. Note that there other ways to maintain the configuration.<\/p><h3>Callbacks<\/h3><p>These are endpoints that are invoked by this service. The callbacks are registered in this service at service registration.<\/p><h3>NearRT-RIC Repository<\/h3><p>This is an API that provides support for looking up a NearRT-RIC. Each A1 policy is targeted for one Near-RT RIC.<\/p><h3>Health Check<\/h3><p>API used for supervision of the PMS component.<\/p><h3>Service Registry and Supervision<\/h3><p>API used for registering services that uses PMS. Each A1 policy is optionally owned by a service. PMS can supervise each registered service by a heart-beat supervision and will automatically remove policies for unavailable services. Note that a service does not need to be registered in order to create A1 Policies. This is a feature that is optional to use.<\/p>",
+        "description": "<h2>General<\/h2><p>The O-RAN Non-RT RIC Policy Management Service provides a REST API for management of A1 policies. <br/>The main tasks of the service are:<\/p><ul><li>A1 Policy creation, modification and deletion.<\/li><li>Monitoring and maintaining consistency of the SMO view of A1 policies and the Near-RT RICs<\/li><li>Maintaining a view of supported Near-RT RIC policy types<\/li><li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.<\/li><\/ul><h2>APIs provided by the service<\/h2><h3>A1 Policy Management<\/h3><p>This is an API for management of A1 Policies.<\/p><ul><li>A1 Policy retrieval, creation, modification and deletion.<\/li><li>Retrieval of supported A1 Policy types for a Near-RT RIC<\/li><li>Retrieval of status for existing A1 policies<\/li><\/ul><h3>Management of configuration<\/h3><p>API for updating and retrieval of the component configuration. Note that there other ways to maintain the configuration.<\/p><h3>Callbacks<\/h3><p>These are endpoints that are invoked by this service. The callbacks are registered in this service at service registration.<\/p><h3>NearRT-RIC Repository<\/h3><p>This is an API that provides support for looking up a NearRT-RIC. Each A1 policy is targeted for one Near-RT RIC.<\/p><h3>Health Check<\/h3><p>API used for supervision of the PMS component.<\/p><h3>Service Registry and Supervision<\/h3><p>API used for registering services that uses PMS. Each A1 policy is optionally owned by a service. PMS can supervise each registered service by a heart-beat supervision and will automatically remove policies for unavailable services. Note that a service does not need to be registered in order to create A1 Policies. This is a feature that is optional to use.<\/p><h3>Spring Boot Actuator<\/h3><p>Provides generic functions  used to monitor and manage the Spring web application.<\/p>",
         "title": "A1 Policy Management Service",
         "version": "1.1.0"
     },
index 6d620c2..2c692de 100644 (file)
@@ -21,9 +21,11 @@ info:
     Each A1 policy is optionally owned by a service. PMS can supervise each registered
     service by a heart-beat supervision and will automatically remove policies for
     unavailable services. Note that a service does not need to be registered in order
-    to create A1 Policies. This is a feature that is optional to use.</p>
+    to create A1 Policies. This is a feature that is optional to use.</p><h3>Spring
+    Boot Actuator</h3><p>Provides generic functions  used to monitor and manage the
+    Spring web application.</p>
   license:
-    name: Copyright (C) 2020-2022 Nordix Foundation. Licensed under the Apache License.
+    name: Copyright (C) 2020-2023 Nordix Foundation. Licensed under the Apache License.
     url: http://www.apache.org/licenses/LICENSE-2.0
   version: 1.1.0
 servers:
@@ -189,6 +191,19 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/error_information'
+  /actuator/shutdown:
+    post:
+      tags:
+      - Actuator
+      summary: Actuator web endpoint 'shutdown'
+      operationId: shutdown
+      responses:
+        200:
+          description: OK
+          content:
+            '*/*':
+              schema:
+                type: object
   /a1-policy/v2/policy-types:
     get:
       tags:
index 2bd8d83..8f37aaa 100644 (file)
@@ -31,7 +31,12 @@ management:
     web:
       exposure:
         # Enabling of springboot actuator features. See springboot documentation.
-        include: "loggers,logfile,health,info,metrics,threaddump,heapdump"
+        include: "loggers,logfile,health,info,metrics,threaddump,heapdump,shutdown"
+  endpoint:
+    shutdown:
+      enabled: true
+lifecycle:
+  timeout-per-shutdown-phase: "20s"
 springdoc:
   show-actuator: true
 logging:
@@ -53,6 +58,7 @@ server:
    # See springboot documentation.
    port : 8433
    http-port: 8081
+   shutdown: "graceful"
    ssl:
       key-store-type: JKS
       key-store-password: policy_agent
index ae114f6..259a5ba 100644 (file)
 
 package org.onap.ccsdk.oran.a1policymanagementservice;
 
+import java.lang.invoke.MethodHandles;
+
 import org.onap.ccsdk.oran.a1policymanagementservice.dmaap.DmaapMessageConsumer;
 import org.onap.ccsdk.oran.a1policymanagementservice.tasks.RefreshConfigTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 
 @SpringBootApplication
@@ -38,8 +43,18 @@ public class Application {
     @Autowired
     private DmaapMessageConsumer dmaapMessageConsumer;
 
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
     public static void main(String[] args) {
-        SpringApplication.run(Application.class);
+        ConfigurableApplicationContext context = SpringApplication.run(Application.class);
+
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                logger.warn("Shutting down, received signal SIGTERM");
+                SpringApplication.exit(context);
+            }
+        });
     }
 
     /**
index 4c3a0c7..b6d3a07 100644 (file)
@@ -43,7 +43,7 @@ import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.StatusContro
                 version = SwaggerConfig.VERSION, //
                 description = SwaggerConfig.DESCRIPTION, //
                 license = @License(
-                        name = "Copyright (C) 2020-2022 Nordix Foundation. Licensed under the Apache License.", //
+                        name = "Copyright (C) 2020-2023 Nordix Foundation. Licensed under the Apache License.", //
                         url = "http://www.apache.org/licenses/LICENSE-2.0")) //
 )
 public class SwaggerConfig {
@@ -83,10 +83,15 @@ public class SwaggerConfig {
             + H3 + StatusController.API_NAME + H3_END + //
             "<p>API used for supervision of the PMS component.</p>" + //
             H3 + ServiceController.API_NAME + H3_END + //
-            "<p>" + "API used for registering services that uses PMS."
+            "<p>" //
+            + "API used for registering services that uses PMS."
             + " Each A1 policy is optionally owned by a service. PMS can supervise each registered service by a heart-beat supervision and will automatically remove policies for unavailable services."
             + " Note that a service does not need to be registered in order to create A1 Policies. This is a feature that is optional to use."
-            + "</p>";
+            + "</p>" + //
+            H3 + "Spring Boot Actuator" + H3_END + //
+            "<p>" //
+            + "Provides generic functions  used to monitor and manage the Spring web application." + //
+            "</p>";
 
     public static final String VERSION = "1.1.0";
 }
index 16f4a7f..1c40f04 100644 (file)
@@ -20,6 +20,8 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.aspect;
 
+import java.lang.invoke.MethodHandles;
+
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.After;
@@ -36,7 +38,7 @@ import org.springframework.util.StopWatch;
 @Component
 public class LogAspect {
 
-    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     @Around("execution(* org.onap.ccsdk.oran.a1policymanagementservice..*(..)))")
     public void executimeTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
index 45c0bc4..0956aa1 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.clients;
 
+import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Constructor;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
@@ -38,7 +39,7 @@ import reactor.core.publisher.Mono;
  */
 public class A1ClientFactory {
 
-    private static final Logger logger = LoggerFactory.getLogger(A1ClientFactory.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     private final ApplicationConfig appConfig;
 
index 4af39c9..9db6620 100644 (file)
@@ -30,6 +30,7 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.lang.invoke.MethodHandles;
 import java.util.Optional;
 
 import javax.validation.constraints.NotNull;
@@ -41,7 +42,7 @@ import org.springframework.stereotype.Component;
 
 @Component
 public class ConfigurationFile {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigurationFile.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     final ApplicationConfig appConfig;
     final Gson gson = new Gson();
index 4c7c3c3..5b81f75 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.datastore;
 
+import java.lang.invoke.MethodHandles;
 import java.net.URI;
 import java.util.concurrent.CompletableFuture;
 
@@ -53,7 +54,7 @@ import software.amazon.awssdk.services.s3.model.PutObjectResponse;
 import software.amazon.awssdk.services.s3.model.S3Object;
 
 class S3ObjectStore implements DataStore {
-    private static final Logger logger = LoggerFactory.getLogger(S3ObjectStore.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
     private final ApplicationConfig applicationConfig;
 
     private static S3AsyncClient s3AsynchClient;
index 47c7350..94888c3 100644 (file)
@@ -26,6 +26,7 @@ import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParser;
 
+import java.lang.invoke.MethodHandles;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
@@ -63,7 +64,7 @@ public class DmaapMessageConsumer {
 
     protected static final Duration TIME_BETWEEN_DMAAP_RETRIES = Duration.ofSeconds(10);
 
-    private static final Logger logger = LoggerFactory.getLogger(DmaapMessageConsumer.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     private final ApplicationConfig applicationConfig;
 
index d035417..022dec0 100644 (file)
@@ -24,6 +24,8 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonObject;
 
+import java.lang.invoke.MethodHandles;
+
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
 import org.onap.ccsdk.oran.a1policymanagementservice.dmaap.DmaapRequestMessage.Operation;
 import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
@@ -42,7 +44,7 @@ import reactor.core.publisher.Mono;
  * response though DMAAP
  */
 public class DmaapMessageHandler {
-    private static final Logger logger = LoggerFactory.getLogger(DmaapMessageHandler.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
     private static Gson gson = new GsonBuilder().create();
     private final AsyncRestClient dmaapClient;
     private final AsyncRestClient pmsClient;
index 547cd6b..77d0196 100644 (file)
@@ -20,6 +20,8 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.exceptions;
 
+import java.lang.invoke.MethodHandles;
+
 import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.ErrorResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,7 +35,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
 @ControllerAdvice(annotations = RestController.class)
 public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
 
-    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     @ExceptionHandler(ServiceException.class)
     public final ResponseEntity<Object> handleServiceException(ServiceException ex) {
index 46033a4..c40bf50 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.repository;
 
+import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
@@ -39,7 +40,7 @@ import reactor.core.publisher.MonoSink;
  * resource (for shared usage).
  */
 public class Lock {
-    private static final Logger logger = LoggerFactory.getLogger(Lock.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     boolean isExclusive = false;
     private int lockCounter = 0;
index 2971feb..290b109 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.repository;
 
+import java.lang.invoke.MethodHandles;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -37,7 +38,7 @@ import org.slf4j.LoggerFactory;
  * Holds information about a Near-RT RIC.
  */
 public class Ric {
-    private static final Logger logger = LoggerFactory.getLogger(Ric.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     @Setter
     private RicConfig ricConfig;
index 9c2846a..d8a902e 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.repository;
 
 import com.google.gson.Gson;
 
+import java.lang.invoke.MethodHandles;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Vector;
@@ -37,7 +38,7 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class Services {
-    private static final Logger logger = LoggerFactory.getLogger(Services.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
     private static Gson gson = Service.createGson();
     private final DataStore dataStore;
 
index 978ae1c..b3023f8 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
 
 import com.google.gson.JsonObject;
 
+import java.lang.invoke.MethodHandles;
 import java.time.Duration;
 import java.util.Optional;
 import java.util.Properties;
@@ -59,7 +60,7 @@ import reactor.util.annotation.Nullable;
 @SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally
 public class RefreshConfigTask {
 
-    private static final Logger logger = LoggerFactory.getLogger(RefreshConfigTask.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     @Value("#{systemEnvironment}")
     public Properties systemEnvironment;
index 1f612e4..3f0d3a0 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
 
+import java.lang.invoke.MethodHandles;
 import java.util.Collection;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
@@ -53,7 +54,7 @@ import reactor.core.publisher.Mono;
 @EnableScheduling
 @SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally
 public class RicSupervision {
-    private static final Logger logger = LoggerFactory.getLogger(RicSupervision.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     private static final int CONCURRENCY = 50; // Number of RIC checked in paralell
     private final Rics rics;
index d1bd433..c07cf2c 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
 
 import static org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
 
+import java.lang.invoke.MethodHandles;
 import java.util.Set;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
@@ -58,7 +59,7 @@ import reactor.core.publisher.SignalType;
 @SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally
 public class RicSynchronizationTask {
 
-    private static final Logger logger = LoggerFactory.getLogger(RicSynchronizationTask.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
     static final int CONCURRENCY_RIC = 1; // How many paralell requests that is sent to one NearRT RIC
 
     private final A1ClientFactory a1ClientFactory;
index e40634e..f9853af 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
 
+import java.lang.invoke.MethodHandles;
 import java.time.Duration;
 
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
@@ -49,7 +50,7 @@ import reactor.core.publisher.Mono;
 @EnableScheduling
 @SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally
 public class ServiceSupervision {
-    private static final Logger logger = LoggerFactory.getLogger(ServiceSupervision.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
     static final int CONCURRENCY_RIC = 1; // How may paralell requests that is sent
     private final Services services;
     private final Policies policies;
index 3b7695e..d60c432 100644 (file)
@@ -27,6 +27,7 @@ import com.google.gson.JsonParser;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.invoke.MethodHandles;
 import java.net.URL;
 import java.nio.file.Files;
 import java.time.Instant;
@@ -61,7 +62,7 @@ import org.springframework.util.StringUtils;
                                 // but a mock
                                 // of the server.
 class MockPolicyManagementService {
-    private static final Logger logger = LoggerFactory.getLogger(MockPolicyManagementService.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     @Autowired
     Rics rics;
index bec5573..1e8278a 100644 (file)
@@ -33,6 +33,7 @@ import com.google.gson.GsonBuilder;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -46,7 +47,9 @@ import java.util.List;
 import org.json.JSONObject;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.MethodOrderer;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
 import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory;
@@ -89,12 +92,14 @@ import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.TestPropertySource;
 import org.springframework.util.FileSystemUtils;
+import org.springframework.web.reactive.function.client.WebClientRequestException;
 import org.springframework.web.reactive.function.client.WebClientResponseException;
 
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 import reactor.util.annotation.Nullable;
 
+@TestMethodOrder(MethodOrderer.MethodName.class)
 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
 @TestPropertySource(properties = { //
         "server.ssl.key-store=./config/keystore.jks", //
@@ -105,7 +110,7 @@ import reactor.util.annotation.Nullable;
         "app.s3.bucket=" // If this is set, S3 will be used to store data.
 })
 class ApplicationTest {
-    private static final Logger logger = LoggerFactory.getLogger(ApplicationTest.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
     @Autowired
     ApplicationContext context;
@@ -200,6 +205,33 @@ class ApplicationTest {
         }
     }
 
+    @Test
+    @SuppressWarnings("squid:S2925") // "Thread.sleep" should not be used in tests.
+    void testZZActuator() throws Exception {
+        // The test must be run last, hence the "ZZ" in the name. All succeeding tests
+        // will fail.
+        AsyncRestClient client = restClient(baseUrl(), false);
+
+        client.post("/actuator/loggers/org.onap.ccsdk.oran.a1policymanagementservice",
+                "{\"configuredLevel\":\"trace\"}").block();
+
+        String resp = client.get("/actuator/loggers/org.onap.ccsdk.oran.a1policymanagementservice").block();
+        assertThat(resp).contains("TRACE");
+
+        client.post("/actuator/loggers/org.springframework.boot.actuate", "{\"configuredLevel\":\"trace\"}").block();
+
+        // This will stop the web server and all coming tests will fail.
+        client.post("/actuator/shutdown", "").block();
+
+        Thread.sleep(1000);
+
+        StepVerifier.create(restClient().get("/rics")) // Any call
+                .expectSubscription() //
+                .expectErrorMatches(t -> t instanceof WebClientRequestException) //
+                .verify();
+
+    }
+
     @Test
     void generateApiDoc() throws IOException {
         String url = "https://localhost:" + this.port + "/v3/api-docs";
index 3a4aae8..4e535ab 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
+import java.lang.invoke.MethodHandles;
 import java.time.Instant;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -44,7 +45,7 @@ import org.springframework.http.ResponseEntity;
  * thread. For test of robustness using concurrent clients.
  */
 class ConcurrencyTestRunnable implements Runnable {
-    private static final Logger logger = LoggerFactory.getLogger(ConcurrencyTestRunnable.class);
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
     private final AsyncRestClient webClient;
     static AtomicInteger nextCount = new AtomicInteger(0);
     private final int count;
index ce2d9aa..b8a9b95 100644 (file)
             ],
             "tags": ["NearRT-RIC Repository"]
         }},
+        "/actuator/shutdown": {"post": {
+            "summary": "Actuator web endpoint 'shutdown'",
+            "operationId": "shutdown",
+            "responses": {"200": {
+                "description": "OK",
+                "content": {"*/*": {
+                    "schema": {
+                        "type": "object",
+                        "example": null
+                    },
+                    "example": null
+                }}
+            }},
+            "tags": ["Actuator"]
+        }},
         "/a1-policy/v2/policy-types": {"get": {
             "summary": "Query policy type identities",
             "operationId": "getPolicyTypes",
     },
     "info": {
         "license": {
-            "name": "Copyright (C) 2020-2022 Nordix Foundation. Licensed under the Apache License.",
+            "name": "Copyright (C) 2020-2023 Nordix Foundation. Licensed under the Apache License.",
             "url": "http://www.apache.org/licenses/LICENSE-2.0"
         },
-        "description": "<h2>General<\/h2><p>The O-RAN Non-RT RIC Policy Management Service provides a REST API for management of A1 policies. <br/>The main tasks of the service are:<\/p><ul><li>A1 Policy creation, modification and deletion.<\/li><li>Monitoring and maintaining consistency of the SMO view of A1 policies and the Near-RT RICs<\/li><li>Maintaining a view of supported Near-RT RIC policy types<\/li><li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.<\/li><\/ul><h2>APIs provided by the service<\/h2><h3>A1 Policy Management<\/h3><p>This is an API for management of A1 Policies.<\/p><ul><li>A1 Policy retrieval, creation, modification and deletion.<\/li><li>Retrieval of supported A1 Policy types for a Near-RT RIC<\/li><li>Retrieval of status for existing A1 policies<\/li><\/ul><h3>Management of configuration<\/h3><p>API for updating and retrieval of the component configuration. Note that there other ways to maintain the configuration.<\/p><h3>Callbacks<\/h3><p>These are endpoints that are invoked by this service. The callbacks are registered in this service at service registration.<\/p><h3>NearRT-RIC Repository<\/h3><p>This is an API that provides support for looking up a NearRT-RIC. Each A1 policy is targeted for one Near-RT RIC.<\/p><h3>Health Check<\/h3><p>API used for supervision of the PMS component.<\/p><h3>Service Registry and Supervision<\/h3><p>API used for registering services that uses PMS. Each A1 policy is optionally owned by a service. PMS can supervise each registered service by a heart-beat supervision and will automatically remove policies for unavailable services. Note that a service does not need to be registered in order to create A1 Policies. This is a feature that is optional to use.<\/p>",
+        "description": "<h2>General<\/h2><p>The O-RAN Non-RT RIC Policy Management Service provides a REST API for management of A1 policies. <br/>The main tasks of the service are:<\/p><ul><li>A1 Policy creation, modification and deletion.<\/li><li>Monitoring and maintaining consistency of the SMO view of A1 policies and the Near-RT RICs<\/li><li>Maintaining a view of supported Near-RT RIC policy types<\/li><li>Supervision of using services (R-APPs). When a service is unavailable, its policies are removed.<\/li><\/ul><h2>APIs provided by the service<\/h2><h3>A1 Policy Management<\/h3><p>This is an API for management of A1 Policies.<\/p><ul><li>A1 Policy retrieval, creation, modification and deletion.<\/li><li>Retrieval of supported A1 Policy types for a Near-RT RIC<\/li><li>Retrieval of status for existing A1 policies<\/li><\/ul><h3>Management of configuration<\/h3><p>API for updating and retrieval of the component configuration. Note that there other ways to maintain the configuration.<\/p><h3>Callbacks<\/h3><p>These are endpoints that are invoked by this service. The callbacks are registered in this service at service registration.<\/p><h3>NearRT-RIC Repository<\/h3><p>This is an API that provides support for looking up a NearRT-RIC. Each A1 policy is targeted for one Near-RT RIC.<\/p><h3>Health Check<\/h3><p>API used for supervision of the PMS component.<\/p><h3>Service Registry and Supervision<\/h3><p>API used for registering services that uses PMS. Each A1 policy is optionally owned by a service. PMS can supervise each registered service by a heart-beat supervision and will automatically remove policies for unavailable services. Note that a service does not need to be registered in order to create A1 Policies. This is a feature that is optional to use.<\/p><h3>Spring Boot Actuator<\/h3><p>Provides generic functions  used to monitor and manage the Spring web application.<\/p>",
         "title": "A1 Policy Management Service",
         "version": "1.1.0"
     },
index 6d620c2..2c692de 100644 (file)
@@ -21,9 +21,11 @@ info:
     Each A1 policy is optionally owned by a service. PMS can supervise each registered
     service by a heart-beat supervision and will automatically remove policies for
     unavailable services. Note that a service does not need to be registered in order
-    to create A1 Policies. This is a feature that is optional to use.</p>
+    to create A1 Policies. This is a feature that is optional to use.</p><h3>Spring
+    Boot Actuator</h3><p>Provides generic functions  used to monitor and manage the
+    Spring web application.</p>
   license:
-    name: Copyright (C) 2020-2022 Nordix Foundation. Licensed under the Apache License.
+    name: Copyright (C) 2020-2023 Nordix Foundation. Licensed under the Apache License.
     url: http://www.apache.org/licenses/LICENSE-2.0
   version: 1.1.0
 servers:
@@ -189,6 +191,19 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/error_information'
+  /actuator/shutdown:
+    post:
+      tags:
+      - Actuator
+      summary: Actuator web endpoint 'shutdown'
+      operationId: shutdown
+      responses:
+        200:
+          description: OK
+          content:
+            '*/*':
+              schema:
+                type: object
   /a1-policy/v2/policy-types:
     get:
       tags: