Updated monitoring with the latest developments

* Moved 'ems-core' into 'nebulous' dir, and updated it from main repo.
* Add 'ems-nebulous' plugin code, the 'metric-model' specs, and a
  top-level pom.xml to build everything (including EMS-Nebulous image)
* Added .gitattributes and changed EOL to LF in top-level files.
* Also adopting code to pass Zuul checks

Change-Id: Ic414a1fa382d0a9112cbc805375cf603af59cd37
This commit is contained in:
ipatini 2024-01-08 18:59:31 +02:00
parent 25f0770225
commit 96701613c8
604 changed files with 7900 additions and 1041 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

17
.gitignore vendored
View File

@ -1,2 +1,15 @@
__pycache__/
.nox/
target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

View File

@ -5,7 +5,7 @@
replicaCount: 1
image:
repository: "quay.io/nebulous/monitoring-java-spring-boot-demo"
repository: "quay.io/nebulous/monitoring"
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""

View File

@ -1 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=plugin.gr.iccs.imu.ems.common.PluginManager

View File

@ -1,7 +0,0 @@
______ __ ___ __________ __
/ ____/___ _____ ___ ___ / / |__ \ / ____/ __ \/ /
/ / / __ `/ __ `__ \/ _ \/ / __/ / / __/ / /_/ / /
/ /___/ /_/ / / / / / / __/ / / __/ / /___/ ____/ /___
\____/\__,_/_/ /_/ /_/\___/_/ /____/ /_____/_/ /_____/

View File

