From 8b3870386af74c5314ebbe922ff6e56845d0b14d Mon Sep 17 00:00:00 2001 From: Vehbi Sinan Tunalioglu Date: Tue, 26 Mar 2024 20:29:58 +0800 Subject: [PATCH 1/2] feat: report enabled systemd services and timers found on host --- src/Lhp/Remote.hs | 31 ++++++++++++++++++++++++++++++- src/Lhp/Types.hs | 4 ++++ src/scripts/systemd-services.sh | 14 ++++++++++++++ src/scripts/systemd-timers.sh | 14 ++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/scripts/systemd-services.sh create mode 100644 src/scripts/systemd-timers.sh diff --git a/src/Lhp/Remote.hs b/src/Lhp/Remote.hs index 3592530..26edec0 100644 --- a/src/Lhp/Remote.hs +++ b/src/Lhp/Remote.hs @@ -17,6 +17,7 @@ import qualified Data.List as List import Data.Maybe (fromMaybe) import qualified Data.Scientific as S import qualified Data.Text as T +import Lhp.Types (Report (_reportSystemdServices)) import qualified Lhp.Types as Types import Text.Read (readEither) import qualified Zamazingo.Ssh as Z.Ssh @@ -42,6 +43,8 @@ compileReport h@Types.Host {..} = do _reportDistribution <- _mkDistribution _hostName kvs _reportDockerContainers <- _fetchHostDockerContainers _hostName _reportSshAuthorizedKeys <- _fetchHostSshAuthorizedKeys _hostName + _reportSystemdServices <- _fetchHostSystemdServices _hostName + _reportSystemdTimers <- _fetchHostSystemdTimers _hostName pure Types.Report {..} @@ -113,11 +116,37 @@ _fetchHostSshAuthorizedKeys => Z.Ssh.Destination -> m [T.Text] _fetchHostSshAuthorizedKeys h = - filter (not . T.null . T.strip) . T.lines . Z.Text.unsafeTextFromBL <$> prog + filter (not . T.null) . fmap T.strip . T.lines . Z.Text.unsafeTextFromBL <$> prog where prog = _toSshError h (Z.Ssh.runScript h $(embedStringFile "src/scripts/ssh-keys.sh") ["bash"]) +-- | Attempts to find and return all systemd services on the remote +-- host. +_fetchHostSystemdServices + :: MonadIO m + => MonadError LhpError m + => Z.Ssh.Destination + -> m [T.Text] +_fetchHostSystemdServices h = + filter (not . T.null) . fmap T.strip . T.lines . Z.Text.unsafeTextFromBL <$> prog + where + prog = _toSshError h (Z.Ssh.runScript h $(embedStringFile "src/scripts/systemd-services.sh") ["bash"]) + + +-- | Attempts to find and return all systemd timers on the remote +-- host. +_fetchHostSystemdTimers + :: MonadIO m + => MonadError LhpError m + => Z.Ssh.Destination + -> m [T.Text] +_fetchHostSystemdTimers h = + filter (not . T.null) . fmap T.strip . T.lines . Z.Text.unsafeTextFromBL <$> prog + where + prog = _toSshError h (Z.Ssh.runScript h $(embedStringFile "src/scripts/systemd-timers.sh") ["bash"]) + + -- | Smart constructor for remote host cloud information. _mkCloud :: MonadError LhpError m diff --git a/src/Lhp/Types.hs b/src/Lhp/Types.hs index fdbf35b..ea3cc5c 100644 --- a/src/Lhp/Types.hs +++ b/src/Lhp/Types.hs @@ -51,6 +51,8 @@ data Report = Report , _reportDistribution :: !Distribution , _reportDockerContainers :: !(Maybe [DockerContainer]) , _reportSshAuthorizedKeys :: ![T.Text] + , _reportSystemdServices :: ![T.Text] + , _reportSystemdTimers :: ![T.Text] } deriving (Eq, Generic, Show) deriving (Aeson.FromJSON, Aeson.ToJSON) via (ADC.Autodocodec Report) @@ -70,6 +72,8 @@ instance ADC.HasCodec Report where <*> ADC.requiredField "distribution" "Distribution information." ADC..= _reportDistribution <*> ADC.requiredField "dockerContainers" "List of Docker containers if the host is a Docker host." ADC..= _reportDockerContainers <*> ADC.requiredField "sshAuthorizedKeys" "List of SSH authorized keys found on host." ADC..= _reportSshAuthorizedKeys + <*> ADC.requiredField "systemdServices" "List of systemd services found on host." ADC..= _reportSystemdServices + <*> ADC.requiredField "systemdTimers" "List of systemd timers found on host." ADC..= _reportSystemdTimers -- * Cloud Information diff --git a/src/scripts/systemd-services.sh b/src/scripts/systemd-services.sh new file mode 100644 index 0000000..4b8aa4f --- /dev/null +++ b/src/scripts/systemd-services.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +############# +# PROCEDURE # +############# + +## Check if systemctl (therefore systemd) is available: +if ! which "systemctl" >/dev/null; then + exit 0 +fi + +## List services: +systemctl list-unit-files --state enabled --type service | + tail -n +2 | head -n -2 | awk '{print $1}' diff --git a/src/scripts/systemd-timers.sh b/src/scripts/systemd-timers.sh new file mode 100644 index 0000000..f5bf3fa --- /dev/null +++ b/src/scripts/systemd-timers.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +############# +# PROCEDURE # +############# + +## Check if systemctl (therefore systemd) is available: +if ! which "systemctl" >/dev/null; then + exit 0 +fi + +## List timers: +systemctl list-unit-files --state enabled --type timer | + tail -n +2 | head -n -2 | awk '{print $1}' From ea980cd0eb5ec231c854c7c24cffdbd7ea034629 Mon Sep 17 00:00:00 2001 From: Vehbi Sinan Tunalioglu Date: Tue, 26 Mar 2024 21:33:52 +0800 Subject: [PATCH 2/2] feat(website): list enabled systemd services and timers found on host --- website/src/components/app/-app.tsx | 12 ++++++++++++ website/src/components/app/-data.tsx | 14 +++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/website/src/components/app/-app.tsx b/website/src/components/app/-app.tsx index 7278c7c..a39fb64 100644 --- a/website/src/components/app/-app.tsx +++ b/website/src/components/app/-app.tsx @@ -129,6 +129,9 @@ export function TabulateHosts({ hosts, onHostSelect }: { hosts: LhpData[]; onHos SSH Keys + + Systemd + Tags @@ -175,6 +178,9 @@ export function TabulateHosts({ hosts, onHostSelect }: { hosts: LhpData[]; onHos : `${host.dockerContainers.filter((x) => x.running).length} / ${host.dockerContainers.length}`} {host.sshAuthorizedKeys.length} + + {host.systemdServices.length} / {host.systemdTimers.length} + {(host.host.tags || []).map((x) => ( @@ -319,6 +325,12 @@ export function HostDetails({ host }: { host: LhpData }) { + +
+ ({ key: x, value: '✅' }))} /> + + ({ key: x, value: '✅' }))} /> +
); } diff --git a/website/src/components/app/-data.tsx b/website/src/components/app/-data.tsx index 64348d6..f4e954d 100644 --- a/website/src/components/app/-data.tsx +++ b/website/src/components/app/-data.tsx @@ -125,8 +125,20 @@ export const LHP_PATROL_REPORT_SCHEMA = { items: { type: 'string' }, type: 'array', }, + systemdServices: { $comment: 'List of systemd services found on host.', items: { type: 'string' }, type: 'array' }, + systemdTimers: { $comment: 'List of systemd timers found on host.', items: { type: 'string' }, type: 'array' }, }, - required: ['sshAuthorizedKeys', 'dockerContainers', 'distribution', 'kernel', 'hardware', 'cloud', 'host'], + required: [ + 'systemdTimers', + 'systemdServices', + 'sshAuthorizedKeys', + 'dockerContainers', + 'distribution', + 'kernel', + 'hardware', + 'cloud', + 'host', + ], type: 'object', } as const satisfies JSONSchema;