Browse Source

move metrics to general

metrics is not per interface
pull/1655/head
Bernd Storath 6 months ago
parent
commit
72feb1eb6d
  1. 11
      src/server/database/migrations/0000_short_skin.sql
  2. 4
      src/server/database/migrations/0001_classy_the_stranger.sql
  3. 77
      src/server/database/migrations/meta/0000_snapshot.json
  4. 79
      src/server/database/migrations/meta/0001_snapshot.json
  5. 4
      src/server/database/migrations/meta/_journal.json
  6. 7
      src/server/database/repositories/general/schema.ts
  7. 61
      src/server/database/repositories/general/service.ts
  8. 6
      src/server/database/repositories/interface/schema.ts
  9. 21
      src/server/database/repositories/metrics/schema.ts
  10. 31
      src/server/database/repositories/metrics/service.ts
  11. 4
      src/server/database/repositories/metrics/types.ts
  12. 1
      src/server/database/schema.ts
  13. 3
      src/server/database/sqlite.ts
  14. 2
      src/server/routes/metrics/json.get.ts
  15. 20
      src/server/utils/handler.ts

11
src/server/database/migrations/0000_short_skin.sql

@ -24,6 +24,9 @@ CREATE TABLE `general_table` (
`setupStep` integer NOT NULL, `setupStep` integer NOT NULL,
`session_password` text NOT NULL, `session_password` text NOT NULL,
`session_timeout` integer NOT NULL, `session_timeout` integer NOT NULL,
`metricsPrometheus` integer NOT NULL,
`metricsJson` integer NOT NULL,
`metricsPassword` text,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL
); );
@ -54,14 +57,6 @@ CREATE TABLE `interfaces_table` (
); );
--> statement-breakpoint --> statement-breakpoint
CREATE UNIQUE INDEX `interfaces_table_port_unique` ON `interfaces_table` (`port`);--> statement-breakpoint CREATE UNIQUE INDEX `interfaces_table_port_unique` ON `interfaces_table` (`port`);--> statement-breakpoint
CREATE TABLE `prometheus_table` (
`id` text PRIMARY KEY NOT NULL,
`password` text NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
FOREIGN KEY (`id`) REFERENCES `interfaces_table`(`name`) ON UPDATE cascade ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `one_time_links_table` ( CREATE TABLE `one_time_links_table` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`one_time_link` text NOT NULL, `one_time_link` text NOT NULL,

4
src/server/database/migrations/0001_classy_the_stranger.sql

@ -1,6 +1,6 @@
PRAGMA journal_mode=WAL;--> statement-breakpoint PRAGMA journal_mode=WAL;--> statement-breakpoint
INSERT INTO `general_table` (`setupStep`, `session_password`, `session_timeout`) INSERT INTO `general_table` (`setupStep`, `session_password`, `session_timeout`, `metricsPrometheus`, `metricsJson`)
VALUES (1, hex(randomblob(256)), 3600); VALUES (1, hex(randomblob(256)), 3600, 0, 0);
--> statement-breakpoint --> statement-breakpoint
INSERT INTO `interfaces_table` (`name`, `device`, `port`, `private_key`, `public_key`, `ipv4_cidr`, `ipv6_cidr`, `mtu`, `enabled`) INSERT INTO `interfaces_table` (`name`, `device`, `port`, `private_key`, `public_key`, `ipv4_cidr`, `ipv6_cidr`, `mtu`, `enabled`)
VALUES ('wg0', 'eth0', 51820, '---default---', '---default---', '10.8.0.0/24', 'fdcc:ad94:bacf:61a4::cafe:0/112', 1420, 1); VALUES ('wg0', 'eth0', 51820, '---default---', '---default---', '10.8.0.0/24', 'fdcc:ad94:bacf:61a4::cafe:0/112', 1420, 1);

77
src/server/database/migrations/meta/0000_snapshot.json

@ -1,7 +1,7 @@
{ {
"version": "6", "version": "6",
"dialect": "sqlite", "dialect": "sqlite",
"id": "25907c5f-be21-4ae6-88c4-1a72b2f335e7", "id": "2c4694af-5916-430f-96d3-55aac2653e7e",
"prevId": "00000000-0000-0000-0000-000000000000", "prevId": "00000000-0000-0000-0000-000000000000",
"tables": { "tables": {
"clients_table": { "clients_table": {
@ -175,6 +175,27 @@
"notNull": true, "notNull": true,
"autoincrement": false "autoincrement": false
}, },
"metricsPrometheus": {
"name": "metricsPrometheus",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"metricsJson": {
"name": "metricsJson",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"metricsPassword": {
"name": "metricsPassword",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": { "created_at": {
"name": "created_at", "name": "created_at",
"type": "text", "type": "text",
@ -370,60 +391,6 @@
"uniqueConstraints": {}, "uniqueConstraints": {},
"checkConstraints": {} "checkConstraints": {}
}, },
"prometheus_table": {
"name": "prometheus_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
}
},
"indexes": {},
"foreignKeys": {
"prometheus_table_id_interfaces_table_name_fk": {
"name": "prometheus_table_id_interfaces_table_name_fk",
"tableFrom": "prometheus_table",
"tableTo": "interfaces_table",
"columnsFrom": [
"id"
],
"columnsTo": [
"name"
],
"onDelete": "cascade",
"onUpdate": "cascade"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"one_time_links_table": { "one_time_links_table": {
"name": "one_time_links_table", "name": "one_time_links_table",
"columns": { "columns": {

79
src/server/database/migrations/meta/0001_snapshot.json

@ -1,6 +1,6 @@
{ {
"id": "60af732f-adc0-405d-96cc-2f818585f593", "id": "91d39ed5-2c45-4af6-ba39-4cd72ba71f6a",
"prevId": "25907c5f-be21-4ae6-88c4-1a72b2f335e7", "prevId": "2c4694af-5916-430f-96d3-55aac2653e7e",
"version": "6", "version": "6",
"dialect": "sqlite", "dialect": "sqlite",
"tables": { "tables": {
@ -175,6 +175,27 @@
"notNull": true, "notNull": true,
"autoincrement": false "autoincrement": false
}, },
"metricsPrometheus": {
"name": "metricsPrometheus",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"metricsJson": {
"name": "metricsJson",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"metricsPassword": {
"name": "metricsPassword",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": { "created_at": {
"name": "created_at", "name": "created_at",
"type": "text", "type": "text",
@ -370,60 +391,6 @@
"uniqueConstraints": {}, "uniqueConstraints": {},
"checkConstraints": {} "checkConstraints": {}
}, },
"prometheus_table": {
"name": "prometheus_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
},
"updated_at": {
"name": "updated_at",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(CURRENT_TIMESTAMP)"
}
},
"indexes": {},
"foreignKeys": {
"prometheus_table_id_interfaces_table_name_fk": {
"name": "prometheus_table_id_interfaces_table_name_fk",
"tableFrom": "prometheus_table",
"columnsFrom": [
"id"
],
"tableTo": "interfaces_table",
"columnsTo": [
"name"
],
"onUpdate": "cascade",
"onDelete": "cascade"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"one_time_links_table": { "one_time_links_table": {
"name": "one_time_links_table", "name": "one_time_links_table",
"columns": { "columns": {

4
src/server/database/migrations/meta/_journal.json

@ -5,14 +5,14 @@
{ {
"idx": 0, "idx": 0,
"version": "6", "version": "6",
"when": 1737122352401, "when": 1739191645161,
"tag": "0000_short_skin", "tag": "0000_short_skin",
"breakpoints": true "breakpoints": true
}, },
{ {
"idx": 1, "idx": 1,
"version": "6", "version": "6",
"when": 1737122356601, "when": 1739191678456,
"tag": "0001_classy_the_stranger", "tag": "0001_classy_the_stranger",
"breakpoints": true "breakpoints": true
} }

7
src/server/database/repositories/general/schema.ts

@ -3,9 +3,16 @@ import { sqliteTable, text, int } from 'drizzle-orm/sqlite-core';
export const general = sqliteTable('general_table', { export const general = sqliteTable('general_table', {
id: int().primaryKey({ autoIncrement: false }).default(1), id: int().primaryKey({ autoIncrement: false }).default(1),
setupStep: int().notNull(), setupStep: int().notNull(),
sessionPassword: text('session_password').notNull(), sessionPassword: text('session_password').notNull(),
sessionTimeout: int('session_timeout').notNull(), sessionTimeout: int('session_timeout').notNull(),
metricsPrometheus: int({ mode: 'boolean' }).notNull(),
metricsJson: int({ mode: 'boolean' }).notNull(),
metricsPassword: text(),
createdAt: text('created_at') createdAt: text('created_at')
.notNull() .notNull()
.default(sql`(CURRENT_TIMESTAMP)`), .default(sql`(CURRENT_TIMESTAMP)`),

61
src/server/database/repositories/general/service.ts

@ -5,7 +5,30 @@ import type { GeneralUpdateType } from './types';
function createPreparedStatement(db: DBType) { function createPreparedStatement(db: DBType) {
return { return {
find: db.query.general.findFirst().prepare(), getSetupStep: db.query.general
.findFirst({
columns: {
setupStep: true,
},
})
.prepare(),
getSessionConfig: db.query.general
.findFirst({
columns: {
sessionPassword: true,
sessionTimeout: true,
},
})
.prepare(),
getMetricsConfig: db.query.general
.findFirst({
columns: {
metricsPrometheus: true,
metricsJson: true,
metricsPassword: true,
},
})
.prepare(),
updateSetupStep: db updateSetupStep: db
.update(general) .update(general)
.set({ .set({
@ -31,19 +54,13 @@ export class GeneralService {
/** /**
* @throws * @throws
*/ */
private async get() { async getSetupStep() {
const result = await this.#statements.find.execute(); const result = await this.#statements.getSetupStep.execute();
if (!result) { if (!result) {
throw new Error('General Config not found'); throw new Error('General Config not found');
} }
return result;
}
/**
* @throws
*/
async getSetupStep() {
const result = await this.get();
return { step: result.setupStep, done: result.setupStep === 0 }; return { step: result.setupStep, done: result.setupStep === 0 };
} }
@ -55,13 +72,35 @@ export class GeneralService {
* @throws * @throws
*/ */
async getSessionConfig() { async getSessionConfig() {
const result = await this.get(); const result = await this.#statements.getSessionConfig.execute();
if (!result) {
throw new Error('General Config not found');
}
return { return {
sessionPassword: result.sessionPassword, sessionPassword: result.sessionPassword,
sessionTimeout: result.sessionTimeout, sessionTimeout: result.sessionTimeout,
}; };
} }
/**
* @throws
*/
async getMetricsConfig() {
const result = await this.#statements.getMetricsConfig.execute();
if (!result) {
throw new Error('General Config not found');
}
return {
prometheus: result.metricsPrometheus,
json: result.metricsJson,
password: result.metricsPassword,
};
}
update(data: GeneralUpdateType) { update(data: GeneralUpdateType) {
return this.#statements.update.execute(data); return this.#statements.update.execute(data);
} }

6
src/server/database/repositories/interface/schema.ts

@ -1,7 +1,7 @@
import { sql, relations } from 'drizzle-orm'; import { sql, relations } from 'drizzle-orm';
import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { userConfig, hooks, prometheus } from '../../schema'; import { userConfig, hooks } from '../../schema';
// maybe support multiple interfaces in the future // maybe support multiple interfaces in the future
export const wgInterface = sqliteTable('interfaces_table', { export const wgInterface = sqliteTable('interfaces_table', {
@ -28,10 +28,6 @@ export const wgInterfaceRelations = relations(wgInterface, ({ one }) => ({
fields: [wgInterface.name], fields: [wgInterface.name],
references: [hooks.id], references: [hooks.id],
}), }),
prometheus: one(prometheus, {
fields: [wgInterface.name],
references: [prometheus.id],
}),
userConfig: one(userConfig, { userConfig: one(userConfig, {
fields: [wgInterface.name], fields: [wgInterface.name],
references: [userConfig.id], references: [userConfig.id],

21
src/server/database/repositories/metrics/schema.ts

@ -1,21 +0,0 @@
import { sql } from 'drizzle-orm';
import { sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { wgInterface } from '../../schema';
export const prometheus = sqliteTable('prometheus_table', {
id: text()
.primaryKey()
.references(() => wgInterface.name, {
onDelete: 'cascade',
onUpdate: 'cascade',
}),
password: text().notNull(),
createdAt: text('created_at')
.notNull()
.default(sql`(CURRENT_TIMESTAMP)`),
updatedAt: text('updated_at')
.notNull()
.default(sql`(CURRENT_TIMESTAMP)`)
.$onUpdate(() => sql`(CURRENT_TIMESTAMP)`),
});

31
src/server/database/repositories/metrics/service.ts

@ -1,31 +0,0 @@
import type { DBType } from '#db/sqlite';
import { eq, sql } from 'drizzle-orm';
import { prometheus } from './schema';
function createPreparedStatement(db: DBType) {
return {
get: db.query.prometheus
.findFirst({ where: eq(prometheus.id, sql.placeholder('interface')) })
.prepare(),
};
}
export class PrometheusService {
#statements: ReturnType<typeof createPreparedStatement>;
constructor(db: DBType) {
this.#statements = createPreparedStatement(db);
}
get(infName: string) {
return this.#statements.get.execute({ interface: infName });
}
}
export class MetricsService {
prometheus: PrometheusService;
constructor(db: DBType) {
this.prometheus = new PrometheusService(db);
}
}

4
src/server/database/repositories/metrics/types.ts

@ -1,4 +0,0 @@
import type { InferSelectModel } from 'drizzle-orm';
import type { prometheus } from './schema';
export type PrometheusType = InferSelectModel<typeof prometheus>;

1
src/server/database/schema.ts

@ -3,7 +3,6 @@ export * from './repositories/client/schema';
export * from './repositories/general/schema'; export * from './repositories/general/schema';
export * from './repositories/hooks/schema'; export * from './repositories/hooks/schema';
export * from './repositories/interface/schema'; export * from './repositories/interface/schema';
export * from './repositories/metrics/schema';
export * from './repositories/oneTimeLink/schema'; export * from './repositories/oneTimeLink/schema';
export * from './repositories/user/schema'; export * from './repositories/user/schema';
export * from './repositories/userConfig/schema'; export * from './repositories/userConfig/schema';

3
src/server/database/sqlite.ts

@ -11,7 +11,6 @@ import { UserConfigService } from './repositories/userConfig/service';
import { InterfaceService } from './repositories/interface/service'; import { InterfaceService } from './repositories/interface/service';
import { HooksService } from './repositories/hooks/service'; import { HooksService } from './repositories/hooks/service';
import { OneTimeLinkService } from './repositories/oneTimeLink/service'; import { OneTimeLinkService } from './repositories/oneTimeLink/service';
import { MetricsService } from './repositories/metrics/service';
const DB_DEBUG = debug('Database'); const DB_DEBUG = debug('Database');
@ -31,7 +30,6 @@ class DBService {
interfaces: InterfaceService; interfaces: InterfaceService;
hooks: HooksService; hooks: HooksService;
oneTimeLinks: OneTimeLinkService; oneTimeLinks: OneTimeLinkService;
metrics: MetricsService;
constructor(db: DBType) { constructor(db: DBType) {
this.clients = new ClientService(db); this.clients = new ClientService(db);
@ -41,7 +39,6 @@ class DBService {
this.interfaces = new InterfaceService(db); this.interfaces = new InterfaceService(db);
this.hooks = new HooksService(db); this.hooks = new HooksService(db);
this.oneTimeLinks = new OneTimeLinkService(db); this.oneTimeLinks = new OneTimeLinkService(db);
this.metrics = new MetricsService(db);
} }
} }

2
src/server/routes/metrics/json.get.ts

@ -1,4 +1,4 @@
export default defineMetricsHandler('prometheus', async () => { export default defineMetricsHandler('json', async () => {
return getMetricsJSON(); return getMetricsJSON();
}); });

20
src/server/utils/handler.ts

@ -58,7 +58,7 @@ export const defineSetupEventHandler = <
}); });
}; };
type Metrics = 'prometheus'; type Metrics = 'prometheus' | 'json';
type MetricsHandler< type MetricsHandler<
TReq extends EventHandlerRequest, TReq extends EventHandlerRequest,
@ -94,22 +94,24 @@ export const defineMetricsHandler = <
}); });
} }
const metricsConfig = await Database.metrics[type].get('wg0'); const metricsConfig = await Database.general.getMetricsConfig();
if (!metricsConfig) { if (metricsConfig[type] !== true) {
throw createError({ throw createError({
statusCode: 400, statusCode: 400,
statusMessage: 'Metrics not enabled', statusMessage: 'Metrics not enabled',
}); });
} }
const tokenValid = await isPasswordValid(value, metricsConfig.password); if (metricsConfig.password) {
const tokenValid = await isPasswordValid(value, metricsConfig.password);
if (!tokenValid) { if (!tokenValid) {
throw createError({ throw createError({
statusCode: 401, statusCode: 401,
statusMessage: 'Incorrect token', statusMessage: 'Incorrect token',
}); });
}
} }
return await handler({ event }); return await handler({ event });

Loading…
Cancel
Save