first commit
This commit is contained in:
commit
e082feae8b
26 changed files with 7238 additions and 0 deletions
125
src/controllers/backup-controller.ts
Normal file
125
src/controllers/backup-controller.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import { Body, Controller, Delete, Get, Post, Route, Security } from "tsoa";
|
||||
import { Client as MinioClient, BucketItem } from "minio";
|
||||
|
||||
function getEnvVar(name: string) {
|
||||
const value = process.env[name];
|
||||
if (!value) throw new Error(`${name} is required.`);
|
||||
return value;
|
||||
}
|
||||
|
||||
const WINDMILL_URL = getEnvVar("WINDMILL_URL");
|
||||
const WINDMILL_WORKSPACE = getEnvVar("WINDMILL_WORKSPACE");
|
||||
const WINDMILL_BACKUP_SCRIPT_ID = getEnvVar("WINDMILL_BACKUP_SCRIPT_ID");
|
||||
const WINDMILL_RESTORE_SCRIPT_ID = getEnvVar("WINDMILL_RESTORE_SCRIPT_ID");
|
||||
const WINDMILL_API_KEY = getEnvVar("WINDMILL_API_KEY");
|
||||
const DB_HOST = getEnvVar("DB_HOST");
|
||||
const DB_PORT = process.env.DB_PORT;
|
||||
const DB_USERNAME = getEnvVar("DB_USERNAME");
|
||||
const DB_PASSWORD = getEnvVar("DB_PASSWORD");
|
||||
const MINIO_USE_SSL = getEnvVar("MINIO_USE_SSL");
|
||||
const MINIO_HOST = getEnvVar("MINIO_HOST");
|
||||
const MINIO_PORT = process.env.MINIO_PORT;
|
||||
const MINIO_ACCESS_KEY = getEnvVar("MINIO_ACCESS_KEY");
|
||||
const MINIO_SECRET_KEY = getEnvVar("MINIO_SECRET_KEY");
|
||||
const MINIO_BUCKET = getEnvVar("MINIO_BUCKET");
|
||||
|
||||
const minio = new MinioClient({
|
||||
useSSL: MINIO_USE_SSL === "true",
|
||||
endPoint: MINIO_HOST,
|
||||
port: +(MINIO_PORT || "9000"),
|
||||
accessKey: MINIO_ACCESS_KEY,
|
||||
secretKey: MINIO_SECRET_KEY,
|
||||
});
|
||||
|
||||
@Route("/api/v1/backup")
|
||||
@Security("keycloak")
|
||||
export class BackupController extends Controller {
|
||||
@Get()
|
||||
async listBackup() {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const data: BucketItem[] = [];
|
||||
const stream = minio.listObjectsV2(MINIO_BUCKET);
|
||||
stream.on("data", (obj) => data.push(obj));
|
||||
stream.on("end", () =>
|
||||
resolve(
|
||||
data.flatMap((v) => ("prefix" in v ? [] : { name: v.name, timestamp: v.lastModified })),
|
||||
),
|
||||
);
|
||||
stream.on("error", (err) => reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
@Post("create")
|
||||
async runBackup() {
|
||||
return await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/jobs/run_wait_result/h/${WINDMILL_BACKUP_SCRIPT_ID}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${WINDMILL_API_KEY}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
s3_endpoint: `${MINIO_USE_SSL === "true" ? "https" : "http"}://${MINIO_HOST}${(MINIO_PORT && ":" + MINIO_PORT) || ""}`,
|
||||
s3_access: MINIO_ACCESS_KEY,
|
||||
s3_secret: MINIO_SECRET_KEY,
|
||||
s3_bucket: MINIO_BUCKET,
|
||||
s3_prefix: "/",
|
||||
db_host: DB_HOST,
|
||||
db_port: DB_PORT,
|
||||
db_user: DB_USERNAME,
|
||||
db_password: DB_PASSWORD,
|
||||
backup_filename: "manual",
|
||||
num_versions_to_keep: 0,
|
||||
}),
|
||||
},
|
||||
).then(async (r) => {
|
||||
const data = await r.json();
|
||||
if (typeof data === "object" && "error" in data) {
|
||||
console.error(data);
|
||||
throw new Error("Backup Error");
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
@Post("restore")
|
||||
async restoreBackup(@Body() body: { filename: string }) {
|
||||
return await fetch(
|
||||
`${WINDMILL_URL}/api/w/${WINDMILL_WORKSPACE}/jobs/run_wait_result/h/${WINDMILL_RESTORE_SCRIPT_ID}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${WINDMILL_API_KEY}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
s3_endpoint: `${MINIO_USE_SSL === "true" ? "https" : "http"}://${MINIO_HOST}${(MINIO_PORT && ":" + MINIO_PORT) || ""}`,
|
||||
s3_access: MINIO_ACCESS_KEY,
|
||||
s3_secret: MINIO_SECRET_KEY,
|
||||
s3_bucket: MINIO_BUCKET,
|
||||
s3_prefix: "/",
|
||||
db_host: DB_HOST,
|
||||
db_port: DB_PORT,
|
||||
db_user: DB_USERNAME,
|
||||
db_password: DB_PASSWORD,
|
||||
restore_filename: body.filename,
|
||||
}),
|
||||
},
|
||||
).then(async (r) => {
|
||||
const data = await r.json();
|
||||
if (typeof data === "object" && "error" in data) {
|
||||
console.error(data);
|
||||
throw new Error("Backup Error");
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
@Delete("delete")
|
||||
async deleteBackup(@Body() body: { filename: string }) {
|
||||
await minio.removeObject(MINIO_BUCKET, body.filename, {
|
||||
forceDelete: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
60
src/controllers/log-controller.ts
Normal file
60
src/controllers/log-controller.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { Controller, Get, Query, Route, Security } from "tsoa";
|
||||
import { Client as ElasticsearchClient } from "@elastic/elasticsearch";
|
||||
|
||||
function getEnvVar(name: string) {
|
||||
const value = process.env[name];
|
||||
if (!value) throw new Error(`${name} is required.`);
|
||||
return value;
|
||||
}
|
||||
|
||||
const ELASTICSEARCH_PROTOCOL = getEnvVar("ELASTICSEARCH_PROTOCOL");
|
||||
const ELASTICSEARCH_HOST = getEnvVar("ELASTICSEARCH_HOST");
|
||||
const ELASTICSEARCH_PORT = getEnvVar("ELASTICSEARCH_PORT");
|
||||
const ELASTICSEARCH_INDEX = getEnvVar("ELASTICSEARCH_INDEX");
|
||||
|
||||
const elasticsearch = new ElasticsearchClient({
|
||||
node: `${ELASTICSEARCH_PROTOCOL}://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}`,
|
||||
});
|
||||
|
||||
@Route("/api/v1/log")
|
||||
@Security("keycloak")
|
||||
export class LogController extends Controller {
|
||||
@Get()
|
||||
async GET(
|
||||
@Query() size: number = 30,
|
||||
@Query() search?: string,
|
||||
@Query() searchAfter?: number,
|
||||
@Query() systemName?: string,
|
||||
) {
|
||||
const queryData = await elasticsearch.search({
|
||||
index: ELASTICSEARCH_INDEX,
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
...(systemName ? [{ match: { systemName } }] : []),
|
||||
...(search
|
||||
? [
|
||||
{
|
||||
bool: {
|
||||
should: [
|
||||
{
|
||||
multi_match: {
|
||||
query: search,
|
||||
fields: ["method", "logType", "endpoint", "host"],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
},
|
||||
search_after: searchAfter ? [searchAfter] : undefined,
|
||||
sort: [{ startTimeStamp: "desc" }],
|
||||
size: size,
|
||||
});
|
||||
return queryData.hits.hits;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue