Add endpoint for participant restart 35/141635/4
authorwaynedunican <wayne.dunican@est.tech>
Tue, 29 Jul 2025 13:42:11 +0000 (14:42 +0100)
committerWayne Dunican <wayne.dunican@est.tech>
Fri, 1 Aug 2025 10:14:06 +0000 (10:14 +0000)
Issue-ID: POLICY-5436
Change-Id: Ie7828d5475366d21b22bc7e04131069cfbc1595a
Signed-off-by: waynedunican <wayne.dunican@est.tech>
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/ParticipantController.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/stub/ParticipantControllerStub.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/participants/AcmParticipantProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionParticipantHandler.java
runtime-acm/src/main/resources/openapi/openapi.yaml
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/contract/ParticipantControllerStubTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/participant/ParticipantControllerTest.java

index 51b3baa..3f96afa 100644 (file)
@@ -66,4 +66,16 @@ public class ParticipantController extends AbstractRestController implements Par
         var participantInformationList = acmParticipantProvider.getAllParticipants(pageable);
         return ResponseEntity.ok().body(participantInformationList);
     }
+
+    @Override
+    public ResponseEntity<Void> manualRestartAllParticipants(UUID onapRequestId) {
+        acmParticipantProvider.restartAllParticipants();
+        return new ResponseEntity<>(HttpStatus.ACCEPTED);
+    }
+
+    @Override
+    public ResponseEntity<Void> manualRestartParticipant(UUID participantId, UUID requestId) {
+        acmParticipantProvider.restartParticipant(participantId);
+        return new ResponseEntity<>(HttpStatus.ACCEPTED);
+    }
 }
index 4b75389..ad7df71 100644 (file)
@@ -65,4 +65,14 @@ public class ParticipantControllerStub extends AbstractRestController implements
         Integer page, Integer size, UUID xonaprequestid) {
         return stubUtils.getResponseList(pathToParticipantList);
     }
+
+    @Override
+    public ResponseEntity<Void> manualRestartAllParticipants(UUID xonaprequestid) {
+        return new ResponseEntity<>(HttpStatus.ACCEPTED);
+    }
+
+    @Override
+    public ResponseEntity<Void> manualRestartParticipant(UUID participantId, UUID xonaprequestid) {
+        return new ResponseEntity<>(HttpStatus.ACCEPTED);
+    }
 }
index a2e35d7..c4ddbd0 100644 (file)
 
 package org.onap.policy.clamp.acm.runtime.participants;
 
+import jakarta.ws.rs.core.Response;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
+import org.onap.policy.clamp.acm.runtime.supervision.SupervisionParticipantHandler;
 import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantStatusReqPublisher;
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
 import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState;
 import org.onap.policy.clamp.models.acm.concepts.Participant;
 import org.onap.policy.clamp.models.acm.concepts.ParticipantInformation;
 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
+import org.onap.policy.models.base.PfModelRuntimeException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.data.domain.Pageable;
@@ -45,6 +48,7 @@ public class AcmParticipantProvider {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AcmParticipantProvider.class);
     private final ParticipantProvider participantProvider;
+    private final SupervisionParticipantHandler supervisionParticipantHandler;
     private final ParticipantStatusReqPublisher participantStatusReqPublisher;
 
     /**
@@ -113,4 +117,27 @@ public class AcmParticipantProvider {
         return acNodeTemplateStates
             .stream().collect(Collectors.toMap(NodeTemplateState::getNodeTemplateStateId, Function.identity()));
     }
+
+    /**
+     * Restart specific participant.
+     *
+     * @param participantId     ID of participant to restart
+     */
+    public void restartParticipant(UUID participantId) {
+        if (participantProvider.findParticipant(participantId).isEmpty()) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                    "Participant Not Found with ID: " + participantId);
+        }
+        supervisionParticipantHandler.handleRestart(participantId, null);
+        LOGGER.debug("Restarting participant with ID: {}", participantId);
+    }
+
+
+    /**
+     * Restart all participants.
+     */
+    public void restartAllParticipants() {
+        supervisionParticipantHandler.handleRestartOfAllParticipants();
+        LOGGER.debug("Restarting all participants");
+    }
 }
index 26374c1..ba223d2 100644 (file)
@@ -172,7 +172,13 @@ public class SupervisionParticipantHandler {
         participantProvider.saveParticipantReplica(replica);
     }
 
