diff --git a/imageroot/actions/get-configuration/10get b/imageroot/actions/get-configuration/10get index 834ca8b..f16e503 100755 --- a/imageroot/actions/get-configuration/10get +++ b/imageroot/actions/get-configuration/10get @@ -5,13 +5,66 @@ # SPDX-License-Identifier: GPL-3.0-or-later # +from datetime import datetime, timezone + import os import json import sys +import subprocess + +# Cloud Log Manager + +cloud_log_manager = {} + +with subprocess.Popen(['systemctl', '--user', 'is-active', 'cloud-log-manager-forwarder'], stdout=subprocess.PIPE, stderr=sys.stderr) as pipe: + response = pipe.stdout.readline().decode('utf-8').replace('\n', '') + if 'inactive' in response: + cloud_log_manager["status"] = 'inactive' + elif 'active' in response: + cloud_log_manager["status"] = 'active' + elif 'failed' in response: + cloud_log_manager["status"] = 'failed' + +cloud_log_manager["address"] = os.getenv('CLOUD_LOG_MANAGER_ADDRESS', '') +cloud_log_manager["tenant"] = os.getenv('CLOUD_LOG_MANAGER_TENANT', '') + +try: + with open("./cloud_log_manager_last_timestamp", "r") as clm_file: + cloud_log_manager["last_timestamp"] = clm_file.read() +except: + cloud_log_manager["last_timestamp"] = "" + +# Syslog + +syslog = {} + +with subprocess.Popen(['systemctl', '--user', 'is-active', 'syslog-forwarder'], stdout=subprocess.PIPE, stderr=sys.stderr) as pipe: + response = pipe.stdout.readline().decode('utf-8').replace('\n', '') + if 'inactive' in response: + syslog["status"] = 'inactive' + elif 'active' in response: + syslog["status"] = 'active' + elif 'failed' in response: + syslog["status"] = 'failed' + +syslog["address"] = os.getenv('SYSLOG_ADDRESS', '') +syslog["port"] = os.getenv('SYSLOG_PORT', '') +syslog["protocol"] = os.getenv('SYSLOG_PROTOCOL', '') +syslog["format"] = os.getenv('SYSLOG_FORMAT', '') + +try: + with open("./syslog_last_timestamp", "r") as syslog_file: + syslog["last_timestamp"] = syslog_file.read() +except: + syslog["last_timestamp"] = "" + +# General response = { "retention_days": int(os.getenv('LOKI_RETENTION_PERIOD')), - "active_from": os.getenv('LOKI_ACTIVE_FROM') + "active_from": os.getenv('LOKI_ACTIVE_FROM'), + "cloud_log_manager": cloud_log_manager, + "syslog": syslog } if os.getenv('LOKI_ACTIVE_TO') is not None: diff --git a/imageroot/actions/get-configuration/validate-output.json b/imageroot/actions/get-configuration/validate-output.json index 47e69a8..65b14ba 100644 --- a/imageroot/actions/get-configuration/validate-output.json +++ b/imageroot/actions/get-configuration/validate-output.json @@ -6,7 +6,9 @@ "type": "object", "required": [ "retention_days", - "active_from" + "active_from", + "cloud_log_manager", + "syslog" ], "properties": { "retention_days": { @@ -23,6 +25,65 @@ "type": "string", "format": "date-time", "description": "The ISO 8601 date-time when the Loki instance was deactivated." + }, + "cloud_log_manager": { + "type": "object", + "description": "Cloud Log Manager forwarder configuration.", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "description": "Forwarder state." + }, + "address": { + "type": "string", + "description": "Forwarder address where datas are sent." + }, + "tenant": { + "type": "string", + "description": "Cloud Log Manager internal data." + }, + "last_timestamp": { + "type": "string", + "description": "Timestamp of the last log sent." + } + } + + }, + "syslog": { + "type": "object", + "description": "Syslog forwarder configuration.", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "description": "Forwarder state." + }, + "address": { + "type": "string", + "description": "Forwarder address where data are sent." + }, + "port": { + "type": "string", + "description": "External server port." + }, + "protocol": { + "type": "string", + "description": "Protocol used to send datas." + }, + "format": { + "type": "string", + "description": "Log format." + }, + "last_timestamp": { + "type": "string", + "description": "Timestamp of the last log sent." + } + } } } } diff --git a/imageroot/actions/set-clm-forwarder/10set b/imageroot/actions/set-clm-forwarder/10set new file mode 100755 index 0000000..c18f982 --- /dev/null +++ b/imageroot/actions/set-clm-forwarder/10set @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +import subprocess +import hashlib +import agent +import json +import uuid +import sys + +request = json.load(sys.stdin) + +rdb = agent.redis_connect() +cluster_uuid = rdb.get('cluster/uuid') +subscription = rdb.hgetall('cluster/subscription') + +if not bool(subscription): + print("No subscription found !") + sys.exit(1) + +if (request['active']): + agent.set_env('CLOUD_LOG_MANAGER_UUID', uuid.uuid5(uuid.NAMESPACE_DNS, cluster_uuid)) + agent.set_env('CLOUD_LOG_MANAGER_HOSTNAME', 'cluster-' + hashlib.sha256(cluster_uuid.encode("utf-8")).hexdigest()[:8]) + agent.set_env('CLOUD_LOG_MANAGER_ADDRESS', f"{request['address']}") + agent.set_env('CLOUD_LOG_MANAGER_TENANT', f"{request['tenant']}") + + if (request['start_time'] != ''): + agent.set_env('CLOUD_LOG_MANAGER_START_TIME', f"{request['start_time']}") + + # If process is running, restart with new env variables, otherwise enable it + with subprocess.Popen(['systemctl', '--user', 'is-active', 'cloud-log-manager-forwarder'], stdout=subprocess.PIPE, stderr=sys.stderr) as pipe: + response = pipe.stdout.readline().decode('utf-8').replace('\n', '') + if response in {'active', 'failed'}: + action = 'restart' + else: + action = 'enable' +else: + agent.unset_env('CLOUD_LOG_MANAGER_UUID') + agent.unset_env('CLOUD_LOG_MANAGER_START_TIME') + agent.unset_env('CLOUD_LOG_MANAGER_ADDRESS') + agent.unset_env('CLOUD_LOG_MANAGER_TENANT') + + action = 'disable' + +subprocess.run(["systemctl", "--user", action, "--now", "cloud-log-manager-forwarder.service"], + stdout=subprocess.PIPE, + stderr=sys.stderr, + text=True, + check=True) diff --git a/imageroot/actions/set-clm-forwarder/validate-input.json b/imageroot/actions/set-clm-forwarder/validate-input.json new file mode 100644 index 0000000..2fa2052 --- /dev/null +++ b/imageroot/actions/set-clm-forwarder/validate-input.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$id": "http://schema.nethserver.org/loki/configure-module.json", + "title": "Configure Cloud Log Manager Forwarder", + "description": "Configure Cloud Log Manager Forwarder service.", + "type": "object", + "required": [ + "active" + ], + "properties": { + "active": { + "type": "boolean", + "description": "Action condition to be set." + }, + "address": { + "type": "string", + "description": "Cloud log manager server address." + }, + "tenant": { + "type": "string", + "description": "Cloud log manager tenant." + }, + "start_time": { + "type": "string", + "description": "Log forwarding start time." + } + } +} diff --git a/imageroot/actions/set-syslog-forwarder/10set b/imageroot/actions/set-syslog-forwarder/10set new file mode 100755 index 0000000..89652ca --- /dev/null +++ b/imageroot/actions/set-syslog-forwarder/10set @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +import subprocess +import agent +import json +import sys + +request = json.load(sys.stdin) + +if (request['active']): + rdb = agent.redis_connect() + cluster_uuid = rdb.get('cluster/uuid') + + agent.set_env('SYSLOG_ADDRESS', f"{request['address']}") + agent.set_env('SYSLOG_PORT', f"{request['port']}") + agent.set_env('SYSLOG_PROTOCOL', f"{request['protocol']}") + agent.set_env('SYSLOG_FORMAT', f"{request['format']}") + + if (request['start_time'] != ''): + agent.set_env('SYSLOG_START_TIME', f"{request['start_time']}") + + # If process is running, restart with new env variables, otherwise enable it + with subprocess.Popen(['systemctl', '--user', 'is-active', 'syslog-forwarder'], stdout=subprocess.PIPE, stderr=sys.stderr) as pipe: + response = pipe.stdout.readline().decode('utf-8').replace('\n', '') + if response in {'active', 'failed'}: + action = 'restart' + else: + action = 'enable' +else: + agent.unset_env('SYSLOG_ADDRESS') + agent.unset_env('SYSLOG_PORT') + agent.unset_env('SYSLOG_PROTOCOL') + agent.unset_env('SYSLOG_FORMAT') + agent.unset_env('SYSLOG_START_TIME') + + action = 'disable' + +subprocess.run(["systemctl", "--user", action, "--now", "syslog-forwarder.service"], + stdout=subprocess.PIPE, + stderr=sys.stderr, + text=True, + check=True) diff --git a/imageroot/actions/set-syslog-forwarder/validate-input.json b/imageroot/actions/set-syslog-forwarder/validate-input.json new file mode 100644 index 0000000..43bd412 --- /dev/null +++ b/imageroot/actions/set-syslog-forwarder/validate-input.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$id": "http://schema.nethserver.org/loki/configure-module.json", + "title": "Configure Syslog Forwarder", + "description": "Configure Syslog Forwarder service.", + "type": "object", + "required": [ + "active" + ], + "properties": { + "active": { + "type": "boolean", + "description": "Action condition to be set." + }, + "address": { + "type": "string", + "description": "Syslog server address." + }, + "port": { + "type": "string", + "description": "Syslog server port." + }, + "protocol": { + "type": "string", + "description": "Protocol to send datas." + }, + "format": { + "type": "string", + "description": "Log format." + }, + "start_time": { + "type": "string", + "description": "Log forwarding start time." + } + } +} diff --git a/imageroot/bin/cloud-log-manager-forwarder b/imageroot/bin/cloud-log-manager-forwarder new file mode 100755 index 0000000..48022d8 --- /dev/null +++ b/imageroot/bin/cloud-log-manager-forwarder @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from datetime import datetime, timedelta, timezone +from urllib3.util import Retry +from requests import Session +from requests.adapters import HTTPAdapter + +import subprocess +import agent +import json +import time +import os +import sys + +#-------------------------------- CONFIG --------------------------------# + +try: + UUID = os.environ.get('CLOUD_LOG_MANAGER_UUID') + HOSTNAME = os.environ.get('CLOUD_LOG_MANAGER_HOSTNAME') + START_TIME = os.environ.get('CLOUD_LOG_MANAGER_START_TIME', '') + ADDRESS = os.environ.get('CLOUD_LOG_MANAGER_ADDRESS', 'https://nar.nethesis.it') + TENANT = os.environ.get('CLOUD_LOG_MANAGER_TENANT') + + os.environ['LOKI_ADDR'] = f"http://127.0.0.1:{os.environ['LOKI_HTTP_PORT']}" + os.environ['LOKI_USERNAME'] = os.environ['LOKI_API_AUTH_USERNAME'] + os.environ['LOKI_PASSWORD'] = os.environ['LOKI_API_AUTH_PASSWORD'] +except Exception as exc: + print(f"Error variables settings: {exc}", file=sys.stderr) + sys.exit(1) + +#--------------------------------- CODE ---------------------------------# + +# Send log to gigasys server +def send_logs_list(logs_list: list, last_timestamp: str): + session = Session() + retries = Retry( + backoff_factor=0.5, + ) + session.mount('https://', HTTPAdapter(max_retries=retries)) + session.post(ADDRESS + "/adm/syslog/noauth_put_json/", verify=True, data=json.dumps(logs_list)) + session.close() + + # Write on file the last log sent timestamp + with open("./cloud_log_manager_last_timestamp", "w") as tf: + tf.write(last_timestamp) + +# Define transport facility +transports = { + 'kernel': 0, + 'driver': 3, + 'audit': 13, + 'journal': 16, + 'stdout': 17 +} + +# Define severity +severity = { + 0: "Emergency", + 1: "Warning", + 2: "Error", + 3: "Error", + 4: "Warning", + 5: "Information", + 6: "Information", + 7: "Debug", + 8: "Warning" +} + +if START_TIME == '': + if os.path.exists("./cloud_log_manager_last_timestamp") and os.path.getsize("./cloud_log_manager_last_timestamp") > 0: + with open("./cloud_log_manager_last_timestamp", "r") as tf: + last_timestamp = tf.read() + else: + last_timestamp = (datetime.now(timezone.utc)).strftime('%Y-%m-%dT%H:%M:%S.%fZ') +else: + last_timestamp = START_TIME + agent.unset_env('CLOUD_LOG_MANAGER_START_TIME') + +logs_list = [] + +while True: + try: + # LogCLI command + logcli_command = ["logcli", "query", "--limit", "0", "--forward", "--timezone", "UTC", "--from", last_timestamp, "--no-labels", "-q", "-o", "jsonl", + '{node_id=~".+"} | json severity="PRIORITY", priority="SYSLOG_IDENTIFIER", pid="_PID", message="MESSAGE" | line_format "<{{.priority}}> [{{.node_id}}:{{.module_id}}:{{.process}}] {{.process}}[{{.pid}}]: {{.message}}"'] + with subprocess.Popen(logcli_command, stdout=subprocess.PIPE) as logs: + for log in logs.stdout.readlines(): + try: + # Log if stdout contains something new + if log: + json_object = json.loads(log) + line = str(json_object["line"]) + + # Check if priority is set + try: + priority = int(line[line.find("<")+1:line.find(">")]) + except: + priority = 6 + + # Json data for post request + json_log = { + "UUID": UUID, + "PC": HOSTNAME, + "DTA": datetime.strptime(json_object["timestamp"], '%Y-%m-%dT%H:%M:%S.%fZ').strftime("%Y-%m-%d"), + "TIME": datetime.strptime(json_object["timestamp"], '%Y-%m-%dT%H:%M:%S.%fZ').strftime("%H:%M:%S"), + "MSG": line[line.find("]")+2:], + "SOURCE": line[line.find("["):line.find("]")+1], + "LOGTYPE": severity.get(priority, 6), + "SITE": TENANT + } + + logs_list.append(json_log) + + # Save log timestamp only when socket send succeed + last_timestamp = json_object["timestamp"] + + # If list size is bigger than 128 kB, send + if sys.getsizeof(logs_list) >= 131072: + send_logs_list(logs_list, last_timestamp) + logs_list.clear() + except Exception as exc: + print(f"Error on log format: {exc}", file=sys.stderr) + pass + + # When loop terminate, if list isn't empty, send + if len(logs_list) > 0: + # Increment timestamp by 1 microsecond to prevent sending the same log multiple times + last_timestamp = (datetime.strptime(last_timestamp, '%Y-%m-%dT%H:%M:%S.%fZ') + timedelta(microseconds=1)).strftime('%Y-%m-%dT%H:%M:%S.%fZ') + + # Send logs to gigasys server + send_logs_list(logs_list, last_timestamp) + logs_list.clear() + + except Exception as exc: + print(f"Error during loop: {exc}", file=sys.stderr) + pass + finally: + time.sleep(10) \ No newline at end of file diff --git a/imageroot/bin/syslog-forwarder b/imageroot/bin/syslog-forwarder new file mode 100755 index 0000000..6553f20 --- /dev/null +++ b/imageroot/bin/syslog-forwarder @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +from datetime import datetime, timedelta, timezone + +import subprocess +import agent +import json +import time +import socket +import os +import sys + +#-------------------------------- CONFIG --------------------------------# + +try: + ADDRESS = os.environ.get('SYSLOG_ADDRESS') + PORT = os.environ.get('SYSLOG_PORT', '514') + PROTOCOL = os.environ.get('SYSLOG_PROTOCOL', 'udp') + FORMAT = os.environ.get('SYSLOG_FORMAT', 'rfc3164') + START_TIME = os.environ.get('SYSLOG_START_TIME', '') + + os.environ['LOKI_ADDR'] = f"http://127.0.0.1:{os.environ['LOKI_HTTP_PORT']}" + os.environ['LOKI_USERNAME'] = os.environ['LOKI_API_AUTH_USERNAME'] + os.environ['LOKI_PASSWORD'] = os.environ['LOKI_API_AUTH_PASSWORD'] +except Exception as exc: + print(f"Error variables settings: {exc}", file=sys.stderr) + sys.exit(1) + +#--------------------------------- CODE ---------------------------------# + +# Define transport facility +transports = { + 'kernel': 0, + 'driver': 3, + 'audit': 13, + 'journal': 16, + 'stdout': 17 +} + +# Logging setup +try: + if PROTOCOL == "udp": + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + elif PROTOCOL == "tcp": + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + sock.connect((ADDRESS, int(PORT))) +except Exception as exc: + print(f"Error during setup: {exc}", file=sys.stderr) + sys.exit(1) + +# If exists, read from file last log timestamp sent +if START_TIME == '': + if os.path.exists("./syslog_last_timestamp") and os.path.getsize("./syslog_last_timestamp") > 0: + with open("./syslog_last_timestamp", "r") as tf: + last_timestamp = tf.read() + else: + last_timestamp = (datetime.now(timezone.utc)).strftime('%Y-%m-%dT%H:%M:%S.%fZ') +else: + last_timestamp = START_TIME + agent.unset_env('SYSLOG_START_TIME') + +# Every x seconds execute logcli command and send logs to syslog server +while True: + try: + # LogCLI command + logcli_command = ["logcli", "query", "--limit", "0", "--forward", "--timezone", "UTC", + "--from", last_timestamp, "--no-labels", "-q", "-o", "jsonl", '{node_id=~".+"}'] + with subprocess.Popen(logcli_command, stdout=subprocess.PIPE) as logs: + for log in logs.stdout.readlines(): + try: + # Log if stdout contains something new + if log: + json_object = json.loads(log) + line = json.loads(json_object["line"]) + + # Format log based on rfc format + if FORMAT == "rfc3164": + if "_HOSTNAME" not in line: + line["_HOSTNAME"] = "" + + if "SYSLOG_IDENTIFIER" not in line: + line["SYSLOG_IDENTIFIER"] = "" + + if "_PID" not in line: + line["_PID"] = "" + + # Set facility value + try: + facility = int(line["SYSLOG_FACILITY"]) + except: + facility = transports.get(line["_TRANSPORT"], 18) + + if "PRIORITY" not in line: + line["PRIORITY"] = 6 + + log_priority=(facility * 8) + int(line["PRIORITY"]) + + # Format message + message = "<{priority}>{timestamp} {hostname} {process}[{pid}]: {message}".format(priority=log_priority, + timestamp=json_object["timestamp"], + hostname=line["_HOSTNAME"], + process=line["SYSLOG_IDENTIFIER"], + pid=line["_PID"], + message=line["MESSAGE"]) + elif FORMAT == "rfc5424": + # Format message + message = "{timestamp} {hostname} {process}[{pid}]: {message}".format(timestamp=json_object["timestamp"], + hostname=line["_HOSTNAME"], + process=line["SYSLOG_IDENTIFIER"], + pid=line["_PID"], + message=line["MESSAGE"]) + + # Control if log has newline characters to avoid overlapping + if message.find("\n") == -1: + message += "\n" + + # Send log to syslog server + sock.send(message.encode()) + + # Save log timestamp only when socket send succeed + last_timestamp = json_object["timestamp"] + except Exception as exc: + print(f"Error on log format: {exc}", file=sys.stderr) + pass + + # Increment timestamp by 1 microsecond to prevent sending the same log multiple times + last_timestamp = (datetime.strptime(last_timestamp, '%Y-%m-%dT%H:%M:%S.%fZ') + timedelta(microseconds=1)).strftime('%Y-%m-%dT%H:%M:%S.%fZ') + + # Write on file the last log sent timestamp + timestamp_file = open("./syslog_last_timestamp", "w") + timestamp_file.write(last_timestamp) + timestamp_file.close() + + except Exception as exc: + print(f"Error during loop: {exc}", file=sys.stderr) + finally: + time.sleep(10) \ No newline at end of file diff --git a/imageroot/events/default-instance-changed/10set b/imageroot/events/default-instance-changed/10set index ebdb671..53e5901 100755 --- a/imageroot/events/default-instance-changed/10set +++ b/imageroot/events/default-instance-changed/10set @@ -9,13 +9,71 @@ import json import os import sys import datetime +import subprocess +import hashlib import agent # Check if event comes from the cluster if os.getenv("AGENT_EVENT_SOURCE") == 'cluster': - # parse data + + # Parse data data = json.load(sys.stdin) + if 'instance' in data and data['instance'] == 'loki': - if 'previous' in data and data['previous'] == os.getenv('MODULE_ID') and os.getenv('LOKI_ACTIVE_TO') is None: - agent.set_env('LOKI_ACTIVE_TO', datetime.datetime.now().astimezone().isoformat()) + + # Old instance + if 'previous' in data and data['previous'] == os.getenv('MODULE_ID'): + # Set loki active to + if os.getenv('LOKI_ACTIVE_TO') is None: + agent.set_env('LOKI_ACTIVE_TO', datetime.datetime.now().astimezone().isoformat()) + + # Disable cloud log manager service + subprocess.run(["systemctl", "--user", "disable", "--now", "cloud-log-manager-forwarder.service"], + stdout=subprocess.PIPE, + stderr=sys.stderr, + text=True, + check=True) + + # Disable syslog service + subprocess.run(["systemctl", "--user", "disable", "--now", "syslog-forwarder.service"], + stdout=subprocess.PIPE, + stderr=sys.stderr, + text=True, + check=True) + + agent.unset_env('CLOUD_LOG_MANAGER_HOSTNAME') + + # New instance + if 'current' in data and data['current'] == os.getenv('MODULE_ID'): + rdb = agent.redis_connect() + previous_environment = rdb.hgetall(f"module/{data['previous']}/environment") + subscription = rdb.hgetall('cluster/subscription') + + # If cloud log manager service was active in old instance, start on new instacnce + if all(key in previous_environment for key in ('CLOUD_LOG_MANAGER_ADDRESS', 'CLOUD_LOG_MANAGER_TENANT', 'CLOUD_LOG_MANAGER_UUID')) and bool(subscription): + cluster_uuid = rdb.get('cluster/uuid') + + agent.set_env('CLOUD_LOG_MANAGER_UUID', previous_environment['CLOUD_LOG_MANAGER_UUID']) + agent.set_env('CLOUD_LOG_MANAGER_HOSTNAME', 'cluster-' + hashlib.sha256(cluster_uuid.encode("utf-8")).hexdigest()[:8]) + agent.set_env('CLOUD_LOG_MANAGER_ADDRESS', previous_environment['CLOUD_LOG_MANAGER_ADDRESS']) + agent.set_env('CLOUD_LOG_MANAGER_TENANT', previous_environment['CLOUD_LOG_MANAGER_TENANT']) + + subprocess.run(["systemctl", "--user", "enable", "--now", "cloud-log-manager-forwarder.service"], + stdout=subprocess.PIPE, + stderr=sys.stderr, + text=True, + check=True) + + # If syslog service was active in old instance, start on new instacnce + if all(key in previous_environment for key in ('SYSLOG_ADDRESS', 'SYSLOG_PORT', 'SYSLOG_PROTOCOL', 'SYSLOG_FORMAT')): + agent.set_env('SYSLOG_ADDRESS', previous_environment['SYSLOG_ADDRESS']) + agent.set_env('SYSLOG_PORT', previous_environment['SYSLOG_PORT']) + agent.set_env('SYSLOG_PROTOCOL', previous_environment['SYSLOG_PROTOCOL']) + agent.set_env('SYSLOG_FORMAT', previous_environment['SYSLOG_FORMAT']) + + subprocess.run(["systemctl", "--user", "enable", "--now", "syslog-forwarder.service"], + stdout=subprocess.PIPE, + stderr=sys.stderr, + text=True, + check=True) diff --git a/imageroot/events/subscription-changed/10check_forwarder b/imageroot/events/subscription-changed/10check_forwarder new file mode 100755 index 0000000..7fff33e --- /dev/null +++ b/imageroot/events/subscription-changed/10check_forwarder @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +import sys +import json +import agent +import subprocess + +data = json.load(sys.stdin) + +if data['action'] == 'terminated': + agent.unset_env('CLOUD_LOG_MANAGER_UUID') + agent.unset_env('CLOUD_LOG_MANAGER_START_TIME') + agent.unset_env('CLOUD_LOG_MANAGER_ADDRESS') + agent.unset_env('CLOUD_LOG_MANAGER_TENANT') + + subprocess.run(["systemctl", "--user", "disable", "--now", "cloud-log-manager-forwarder.service"], + stdout=subprocess.PIPE, + stderr=sys.stderr, + text=True, + check=True) \ No newline at end of file diff --git a/imageroot/systemd/user/cloud-log-manager-forwarder.service b/imageroot/systemd/user/cloud-log-manager-forwarder.service new file mode 100644 index 0000000..13e8dbe --- /dev/null +++ b/imageroot/systemd/user/cloud-log-manager-forwarder.service @@ -0,0 +1,11 @@ +[Unit] +Description=Cloud Log Manager Forwarder +Requires=loki-server.service +After=loki-server.service + +[Service] +Restart=always +ExecStart=runagent %S/bin/cloud-log-manager-forwarder + +[Install] +WantedBy=default.target \ No newline at end of file diff --git a/imageroot/systemd/user/syslog-forwarder.service b/imageroot/systemd/user/syslog-forwarder.service new file mode 100644 index 0000000..43b9ad5 --- /dev/null +++ b/imageroot/systemd/user/syslog-forwarder.service @@ -0,0 +1,11 @@ +[Unit] +Description=Syslog Forwarder +Requires=loki-server.service +After=loki-server.service + +[Service] +Restart=always +ExecStart=runagent %S/bin/syslog-forwarder + +[Install] +WantedBy=default.target \ No newline at end of file