aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/concepts/ControlLoopElementAck.java40
-rw-r--r--models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAck.java4
-rw-r--r--models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAckTest.java17
-rw-r--r--models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopUpdateTest.java5
-rw-r--r--packages/policy-clamp-tarball/src/main/resources/etc/ClRuntimeParameters.yaml6
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java116
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java54
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java91
-rw-r--r--pom.xml2
-rw-r--r--runtime-controlloop/pom.xml10
-rw-r--r--runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/ConverterConfiguration.java7
-rw-r--r--runtime-controlloop/src/main/resources/application.yaml6
-rw-r--r--runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/rest/ActuatorControllerTest.java91
-rw-r--r--runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java45
-rw-r--r--runtime-controlloop/src/test/resources/application_test.properties2
15 files changed, 323 insertions, 173 deletions
diff --git a/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/concepts/ControlLoopElementAck.java b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/concepts/ControlLoopElementAck.java
new file mode 100644
index 000000000..a5918fe94
--- /dev/null
+++ b/models/src/main/java/org/onap/policy/clamp/controlloop/models/controlloop/concepts/ControlLoopElementAck.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.models.controlloop.concepts;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@ToString
+public class ControlLoopElementAck {
+
+ // Result: Success/Fail.
+ private Boolean result;
+
+ // Message indicating reason for failure
+ private String message;
+
+}
diff --git a/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAck.java b/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAck.java
index 55ba7faf5..8e3604916 100644
--- a/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAck.java
+++ b/models/src/main/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAck.java
@@ -27,7 +27,7 @@ import java.util.function.UnaryOperator;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
-import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementAck;
import org.onap.policy.models.base.PfUtils;
import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
@@ -45,7 +45,7 @@ public class ControlLoopAck extends ParticipantAckMessage {
// A map with ControlLoopElementID as its key, and a pair of result and message as value per
// ControlLoopElement.
- private Map<UUID, Pair<Boolean, String>> controlLoopResultMap = new LinkedHashMap<>();
+ private Map<UUID, ControlLoopElementAck> controlLoopResultMap = new LinkedHashMap<>();
/**
* Constructor for instantiating ParticipantRegisterAck class with message name.
diff --git a/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAckTest.java b/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAckTest.java
index d7d7e4327..5fded7341 100644
--- a/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAckTest.java
+++ b/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopAckTest.java
@@ -22,35 +22,36 @@ package org.onap.policy.clamp.controlloop.models.messages.dmaap.participant;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
+import static org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageUtils.assertSerializable;
import static org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageUtils.removeVariableFields;
import java.util.Map;
import java.util.UUID;
-import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementAck;
+import org.onap.policy.common.utils.coder.CoderException;
import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
class ControlLoopAckTest {
@Test
- void testCopyConstructor() {
+ void testCopyConstructor() throws CoderException {
assertThatThrownBy(() -> new ControlLoopAck((ControlLoopAck) null))
.isInstanceOf(NullPointerException.class);
- final ControlLoopAck orig = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_UPDATE);
+ final var orig = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_UPDATE);
// verify with null values
assertEquals(removeVariableFields(orig.toString()),
removeVariableFields(new ControlLoopAck(orig).toString()));
// verify with all values
- ToscaConceptIdentifier id = new ToscaConceptIdentifier("id", "1.2.3");
+ var id = new ToscaConceptIdentifier("id", "1.2.3");
orig.setControlLoopId(id);
orig.setParticipantId(id);
orig.setParticipantType(id);
-
- Pair<Boolean, String> clElementResult = Pair.of(true, "ControlLoopElement result");
- final Map<UUID, Pair<Boolean, String>> controlLoopResultMap = Map.of(UUID.randomUUID(), clElementResult);
+ var clElementResult = new ControlLoopElementAck(true, "ControlLoopElement result");
+ final var controlLoopResultMap = Map.of(UUID.randomUUID(), clElementResult);
orig.setControlLoopResultMap(controlLoopResultMap);
orig.setResponseTo(UUID.randomUUID());
@@ -59,5 +60,7 @@ class ControlLoopAckTest {
assertEquals(removeVariableFields(orig.toString()),
removeVariableFields(new ControlLoopAck(orig).toString()));
+
+ assertSerializable(orig, ControlLoopAck.class);
}
}
diff --git a/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopUpdateTest.java b/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopUpdateTest.java
index 3aafe56f1..1b155a12a 100644
--- a/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopUpdateTest.java
+++ b/models/src/test/java/org/onap/policy/clamp/controlloop/models/messages/dmaap/participant/ControlLoopUpdateTest.java
@@ -22,6 +22,7 @@ package org.onap.policy.clamp.controlloop.models.messages.dmaap.participant;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
+import static org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageUtils.assertSerializable;
import static org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageUtils.removeVariableFields;
import java.time.Instant;
@@ -33,6 +34,7 @@ import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantUpdates;
+import org.onap.policy.common.utils.coder.CoderException;
import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
/**
@@ -40,7 +42,7 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
*/
class ControlLoopUpdateTest {
@Test
- void testCopyConstructor() {
+ void testCopyConstructor() throws CoderException {
assertThatThrownBy(() -> new ControlLoopUpdate(null)).isInstanceOf(NullPointerException.class);
ControlLoopUpdate orig = new ControlLoopUpdate();
@@ -71,5 +73,6 @@ class ControlLoopUpdateTest {
ControlLoopUpdate other = new ControlLoopUpdate(orig);
assertEquals(removeVariableFields(orig.toString()), removeVariableFields(other.toString()));
+ assertSerializable(orig, ControlLoopUpdate.class);
}
}
diff --git a/packages/policy-clamp-tarball/src/main/resources/etc/ClRuntimeParameters.yaml b/packages/policy-clamp-tarball/src/main/resources/etc/ClRuntimeParameters.yaml
index 0aa3fb782..635b98cb8 100644
--- a/packages/policy-clamp-tarball/src/main/resources/etc/ClRuntimeParameters.yaml
+++ b/packages/policy-clamp-tarball/src/main/resources/etc/ClRuntimeParameters.yaml
@@ -50,3 +50,9 @@ runtime:
servers:
- ${topicServer:message-router}
topicCommInfrastructure: dmaap
+
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health, metrics, prometheus
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java
index 680acd276..e11c883b4 100644
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/comm/MessageSender.java
@@ -25,52 +25,41 @@ import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
-import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
-import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
-import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopAck;
-import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantDeregister;
-import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantRegister;
-import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatus;
-import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck;
-import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
import org.onap.policy.clamp.controlloop.participant.intermediary.handler.ParticipantHandler;
-import org.onap.policy.models.base.PfModelException;
-import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
/**
* This class sends messages from participants to CLAMP.
*/
+@Component
public class MessageSender extends TimerTask implements Closeable {
private static final Logger LOGGER = LoggerFactory.getLogger(MessageSender.class);
private final ParticipantHandler participantHandler;
- private final ParticipantMessagePublisher publisher;
private ScheduledExecutorService timerPool;
/**
* Constructor, set the publisher.
*
* @param participantHandler the participant handler to use for gathering information
- * @param publisher the publisher to use for sending messages
- * @param interval time interval to send Participant Status periodic messages
+ * @param parameters the parameters of the participant
*/
- public MessageSender(ParticipantHandler participantHandler, ParticipantMessagePublisher publisher,
- long interval) {
+ public MessageSender(ParticipantHandler participantHandler, ParticipantParameters parameters) {
this.participantHandler = participantHandler;
- this.publisher = publisher;
// Kick off the timer
timerPool = makeTimerPool();
+ var interval = parameters.getIntermediaryParameters().getReportingTimeIntervalMs();
timerPool.scheduleAtFixedRate(this, interval, interval, TimeUnit.MILLISECONDS);
}
@Override
public void run() {
LOGGER.debug("Sent heartbeat to CLAMP");
- this.sendHeartbeat();
+ participantHandler.sendHeartbeat();
}
@Override
@@ -79,97 +68,6 @@ public class MessageSender extends TimerTask implements Closeable {
}
/**
- * Send a response message for this participant.
- *
- * @param ackMessage the details to include in the response message
- */
- public void sendAckResponse(ControlLoopAck ackMessage) {
- sendAckResponse(null, ackMessage);
- }
-
- /**
- * Dispatch a response message for this participant.
- *
- * @param controlLoopId the control loop to which this message is a response
- * @param ackMessage the details to include in the response message
- */
- public void sendAckResponse(ToscaConceptIdentifier controlLoopId, ControlLoopAck ackMessage) {
- // Participant related fields
- ackMessage.setParticipantType(participantHandler.getParticipantType());
- ackMessage.setParticipantId(participantHandler.getParticipantId());
- publisher.sendControlLoopAck(ackMessage);
- }
-
- /**
- * Send a ParticipantRegister message for this participant.
- *
- * @param message the participantRegister message
- */
- public void sendParticipantRegister(ParticipantRegister message) {
- publisher.sendParticipantRegister(message);
- }
-
- /**
- * Send a ParticipantDeregister message for this participant.
- *
- * @param message the participantDeRegister message
- */
- public void sendParticipantDeregister(ParticipantDeregister message) {
- publisher.sendParticipantDeregister(message);
- }
-
- /**
- * Send a ParticipantUpdateAck message for this participant update.
- *
- * @param message the participantUpdateAck message
- */
- public void sendParticipantUpdateAck(ParticipantUpdateAck message) {
- publisher.sendParticipantUpdateAck(message);
- }
-
- /**
- * Send a ParticipantStatus message for this participant.
- *
- * @param participantStatus the ParticipantStatus message
- */
- public void sendParticipantStatus(ParticipantStatus participantStatus) {
- var controlLoops = participantHandler.getControlLoopHandler().getControlLoops();
- for (ControlLoopElementListener clElementListener :
- participantHandler.getControlLoopHandler().getListeners()) {
- updateClElementStatistics(controlLoops, clElementListener);
- }
-
- publisher.sendParticipantStatus(participantStatus);
- }
-
- /**
- * Dispatch a heartbeat for this participant.
- */
- public void sendHeartbeat() {
- publisher.sendHeartbeat(participantHandler.makeHeartbeat(false));
- }
-
- /**
- * Update ControlLoopElement statistics. The control loop elements listening will be
- * notified to retrieve statistics from respective controlloop elements, and controlloopelements
- * data on the handler will be updated.
- *
- * @param controlLoops the control loops
- * @param clElementListener control loop element listener
- */
- public void updateClElementStatistics(ControlLoops controlLoops, ControlLoopElementListener clElementListener) {
- for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
- for (ControlLoopElement element : controlLoop.getElements().values()) {
- try {
- clElementListener.handleStatistics(element.getId());
- } catch (PfModelException e) {
- LOGGER.debug("Getting statistics for Control loop element failed");
- }
- }
- }
- }
-
- /**
* Makes a new timer pool.
*
* @return a new timer pool
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java
index 0e276f390..8b4c61dca 100644
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ControlLoopHandler.java
@@ -29,12 +29,11 @@ import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.tuple.Pair;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementAck;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
@@ -45,24 +44,25 @@ import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.Contr
import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ControlLoopUpdate;
import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantMessageType;
import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
-import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender;
-import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters;
+import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantMessagePublisher;
+import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters;
import org.onap.policy.models.base.PfModelException;
import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
/*
* This class is responsible for managing the state of all control loops in the participant.
*/
-@NoArgsConstructor
+@Component
public class ControlLoopHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopHandler.class);
- private ToscaConceptIdentifier participantType = null;
- private ToscaConceptIdentifier participantId = null;
- private MessageSender messageSender = null;
+ private final ToscaConceptIdentifier participantType;
+ private final ToscaConceptIdentifier participantId;
+ private final ParticipantMessagePublisher publisher;
@Getter
private final Map<ToscaConceptIdentifier, ControlLoop> controlLoopMap = new LinkedHashMap<>();
@@ -77,12 +77,12 @@ public class ControlLoopHandler {
* Constructor, set the participant ID and messageSender.
*
* @param parameters the parameters of the participant
- * @param messageSender the messageSender for sending responses to messages
+ * @param publisher the ParticipantMessage Publisher
*/
- public ControlLoopHandler(ParticipantIntermediaryParameters parameters, MessageSender messageSender) {
- this.participantType = parameters.getParticipantType();
- this.participantId = parameters.getParticipantId();
- this.messageSender = messageSender;
+ public ControlLoopHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) {
+ this.participantType = parameters.getIntermediaryParameters().getParticipantType();
+ this.participantId = parameters.getIntermediaryParameters().getParticipantId();
+ this.publisher = publisher;
}
public void registerControlLoopElementListener(ControlLoopElementListener listener) {
@@ -104,18 +104,20 @@ public class ControlLoopHandler {
LOGGER.warn("Cannot update Control loop element state, id is null");
}
- var controlLoopStateChangeAck =
- new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
ControlLoopElement clElement = elementsOnThisParticipant.get(id);
if (clElement != null) {
+ var controlLoopStateChangeAck =
+ new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_STATECHANGE_ACK);
+ controlLoopStateChangeAck.setParticipantId(participantId);
+ controlLoopStateChangeAck.setParticipantType(participantType);
clElement.setOrderedState(orderedState);
clElement.setState(newState);
controlLoopStateChangeAck.getControlLoopResultMap().put(clElement.getId(),
- Pair.of(true, "Control loop element {} state changed to {}\", id, newState)"));
+ new ControlLoopElementAck(true, "Control loop element {} state changed to {}\", id, newState)"));
LOGGER.debug("Control loop element {} state changed to {}", id, newState);
controlLoopStateChangeAck.setMessage("ControlLoopElement state changed to {} " + newState);
controlLoopStateChangeAck.setResult(true);
- messageSender.sendAckResponse(controlLoopStateChangeAck);
+ publisher.sendControlLoopAck(controlLoopStateChangeAck);
return clElement;
}
return null;
@@ -147,15 +149,17 @@ public class ControlLoopHandler {
}
var controlLoop = controlLoopMap.get(stateChangeMsg.getControlLoopId());
- var controlLoopAck = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_STATE_CHANGE);
if (controlLoop == null) {
+ var controlLoopAck = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_STATE_CHANGE);
+ controlLoopAck.setParticipantId(participantId);
+ controlLoopAck.setParticipantType(participantType);
controlLoopAck.setMessage("Control loop " + stateChangeMsg.getControlLoopId()
+ " does not use this participant " + participantId);
controlLoopAck.setResult(false);
controlLoopAck.setResponseTo(stateChangeMsg.getMessageId());
controlLoopAck.setControlLoopId(stateChangeMsg.getControlLoopId());
- messageSender.sendAckResponse(controlLoopAck);
+ publisher.sendControlLoopAck(controlLoopAck);
LOGGER.debug("Control loop {} does not use this participant", stateChangeMsg.getControlLoopId());
return;
}
@@ -200,17 +204,19 @@ public class ControlLoopHandler {
var controlLoop = controlLoopMap.get(updateMsg.getControlLoopId());
- var controlLoopUpdateAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_UPDATE_ACK);
-
// TODO: Updates to existing ControlLoops are not supported yet (Addition/Removal of ControlLoop
// elements to existing ControlLoop has to be supported).
if (controlLoop != null) {
+ var controlLoopUpdateAck = new ControlLoopAck(ParticipantMessageType.CONTROLLOOP_UPDATE_ACK);
+ controlLoopUpdateAck.setParticipantId(participantId);
+ controlLoopUpdateAck.setParticipantType(participantType);
+
controlLoopUpdateAck.setMessage("Control loop " + updateMsg.getControlLoopId()
+ " already defined on participant " + participantId);
controlLoopUpdateAck.setResult(false);
controlLoopUpdateAck.setResponseTo(updateMsg.getMessageId());
controlLoopUpdateAck.setControlLoopId(updateMsg.getControlLoopId());
- messageSender.sendAckResponse(controlLoopUpdateAck);
+ publisher.sendControlLoopAck(controlLoopUpdateAck);
return;
}
@@ -319,10 +325,12 @@ public class ControlLoopHandler {
if (orderedState.equals(controlLoop.getOrderedState())) {
var controlLoopAck = new ControlLoopAck(ParticipantMessageType.CONTROL_LOOP_STATE_CHANGE);
+ controlLoopAck.setParticipantId(participantId);
+ controlLoopAck.setParticipantType(participantType);
controlLoopAck.setMessage("Control loop is already in state" + orderedState);
controlLoopAck.setResult(false);
controlLoopAck.setControlLoopId(controlLoop.getDefinition());
- messageSender.sendAckResponse(controlLoopAck);
+ publisher.sendControlLoopAck(controlLoopAck);
return;
}
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java
index 66e09e7f6..be8ef0098 100644
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/controlloop/participant/intermediary/handler/ParticipantHandler.java
@@ -22,7 +22,6 @@
package org.onap.policy.clamp.controlloop.participant.intermediary.handler;
-import java.io.Closeable;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -33,9 +32,11 @@ import lombok.Getter;
import lombok.Setter;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElementDefinition;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopInfo;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopStatistics;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.Participant;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantDefinition;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantHealthStatus;
@@ -53,9 +54,10 @@ import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.Parti
import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantStatusReq;
import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdate;
import org.onap.policy.clamp.controlloop.models.messages.dmaap.participant.ParticipantUpdateAck;
-import org.onap.policy.clamp.controlloop.participant.intermediary.comm.MessageSender;
+import org.onap.policy.clamp.controlloop.participant.intermediary.api.ControlLoopElementListener;
import org.onap.policy.clamp.controlloop.participant.intermediary.comm.ParticipantMessagePublisher;
import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters;
+import org.onap.policy.models.base.PfModelException;
import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
import org.slf4j.Logger;
@@ -67,14 +69,14 @@ import org.springframework.stereotype.Component;
*/
@Getter
@Component
-public class ParticipantHandler implements Closeable {
+public class ParticipantHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ParticipantHandler.class);
private final ToscaConceptIdentifier participantType;
private final ToscaConceptIdentifier participantId;
- private final MessageSender sender;
private final ControlLoopHandler controlLoopHandler;
private final ParticipantStatistics participantStatistics;
+ private final ParticipantMessagePublisher publisher;
@Setter
private ParticipantState state = ParticipantState.UNKNOWN;
@@ -82,10 +84,9 @@ public class ParticipantHandler implements Closeable {
@Setter
private ParticipantHealthStatus healthStatus = ParticipantHealthStatus.UNKNOWN;
- private List<ControlLoopElementDefinition> clElementDefsOnThisParticipant =
- new ArrayList<>();
+ private final List<ControlLoopElementDefinition> clElementDefsOnThisParticipant = new ArrayList<>();
- public ToscaServiceTemplate toscaServiceTemplate = new ToscaServiceTemplate();
+ private ToscaServiceTemplate toscaServiceTemplate = new ToscaServiceTemplate();
/**
* Constructor, set the participant ID and sender.
@@ -93,13 +94,12 @@ public class ParticipantHandler implements Closeable {
* @param parameters the parameters of the participant
* @param publisher the publisher for sending responses to messages
*/
- public ParticipantHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher) {
+ public ParticipantHandler(ParticipantParameters parameters, ParticipantMessagePublisher publisher,
+ ControlLoopHandler controlLoopHandler) {
this.participantType = parameters.getIntermediaryParameters().getParticipantType();
this.participantId = parameters.getIntermediaryParameters().getParticipantId();
- this.sender =
- new MessageSender(this, publisher,
- parameters.getIntermediaryParameters().getReportingTimeIntervalMs());
- this.controlLoopHandler = new ControlLoopHandler(parameters.getIntermediaryParameters(), sender);
+ this.publisher = publisher;
+ this.controlLoopHandler = controlLoopHandler;
this.participantStatistics = new ParticipantStatistics();
this.participantStatistics.setParticipantId(participantId);
this.participantStatistics.setState(state);
@@ -107,18 +107,40 @@ public class ParticipantHandler implements Closeable {
this.participantStatistics.setTimeStamp(Instant.now());
}
- @Override
- public void close() {
- sender.close();
- }
-
/**
* Method which handles a participant health check event from clamp.
*
* @param participantStatusReqMsg participant participantStatusReq message
*/
public void handleParticipantStatusReq(final ParticipantStatusReq participantStatusReqMsg) {
- sender.sendParticipantStatus(makeHeartbeat(true));
+ var controlLoops = controlLoopHandler.getControlLoops();
+ for (ControlLoopElementListener clElementListener : controlLoopHandler.getListeners()) {
+ updateClElementStatistics(controlLoops, clElementListener);
+ }
+
+ var participantStatus = makeHeartbeat(true);
+ publisher.sendParticipantStatus(participantStatus);
+ }
+
+ /**
+ * Update ControlLoopElement statistics. The control loop elements listening will be
+ * notified to retrieve statistics from respective controlloop elements, and controlloopelements
+ * data on the handler will be updated.
+ *
+ * @param controlLoops the control loops
+ * @param clElementListener control loop element listener
+ */
+ private void updateClElementStatistics(ControlLoops controlLoops, ControlLoopElementListener clElementListener) {
+ for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
+ for (ControlLoopElement element : controlLoop.getElements().values()) {
+ try {
+ clElementListener.handleStatistics(element.getId());
+ } catch (PfModelException e) {
+ LOGGER.debug("Getting statistics for Control loop element failed for element ID {}",
+ element.getId(), e);
+ }
+ }
+ }
}
/**
@@ -165,7 +187,7 @@ public class ParticipantHandler implements Closeable {
var participantUpdateAck = new ParticipantUpdateAck();
handleStateChange(participantState, participantUpdateAck);
- sender.sendParticipantUpdateAck(participantUpdateAck);
+ publisher.sendParticipantUpdateAck(participantUpdateAck);
return getParticipant(definition.getName(), definition.getVersion());
}
@@ -215,7 +237,7 @@ public class ParticipantHandler implements Closeable {
participantRegister.setParticipantId(participantId);
participantRegister.setParticipantType(participantType);
- sender.sendParticipantRegister(participantRegister);
+ publisher.sendParticipantRegister(participantRegister);
}
/**
@@ -226,6 +248,14 @@ public class ParticipantHandler implements Closeable {
public void handleParticipantRegisterAck(ParticipantRegisterAck participantRegisterAckMsg) {
LOGGER.debug("ParticipantRegisterAck message received as responseTo {}",
participantRegisterAckMsg.getResponseTo());
+ if (ParticipantHealthStatus.UNKNOWN.equals(this.healthStatus)) {
+ this.healthStatus = ParticipantHealthStatus.HEALTHY;
+ }
+
+ if (ParticipantState.UNKNOWN.equals(this.state)) {
+ this.state = ParticipantState.PASSIVE;
+ }
+ sender.sendParticipantStatus(makeHeartbeat(false));
}
/**
@@ -236,7 +266,7 @@ public class ParticipantHandler implements Closeable {
participantDeregister.setParticipantId(participantId);
participantDeregister.setParticipantType(participantType);
- sender.sendParticipantDeregister(participantDeregister);
+ publisher.sendParticipantDeregister(participantDeregister);
}
/**
@@ -267,7 +297,8 @@ public class ParticipantHandler implements Closeable {
// This message is to commission the controlloop
for (ParticipantDefinition participantDefinition : participantUpdateMsg.getParticipantDefinitionUpdates()) {
if (participantDefinition.getParticipantId().equals(participantType)) {
- clElementDefsOnThisParticipant = participantDefinition.getControlLoopElementDefinitionList();
+ clElementDefsOnThisParticipant.clear();
+ clElementDefsOnThisParticipant.addAll(participantDefinition.getControlLoopElementDefinitionList());
break;
}
}
@@ -289,7 +320,14 @@ public class ParticipantHandler implements Closeable {
participantUpdateAck.setParticipantId(participantId);
participantUpdateAck.setParticipantType(participantType);
- sender.sendParticipantUpdateAck(participantUpdateAck);
+ publisher.sendParticipantUpdateAck(participantUpdateAck);
+ }
+
+ /**
+ * Dispatch a heartbeat for this participant.
+ */
+ public void sendHeartbeat() {
+ publisher.sendHeartbeat(makeHeartbeat(false));
}
/**
@@ -322,15 +360,14 @@ public class ParticipantHandler implements Closeable {
private List<ControlLoopInfo> getControlLoopInfoList() {
List<ControlLoopInfo> controlLoopInfoList = new ArrayList<>();
- for (Map.Entry<ToscaConceptIdentifier, ControlLoop> entry :
- controlLoopHandler.getControlLoopMap().entrySet()) {
+ for (Map.Entry<ToscaConceptIdentifier, ControlLoop> entry : controlLoopHandler.getControlLoopMap().entrySet()) {
ControlLoopInfo clInfo = new ControlLoopInfo();
clInfo.setControlLoopId(entry.getKey());
ControlLoopStatistics clStatitistics = new ControlLoopStatistics();
clStatitistics.setControlLoopId(entry.getKey());
ClElementStatisticsList clElementStatisticsList = new ClElementStatisticsList();
- clElementStatisticsList.setClElementStatistics(
- entry.getValue().getControlLoopElementStatisticsList(entry.getValue()));
+ clElementStatisticsList
+ .setClElementStatistics(entry.getValue().getControlLoopElementStatisticsList(entry.getValue()));
clStatitistics.setClElementStatisticsList(clElementStatisticsList);
clInfo.setControlLoopStatistics(clStatitistics);
clInfo.setState(entry.getValue().getState());
diff --git a/pom.xml b/pom.xml
index 61af7c48e..9fdfed004 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.onap.policy.parent</groupId>
<artifactId>integration</artifactId>
- <version>3.4.0-SNAPSHOT</version>
+ <version>3.4.1-SNAPSHOT</version>
</parent>
<groupId>org.onap.policy.clamp</groupId>
diff --git a/runtime-controlloop/pom.xml b/runtime-controlloop/pom.xml
index 508f44a80..54405548f 100644
--- a/runtime-controlloop/pom.xml
+++ b/runtime-controlloop/pom.xml
@@ -84,6 +84,16 @@
<version>${version.springfox}</version>
</dependency>
<dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-actuator</artifactId>
+ <version>${version.springboot}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-registry-prometheus</artifactId>
+ <version>${version.io.micrometer}</version>
+ </dependency>
+ <dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<scope>runtime</scope>
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/ConverterConfiguration.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/ConverterConfiguration.java
index ee0461994..b14c675df 100644
--- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/ConverterConfiguration.java
+++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/config/ConverterConfiguration.java
@@ -20,9 +20,12 @@
package org.onap.policy.clamp.controlloop.runtime.config;
+import java.util.Arrays;
import java.util.List;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@@ -32,5 +35,9 @@ public class ConverterConfiguration implements WebMvcConfigurer {
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new CoderHttpMesageConverter<>("yaml"));
converters.add(new CoderHttpMesageConverter<>("json"));
+
+ StringHttpMessageConverter converter = new StringHttpMessageConverter();
+ converter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
+ converters.add(converter);
}
}
diff --git a/runtime-controlloop/src/main/resources/application.yaml b/runtime-controlloop/src/main/resources/application.yaml
index ea98aaa8c..cddb3d0fb 100644
--- a/runtime-controlloop/src/main/resources/application.yaml
+++ b/runtime-controlloop/src/main/resources/application.yaml
@@ -50,3 +50,9 @@ runtime:
servers:
- ${topicServer:localhost}
topicCommInfrastructure: dmaap
+
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health, metrics, prometheus
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/rest/ActuatorControllerTest.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/rest/ActuatorControllerTest.java
new file mode 100644
index 000000000..433e914ae
--- /dev/null
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/main/rest/ActuatorControllerTest.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.rest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.core.Response;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.onap.policy.clamp.controlloop.runtime.util.rest.CommonRestController;
+import org.springframework.boot.test.autoconfigure.actuate.metrics.AutoConfigureMetrics;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@AutoConfigureMetrics
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@TestPropertySource(locations = {"classpath:application_test.properties"})
+class ActuatorControllerTest extends CommonRestController {
+
+ private static final String HEALTH_ENDPOINT = "health";
+ private static final String METRICS_ENDPOINT = "metrics";
+ private static final String PROMETHEUS_ENDPOINT = "prometheus";
+
+ @LocalServerPort
+ private int randomServerPort;
+
+ @BeforeEach
+ public void setUpPort() {
+ super.setHttpPrefix(randomServerPort);
+ }
+
+ @Test
+ void testGetHealth_Unauthorized() throws Exception {
+ assertUnauthorizedActGet(HEALTH_ENDPOINT);
+ }
+
+ @Test
+ void testGetMetrics_Unauthorized() throws Exception {
+ assertUnauthorizedActGet(METRICS_ENDPOINT);
+ }
+
+ @Test
+ void testGetPrometheus_Unauthorized() throws Exception {
+ assertUnauthorizedActGet(PROMETHEUS_ENDPOINT);
+ }
+
+ @Test
+ void testGetHealth() throws Exception {
+ Invocation.Builder invocationBuilder = super.sendActRequest(HEALTH_ENDPOINT);
+ Response rawresp = invocationBuilder.buildGet().invoke();
+ assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+ }
+
+ @Test
+ void testGetMetrics() throws Exception {
+ Invocation.Builder invocationBuilder = super.sendActRequest(METRICS_ENDPOINT);
+ Response rawresp = invocationBuilder.buildGet().invoke();
+ assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+ }
+
+ @Test
+ void testGePrometheus() throws Exception {
+ Invocation.Builder invocationBuilder = super.sendActRequest(PROMETHEUS_ENDPOINT);
+ Response rawresp = invocationBuilder.buildGet().invoke();
+ assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
+ }
+}
diff --git a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java
index eebaa5281..ccac0c63b 100644
--- a/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java
+++ b/runtime-controlloop/src/test/java/org/onap/policy/clamp/controlloop/runtime/util/rest/CommonRestController.java
@@ -42,7 +42,9 @@ import org.onap.policy.common.utils.network.NetworkUtil;
public class CommonRestController {
public static final String SELF = NetworkUtil.getHostname();
- public static final String ENDPOINT_PREFIX = "onap/controlloop/v2/";
+ public static final String CONTEXT_PATH = "onap/controlloop";
+ public static final String ENDPOINT_PREFIX = CONTEXT_PATH + "/v2/";
+ public static final String ACTUATOR_ENDPOINT = CONTEXT_PATH + "/actuator/";
private static String httpPrefix;
@@ -71,7 +73,18 @@ public class CommonRestController {
}
/**
- * Sends a request to an endpoint, without any authorization header.
+ * Sends a request to an actuator endpoint.
+ *
+ * @param endpoint the target endpoint
+ * @return a request builder
+ * @throws Exception if an error occurs
+ */
+ protected Invocation.Builder sendActRequest(final String endpoint) throws Exception {
+ return sendFqeRequest(httpPrefix + ACTUATOR_ENDPOINT + endpoint, true);
+ }
+
+ /**
+ * Sends a request to an Rest Api endpoint, without any authorization header.
*
* @param endpoint the target endpoint
* @return a request builder
@@ -82,6 +95,17 @@ public class CommonRestController {
}
/**
+ * Sends a request to an actuator endpoint, without any authorization header.
+ *
+ * @param endpoint the target endpoint
+ * @return a request builder
+ * @throws Exception if an error occurs
+ */
+ protected Invocation.Builder sendNoAuthActRequest(final String endpoint) throws Exception {
+ return sendFqeRequest(httpPrefix + ACTUATOR_ENDPOINT + endpoint, false);
+ }
+
+ /**
* Sends a request to a fully qualified endpoint.
*
* @param fullyQualifiedEndpoint the fully qualified target endpoint
@@ -102,7 +126,7 @@ public class CommonRestController {
final WebTarget webTarget = client.target(fullyQualifiedEndpoint);
- return webTarget.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
+ return webTarget.request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN);
}
/**
@@ -141,6 +165,17 @@ public class CommonRestController {
}
/**
+ * Assert that GET call to actuator endpoint is Unauthorized.
+ *
+ * @param endPoint the endpoint
+ * @throws Exception if an error occurs
+ */
+ protected void assertUnauthorizedActGet(final String endPoint) throws Exception {
+ Response rawresp = sendNoAuthActRequest(endPoint).buildGet().invoke();
+ assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), rawresp.getStatus());
+ }
+
+ /**
* Assert that DELETE call is Unauthorized.
*
* @param endPoint the endpoint
@@ -159,4 +194,8 @@ public class CommonRestController {
protected void setHttpPrefix(int port) {
httpPrefix = "http://" + SELF + ":" + port + "/";
}
+
+ protected String getHttpPrefix() {
+ return httpPrefix;
+ }
}
diff --git a/runtime-controlloop/src/test/resources/application_test.properties b/runtime-controlloop/src/test/resources/application_test.properties
index ad2a4b12c..0074d9f95 100644
--- a/runtime-controlloop/src/test/resources/application_test.properties
+++ b/runtime-controlloop/src/test/resources/application_test.properties
@@ -28,3 +28,5 @@ runtime.topicParameterGroup.topicSources[0].fetchTimeout=15000
runtime.topicParameterGroup.topicSinks[0].topic=POLICY-CLRUNTIME-PARTICIPANT
runtime.topicParameterGroup.topicSinks[0].servers[0]=localhost
runtime.topicParameterGroup.topicSinks[0].topicCommInfrastructure=dmaap
+
+management.endpoints.web.exposure.include=health,metrics,prometheus