-    private void handleRestart(UUID participantId, UUID replicaId) {
+    /**
+     * Handle restart of a participant.
+     *
+     * @param participantId     ID of the participant to restart
+     * @param replicaId         ID of the participant replica
+     */
+    public void handleRestart(UUID participantId, UUID replicaId) {
         var compositionIds = participantProvider.getCompositionIds(participantId);
         for (var compositionId : compositionIds) {
             var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
@@ -196,6 +202,16 @@ public class SupervisionParticipantHandler {
         participantSyncPublisher.sendRestartMsg(participantId, replicaId, acDefinition, automationCompositions);
     }
 
+    /**
+     * Handle restart of all participants.
+     */
+    public void handleRestartOfAllParticipants() {
+        var participants = participantProvider.getParticipants();
+        for (var participant:participants) {
+            handleRestart(participant.getParticipantId(), null);
+        }
+    }
+
     private boolean isAcToBeSyncRestarted(UUID participantId, AutomationComposition automationComposition) {
         for (var element : automationComposition.getElements().values()) {
             if (participantId.equals(element.getParticipantId())) {
index 6bc692e..d070178 100644 (file)
@@ -447,6 +447,189 @@ paths:
         api-version: 8.2.1
         last-mod-release: Paris
       x-codegen-request-body-name: body
+  /participants/sync:
+    put:
+      tags:
+        - Participant Monitoring
+      summary: Manually restart (sync) all registered participants
+      description: Initiates a manual sync (restart) operation for all registered participants.
+        Each participant will restart and report its status and the status of its AC element types and instances.
+        The result will be available through subsequent GET requests to the "participants" endpoint.
+      operationId: manualRestartAllParticipants
+      parameters:
+        - name: X-onap-RequestId
+          in: header
+          description: RequestID for http transaction
+          required: false
+          schema:
+            type: string
+            format: uuid
+      responses:
+        202:
+          description: Accepted, sync request has been accepted and forwarded to all participants
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+        400:
+          description: Bad Request, returns an instance of SimpleResponse
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SimpleResponse'
+        401:
+          description: Authentication Error, returns an instance of SimpleResponse
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SimpleResponse'
+        500:
+          description: Internal Server Error, returns an instance of SimpleResponse
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SimpleResponse'
+      security:
+        - basicAuth: []
+      x-interface info:
+        api-version: 8.2.1
+        last-mod-release: Paris
+      x-codegen-request-body-name: body
+
+  /participants/sync/{participantId}:
+    put:
+      tags:
+        - Participant Monitoring
+      summary: Manually restart (sync) the specified participant
+      description: Initiates a manual sync (restart) operation for the specified participant.
+        The participant will restart and report its status and the status of its AC element types and instances.
+        The result will be available through subsequent GET requests to the "participants" endpoint.
+      operationId: manualRestartParticipant
+      parameters:
+        - name: participantId
+          in: path
+          description: The UUID of the participant to manually sync
+          required: true
+          schema:
+            type: string
+            format: uuid
+        - name: X-onap-RequestId
+          in: header
+          description: RequestID for http transaction
+          required: false
+          schema:
+            type: string
+            format: uuid
+      responses:
+        202:
+          description: Accepted, sync request has been accepted and forwarded to the participant
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+        400:
+          description: Bad Request, returns an instance of SimpleResponse
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SimpleResponse'
+        401:
+          description: Authentication Error, returns an instance of SimpleResponse
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SimpleResponse'
+        404:
+          description: Specified participant not found, returns an instance of SimpleResponse
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SimpleResponse'
+        500:
+          description: Internal Server Error, returns an instance of SimpleResponse
+          headers:
+            X-LatestVersion:
+              $ref: '#/components/headers/X-LatestVersion'
+            X-PatchVersion:
+              $ref: '#/components/headers/X-PatchVersion'
+            X-MinorVersion:
+              $ref: '#/components/headers/X-MinorVersion'
+            X-onap-RequestId:
+              $ref: '#/components/headers/X-onap-RequestId'
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SimpleResponse'
+      security:
+        - basicAuth: []
+      x-interface info:
+        api-version: 8.2.1
+        last-mod-release: Paris
+      x-codegen-request-body-name: body
   /compositions:
     get:
       tags:
index b15a5bd..736f130 100644 (file)
 package org.onap.policy.clamp.acm.runtime.contract;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import jakarta.ws.rs.client.Entity;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
+import java.util.UUID;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -82,4 +84,23 @@ class ParticipantControllerStubTest extends CommonRestController {
         assertThat(Response.Status.ACCEPTED.getStatusCode()).isEqualTo(respPost.getStatus());
         respPost.close();
     }
+
+    @Test
+    void testRestartParticipants() {
+        var invocationBuilder = super.sendRequest(PARTICIPANT_ENDPOINT + "/sync");
+
+        var response = invocationBuilder.header("Content-Length", 0)
+                .put(Entity.entity("", MediaType.APPLICATION_JSON));
+        assertEquals(Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
+    }
+
+    @Test
+    void testRestartParticipantById() {
+        var invocationBuilder = super.sendRequest(PARTICIPANT_ENDPOINT + "/sync/"
+            + UUID.randomUUID());
+
+        var response = invocationBuilder.header("Content-Length", 0)
+                .put(Entity.entity("", MediaType.APPLICATION_JSON));
+        assertEquals(Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
+    }
 }
index 81dce9a..ed60977 100644 (file)
@@ -277,4 +277,36 @@ class ParticipantControllerTest extends CommonRestController {
             assertEquals(Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
         }
     }
+
+    @Test
+    void testRestartParticipants() {
+        inputParticipants.forEach(participantProvider::saveParticipant);
+        var invocationBuilder = super.sendRequest(PARTICIPANTS_ENDPOINT + "/sync");
+        try (var response = invocationBuilder.header("Content-Length", 0)
+                .put(Entity.entity("", MediaType.APPLICATION_JSON))) {
+            assertEquals(Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
+        }
+    }
+
+    @Test
+    void testRestartParticipantById() {
+        inputParticipants.forEach(participantProvider::saveParticipant);
+        var invocationBuilder = super.sendRequest(PARTICIPANTS_ENDPOINT + "/sync/"
+            + "82fd8ef9-1d1e-4343-9b28-7f9564ee3de6");
+        try (var response = invocationBuilder.header("Content-Length", 0)
+                .put(Entity.entity("", MediaType.APPLICATION_JSON))) {
+            assertEquals(Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
+        }
+    }
+
+    @Test
+    void testRestartParticipantFailure() {
+        inputParticipants.forEach(participantProvider::saveParticipant);
+        var invocationBuilder = super.sendRequest(PARTICIPANTS_ENDPOINT + "/sync/"
+                + UUID.randomUUID());
+        try (var response = invocationBuilder.header("Content-Length", 0)
+                .put(Entity.entity("", MediaType.APPLICATION_JSON))) {
+            assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus());
+        }
+    }
 }