@ -1,8 +0,0 @@
_____ _ ___ ______ _____ _
/ ____| | | |__ \ | ____| __ \| |
| | __ _ _ __ ___ ___| | ) | | |__ | |__) | |
| | / _` | '_ ` _ \ / _ \ | / / | __| | ___/| |
| |___| (_| | | | | | | __/ | / /_ | |____| | | |____
\_____\__,_|_| |_| |_|\___|_| |____| |______|_| |______|

View File

@ -1,237 +0,0 @@
#
# Copyright (C) 2017-2023 Institute of Communication and Computer Systems (imu.iccs.gr)
#
# This Source Code Form is subject to the terms of the Mozilla Public License, v2.0, unless
# Esper library is used, in which case it is subject to the terms of General Public License v2.0.
# If a copy of the MPL was not distributed with this file, you can obtain one at
# https://www.mozilla.org/en-US/MPL/2.0/
#
# EPL Rule templates per Element-Type and Monitoring-Grouping
DOLLAR: '$'
translator.generator:
language: EPL
rule-templates:
# SCHEDULE (i.e. IUTPUT) CLAUSE
SCHEDULE:
__ANY__:
- |
OUTPUT ALL EVERY [(${DOLLAR}{period})] [(${DOLLAR}{unit})]
AGG:
- |
OUTPUT SNAPSHOT EVERY [(${DOLLAR}{period})] [(${DOLLAR}{unit})]
# Binary-Event-Pattern templates
BEP-AND:
GLOBAL:
- |
/* BEP-AND-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT le.* FROM [(${DOLLAR}{leftEvent})].std:lastevent() AS le, [(${DOLLAR}{rightEvent})].std:lastevent() AS re
BEP-OR:
GLOBAL:
#XXX: TEST:
- |
/* BEP-OR-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT CASE WHEN le IS NULL THEN re ELSE le END AS evt FROM PATTERN [ EVERY ( le=[(${DOLLAR}{leftEvent})] OR re=[(${DOLLAR}{rightEvent})] ) ]
BEP-XOR:
#XXX: XOR is NOT SUPPORTED: IS IT EQUIVALENT TO OR??
GLOBAL:
#XXX: TEST:
- |
/* BEP-XOR-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT CASE WHEN le IS NULL THEN re ELSE le END AS evt FROM PATTERN [ EVERY ( le=[(${DOLLAR}{leftEvent})] OR re=[(${DOLLAR}{rightEvent})] ) ]
BEP-PRECEDES:
GLOBAL:
#XXX: TEST:
- |
/* BEP-PRECEDES-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT le.* FROM PATTERN [ EVERY ( le=[(${DOLLAR}{leftEvent})] -> re=[(${DOLLAR}{rightEvent})] ) ]
BEP-REPEAT_UNTIL:
GLOBAL:
#XXX: TEST:
- |
/* BEP-REPEAT_UNTIL-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT re.* FROM PATTERN [ EVERY [ le=[(${DOLLAR}{leftEvent})] UNTIL re=[(${DOLLAR}{rightEvent})] ] ] WHERE le IS NOT NULL
# Unary-Event-Pattern templates
UEP-EVERY:
#XXX: WHAT'S THE MEANING OF THIS OPERATOR?? ...IF STANDALONE??
GLOBAL:
- |
/* UEP-EVERY-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT ue.* FROM PATTERN [ EVERY ue=[(${DOLLAR}{unaryEvent})] ]
UEP-NOT:
#XXX: WHAT'S THE MEANING OF THIS OPERATOR?? ...IF STANDALONE??
GLOBAL:
- |
/* UEP-NOT-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT ue.* FROM PATTERN [ NOT ue=[(${DOLLAR}{unaryEvent})] ]
UEP-REPEAT:
GLOBAL:
#XXX: TEST:
- |
/* UEP-REPEAT-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT ue[0].* FROM PATTERN [ [[(${DOLLAR}{occurrenceNum})]] ue=[(${DOLLAR}{unaryEvent})] ]
UEP-WHEN:
#XXX: WHAT'S THE MEANING OF THIS OPERATOR?? ...IF STANDALONE??
GLOBAL:
- |
/* UEP-WHEN-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT ue.* FROM [(${DOLLAR}{leftEvent})].std:lastevent() AS ue
# Non-Functional-Event templates
NFE:
GLOBAL:
- |
/* NFE-GLOBAL */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT * FROM [(${DOLLAR}{metricConstraint})].std:lastevent()
# Metric-Constraint templates
CONSTR-MET:
__ANY__:
- |
/* CONSTR-MET-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT * FROM [(${DOLLAR}{metricContext})] HAVING [(${DOLLAR}{metricContext})].metricValue [(${DOLLAR}{operator})] [(${DOLLAR}{threshold})]
# Logical-Constraint templates
CONSTR-LOG:
__ANY__:
- |
/* CONSTR-LOG-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT 1 AS metricValue, 3 AS level, current_timestamp AS timestamp
FROM PATTERN [ EVERY ( [# th:each="con,iterStat : ${DOLLAR}{constraints}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{con} + ' '+${DOLLAR}{operator}+' ' : ${DOLLAR}{con}"] [/] ) ]
# If-Then-Constraint templates
CONSTR-IF-THEN:
__ANY__:
#XXX: TEST:
- |
/* CONSTR-IF-THEN-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT 1 AS metricValue, 3 AS level, current_timestamp AS timestamp
FROM PATTERN [ EVERY ( [(${DOLLAR}{ifConstraint})] AND [(${DOLLAR}{thenConstraint})] [# th:if="${DOLLAR}{elseConstraint != null}" th:text="'OR NOT ( ' + ${DOLLAR}{ifConstraint} + ' ) AND ' + ${DOLLAR}{elseConstraint}"] [/] ) ]
# Context templates
COMP-CTX:
__ANY__:
- |
/* COMP-CTX-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/ [# th:switch="${DOLLAR}{selectMode}"] [# th:case="'epl'"]
SELECT [(${DOLLAR}{formula})] [/] [# th:case="*"]
SELECT EVAL( '[(${DOLLAR}{formula})]', '[# th:each="ctx,iterStat : ${DOLLAR}{components}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ',' : ${DOLLAR}{ctx}"] [/]', [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}"] [/] ) AS metricValue,
3 AS level,
current_timestamp AS timestamp [/] [/]
FROM [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:utext="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx}+${DOLLAR}{windowClause}+' AS '+${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}+${DOLLAR}{windowClause}+' AS '+${DOLLAR}{ctx}"] [/]
[(${DOLLAR}{scheduleClause})]
AGG-COMP-CTX:
__ANY__:
- |
/* COMP-CTX-AGG-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/ [# th:switch="${DOLLAR}{selectMode}"] [# th:case="'epl'"]
SELECT [(${DOLLAR}{formula})] [/] [# th:case="*"]
SELECT EVALAGG( '[(${DOLLAR}{formula})]', '[# th:each="ctx,iterStat : ${DOLLAR}{components}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ',' : ${DOLLAR}{ctx}"] [/]', [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}"] [/] ) AS metricValue,
3 AS level,
current_timestamp AS timestamp [/] [/]
FROM [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:utext="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx}+${DOLLAR}{windowClause}+' AS '+${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}+${DOLLAR}{windowClause}+' AS '+${DOLLAR}{ctx}"] [/]
[(${DOLLAR}{scheduleClause})]
RAW-CTX:
PER_INSTANCE:
- |
/* RAW-CTX-PER_INSTANCE */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT * FROM [(${DOLLAR}{sensor})] [(${DOLLAR}{scheduleClause})]
# Metric templates
TL-MET:
__ANY__:
- |
/* MET-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT * FROM [(${DOLLAR}{context})]
# Metric Variable templates
VAR:
__ANY__:
- |
/* VAR-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/ [# th:switch="${DOLLAR}{selectMode}"] [# th:case="'epl'"]
SELECT [(${DOLLAR}{formula})] [/] [# th:case="*"]
SELECT EVAL( '[(${DOLLAR}{formula})]', '[# th:each="ctx,iterStat : ${DOLLAR}{components}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ',' : ${DOLLAR}{ctx}"] [/]', [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}"] [/] ) AS metricValue,
3 AS level,
current_timestamp AS timestamp [/] [/]
FROM [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx}+' AS '+${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}+' AS '+${DOLLAR}{ctx}"] [/]
AGG-VAR:
__ANY__:
- |
/* VAR-AGG-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/ [# th:switch="${DOLLAR}{selectMode}"] [# th:case="'epl'"]
SELECT [(${DOLLAR}{formula})] [/] [# th:case="*"]
SELECT EVALAGG( '[(${DOLLAR}{formula})]', '[# th:each="ctx,iterStat : ${DOLLAR}{components}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ',' : ${DOLLAR}{ctx}"] [/]', [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}"] [/] ) AS metricValue,
3 AS level,
current_timestamp AS timestamp [/] [/]
FROM [# th:each="ctx,iterStat : ${DOLLAR}{contexts}" th:text="!${DOLLAR}{iterStat.last} ? ${DOLLAR}{ctx}+' AS '+${DOLLAR}{ctx} + ', ' : ${DOLLAR}{ctx}+' AS '+${DOLLAR}{ctx}"] [/]
LOAD-VAR:
__ANY__:
- |
/* LOAD-VAR-any */ /*INSERT INTO [(${outputStream})]*/
SELECT * FROM [(${context})]
# Optimisation-Requirement templates
OPT-REQ-CTX:
__ANY__:
- |
/* OPT-REQ-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT * FROM [(${DOLLAR}{context})]
OPT-REQ-VAR:
__ANY__:
- |
/* OPT-REQ-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT * FROM [(${DOLLAR}{variable})]
# SLO templates
SLO:
__ANY__:
- |
/* SLO-any */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT * FROM [(${DOLLAR}{constraint})]
#XXX:DEL:...remove next rule
XXX-extra-rule-templates:
BEP-AND:
GLOBAL:
- |
/* BEP-AND-GLOBAL : ALTERNATIVE */ /*INSERT INTO [(${DOLLAR}{outputStream})]*/
SELECT le.* FROM PATTERN [ EVERY (le=[(${DOLLAR}{leftEvent})] AND re=[(${DOLLAR}{rightEvent})]) ]
RAW-CTX:
PER_INSTANCE:
- |
/* RAW-CTX-PER_INSTANCE */
INSERT INTO TEST_STREAM
SELECT EVAL('-1*CPUMetric+CPUMetric_2+CPUMetric_3', '[(${DOLLAR}{metric})],[(${DOLLAR}{metric})]_2,[(${DOLLAR}{metric})]_3', [(${DOLLAR}{metric})], [(${DOLLAR}{metric})]_2, [(${DOLLAR}{metric})]_3) AS metricValue,
1 AS level,
current_timestamp AS timestamp
FROM [(${DOLLAR}{metric})] as [(${DOLLAR}{metric})], [(${DOLLAR}{metric})] as [(${DOLLAR}{metric})]_2, [(${DOLLAR}{metric})] as [(${DOLLAR}{metric})]_3[(${DOLLAR}{scheduleClause})]
FE:
PER_INSTANCE:
- |
/* XXX: TODO: FE-PER_INSTANCE */
.......... Functional Event
CONSTR-IF-THEN:
PER_INSTANCE:
- |
/* XXX: TODO: CONSTR-IF-THEN-PER_INSTANCE */
.......... If-Then constraint
CONSTR-VAR:
PER_INSTANCE:
- |
/* XXX: TODO: CONSTR-VAR-PER_INSTANCE */
.......... Metric Variable constraint
CONSTR-LOG:
PER_INSTANCE:
- |
/* XXX: TODO: CONSTR-LOG-PER_INSTANCE */
.......... Logical constraint
VAR:
PER_INSTANCE:
- |
/* XXX: TODO: VAR-PER_INSTANCE */
.......... Metric Variable

16
nebulous/Dockerfile Normal file
View File

@ -0,0 +1,16 @@
# ----------------- Builder image -----------------
FROM docker.io/library/maven:3.9.6-eclipse-temurin-21 as builder
ENV BASEDIR /app
WORKDIR ${BASEDIR}
COPY ems-core ${BASEDIR}/ems-core
COPY ems-nebulous ${BASEDIR}/ems-nebulous
COPY pom.xml ${BASEDIR}/
RUN mvn -f ${BASEDIR}/pom.xml -DskipTests clean install
# ----------------- Runtime image -----------------
FROM registry.gitlab.com/nebulous-project/ems-main/ems-server:2024-jan
COPY --from=builder /app/ems-nebulous/target/ems-nebulous-plugin-1.0.0-SNAPSHOT-jar-with-dependencies.jar /plugins/
ENV EXTRA_LOADER_PATHS=/plugins/*
ENV SCAN_PACKAGES=eu.nebulous.ems

View File

@ -41,6 +41,8 @@ public class ClientInstallationProperties implements InitializingBean {
private String clientInstallationRequestsTopic = "ems.client.installation.requests";
private String clientInstallationReportsTopic = "ems.client.installation.reports";
private List<Pattern> clientInstallationReportNodeInfoPatterns = new ArrayList<>();
private String clientInfoRequestsTopic = "ems.client.info.requests";
private String clientInfoReportsTopic = "ems.client.info.reports";
private String baseDir; // EMS client home directory
private String rootCmd; // Root command (e.g. 'sudo', or 'echo ${NODE_SSH_PASSWORD} | sudo -S ')

View File

@ -29,11 +29,13 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import javax.jms.*;
import jakarta.jms.*;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import static gr.iccs.imu.ems.baguette.client.install.ClientInstallationTask.TASK_TYPE;
/**
* Installation Event Listener
*/
@ -93,54 +95,92 @@ public class ClientInstallationRequestListener implements InitializingBean {
? connectionFactory.createConnection(brokerCepService.getBrokerUsername(), brokerCepService.getBrokerPassword())
: connectionFactory.createConnection());
Session session = connection.createSession(true, 0);
MessageConsumer consumer = session.createConsumer(
new ActiveMQTopic(properties.getClientInstallationRequestsTopic()));
consumer.setMessageListener(getMessageListener());
List<String> topics = Arrays.asList(
properties.getClientInstallationRequestsTopic(),
properties.getClientInfoRequestsTopic()
);
log.debug("InstallationEventListener: Will subscribe to topics: {}", topics);
MessageListener listener = getMessageListener();
for (String topic : topics) {
MessageConsumer consumer = session.createConsumer(
new ActiveMQTopic( topic ));
consumer.setMessageListener(listener);
log.debug("InstallationEventListener: Subscribed to topic: {}", topic);
}
connection.start();
log.debug("InstallationEventListener: STARTED");
}
private MessageListener getMessageListener() {
return message -> {
String requestId = null;
Map<String, String> request = null;
TASK_TYPE requestType = TASK_TYPE.OTHER;
try {
// Extract request from JMS message
Map<String, String> request = extractRequest(message);
request = extractRequest(message);
log.debug("InstallationEventListener: Got a client installation request: {}", request);
if (request==null)
throw new IllegalArgumentException("Could not extract request data");
requestId = request.get("requestId").trim();
if (request==null) {
clientInstaller.sendErrorClientInstallationReport(TASK_TYPE.OTHER,
null, "ERROR: Invalid request. Could not extract request data");
return;
}
// Check incoming request
List<String> errors = new ArrayList<>();
if (StringUtils.isBlank(request.get("requestId"))) errors.add("requestId");
if (StringUtils.isBlank(request.get("requestType"))) errors.add("requestType");
if (StringUtils.isBlank(request.get("deviceOs"))) errors.add("deviceOs");
if (StringUtils.isBlank(request.get("deviceIpAddress"))) errors.add("deviceIpAddress");
if (StringUtils.isBlank(request.get("deviceUsername"))) errors.add("deviceUsername");
if (StringUtils.isBlank(request.get("devicePassword")) && StringUtils.isBlank(request.get("devicePublicKey")))
errors.add("Both devicePublicKey and devicePublicKey");
if (! errors.isEmpty()) {
String errorMessage = "Missing fields: " + String.join(", ", errors);
throw new IllegalArgumentException(errorMessage);
// Get request type
String requestTypeStr = request.get("requestType");
if (StringUtils.isBlank(requestTypeStr)) {
clientInstaller.sendErrorClientInstallationReport(TASK_TYPE.OTHER,
request, "ERROR: Invalid request. Missing requestType field");
return;
}
try {
if ("VM".equalsIgnoreCase(requestTypeStr)) requestTypeStr = TASK_TYPE.INSTALL.name();
if ("REMOVE".equalsIgnoreCase(requestTypeStr)) requestTypeStr = TASK_TYPE.UNINSTALL.name();
if ("UPDATE".equalsIgnoreCase(requestTypeStr)) requestTypeStr = TASK_TYPE.INFO.name();
requestType = TASK_TYPE.valueOf(requestTypeStr.trim().toUpperCase());
} catch (Exception e) {
clientInstaller.sendErrorClientInstallationReport(TASK_TYPE.OTHER,
request, "ERROR: Invalid request. Invalid requestType field value: "+requestTypeStr);
return;
}
// If not an INFO or NODE_DETAILS request run extra checks
if (TASK_TYPE.INFO != requestType && TASK_TYPE.NODE_DETAILS != requestType) {
// Check incoming request
List<String> errors = new ArrayList<>();
if (StringUtils.isBlank(request.get("requestId")) &&
(TASK_TYPE.DIAGNOSTICS==requestType || TASK_TYPE.INSTALL==requestType))
errors.add("requestId");
if (StringUtils.isBlank(request.get("deviceOs"))) errors.add("deviceOs");
if (StringUtils.isBlank(request.get("deviceIpAddress"))) errors.add("deviceIpAddress");
if (StringUtils.isBlank(request.get("deviceUsername"))) errors.add("deviceUsername");
if (StringUtils.isBlank(request.get("devicePassword"))
&& StringUtils.isBlank(request.get("devicePublicKey"))) errors.add("Both devicePublicKey and devicePublicKey");
if (!errors.isEmpty()) {
String errorMessage = "Missing fields: " + String.join(", ", errors);
clientInstaller.sendErrorClientInstallationReport(requestType, request, "ERROR: "+errorMessage);
return;
}
}
// Process request based on its type
String requestType = request.get("requestType").trim();
switch (requestType) {
case "DIAGNOSTICS" -> processDiagnosticsRequest(request);
case "VM" -> processOnboardingRequest(request);
case "REMOVE" -> processRemoveRequest(request);
case DIAGNOSTICS -> processDiagnosticsRequest(request);
case INSTALL -> processOnboardingRequest(request);
case REINSTALL -> processReinstallRequest(request);
case UNINSTALL -> processRemoveRequest(request);
case NODE_DETAILS -> processNodeDetailsRequest(request);
case INFO -> processInfoRequest(request);
default -> throw new IllegalArgumentException("Unsupported request type: "+requestType);
};
} catch (Throwable e) {
log.error("InstallationEventListener: ERROR: ", e);
try {
if (StringUtils.isNotBlank(requestId))
clientInstaller.sendErrorClientInstallationReport(requestId, "ERROR: "+e.getMessage());
else
clientInstaller.sendErrorClientInstallationReport("UNKNOWN-REQUEST-ID", "ERROR: "+e.getMessage()+"\n"+message);
clientInstaller.sendErrorClientInstallationReport(
requestType, request, "ERROR: "+e.getMessage()+"\n"+message);
} catch (Throwable t) {
log.info("InstallationEventListener: EXCEPTION while sending Client installation report for incoming request: request={}, Exception: ", message, t);
}
@ -175,7 +215,7 @@ public class ClientInstallationRequestListener implements InitializingBean {
// Create client installation task
ClientInstallationTask newTask = ClientInstallationTask.builder()
.id(request.get("requestId"))
.taskType(ClientInstallationTask.TASK_TYPE.DIAGNOSTIC)
.taskType(ClientInstallationTask.TASK_TYPE.DIAGNOSTICS)
.requestId(request.get("requestId"))
.type(request.get("requestType"))
.nodeId(request.get("deviceId"))
@ -214,7 +254,8 @@ public class ClientInstallationRequestListener implements InitializingBean {
String requestId = request.getOrDefault("requestId", "").trim();
log.info("InstallationEventListener: New node ONBOARDING request with Id: {}", requestId);
if (StringUtils.isBlank(requestId)) {
clientInstaller.sendErrorClientInstallationReport("MISSING-REQUEST-ID", "INVALID REQUEST. MISSING REQUEST ID");
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.INSTALL, request, "INVALID REQUEST. MISSING REQUEST ID");
return;
}
@ -223,14 +264,132 @@ public class ClientInstallationRequestListener implements InitializingBean {
nodeRegistration.registerNode(null, convertToNodeInfoMap(request), new TranslationContext(requestId));
} catch (Exception e) {
log.warn("InstallationEventListener: EXCEPTION while executing ONBOARDING request with Id: {}\n", requestId, e);
clientInstaller.sendErrorClientInstallationReport(requestId, "ERROR: "+e.getMessage());
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.INSTALL, request, "ERROR: "+e.getMessage());
}
}
private void processReinstallRequest(Map<String,String> request) throws Exception {
String requestId = request.getOrDefault("requestId", "").trim();
String deviceId = request.getOrDefault("deviceId", "").trim();
String ipAddress = request.getOrDefault("deviceIpAddress", "").trim();
log.info("InstallationEventListener: REINSTALL request with device Id: {}, ip-address={}", deviceId, ipAddress);
if (StringUtils.isBlank(deviceId)) {
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.REINSTALL, request, "INVALID REQUEST. MISSING DEVICE ID");
return;
}
if (StringUtils.isBlank(ipAddress)) {
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.REINSTALL, request, "INVALID REQUEST. MISSING DEVICE IP ADDRESS");
return;
}
try {
log.debug("InstallationEventListener: Reinstalling node due to REINSTALL request with Id: {}", deviceId);
nodeRegistration.reinstallNode(ipAddress, new TranslationContext(requestId));
} catch (Exception e) {
log.warn("InstallationEventListener: EXCEPTION while executing REINSTALL request with Id: {}\n", deviceId, e);
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.REINSTALL, request, "ERROR: "+e.getMessage());
}
}
private void processRemoveRequest(Map<String,String> request) throws Exception {
String requestId = request.getOrDefault("requestId", "").trim();
String deviceId = request.getOrDefault("deviceId", "").trim();
String nodeAddress = request.getOrDefault("deviceIpAddress", "").trim();
log.info("InstallationEventListener: New node REMOVE request with Id: {}, address={}", deviceId, nodeAddress);
if (StringUtils.isBlank(deviceId)) {
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.UNINSTALL, request, "INVALID REQUEST. MISSING DEVICE ID");
return;
}
if (StringUtils.isBlank(nodeAddress)) {
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.UNINSTALL, request, "INVALID REQUEST. MISSING IP ADDRESS");
return;
}
try {
log.debug("InstallationEventListener: Off-boarding node due to REMOVE request with Id: {}, requestId={}", deviceId, requestId);
nodeRegistration.unregisterNode(nodeAddress, new TranslationContext(requestId));
} catch (Exception e) {
log.warn("InstallationEventListener: EXCEPTION while executing REMOVE request with Id: {}\n", deviceId, e);
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.UNINSTALL, request, "ERROR: "+e.getMessage());
}
}
private void processNodeDetailsRequest(Map<String,String> request) throws Exception {
String nodeAddress = request.getOrDefault("deviceIpAddress", "").trim();
log.info("InstallationEventListener: New node NODE_DETAILS request with: address={}", nodeAddress);
if (StringUtils.isBlank(nodeAddress)) {
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.NODE_DETAILS, request, "INVALID REQUEST. MISSING IP ADDRESS");
return;
}
log.info("InstallationEventListener: Processing NODE_DETAILS request");
try {
log.debug("InstallationEventListener: Requesting NODE_DETAILS");
NodeRegistryEntry entry = nodeRegistration.requestNodeDetails(nodeAddress);
log.trace("InstallationEventListener: NODE_DETAILS: entry={}", entry);
if (entry!=null) {
// Get node details from NodeRegistry
Map<String, Object> response = clientInstaller.createReportEventFromNodeData(
-1, TASK_TYPE.NODE_DETAILS, "", "",
entry.getIpAddress(), entry.getReference(), entry.getPreregistration(), "SUCCESS");
log.debug("InstallationEventListener: NODE_DETAILS response (1): {}", response);
// ...make response map mutable
response = new LinkedHashMap<>(response);
// ...include additional fields
Map<String, String> preregData = entry.getPreregistration();
response.put("os", preregData.getOrDefault("NODE_OPERATINGSYSTEM", ""));
response.put("name", preregData.getOrDefault("NODE_NAME", ""));
response.put("username", preregData.getOrDefault("NODE_SSH_USERNAME", ""));
response.put("password", preregData.getOrDefault("NODE_SSH_PASSWORD", ""));
response.put("key", preregData.getOrDefault("NODE_SSH_KEY", ""));
response.put("requestId", "");
response.put("state", entry.getState()!=null ? entry.getState().name() : "");
log.debug("InstallationEventListener: NODE_DETAILS response (2): {}", response);
// Send NODE_DETAILS response
log.trace("InstallationEventListener: Sending NODE_DETAILS response: {}", response);
clientInstaller.publishReport(new LinkedHashMap<>(response));
log.debug("InstallationEventListener: Sent NODE_DETAILS response: {}", response);
} else {
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.NODE_DETAILS, request, "ERROR: No node found in NodeRegistry with IP address: "+nodeAddress);
}
} catch (Exception e) {
log.warn("InstallationEventListener: EXCEPTION while retrieving NODE_DETAILS:\n", e);
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.INFO, request, "ERROR: "+e.getMessage());
}
}
private void processInfoRequest(Map<String,String> request) throws Exception {
log.info("InstallationEventListener: INFO request");
try {
log.debug("InstallationEventListener: Requesting INFO");
nodeRegistration.requestInfo();
} catch (Exception e) {
log.warn("InstallationEventListener: EXCEPTION while executing INFO:\n", e);
clientInstaller.sendErrorClientInstallationReport(
TASK_TYPE.INFO, request, "ERROR: "+e.getMessage());
}
}
private Map<String, Object> convertToNodeInfoMap(Map<String, String> request) {
log.trace("InstallationEventListener.convertToNodeInfoMap(): BEGIN: request: {}", request);
String requestId = request.get("requestId");
String nodeId = request.get("requestId");
String nodeId = request.get("deviceId");
String nodeOs = request.get("deviceOs");
String nodeAddress = request.get("deviceIpAddress");
String nodeType = request.get("deviceType");
@ -267,26 +426,4 @@ public class ClientInstallationRequestListener implements InitializingBean {
log.trace("InstallationEventListener.convertToNodeInfoMap(): END: nodeMap: {}", nodeMap);
return nodeMap;
}
private void processRemoveRequest(Map<String,String> request) throws Exception {
String requestId = request.getOrDefault("requestId", "").trim();
String nodeAddress = request.getOrDefault("deviceIpAddress", "").trim();
log.info("InstallationEventListener: New node REMOVE request with Id: {}, address={}", requestId, nodeAddress);
if (StringUtils.isBlank(requestId)) {
clientInstaller.sendErrorClientInstallationReport("MISSING-REQUEST-ID", "INVALID REQUEST. MISSING REQUEST ID");
return;
}
if (StringUtils.isBlank(nodeAddress)) {
clientInstaller.sendErrorClientInstallationReport(requestId, "INVALID REQUEST. MISSING IP ADDRESS");
return;
}
try {
log.debug("InstallationEventListener: Off-boarding node due to REMOVE request with Id: {}", requestId);
nodeRegistration.unregisterNode(nodeAddress, new TranslationContext(requestId));
} catch (Exception e) {
log.warn("InstallationEventListener: EXCEPTION while executing REMOVE request with Id: {}\n", requestId, e);
clientInstaller.sendErrorClientInstallationReport(requestId, "ERROR: "+e.getMessage());
}
}
}

