Skip to content

Commit d38aaed

Browse files
committed
alerts sync and rendering in app
1 parent ee300d3 commit d38aaed

File tree

13 files changed

+813
-6
lines changed

13 files changed

+813
-6
lines changed

config/docker-config/backend-entrypoint.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,40 @@ setup_symfony() {
143143
setup_symfony
144144
EOF
145145

146+
echo "=== Setting up ElastAlert sync daemon ==="
147+
chmod +x /usr/local/bin/elastalert-sync-daemon.sh
148+
chown www-data:www-data /usr/local/bin/elastalert-sync-daemon.sh
149+
150+
echo "Creating ElastAlert sync daemon script..."
151+
152+
touch /var/log/elastalert-sync.log
153+
chown www-data:www-data /var/log/elastalert-sync.log
154+
155+
cat > /tmp/elastalert-sync-daemon.sh << 'EOF'
156+
#!/bin/bash
157+
158+
echo "$(date): Starting ElastAlert sync daemon"
159+
160+
while true; do
161+
echo "$(date): Running ElastAlert sync..."
162+
163+
# Run the sync command from the correct directory
164+
cd /var/www/html
165+
if php bin/console app:alerts:sync --since="-1 minute" 2>&1; then
166+
echo "$(date): Sync completed successfully"
167+
else
168+
echo "$(date): Sync failed with exit code $?"
169+
fi
170+
171+
# Wait 30 seconds before next sync
172+
sleep 30
173+
done
174+
EOF
175+
176+
chmod +x /tmp/elastalert-sync-daemon.sh
177+
echo "Starting ElastAlert sync daemon..."
178+
su -s /bin/bash www-data -c '/tmp/elastalert-sync-daemon.sh' &
179+
146180
if [ "$APP_ENV" = "prod" ]; then
147181
echo "Starting PRODUCTION mode with Nginx + PHP-FPM..."
148182

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
3+
while true; do
4+
echo "[$(date)] Running ElastAlert sync..."
5+
cd /var/www/html
6+
/usr/local/bin/php bin/console app:elastalert:sync-alerts --since='-1 minute' >> /var/log/elastalert-sync.log 2>&1
7+
if [ $? -eq 0 ]; then
8+
echo "[$(date)] Sync completed successfully" >> /var/log/elastalert-sync.log
9+
else
10+
echo "[$(date)] Sync failed with exit code $?" >> /var/log/elastalert-sync.log
11+
fi
12+
sleep 30
13+
done

docker-compose.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ services:
4747
- DATAMONITOR_SERVER_TOKEN=${SENTINELKIT_DATAMONITOR_SERVER_TOKEN}
4848
- CORS_ALLOW_ORIGIN=https://${SENTINELKIT_FRONTEND_HOSTNAME}
4949
- FLUENTBIT_SERVER_URL=http://sentinel-kit-server-fluentbit:24224
50+
- ELASTICSEARCH_HOST=sentinel-kit-db-elasticsearch-es01:9200
51+
- ELASTICSEARCH_USERNAME=elastic
52+
- ELASTICSEARCH_SSL=true
5053
- ELASTICSEARCH_PASSWORD=${ELASTICSEARCH_PASSWORD}
5154
volumes:
5255
- ./config/docker-config/backend-entrypoint.sh:/usr/local/bin/backend-entrypoint.sh:ro
@@ -70,6 +73,8 @@ services:
7073
depends_on:
7174
sentinel-kit-db-mysql:
7275
condition: service_healthy
76+
sentinel-kit-db-elasticsearch-es01:
77+
condition: service_healthy
7378

7479
sentinel-kit-server-rules-scanner:
7580
container_name: sentinel-kit-server-rules-scanner

sentinel-kit_server_backend/.env

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
4545
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
4646
###< lexik/jwt-authentication-bundle ###
4747

48-
ELASTICSEARCH_HOST=sentinel-kit-db-elasticsearch
48+
ELASTICSEARCH_HOST=sentinel-kit-db-elasticsearch-es01:9200
4949
ELASTICSEARCH_PORT=9200
50-
ELASTICSEARCH_LOGIN=elastic
50+
ELASTICSEARCH_USERNAME=elastic
51+
ELASTICSEARCH_SSL=true
5152
#ELASTICSEARCH_PASSWORD=propagated by OS environment variable

sentinel-kit_server_backend/config/services.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
# Put parameters here that don't need to change on each machine where the app is deployed
55
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
66
parameters:
7+
elasticsearch.host: '%env(ELASTICSEARCH_HOST)%'
8+
elasticsearch.username: '%env(ELASTICSEARCH_USERNAME)%'
9+
elasticsearch.password: '%env(ELASTICSEARCH_PASSWORD)%'
10+
elasticsearch.ssl: '%env(bool:ELASTICSEARCH_SSL)%'
711

812
services:
913
# default configuration for services in *this* file
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
namespace App\Command;
4+
5+
use App\Service\ElastalertSyncService;
6+
use Symfony\Component\Console\Attribute\AsCommand;
7+
use Symfony\Component\Console\Command\Command;
8+
use Symfony\Component\Console\Input\InputInterface;
9+
use Symfony\Component\Console\Input\InputOption;
10+
use Symfony\Component\Console\Output\OutputInterface;
11+
use Symfony\Component\Console\Style\SymfonyStyle;
12+
13+
#[AsCommand(
14+
name: 'app:alerts:sync',
15+
description: 'ElastAlert synchronization with the Alert entity'
16+
)]
17+
class ElastalertSyncAlertsCommand extends Command
18+
{
19+
private ElastalertSyncService $elastalertSyncService;
20+
21+
public function __construct(ElastalertSyncService $elastalertSyncService)
22+
{
23+
parent::__construct();
24+
$this->elastalertSyncService = $elastalertSyncService;
25+
}
26+
27+
protected function configure(): void
28+
{
29+
$this
30+
->addOption(
31+
'since',
32+
's',
33+
InputOption::VALUE_REQUIRED,
34+
'Synchronize alerts since this date (format: Y-m-d H:i:s or -1 hour, -1 day, etc.)',
35+
'-1 hour'
36+
)
37+
->addOption(
38+
'stats',
39+
null,
40+
InputOption::VALUE_NONE,
41+
'Show statistics only without synchronizing'
42+
)
43+
->setHelp('
44+
This command synchronizes ElastAlert alerts with the backend Alert entity.
45+
46+
Examples:
47+
app:elastalert:sync-alerts --stats
48+
app:elastalert:sync-alerts --since="-5 minutes"
49+
app:elastalert:sync-alerts --since "2024-12-03 10:00:00"
50+
app:elastalert:sync-alerts -s "-1 hour" --stats
51+
');
52+
}
53+
54+
protected function execute(InputInterface $input, OutputInterface $output): int
55+
{
56+
$io = new SymfonyStyle($input, $output);
57+
$sinceOption = $input->getOption('since');
58+
$showStatsOnly = $input->getOption('stats');
59+
60+
try {
61+
if (str_starts_with($sinceOption, '-')) {
62+
$since = new \DateTime($sinceOption);
63+
} else {
64+
$since = new \DateTime($sinceOption);
65+
}
66+
} catch (\Exception $e) {
67+
$io->error('Invalid date format: ' . $sinceOption);
68+
return Command::FAILURE;
69+
}
70+
71+
$io->title('Sync ElastAlert alerts');
72+
$io->info('Time: since ' . $since->format('Y-m-d H:i:s'));
73+
74+
if ($showStatsOnly) {
75+
return $this->showStats($io, $since);
76+
}
77+
78+
$io->section('Synchronization in progress...');
79+
$stats = $this->elastalertSyncService->syncElastalertAlerts($since);
80+
81+
$io->section('Synchronization results');
82+
$io->definitionList(
83+
['Processed' => $stats['processed']],
84+
['Created alerts' => '<fg=green>' . $stats['created'] . '</>'],
85+
['Ignored alerts (already existing)' => '<fg=yellow>' . $stats['skipped'] . '</>'],
86+
['Errors' => $stats['errors'] > 0 ? '<fg=red>' . $stats['errors'] . '</>' : $stats['errors']]
87+
);
88+
89+
if ($stats['errors'] > 0) {
90+
$io->warning('Errors were encountered. Check the logs for more details.');
91+
return Command::FAILURE;
92+
}
93+
94+
if ($stats['created'] > 0 || $stats['processed'] > 0) {
95+
$io->success('Synchronization completed successfully!');
96+
} else {
97+
$io->info('No new alerts to synchronize.');
98+
}
99+
100+
return Command::SUCCESS;
101+
}
102+
103+
private function showStats(SymfonyStyle $io, \DateTime $since): int
104+
{
105+
$io->section('Alert statistics');
106+
107+
try {
108+
$stats = $this->elastalertSyncService->getAlertStats($since);
109+
110+
$io->info('Total synchronized alerts: ' . $stats['total_alerts']);
111+
112+
if (!empty($stats['alerts_by_rule'])) {
113+
$io->section('Alerts by rule');
114+
$tableData = [];
115+
foreach ($stats['alerts_by_rule'] as $rule) {
116+
$tableData[] = [$rule['rule_title'], $rule['alert_count']];
117+
}
118+
119+
$io->table(
120+
['Rule', 'Number of alerts'],
121+
$tableData
122+
);
123+
} else {
124+
$io->info('No alerts found for this period.');
125+
}
126+
127+
} catch (\Exception $e) {
128+
$io->error('Error retrieving statistics: ' . $e->getMessage());
129+
return Command::FAILURE;
130+
}
131+
132+
return Command::SUCCESS;
133+
}
134+
}

0 commit comments

Comments
 (0)