a
This commit is contained in:
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
FROM node:20-slim
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY test /app/test
|
||||||
|
COPY scheduler.js /app/scheduler.js
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["npm", "start"]
|
||||||
39
docker-compose.yml
Normal file
39
docker-compose.yml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
e2e-monitor:
|
||||||
|
build: .
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
|
ports:
|
||||||
|
- "3020:3000" # Web API: /status, /healthz, /run-now
|
||||||
|
volumes:
|
||||||
|
- ./test:/app/test:ro
|
||||||
|
- ./test-results:/app/test-results
|
||||||
|
depends_on:
|
||||||
|
- pushgateway
|
||||||
|
|
||||||
|
pushgateway:
|
||||||
|
image: prom/pushgateway
|
||||||
|
ports:
|
||||||
|
- "9091:9091"
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
image: prom/prometheus
|
||||||
|
volumes:
|
||||||
|
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||||
|
ports:
|
||||||
|
- "9090:9090"
|
||||||
|
depends_on:
|
||||||
|
- pushgateway
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana
|
||||||
|
ports:
|
||||||
|
- "3031:3000"
|
||||||
|
volumes:
|
||||||
|
- ./grafana/provisioning:/etc/grafana/provisioning
|
||||||
|
- ./grafana/dashboards:/var/lib/grafana/dashboards
|
||||||
|
depends_on:
|
||||||
|
- prometheus
|
||||||
|
|
||||||
1
grafana/dashboards/oidc-dashboard.json
Executable file
1
grafana/dashboards/oidc-dashboard.json
Executable file
@@ -0,0 +1 @@
|
|||||||
|
// Placeholder Dashboard JSON
|
||||||
8
grafana/provisioning/dashboards/dashboard.yml
Executable file
8
grafana/provisioning/dashboards/dashboard.yml
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
apiVersion: 1
|
||||||
|
providers:
|
||||||
|
- name: 'OIDC Monitoring'
|
||||||
|
folder: ''
|
||||||
|
type: file
|
||||||
|
options:
|
||||||
|
path: /var/lib/grafana/dashboards
|
||||||
8
grafana/provisioning/datasources/datasource.yml
Executable file
8
grafana/provisioning/datasources/datasource.yml
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
apiVersion: 1
|
||||||
|
datasources:
|
||||||
|
- name: Prometheus
|
||||||
|
type: prometheus
|
||||||
|
access: proxy
|
||||||
|
url: http://prometheus:9090
|
||||||
|
isDefault: true
|
||||||
BIN
oidc-monitor-full.zip
Normal file
BIN
oidc-monitor-full.zip
Normal file
Binary file not shown.
16
package.json
Normal file
16
package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
"name": "oidc-monitor",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node scheduler.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.8",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"express": "^4.18.4",
|
||||||
|
"nodemailer": "^6.9.8",
|
||||||
|
"playwright": "^1.43.0",
|
||||||
|
"speakeasy": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
prometheus/prometheus.yml
Executable file
8
prometheus/prometheus.yml
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: 'pushgateway'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['pushgateway:9091']
|
||||||
83
scheduler.js
Normal file
83
scheduler.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
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);
|
||||||
3
test/monitor.js
Normal file
3
test/monitor.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
// Placeholder für dein Playwright-Login-Script
|
||||||
|
console.log("▶️ Simulierter Playwright-Check gestartet...");
|
||||||
Reference in New Issue
Block a user