| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- import { randomUUID } from "crypto";
- import "dotenv/config";
- import { ConfigService } from "@nestjs/config";
- import { DataSource } from "typeorm";
- import { buildDataSourceOptions } from "../src/database/database.config";
- import { MonitorRunEntity } from "../src/monitoring/monitor-run.entity";
- import { MonitorAgentEntity } from "../src/monitoring/monitor-agent.entity";
- import { MonitorTargetEntity } from "../src/monitoring/monitor-target.entity";
- import { InspectionRunEntity } from "../src/runs/inspection-run.entity";
- import { InspectionTaskEntity } from "../src/tasks/inspection-task.entity";
- function buildSteps(siteUrl: string, titleKeyword?: string) {
- const steps = [
- { action: "goto", url: siteUrl, timeoutMs: 20000 },
- { action: "waitForLoadState", value: "domcontentloaded", timeoutMs: 12000 },
- { action: "waitForSelector", selector: "body", timeoutMs: 12000 },
- { action: "assertVisible", selector: "body", timeoutMs: 12000 },
- ] as Array<Record<string, unknown>>;
- if (titleKeyword) {
- steps.push({
- action: "assertText",
- selector: "title",
- contains: titleKeyword,
- timeoutMs: 4000,
- });
- }
- steps.push({ action: "screenshot", value: "landing-page" });
- return JSON.stringify(steps, null, 2);
- }
- async function seedInspectionData(dataSource: DataSource) {
- const taskRepo = dataSource.getRepository(InspectionTaskEntity);
- const runRepo = dataSource.getRepository(InspectionRunEntity);
- const tasks = [
- {
- id: "gov-portal-main-seed",
- name: "呼和浩特市政府首页巡检",
- siteUrl: "http://www.huhhot.gov.cn/",
- cronExpr: "*/15 * * * *",
- serviceKey: "gov-portal-main",
- titleKeyword: "呼和浩特",
- },
- {
- id: "gov-portal-secondary-seed",
- name: "土默特右旗政府首页巡检",
- siteUrl: "http://www.tmtyq.gov.cn/",
- cronExpr: "*/30 * * * *",
- serviceKey: "gov-portal-secondary",
- titleKeyword: "土默特右旗",
- },
- ];
- for (const item of tasks) {
- let task = await taskRepo.findOne({ where: { id: item.id } });
- if (!task) {
- task = taskRepo.create({
- ...item,
- stepsJson: buildSteps(item.siteUrl, item.titleKeyword),
- preferredExecutor: "browser",
- allowAgentFallback: false,
- status: "enabled",
- lastRunAt: null,
- });
- } else {
- task.name = item.name;
- task.siteUrl = item.siteUrl;
- task.cronExpr = item.cronExpr;
- task.serviceKey = item.serviceKey;
- task.stepsJson = buildSteps(item.siteUrl, item.titleKeyword);
- task.preferredExecutor = "browser";
- task.allowAgentFallback = false;
- task.status = "enabled";
- }
- await taskRepo.save(task);
- const existingRunCount = await runRepo.count({ where: { taskId: task.id } });
- if (existingRunCount === 0) {
- const startedAt = new Date(Date.now() - 10 * 60 * 1000);
- const endedAt = new Date(Date.now() - 9 * 60 * 1000);
- const run = runRepo.create({
- id: randomUUID(),
- taskId: task.id,
- traceId: `seed-${task.serviceKey}`,
- status: "success",
- errorTag: null,
- failureReason: null,
- screenshotUrls: JSON.stringify([]),
- stepLogsJson: JSON.stringify([]),
- pageUrl: task.siteUrl,
- domSummary: null,
- startedAt,
- endedAt,
- });
- await runRepo.save(run);
- }
- }
- }
- async function seedMonitoringData(dataSource: DataSource) {
- const agentRepo = dataSource.getRepository(MonitorAgentEntity);
- const targetRepo = dataSource.getRepository(MonitorTargetEntity);
- const runRepo = dataSource.getRepository(MonitorRunEntity);
- const agentSeeds = [
- {
- id: "monitor-agent-local-linux-seed",
- name: "本地 Linux Agent 模板",
- agentKey: "linux-demo-agent",
- host: "192.168.1.50",
- platform: "linux" as const,
- status: "disabled" as const,
- monitoringEnabled: false,
- logIngestEnabled: false,
- proactivePushEnabled: false,
- },
- {
- id: "monitor-agent-local-windows-seed",
- name: "本地 Windows Agent",
- agentKey: "local-windows-agent",
- host: "localhost",
- platform: "windows" as const,
- status: "enabled" as const,
- monitoringEnabled: true,
- logIngestEnabled: false,
- proactivePushEnabled: false,
- },
- ];
- for (const item of agentSeeds) {
- let agent = await agentRepo.findOne({ where: { id: item.id } });
- if (!agent) {
- agent = agentRepo.create({
- ...item,
- version: null,
- lastHeartbeatAt: null,
- lastHeartbeatMetaJson: null,
- lastVerifyAt: null,
- lastVerifyStatus: null,
- lastVerifyMessage: null,
- });
- } else {
- agent.name = item.name;
- agent.agentKey = item.agentKey;
- agent.host = item.host;
- agent.platform = item.platform;
- agent.status = item.status;
- agent.monitoringEnabled = item.monitoringEnabled;
- agent.logIngestEnabled = item.logIngestEnabled;
- agent.proactivePushEnabled = item.proactivePushEnabled;
- }
- await agentRepo.save(agent);
- }
- const targets = [
- {
- id: "monitor-http-seed",
- name: "本机 API 健康检查",
- type: "http" as const,
- serviceKey: "sentai-api",
- cronExpr: "*/5 * * * *",
- endpoint: "http://127.0.0.1:3001/health",
- configJson: JSON.stringify(
- {
- timeoutMs: 8000,
- expectedStatus: 200,
- expectedText: "\"ok\":true",
- },
- null,
- 2,
- ),
- secretJson: JSON.stringify({}, null, 2),
- status: "enabled" as const,
- },
- {
- id: "monitor-http-blackbox-template-seed",
- name: "HTTP Blackbox 接入模板",
- type: "http" as const,
- serviceKey: "http-blackbox-template",
- cronExpr: "*/10 * * * *",
- endpoint: "http://192.168.1.30:8080/health",
- configJson: JSON.stringify(
- {
- collectionMode: "blackbox",
- blackboxBaseUrl: "http://192.168.1.50:9115",
- blackboxModule: "http_2xx",
- blackboxTarget: "http://192.168.1.30:8080/health",
- },
- null,
- 2,
- ),
- secretJson: JSON.stringify({}, null, 2),
- status: "disabled" as const,
- },
- {
- id: "monitor-redis-template-seed",
- name: "Redis 接入模板",
- type: "redis" as const,
- serviceKey: "infra-redis-template",
- cronExpr: "*/10 * * * *",
- endpoint: "192.168.1.10",
- configJson: JSON.stringify(
- {
- tcpHost: "192.168.1.10",
- tcpPort: 6379,
- timeoutMs: 5000,
- redisSections: ["server", "memory", "stats", "replication"],
- },
- null,
- 2,
- ),
- secretJson: JSON.stringify(
- {
- authPassword: "",
- sshHost: "",
- sshPort: 22,
- sshUsername: "",
- sshPassword: "",
- logFilePath: "",
- logTailLines: 120,
- logKeyword: "ERROR|Exception|Timeout|Refused",
- },
- null,
- 2,
- ),
- status: "disabled" as const,
- },
- {
- id: "monitor-java-template-seed",
- name: "Java 应用接入模板",
- type: "java-app" as const,
- serviceKey: "java-app-template",
- cronExpr: "*/10 * * * *",
- endpoint: "http://192.168.1.20:8080",
- configJson: JSON.stringify(
- {
- javaCollectionMode: "hybrid",
- javaHealthPath: "/actuator/health",
- javaMetricsPath: "/actuator/metrics",
- jmxExporterUrl: "http://192.168.1.20:9404/metrics",
- jmxMetricsPath: "",
- javaRequireHealthCheck: true,
- },
- null,
- 2,
- ),
- secretJson: JSON.stringify(
- {
- sshHost: "",
- sshPort: 22,
- sshUsername: "",
- sshPassword: "",
- logFilePath: "/data/logs/app/application.log",
- logTailLines: 150,
- logKeyword: "ERROR|Exception|Timeout|Refused",
- },
- null,
- 2,
- ),
- status: "disabled" as const,
- },
- ];
- for (const item of targets) {
- let target = await targetRepo.findOne({ where: { id: item.id } });
- if (!target) {
- target = targetRepo.create({
- ...item,
- lastRunAt: null,
- });
- } else {
- target.name = item.name;
- target.type = item.type;
- target.serviceKey = item.serviceKey;
- target.cronExpr = item.cronExpr;
- target.endpoint = item.endpoint;
- target.configJson = item.configJson;
- target.secretJson = item.secretJson;
- target.status = item.status;
- }
- await targetRepo.save(target);
- }
- const healthTarget = await targetRepo.findOneByOrFail({ id: "monitor-http-seed" });
- const existingRunCount = await runRepo.count({ where: { targetId: healthTarget.id } });
- if (existingRunCount === 0) {
- const startedAt = new Date(Date.now() - 5 * 60 * 1000);
- const endedAt = new Date(Date.now() - 4 * 60 * 1000);
- const run = runRepo.create({
- id: randomUUID(),
- targetId: healthTarget.id,
- traceId: "seed-monitor-http",
- status: "success",
- errorTag: null,
- summary: "API 健康检查通过",
- failureReason: null,
- metricsJson: JSON.stringify({ statusCode: 200 }, null, 2),
- detailsJson: JSON.stringify({ endpoint: healthTarget.endpoint }, null, 2),
- logExcerpt: null,
- resultJsonUrl: null,
- startedAt,
- endedAt,
- });
- await runRepo.save(run);
- }
- }
- async function main() {
- const configService = new ConfigService(process.env);
- const dataSource = new DataSource(
- buildDataSourceOptions(configService, { synchronize: false }),
- );
- await dataSource.initialize();
- await seedInspectionData(dataSource);
- await seedMonitoringData(dataSource);
- await dataSource.destroy();
- }
- void main().catch((error) => {
- console.error(error);
- process.exit(1);
- });
|