View File

@ -24,7 +24,7 @@ import java.util.concurrent.Callable;
@Data
@Builder
public class ClientInstallationTask {
public enum TASK_TYPE { INSTALL, UNINSTALL, DIAGNOSTIC, OTHER }
public enum TASK_TYPE { INSTALL, REINSTALL, UNINSTALL, NODE_DETAILS, INFO, DIAGNOSTICS, OTHER }
private final String id;
private final TASK_TYPE taskType;
@ -39,6 +39,7 @@ public class ClientInstallationTask {
private final NodeRegistryEntry nodeRegistryEntry;
private final List<InstructionsSet> instructionSets;
private final TranslationContext translationContext;
@Builder.Default
private boolean nodeMustBeInRegistry = true;
private Callable<String> callback;

View File

@ -22,8 +22,9 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.jms.JMSException;
import javax.validation.constraints.NotNull;
import jakarta.jms.JMSException;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.Instant;
import java.util.Collections;
import java.util.LinkedHashMap;
@ -33,6 +34,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import static gr.iccs.imu.ems.baguette.client.install.ClientInstallationTask.TASK_TYPE;
/**
* Client installer
*/
@ -128,7 +131,7 @@ public class ClientInstaller implements InitializingBean {
return executeVmOrBaremetalTask(task, taskCounter);
} else
//if ("DIAGNOSTICS".equalsIgnoreCase(task.getType())) {
if (task.getTaskType()==ClientInstallationTask.TASK_TYPE.DIAGNOSTIC) {
if (task.getTaskType()==TASK_TYPE.DIAGNOSTICS) {
return executeDiagnosticsTask(task, taskCounter);
} else {
log.error("ClientInstaller: UNSUPPORTED TASK TYPE: {}", task.getType());
@ -181,13 +184,13 @@ public class ClientInstaller implements InitializingBean {
}
// Pre-register Node to baguette Server Coordinator
if (task.getTaskType()==ClientInstallationTask.TASK_TYPE.INSTALL) {
if (task.getTaskType()==TASK_TYPE.INSTALL) {
log.debug("ClientInstaller: POST-INSTALLATION: Node is being pre-registered: {}", entry);
baguetteServer.getNodeRegistry().getCoordinator().preregister(entry);
}
// Un-register Node from baguette Server Coordinator
if (task.getTaskType()==ClientInstallationTask.TASK_TYPE.UNINSTALL) {
if (task.getTaskType()==TASK_TYPE.UNINSTALL) {
ClientShellCommand csc = ClientShellCommand.getActiveByIpAddress(entry.getIpAddress());
log.debug("ClientInstaller: POST-INSTALLATION: CSC of node to be unregistered: {}", csc);
if (csc!=null) {
@ -247,43 +250,89 @@ public class ClientInstaller implements InitializingBean {
createReportEventFromExecutionResults(taskCnt, task, resultStr));
log.info("ClientInstaller: Sending SUCCESS execution report for Task #{}: destination={}, report={}",
taskCnt, properties.getClientInstallationReportsTopic(), executionReport);
brokerCepService.publishSerializable(
null, properties.getClientInstallationReportsTopic(), executionReport, true);
publishReport(executionReport);
}
public void sendErrorClientInstallationReport(String requestId, String resultStr) throws JMSException {
log.trace("ClientInstaller: Preparing ERROR execution report event for request: result={}, requestId={}", resultStr, requestId);
public void sendErrorClientInstallationReport(@NonNull TASK_TYPE requestType, Map<String,String> request, String resultStr) throws JMSException {
sendErrorClientInstallationReport(requestType, request, null, resultStr);
}
public void sendErrorClientInstallationReport(@NonNull TASK_TYPE requestType, Map<String,String> request, String reference, String resultStr) throws JMSException {
log.trace("ClientInstaller: Preparing ERROR execution report event for request: result={}, request={}", resultStr, request);
String requestId = getOrDefault(request, "requestId", "MISSING-REQUEST-ID");
String deviceId = getOrDefault(request, "deviceId", "MISSING-DEVICE-ID");
String ipAddress = getOrDefault(request, "deviceIpAddress", "MISSING-DEVICE-ADDRESS");
LinkedHashMap<String, Object> executionReport = new LinkedHashMap<>(
createReportEvent(requestId, null, resultStr, Collections.emptyMap()));
log.info("ClientInstaller: Sending ERROR execution report for request: destination={}, report={}",
createReportEvent(requestType,
requestId, deviceId, ipAddress, reference, resultStr, Collections.emptyMap()));
log.info("ClientInstaller: Sending ERROR execution report: destination={}, report={}",
properties.getClientInstallationReportsTopic(), executionReport);
publishReport(executionReport);
}
private String getOrDefault(Map<String,String> map, String key, String defaultValue) {
if (map==null) return defaultValue;
return map.getOrDefault(key, defaultValue);
}
public void publishReport(Serializable report) throws JMSException {
brokerCepService.publishSerializable(
null, properties.getClientInstallationReportsTopic(), executionReport, true);
null, properties.getClientInstallationReportsTopic(), report, true);
}
private Map<String, Object> createReportEventFromExecutionResults(long taskCnt, @NonNull ClientInstallationTask task, String resultStr) {
log.trace("ClientInstaller: createReportEventFromExecutionResults: Task #{}: ARGS: result={}, task={}", taskCnt, resultStr, task);
// Get execution results
Map<String, String> data = task.getNodeRegistryEntry().getPreregistration();
log.trace("ClientInstaller: createReportEventFromExecutionResults: Task #{}: Execution data:\n{}", taskCnt, data);
// Create report event
TASK_TYPE requestType = task.getTaskType();
String requestId = task.getRequestId();
String deviceId = task.getNodeId();
return createReportEventFromNodeData(taskCnt, requestType, requestId, deviceId,
task.getAddress(), task.getNodeRegistryEntry().getReference(), data, resultStr);
}
public Map<String, Object> createReportEventFromNodeData(long taskCnt,
TASK_TYPE requestType,
String requestId,
String deviceId,
String ipAddress,
String reference,
Map<String, String> data,
String resultStr)
{
// Copy node info from execution results
Map<String, Object> nodeInfoMap = new LinkedHashMap<>();
properties.getClientInstallationReportNodeInfoPatterns().forEach(pattern -> {
log.trace("ClientInstaller: createReportEventFromExecutionResults: Task #{}:Applying pattern: {}", taskCnt, pattern);
log.trace("ClientInstaller: createReportEventFromNodeData: Task #{}: Applying pattern: {}", taskCnt, pattern);
data.keySet().stream()
//.peek(key->log.trace(" ----> Checking: key={}, match={}", key, pattern.matcher(key).matches()))
.filter(key -> pattern.matcher(key).matches())
.forEach(key -> nodeInfoMap.put(key, data.get(key)));
});
log.debug("ClientInstaller: createReportEventFromExecutionResults: Task #{}: Node info collected: {}", taskCnt, nodeInfoMap);
String requestId = StringUtils.defaultIfBlank(task.getRequestId(), task.getId());
return createReportEvent(requestId, task.getNodeRegistryEntry().getReference(), resultStr, nodeInfoMap);
log.debug("ClientInstaller: createReportEventFromNodeData: Task #{}: Node info collected: {}", taskCnt, nodeInfoMap);
// Create and send report event
return createReportEvent(
requestType, requestId, deviceId, ipAddress, reference, resultStr, nodeInfoMap);
}
private static Map<String, Object> createReportEvent(@NonNull String requestId,
private static Map<String, Object> createReportEvent(@NonNull TASK_TYPE requestType,
String requestId,
String deviceId,
String ipAddress,
String reference,
@NonNull String statusStr,
Map<String, Object> nodeInfoMap)
{
return Map.of(
"requestId", requestId,
"requestType", requestType.name(),
"requestId", Objects.requireNonNullElse(requestId, ""),
"deviceId", Objects.requireNonNullElse(deviceId, ""),
"deviceIpAddress", Objects.requireNonNullElse(ipAddress, ""),
"reference", Objects.requireNonNullElse(reference, ""),
"status", statusStr,
"nodeInfo", nodeInfoMap!=null ? nodeInfoMap : Collections.emptyMap(),

View File

@ -408,7 +408,7 @@ public class SshClientInstaller implements ClientInstallerPlugin {
setChannelStreams(channel);
log.debug("SshClientInstaller: task #{}: EXEC: New channel id: {}", taskCounter, channel.getChannelId());
//streamLogger.getInvertedIn().write(command.getBytes());
streamLogger.logMessage(String.format("EXEC: %s\n", command));
streamLogger.logMessage("EXEC: %s\n".formatted(command));
try {
// Sending command to remote side
log.debug("SshClientInstaller: task #{}: EXEC: Sending command for execution: {} (connect timeout: {}ms)", taskCounter, command, connectTimeout);
@ -444,7 +444,7 @@ public class SshClientInstaller implements ClientInstallerPlugin {
return true;
}
streamLogger.logMessage(String.format("DOWNLOAD: SCP: %s -> %s\n", remoteFilePath, localFilePath));
streamLogger.logMessage("DOWNLOAD: SCP: %s -> %s\n".formatted(remoteFilePath, localFilePath));
try {
log.info("SshClientInstaller: Downloading file: task #{}: remote: {} -> local: {}", taskCounter, remoteFilePath, localFilePath);
ScpClientCreator creator = new DefaultScpClientCreator();
@ -465,7 +465,7 @@ public class SshClientInstaller implements ClientInstallerPlugin {
return true;
}
streamLogger.logMessage(String.format("UPLOAD: SCP: %s -> %s\n", localFilePath, remoteFilePath));
streamLogger.logMessage("UPLOAD: SCP: %s -> %s\n".formatted(localFilePath, remoteFilePath));
try {
long startTm = System.currentTimeMillis();
log.info("SshClientInstaller: Uploading file: task #{}: local: {} -> remote: {}", taskCounter, localFilePath, remoteFilePath);
@ -488,7 +488,7 @@ public class SshClientInstaller implements ClientInstallerPlugin {
return true;
}
streamLogger.logMessage(String.format("WRITE FILE: SCP: %s, content-length=%d \n", remoteFilePath, content.length()));
streamLogger.logMessage("WRITE FILE: SCP: %s, content-length=%d \n".formatted(remoteFilePath, content.length()));
try {
long timestamp = System.currentTimeMillis();
/*Collection<PosixFilePermission> permissions = isExecutable
@ -819,7 +819,7 @@ public class SshClientInstaller implements ClientInstallerPlugin {
contents = StringSubstitutor.replace(contents, valueMap);
log.trace("SshClientInstaller: Task #{}: FILE: {}, final-content:\n{}", taskCounter, targetFile, contents);
String description = String.format("Copy file from server to temp to client: %s -> %s", sourcePath.toString(), targetFile);
String description = "Copy file from server to temp to client: %s -> %s".formatted(sourcePath.toString(), targetFile);
return sshFileWrite(contents, targetFile, isExecutable);
}

View File

@ -156,8 +156,7 @@ public class SshJsClientInstaller extends SshClientInstaller {
log.error("SshJsClientInstaller: Task #{}: JS installation script returned NULL: {}", getTaskCounter(), jsScript);
return INSTRUCTION_RESULT.FAIL;
}
if (result instanceof Integer) {
int code = (int)result;
if (result instanceof Integer code) {
log.info("SshJsClientInstaller: Task #{}: JS installation script returned: code={}, script: {}", getTaskCounter(), code, jsScript);
return code==0 ? INSTRUCTION_RESULT.SUCCESS : INSTRUCTION_RESULT.FAIL;
} else {

View File

@ -9,6 +9,7 @@
package gr.iccs.imu.ems.baguette.client.install.api;
import gr.iccs.imu.ems.baguette.server.NodeRegistryEntry;
import gr.iccs.imu.ems.translate.TranslationContext;
import java.util.Map;
@ -16,4 +17,7 @@ import java.util.Map;
public interface INodeRegistration {
String registerNode(String baseUrl, Map<String,Object> nodeInfo, TranslationContext translationContext) throws Exception;
String unregisterNode(String nodeAddress, TranslationContext translationContext) throws Exception;
String reinstallNode(String ipAddress, TranslationContext translationContext) throws Exception;
NodeRegistryEntry requestNodeDetails(String nodeAddress) throws Exception;
void requestInfo() throws Exception;
}

View File

@ -281,7 +281,8 @@ public abstract class AbstractInstallationHelper implements InitializingBean, Ap
contents = StringSubstitutor.replace(contents, valueMap);
String tmpFile = clientTmpDir+"/installEMS_"+System.currentTimeMillis();
instructionsSet
.appendLog(String.format("Copy file from server to temp to client: %s -> %s -> %s", p.toString(), tmpFile, targetFile));
.appendLog("Copy file from server to temp to client: %s -> %s -> %s"
.formatted(p.toString(), tmpFile, targetFile));
return _appendCopyInstructions(instructionsSet, targetFile, tmpFile, contents, clientTmpDir);
}

View File

@ -33,5 +33,6 @@ public interface InstallationHelper {
return createClientInstallationTask(entry, null);
}
ClientInstallationTask createClientInstallationTask(NodeRegistryEntry entry, TranslationContext translationContext) throws Exception;
ClientInstallationTask createClientReinstallTask(NodeRegistryEntry entry, TranslationContext translationContext) throws Exception;
ClientInstallationTask createClientUninstallTask(NodeRegistryEntry entry, TranslationContext translationContext) throws Exception;
}

View File

@ -68,6 +68,15 @@ public class VmInstallationHelper extends AbstractInstallationHelper {
return createClientTask(ClientInstallationTask.TASK_TYPE.INSTALL, entry, translationContext, instructionsSetList);
}
@Override
public ClientInstallationTask createClientReinstallTask(NodeRegistryEntry entry, TranslationContext translationContext) throws IOException {
// Get EMS client reinstall instructions for VM node
List<InstructionsSet> instructionsSetList =
prepareInstallationInstructionsForOs(entry);
return createClientTask(ClientInstallationTask.TASK_TYPE.REINSTALL, entry, translationContext, instructionsSetList);
}
@Override
public ClientInstallationTask createClientUninstallTask(NodeRegistryEntry entry, TranslationContext translationContext) throws Exception {
// Clear any cached 'instruction-files' override (from a previous run)
@ -358,7 +367,7 @@ public class VmInstallationHelper extends AbstractInstallationHelper {
targetFile = remoteTargetDir + targetFile;
String contents = new String(Files.readAllBytes(path));
contents = StringSubstitutor.replace(contents, valueMap);
String description = String.format("Copy file from server to temp to client: %s -> %s", path.toString(), targetFile);
String description = "Copy file from server to temp to client: %s -> %s".formatted(path.toString(), targetFile);
return _appendCopyInstructions(instructionsSet, targetFile, description, contents);
}

View File

@ -13,7 +13,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import jakarta.validation.constraints.NotNull;
import java.util.Map;
import java.util.regex.Pattern;

View File

@ -59,8 +59,8 @@ public class InstructionsService implements EnvironmentAware {
log.trace("InstructionsService: checkCondition: Expression result: {}", result);
if (result==null)
throw new IllegalArgumentException("Condition evaluation returned null: " + condition);
if (result instanceof Boolean)
return (Boolean)result;
if (result instanceof Boolean booleanValue)
return booleanValue;
throw new IllegalArgumentException("Condition evaluation returned a non-boolean value: " + result + ", condition: " + condition+", resolved condition: "+ conditionResolved);
}

View File

@ -52,22 +52,15 @@ public class AllowedTopicsProcessorPlugin implements InstallationContextProcesso
addedTopicsSet.add(metricName);
}
// Get sensor configuration (as a list of KeyValuePair's)
Map<String,String> sensorConfig = null;
if (monitor.getSensor().isPullSensor()) {
// Pull Sensor
sensorConfig = monitor.getSensor().pullSensor().getConfiguration();
} else {
// Push Sensor
sensorConfig = monitor.getSensor().pushSensor().getAdditionalProperties();
}
// Get sensor configuration
Map<String,Object> sensorConfig = monitor.getSensor().getConfiguration();;
// Process Destination aliases, if specified in configuration
if (sensorConfig!=null) {
String k = sensorConfig.keySet().stream()
.filter(key -> StrUtil.compareNormalized(key, EmsConstant.COLLECTOR_DESTINATION_ALIASES))
.findAny().orElse(null);
String aliases = (k!=null) ? sensorConfig.get(k) : null;
String aliases = (k!=null && sensorConfig.get(k) instanceof String) ? sensorConfig.get(k).toString() : null;
if (StringUtils.isNotBlank(aliases)) {
for (String alias : aliases.trim().split(EmsConstant.COLLECTOR_DESTINATION_ALIASES_DELIMITERS)) {

View File

@ -62,7 +62,8 @@ public class PrometheusProcessorPlugin implements InstallationContextProcessorPl
log.trace("PrometheusProcessorPlugin: Task #{}: MONITOR: component={}, metric={}", taskCounter, componentName, metricName);
if (monitor.getSensor().isPullSensor()) {
if (monitor.getSensor().pullSensor().getConfiguration()!=null) {
Map<String, String> config = monitor.getSensor().pullSensor().getConfiguration();
Map<String, String> config = StrUtil.deepFlattenMap(
monitor.getSensor().getConfiguration());
log.trace("PrometheusProcessorPlugin: Task #{}: MONITOR with PULL SENSOR: config: {}", taskCounter, config);
// Get Prometheus related settings

View File

@ -654,6 +654,8 @@ public class CommandExecutor {
log.info("Cluster: configuration:\n{}", clusterManagerProperties);
} else if ("GET-STATS".equals(cmd)) {
getStatistics(args[1]);
} else if ("COLLECT-STATS".equals(cmd)) {
collectStatistics();
} else if ("SEND-STATS".equals(cmd)) {
if (args.length < 2) {
log.warn("Too few arguments");
@ -1260,6 +1262,29 @@ public class CommandExecutor {
if (out!=null) out.println("-INPUT:"+inputUuid+":"+SerializationUtil.serializeToString(statsMap));
}
private void collectStatistics() {
try {
// Run system metrics collection script
log.debug("Running system metrics collection...");
boolean result = systemResourceMonitor.runImmediatelyBlocking(-1); // >=0: timeout in millis; <0: wait forever
log.debug("Running system metrics collection... {}", result ? "done" : "cancel/timeout");
// Collect metrics
Map<String, Object> statsMap = brokerCepService.getBrokerCepStatistics();
log.debug("BCEP Statistics: {}", statsMap);
Map<String, Object> sysMap = systemResourceMonitor.getLatestMeasurements();
log.debug("System Statistics: {}", sysMap);
// Prepare and send response
Map<String, Object> clientStats = new HashMap<>();
if (statsMap!=null) clientStats.putAll(statsMap);
if (sysMap!=null) clientStats.putAll(sysMap);
if (out!=null) out.println("-STATS:" + SerializationUtil.serializeToString(statsMap));
} catch (Exception ex) {
log.error("Exception while getting Statistics to server: ", ex);
}
}
@SneakyThrows
private void sendStatisticsStart() {
statsSendTask = taskScheduler.scheduleWithFixedDelay(() -> {

View File

@ -75,7 +75,7 @@ public class TestCallback extends AbstractLogBase implements BrokerUtil.NodeCall
}
public String getConfiguration(Member local) {
return String.format("ssl://%s:61617", local.address().host());
return "ssl://%s:61617".formatted(local.address().host());
}
public void setConfiguration(String newConfig) {

View File

@ -50,19 +50,8 @@ public class NetdataCollector extends gr.iccs.imu.ems.common.collector.netdata.N
if (grp!=null)
topics.addAll(grp.getEventTypeNames());
}
log.warn("Collectors::Netdata: activeGroupingChanged: New Allowed Topics for active grouping: {} -- {}", newGrouping, topics);
List<String> tmpList = new ArrayList<>(topics);
Map<String,String> tmpMap = null;
if (properties.getAllowedTopics()!=null) {
tmpMap = properties.getAllowedTopics().stream()
.map(s -> s.split(":", 2))
.collect(Collectors.toMap(a -> a[0], a -> a.length>1 ? a[1]: ""));
}
log.warn("Collectors::Netdata: activeGroupingChanged: New Allowed Topics -- Topics Map: {} -- {}", tmpList, tmpMap);
synchronized (this) {
this.allowedTopics = tmpList;
this.topicMap = tmpMap;
}
log.info("Collectors::Netdata: activeGroupingChanged: New Allowed Topics for active grouping: {} -- {}", newGrouping, topics);
processAllowedTopics(topics);
}
}

View File

@ -50,19 +50,8 @@ public class PrometheusCollector extends gr.iccs.imu.ems.common.collector.promet
if (grp!=null)
topics.addAll(grp.getEventTypeNames());
}
log.warn("Collectors::Prometheus: activeGroupingChanged: New Allowed Topics for active grouping: {} -- {}", newGrouping, topics);
List<String> tmpList = new ArrayList<>(topics);
Map<String,String> tmpMap = null;
if (properties.getAllowedTopics()!=null) {
tmpMap = properties.getAllowedTopics().stream()
.map(s -> s.split(":", 2))
.collect(Collectors.toMap(a -> a[0], a -> a.length>1 ? a[1]: ""));
}
log.warn("Collectors::Prometheus: activeGroupingChanged: New Allowed Topics -- Topics Map: {} -- {}", tmpList, tmpMap);
synchronized (this) {
this.allowedTopics = tmpList;
this.topicMap = tmpMap;
}
log.info("Collectors::Prometheus: activeGroupingChanged: New Allowed Topics for active grouping: {} -- {}", newGrouping, topics);
processAllowedTopics(topics);
}
}

View File

@ -137,9 +137,8 @@ public class SelfHealingPlugin implements Plugin, InitializingBean, EventBus.Eve
private void processClusterNodeRemovedEvent(Object message) {
log.debug("SelfHealingPlugin: processClusterNodeRemovedEvent(): BEGIN: message={}", message);
if (message instanceof ClusterMembershipEvent) {
if (message instanceof ClusterMembershipEvent event) {
// Get removed node id and address
ClusterMembershipEvent event = (ClusterMembershipEvent)message;
String nodeId = event.subject().id().id();
String nodeAddress = event.subject().address().host();
log.debug("SelfHealingPlugin: processClusterNodeRemovedEvent(): node-id={}, node-address={}", nodeId, nodeAddress);
@ -156,9 +155,8 @@ public class SelfHealingPlugin implements Plugin, InitializingBean, EventBus.Eve
private void processClusterNodeAddedEvent(Object message) {
log.debug("SelfHealingPlugin: processClusterNodeAddedEvent(): BEGIN: message={}", message);
if (message instanceof ClusterMembershipEvent) {
if (message instanceof ClusterMembershipEvent event) {
// Get added node id and address
ClusterMembershipEvent event = (ClusterMembershipEvent)message;
String nodeId = event.subject().id().id();
String nodeAddress = event.subject().address().host();
log.debug("SelfHealingPlugin: processClusterNodeAddedEvent(): node-id={}, node-address={}", nodeId, nodeAddress);

View File

@ -77,15 +77,14 @@
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Apache Commons Text (for StringSubstitutor) -->
@ -98,7 +97,7 @@
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>3.1.3</version>
<version>3.1.4</version>
</dependency>
</dependencies>

View File

@ -376,7 +376,7 @@ public class BaguetteServer implements InitializingBean, EventBus.EventConsumer<
})
.sorted(Comparator.comparing(m -> m.get("id")))
.collect(Collectors.toMap(m -> m.get("id"), m -> m,
(u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); },
(u,v) -> { throw new IllegalStateException("Duplicate key %s".formatted(u)); },
LinkedHashMap::new));
}

View File

@ -30,7 +30,7 @@ import org.apache.sshd.server.session.ServerSessionAware;
import org.cryptacular.util.CertUtil;
import org.slf4j.event.Level;
import javax.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotBlank;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
@ -115,7 +115,7 @@ public class ClientShellCommand implements Command, Runnable, ServerSessionAware
public ClientShellCommand(ServerCoordinator coordinator, boolean allowClientOverrideItsAddress, EventBus<String,Object,Object> eventBus, NodeRegistry registry) {
synchronized (LOCK) {
id = String.format("#%05d", counter.getAndIncrement());
id = "#%05d".formatted(counter.getAndIncrement());
}
this.coordinator = coordinator;
this.clientAddressOverrideAllowed = allowClientOverrideItsAddress;
@ -688,8 +688,9 @@ public class ClientShellCommand implements Command, Runnable, ServerSessionAware
log.debug("sendGroupingConfiguration: id={}, grouping={}, grouping-config={}", id, grouping, gc);
try {
String allStr = serializeToString(gc);
log.info("sendGroupingConfiguration: Serialization of Grouping configuration for {}: {}", grouping, allStr);
sendToClient("SET-GROUPING-CONFIG " + allStr);
log.debug("sendGroupingConfiguration: Serialization of Grouping configuration for {}: {}", grouping, allStr);
sendToClient("SET-GROUPING-CONFIG " + allStr, Level.DEBUG);
log.info("sendGroupingConfiguration: Sent grouping configuration for {}", grouping);
} catch (IOException ex) {
log.error("sendGroupingConfiguration: Exception while serializing Grouping configuration: ", ex);
log.error("sendGroupingConfiguration: SET-GROUPING-CONFIG command *NOT* sent to client");

View File

@ -95,8 +95,8 @@ public class NodeRegistryEntry {
private void _canUpdateEntry(@NonNull STATE newState) {
if (! canChangeStateTo(newState)) {
throw new IllegalStateException(String.format("Cannot change NodeRegistryEntry state from %s to %s: client-id=%s, client-address=%s",
state, newState, clientId, ipAddress));
throw new IllegalStateException("Cannot change NodeRegistryEntry state from %s to %s: client-id=%s, client-address=%s"
.formatted(state, newState, clientId, ipAddress));
}
}
@ -112,7 +112,7 @@ public class NodeRegistryEntry {
_canUpdateEntry(newState);
if (clear) map.clear();
map.put(key, val!=null ? val.toString() : defVal);
setState(STATE.IGNORE_NODE);
setState(newState);
return this;
}

View File

@ -155,7 +155,7 @@ public class Sshd {
Thread.sleep(period);
} catch (InterruptedException ex) {
}
String msg = String.format("Heartbeat %d", System.currentTimeMillis());
String msg = "Heartbeat %d".formatted(System.currentTimeMillis());
log.debug("--> Heartbeat: {}", msg);
for (ClientShellCommand csc : ClientShellCommand.getActive()) {
csc.sendToClient(msg, Level.DEBUG);

View File

@ -86,11 +86,11 @@ public class NoopCoordinator implements ServerCoordinator {
protected boolean _logInvocation(String methodName, Object o, boolean checkStarted) {
String className = getClass().getSimpleName();
String str = (o==null) ? "" : (
o instanceof ClientShellCommand ? String.format(". CSC: %s", o) : (
o instanceof NodeRegistryEntry ? String.format(". NRE: %s", o) :
String.format(". Object: %s", o)
)
);
o instanceof ClientShellCommand
? ". CSC: %s".formatted(o)
: (o instanceof NodeRegistryEntry
? ". NRE: %s".formatted(o)
: ". Object: %s".formatted(o)) );
if (checkStarted && !started) {
log.warn("{}: {}(): Coordinator has not been started{}", className, methodName, str);
} else

View File

@ -144,8 +144,8 @@ public class ServerCoordinatorTimeWin implements ServerCoordinator {
int brokerPort = broker.getClientPort();
if (brokerIpAddress == null || brokerIpAddress.trim().isEmpty() || brokerPort <= 0)
throw new Exception("ServerCoordinatorTimeWin: startPhase1(): Unable to get broker IP address or Port: " + broker);
this.brokerCfgIpAddressCmd = String.format("SET-PARAM bin/broker.cfg-template BROKER_IP_ADDR %s bin/broker.cfg", brokerIpAddress);
this.brokerCfgPortCmd = String.format("SET-PARAM bin/broker.cfg-template BROKER_PORT %d bin/broker.cfg", brokerPort);
this.brokerCfgIpAddressCmd = "SET-PARAM bin/broker.cfg-template BROKER_IP_ADDR %s bin/broker.cfg".formatted(brokerIpAddress);
this.brokerCfgPortCmd = "SET-PARAM bin/broker.cfg-template BROKER_PORT %d bin/broker.cfg".formatted(brokerPort);
} catch (Exception ex) {
this.brokerCfgIpAddressCmd = null;
this.brokerCfgPortCmd = null;

View File

@ -20,7 +20,7 @@ import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.operator.OperatorCreationException;
import javax.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotBlank;
import java.io.File;
import java.io.IOException;
import java.security.KeyStoreException;

View File

@ -22,6 +22,7 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
import org.slf4j.event.Level;
import java.util.*;
import java.util.stream.Collectors;
@ -383,9 +384,10 @@ public class ClusteringCoordinator extends NoopCoordinator {
// ------------------------------------------------------------------------
void sendClusterKey(ClientShellCommand csc, IClusterZone zoneInfo) {
csc.sendCommand(String.format("CLUSTER-KEY %s %s %s %s",
csc.sendCommand("CLUSTER-KEY %s %s %s %s".formatted(
zoneInfo.getClusterKeystoreFile().getName(), zoneInfo.getClusterKeystoreType(),
zoneInfo.getClusterKeystorePassword(), zoneInfo.getClusterKeystoreBase64()));
zoneInfo.getClusterKeystorePassword(), zoneInfo.getClusterKeystoreBase64()), Level.DEBUG);
log.info("sendClusterKey: Sent cluster key to node {}", csc.getClientIpAddress());
}
void sendCommandToZone(String command, List<ClientShellCommand> zoneNodes) {

View File

@ -19,8 +19,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Some files were not shown because too many files have changed in this diff Show More