Compare commits
6 Commits
6fb253334b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 832c382b41 | |||
|
|
243a74a09b | ||
|
|
2de167b6bc | ||
|
|
7023c02b88 | ||
|
|
477c7c63cd | ||
|
|
92bb2928e1 |
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.env
|
||||
.env-*
|
||||
test-results/*
|
||||
data-grafana/*
|
||||
data-prometheus/*
|
||||
@@ -1,12 +1,12 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
e2e-monitor:
|
||||
e2e-monitor-uam-prod:
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
env_file: .env-uam-prod
|
||||
ports:
|
||||
- "3020:3000" # Web API: /status, /healthz, /run-now
|
||||
- "3033:3000" # Web API: /status, /healthz, /run-now
|
||||
volumes:
|
||||
- ./test:/app/test:ro
|
||||
- ./test-results:/app/test-results
|
||||
@@ -15,23 +15,23 @@ services:
|
||||
|
||||
pushgateway:
|
||||
image: prom/pushgateway
|
||||
ports:
|
||||
- "9091:9091"
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus
|
||||
volumes:
|
||||
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- ./data-prometheus:/prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
- "3031:9090"
|
||||
depends_on:
|
||||
- pushgateway
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana
|
||||
ports:
|
||||
- "3031:3000"
|
||||
- "3030:3000"
|
||||
volumes:
|
||||
- ./data-grafana:/var/lib/grafana
|
||||
- ./grafana/provisioning:/etc/grafana/provisioning
|
||||
- ./grafana/dashboards:/var/lib/grafana/dashboards
|
||||
depends_on:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
// Placeholder Dashboard JSON
|
||||
83
scheduler.js
83
scheduler.js
@@ -1,83 +0,0 @@
|
||||
|
||||
require('dotenv').config();
|
||||
const express = require('express');
|
||||
const { exec } = require('child_process');
|
||||
const axios = require('axios');
|
||||
const nodemailer = require('nodemailer');
|
||||
|
||||
const INTERVAL_MINUTES = 30;
|
||||
const MAX_RETRIES = 3;
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const app = express();
|
||||
let lastStatus = { success: null, message: null, timestamp: null, duration: null };
|
||||
|
||||
function runCheck(attempt = 1) {
|
||||
const startTs = Date.now();
|
||||
console.log(`[{new Date().toISOString()}] ▶️ Starting OIDC check (try {attempt}/{MAX_RETRIES})...`);
|
||||
|
||||
const child = exec('node /app/test/monitor.js', (error, stdout, stderr) => {
|
||||
lastStatus.timestamp = new Date().toISOString();
|
||||
lastStatus.duration = Date.now() - startTs;
|
||||
|
||||
if (stdout) console.log(stdout);
|
||||
if (stderr) console.error(stderr);
|
||||
|
||||
lastStatus.success = !error;
|
||||
lastStatus.message = error ? `Fehlgeschlagen: ${error.message}` : 'Login erfolgreich';
|
||||
|
||||
if (error) {
|
||||
notifySlack(`Fehler beim Login:\n${lastStatus.message}`);
|
||||
sendEmail('❌ OIDC Monitoring Fehler', `Zeit: ${lastStatus.timestamp}\n${lastStatus.message}`);
|
||||
}
|
||||
|
||||
pushToPrometheus(!error, lastStatus.duration);
|
||||
});
|
||||
}
|
||||
|
||||
function pushToPrometheus(success, duration) {
|
||||
const labels = `{job="oidc-monitor",instance="${process.env.PROMETHEUS_INSTANCE_ID}"}`;
|
||||
const metrics = `
|
||||
oidc_login_success${labels} ${success ? 1 : 0}
|
||||
oidc_login_duration_seconds${labels} ${(duration / 1000).toFixed(2)}
|
||||
`;
|
||||
axios.post(`${process.env.PUSHGATEWAY_URL}/metrics/job/oidc-monitor`, metrics, {
|
||||
headers: { 'Content-Type': 'text/plain' }
|
||||
}).then(() => console.log('📡 Prometheus Push erfolgreich'))
|
||||
.catch(err => console.error('❌ Prometheus Push fehlgeschlagen:', err.message));
|
||||
}
|
||||
|
||||
function notifySlack(message) {
|
||||
if (!process.env.SLACK_WEBHOOK_URL) return;
|
||||
axios.post(process.env.SLACK_WEBHOOK_URL, { text: `❗️OIDC Monitoring Alert:\n${message}` })
|
||||
.then(() => console.log('📣 Slack-Nachricht gesendet'))
|
||||
.catch(err => console.error('❌ Slack fehlgeschlagen:', err.message));
|
||||
}
|
||||
|
||||
function sendEmail(subject, text) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: parseInt(process.env.SMTP_PORT || '25', 10),
|
||||
secure: false
|
||||
});
|
||||
transporter.sendMail({
|
||||
from: process.env.MAIL_FROM,
|
||||
to: process.env.MAIL_TO,
|
||||
subject,
|
||||
text
|
||||
}).then(() => console.log('✉️ E-Mail gesendet'))
|
||||
.catch(err => console.error('❌ Mail fehlgeschlagen:', err.message));
|
||||
}
|
||||
|
||||
app.get('/run-now', (req, res) => { runCheck(); res.send('▶️ Check gestartet'); });
|
||||
app.get('/healthz', (req, res) => {
|
||||
if (lastStatus.success === false) return res.status(500).send('Letzter Check fehlgeschlagen');
|
||||
res.send('OK');
|
||||
});
|
||||
app.get('/status', (req, res) => res.json(lastStatus));
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🌐 Web API läuft auf Port ${PORT}`);
|
||||
});
|
||||
|
||||
runCheck();
|
||||
setInterval(runCheck, INTERVAL_MINUTES * 60 * 1000);
|
||||
@@ -145,7 +145,7 @@ if (!PUSHGATEWAY_URL) {
|
||||
page.click('span:nth-child(2)'),
|
||||
page.waitForNavigation()
|
||||
]);
|
||||
await page.screenshot({ path: `${resultDir}/eiamselect-${timestamp}.png`, fullPage: true });
|
||||
await page.screenshot({ path: `${resultDir}/${timestamp}-eiamselect.png`, fullPage: true });
|
||||
await Promise.all([
|
||||
page.click('#social-eIAM'),
|
||||
page.waitForNavigation()
|
||||
@@ -157,7 +157,7 @@ if (!PUSHGATEWAY_URL) {
|
||||
await doStep(2, 'Benutzernamen eingeben', async () => {
|
||||
await page.click('#isiwebuserid');
|
||||
await page.fill('#isiwebuserid', USERNAME);
|
||||
await page.screenshot({ path: `${resultDir}/userid-${timestamp}.png`, fullPage: true });
|
||||
await page.screenshot({ path: `${resultDir}/${timestamp}-userid.png`, fullPage: true });
|
||||
await Promise.all([
|
||||
page.press('#isiwebuserid', 'Enter'),
|
||||
page.waitForNavigation()
|
||||
@@ -169,7 +169,7 @@ if (!PUSHGATEWAY_URL) {
|
||||
await doStep(3, 'Passwort eingeben', async () => {
|
||||
await page.click('#isiwebpasswd');
|
||||
await page.fill('#isiwebpasswd', PASSWORD);
|
||||
await page.screenshot({ path: `${resultDir}/pw-${timestamp}.png`, fullPage: true });
|
||||
await page.screenshot({ path: `${resultDir}/${timestamp}-pw.png`, fullPage: true });
|
||||
await Promise.all([
|
||||
page.press('#isiwebpasswd', 'Enter'),
|
||||
page.waitForNavigation()
|
||||
@@ -183,7 +183,7 @@ if (!PUSHGATEWAY_URL) {
|
||||
console.log(`✅ Login eIAM TOTP Code: ${totp}`);
|
||||
console.log('✅ Login eIAM TOTP eintragen');
|
||||
await page.fill('#code2FA', totp);
|
||||
await page.screenshot({ path: `${resultDir}/totp-${timestamp}.png`, fullPage: true });
|
||||
await page.screenshot({ path: `${resultDir}/${timestamp}totp.png`, fullPage: true });
|
||||
await Promise.all([
|
||||
page.press('#code2FA', 'Enter'),
|
||||
page.waitForNavigation()
|
||||
@@ -194,11 +194,11 @@ if (!PUSHGATEWAY_URL) {
|
||||
console.log('✅ WhoAmI Seite laden und prüfen');
|
||||
await doStep(5, 'Login-Erfolg prüfen', async () => {
|
||||
await page.waitForSelector(`text=${SUCCESS_TEXT}`, { timeout: 10000 });
|
||||
await page.screenshot({ path: `${resultDir}/result-${timestamp}.png`, fullPage: true });
|
||||
await page.screenshot({ path: `${resultDir}/${timestamp}-result.png`, fullPage: true });
|
||||
console.log(` Suche nach Benutzername: ${SUCCESS_TEXT}`);
|
||||
const pageText = await page.textContent('body');
|
||||
fs.writeFileSync(path.join(resultDir, `final-${timestamp}.html`), await page.content());
|
||||
fs.writeFileSync(path.join(resultDir, `final-${timestamp}.txt`), pageText);
|
||||
fs.writeFileSync(path.join(resultDir, `${timestamp}-final.html`), await page.content());
|
||||
fs.writeFileSync(path.join(resultDir, `${timestamp}-final.txt`), pageText);
|
||||
if (!pageText.includes(SUCCESS_TEXT)) {
|
||||
throw new Error('Benutzername nicht gefunden – Login möglicherweise fehlerhaft');
|
||||
}
|
||||
@@ -213,7 +213,7 @@ if (!PUSHGATEWAY_URL) {
|
||||
page.click('#kc-logout'),
|
||||
page.waitForNavigation()
|
||||
]);
|
||||
await page.screenshot({ path: `${resultDir}/logout-${timestamp}.png`, fullPage: true });
|
||||
await page.screenshot({ path: `${resultDir}/${timestamp}logout.png`, fullPage: true });
|
||||
console.log('✅ Logout erfolgreich');
|
||||
});
|
||||
|
||||
@@ -223,9 +223,9 @@ if (!PUSHGATEWAY_URL) {
|
||||
} catch (err) {
|
||||
console.error('❌ Fehler beim Login:', err.message);
|
||||
// Fehlerbehandlung und Ergebnisse sichern
|
||||
const screenshotPath = path.join(resultDir, `error_${timestamp}.png`);
|
||||
const htmlPath = path.join(resultDir, `page_${timestamp}.html`);
|
||||
const textPath = path.join(resultDir, `page-${timestamp}.txt`);
|
||||
const screenshotPath = path.join(resultDir, `${timestamp}-error.png`);
|
||||
const htmlPath = path.join(resultDir, `${timestamp}-page.html`);
|
||||
const textPath = path.join(resultDir, `${timestamp}-page.txt`);
|
||||
await page.screenshot({ path: screenshotPath });
|
||||
const pageText = await page.textContent('body');
|
||||
fs.writeFileSync(htmlPath, await page.content());
|
||||
|
||||
@@ -26,7 +26,6 @@ function runCheck(attempt = 1) {
|
||||
lastStatus.message = error ? `Fehlgeschlagen: ${error.message}` : 'Login erfolgreich';
|
||||
|
||||
if (error) {
|
||||
notifySlack(`Fehler beim Login:\n${lastStatus.message}`);
|
||||
sendEmail('❌ OIDC Monitoring Fehler', `Zeit: ${lastStatus.timestamp}\n${lastStatus.message}`);
|
||||
}
|
||||
|
||||
@@ -46,12 +45,6 @@ oidc_login_duration_seconds${labels} ${(duration / 1000).toFixed(2)}
|
||||
.catch(err => console.error('❌ Prometheus Push fehlgeschlagen:', err.message));
|
||||
}
|
||||
|
||||
function notifySlack(message) {
|
||||
if (!process.env.SLACK_WEBHOOK_URL) return;
|
||||
axios.post(process.env.SLACK_WEBHOOK_URL, { text: `❗️OIDC Monitoring Alert:\n${message}` })
|
||||
.then(() => console.log('📣 Slack-Nachricht gesendet'))
|
||||
.catch(err => console.error('❌ Slack fehlgeschlagen:', err.message));
|
||||
}
|
||||
|
||||
function sendEmail(subject, text) {
|
||||
const transporter = nodemailer.createTransport({
|
||||
|
||||
Reference in New Issue
Block a user