Browse Source

Merge branch 'dockerize/server' of hostbbq/hostbbq-monitoring into master

tunefish 2 years ago
parent
commit
2d0f74e3ff

+ 2 - 4
server/package.json

@@ -5,7 +5,7 @@
   "main": "dist/server/src/index.js",
   "scripts": {
     "start": "npm run build && node .",
-    "build": "tsc -b && rm -rfv dist/server/src/migrations && tsc -p tsconfig.mig.json && cp -v src/migrations/*.sql dist/server/src/migrations/"
+    "build": "tsc -b"
   },
   "author": "Christian Kahlau, HostBBQ ©2022",
   "license": "ISC",
@@ -14,14 +14,12 @@
     "express": "^4.18.1",
     "firebase-admin": "^11.4.1",
     "moment": "^2.29.4",
-    "mysql": "^2.18.1",
-    "sqlite3": "^5.1.1"
+    "mysql": "^2.18.1"
   },
   "devDependencies": {
     "@types/express": "^4.17.14",
     "@types/mysql": "^2.15.21",
     "@types/node": "^18.7.19",
-    "@types/sqlite3": "^3.1.8",
     "typescript": "^4.8.3"
   }
 }

+ 0 - 97
server/src/ctrl/db-migration.class.ts

@@ -1,97 +0,0 @@
-import fs from 'fs';
-import fsp from 'fs/promises';
-import path from 'path';
-import { Database } from 'sqlite3';
-import { Logger } from '../../../common/util/logger.class';
-
-import { MigrationException } from '../lib/migration-exception.class';
-import { MigrationRunner } from '../lib/migration-runner.interface';
-import { SQLiteController } from './sqlite-controller.base';
-
-export class DBMigration extends SQLiteController {
-  constructor(protected db: Database) {
-    super();
-  }
-
-  public async update() {
-    const migrationsDir = path.resolve(__dirname, '../migrations');
-    if (!fs.existsSync(migrationsDir)) return;
-
-    const files = await fsp.readdir(migrationsDir);
-    if (files.length) {
-      files.sort((a, b) => Number(a.substring(0, 12)) - Number(b.substring(0, 12)));
-
-      await this.createMigrationsTable();
-      const lastID = await this.getLastID();
-
-      Logger.debug('[DEBUG] lastid', lastID);
-
-      for (const file of files) {
-        const m = /^(\d{12})_(.*)\.(sql|js)$/.exec(file);
-
-        if (!m) {
-          throw new MigrationException(`File ${file} does not match migration file pattern. Aborted processing migrations.`);
-        }
-
-        const id = Number(m[1]);
-        if (id <= lastID) continue;
-
-        if (m[3] === 'sql') {
-          const migFilepath = path.join(migrationsDir, file);
-          const migration = await fsp.readFile(migFilepath, { encoding: 'utf-8' });
-
-          Logger.info('[INFO] Applying SQL DB migration', file);
-          await this.beginTransaction();
-          try {
-            await this.exec(migration);
-            await this.run('INSERT INTO db_migrations(id, title, migrated) VALUES(?, ?, ?);', [id, m[2], new Date().getTime()]);
-            await this.commit();
-            Logger.info('[INFO] DB migration', file, 'succeeded.');
-          } catch (error) {
-            Logger.error('[ERROR] DB migration failed at', file, '- Rolling back...');
-            await this.rollback();
-
-            throw error;
-          }
-        } else {
-          const migFilepath = path.join(migrationsDir, file.substring(0, file.length - 3));
-          const imp = require(migFilepath).default;
-          if (typeof imp !== 'function') {
-            throw new MigrationException(`File ${file} is not a valid <MigrationRunner> implementation!`);
-          }
-          const mig = imp as MigrationRunner;
-
-          Logger.info('[INFO] Applying TypeScript DB migration', file);
-          await this.beginTransaction();
-          try {
-            await mig(this);
-            await this.run('INSERT INTO db_migrations(id, title, migrated) VALUES(?, ?, ?);', [id, m[2], new Date().getTime()]);
-            await this.commit();
-            Logger.info('[INFO] DB migration', file, 'succeeded.');
-          } catch (error) {
-            Logger.error('[ERROR] DB migration failed at', file, '- Rolling back...');
-            await this.rollback();
-
-            throw error;
-          }
-        }
-      }
-    }
-  }
-
-  private async createMigrationsTable() {
-    await this.run(
-      `CREATE TABLE IF NOT EXISTS db_migrations (
-        id INTEGER PRIMARY KEY,
-        title TEXT NOT NULL,
-        migrated INTEGER NOT NULL
-      );`,
-      []
-    );
-  }
-
-  private async getLastID() {
-    const results = await this.stmt(`SELECT id FROM db_migrations ORDER BY id DESC LIMIT 0, 1;`, []);
-    return Number(results.rows[0]?.['id'] ?? '0');
-  }
-}

+ 0 - 245
server/src/ctrl/mariadb-importer.class.ts

@@ -1,245 +0,0 @@
-import moment from 'moment';
-import { Pool as MariaPool } from 'mysql';
-
-import { Logger } from '../../../common/util/logger.class';
-
-import { SQLiteDatabase as SQLiteDB } from './sqlite-database.class';
-import { MariaDBConnector } from './mariadb-connector.class';
-
-const CHUNK_SIZE = 5000;
-
-export class MariaDBImporter {
-  private oldDb!: SQLiteDB;
-  private newDb!: MariaDBConnector;
-
-  constructor(pool: MariaPool) {
-    this.oldDb = new SQLiteDB();
-    this.newDb = new MariaDBConnector(pool);
-  }
-
-  async connect() {
-    try {
-      await this.oldDb.open();
-      await this.newDb.connect();
-    } catch (e) {
-      Logger.error('[FATAL] Initializing MariaDBImporter failed:', e);
-      Logger.error('[EXITING]');
-      process.exit(1);
-    }
-  }
-
-  async runImport() {
-    // await this.newDb.beginTransaction();
-    try {
-      // await this.cutoffOldData(moment().add(-4, 'months').toDate());
-      await this.truncateTables();
-
-      await this.importServer();
-      await this.importServerConfig();
-      await this.importServerDataEntry();
-      await this.importServerDataValue();
-      await this.importHealthCheckConfig();
-      await this.importHealthCheckParams();
-      await this.importHealthCheckDataEntry();
-
-      // await this.newDb.commit();
-    } catch (e) {
-      Logger.error('[ERROR] Import to MariaDB failed:', e);
-      // await this.newDb.rollback();
-      process.exit(2);
-    }
-  }
-
-  // private async cutoffOldData(cutoffDate: Date) {
-  //   Logger.info('[INFO]', 'Cutting off old DataEntries before', cutoffDate);
-  //   await this.oldDb.run('DELETE FROM `ServerDataEntry` WHERE `Timestamp` < ?;', [cutoffDate.getTime()]);
-  //   await this.oldDb.run('DELETE FROM `HealthCheckDataEntry` WHERE `Timestamp` < ?;', [cutoffDate.getTime()]);
-  // }
-
-  private async truncateTables() {
-    Logger.info('[INFO]', 'Truncating all Tables in MariaDB ...');
-    await this.newDb.query(
-      `
-      SET autocommit = OFF;
-      START TRANSACTION;
-      SET FOREIGN_KEY_CHECKS=0;
-
-      TRUNCATE TABLE \`ServerDataValue\`;
-      TRUNCATE TABLE \`ServerDataEntry\`;
-      TRUNCATE TABLE \`ServerConfig\`;
-      
-      TRUNCATE TABLE \`HealthCheckDataEntry\`;
-      TRUNCATE TABLE \`HealthCheckParams\`;
-      TRUNCATE TABLE \`HealthCheckConfig\`;
-
-      TRUNCATE TABLE \`Server\`;
-
-      COMMIT;
-      SET FOREIGN_KEY_CHECKS=1;
-      SET autocommit = ON;
-    `,
-      []
-    );
-  }
-
-  private async importServer() {
-    Logger.info('[INFO]', 'Importing Server Table ...');
-    const res = await this.oldDb.stmt('SELECT * FROM `Server`;', []);
-    for (const row of res.rows) {
-      await this.newDb.query('INSERT INTO `Server`(`ID`, `Title`, `FQDN`) VALUES (?, ?, ?)', [row['ID'], row['Title'], row['FQDN']]);
-    }
-  }
-
-  private async importServerConfig() {
-    Logger.info('[INFO]', 'Importing ServerConfig Table ...');
-    const res = await this.oldDb.stmt('SELECT * FROM `ServerConfig`;', []);
-    for (const row of res.rows) {
-      await this.newDb.query('INSERT INTO `ServerConfig`(`ID`, `ServerID`, `Key`, `Value`) VALUES (?, ?, ?, ?)', [
-        row['ID'],
-        row['ServerID'],
-        row['Key'],
-        row['Value']
-      ]);
-    }
-  }
-
-  private async importServerDataEntry() {
-    Logger.info('[INFO]', 'Importing ServerDataEntry Table ...');
-    let res = await this.oldDb.stmt('SELECT COUNT(*) as Count FROM `ServerDataEntry`;', []);
-    const count = res.rows[0]['Count'] as number;
-    let offset = 0;
-    let pageSize = Math.min(CHUNK_SIZE, count);
-    let measure: number[] = [];
-    let estimate = '-- Rows/s | EST --:--:--';
-    let prevTime = new Date().getTime();
-    while (offset + pageSize <= count) {
-      Logger.info('[INFO]', `Importing ServerDataEntry (${offset}/${count}) - ${estimate} ...`);
-      res = await this.oldDb.stmt('SELECT * FROM `ServerDataEntry` LIMIT ? OFFSET ?;', [pageSize, offset]);
-
-      if (!res.rows.length) break;
-
-      const sql = 'INSERT INTO `ServerDataEntry`(`ID`, `ServerID`, `Timestamp`) VALUES ' + res.rows.map(() => '(?,?,?)').join(',') + ';';
-      const data = res.rows.reduce((res, row) => [...res, row['ID'], row['ServerID'], new Date(row['Timestamp'])], []);
-
-      await this.newDb.query(sql, data);
-
-      measure.push((pageSize / (new Date().getTime() - prevTime)) * 1000);
-      if (measure.length > 10) measure.shift();
-      prevTime = new Date().getTime();
-
-      if (measure.length > 0) {
-        const rowsPerSec = measure.reduce((res, meas) => (res += meas), 0) / measure.length;
-        const estSecs = (count - offset) / rowsPerSec;
-        estimate = `${Math.round(rowsPerSec * 10) / 10} rows/s | EST ${moment(0).add(estSecs, 'seconds').format('HH:mm:ss')}`;
-      }
-
-      offset += pageSize;
-      pageSize = Math.min(pageSize, count - offset);
-    }
-  }
-
-  private async importServerDataValue() {
-    Logger.info('[INFO]', 'Importing ServerDataValue Table ...');
-    let res = await this.oldDb.stmt('SELECT COUNT(*) as Count FROM `ServerDataValue`;', []);
-    const count = res.rows[0]['Count'] as number;
-    let offset = 0;
-    let pageSize = Math.min(CHUNK_SIZE, count);
-    let measure: number[] = [];
-    let estimate = '-- Rows/s | EST --:--:--';
-    let prevTime = new Date().getTime();
-    while (offset + pageSize <= count) {
-      Logger.info('[INFO]', `Importing ServerDataValue (${offset}/${count}) - ${estimate} ...`);
-      const res = await this.oldDb.stmt('SELECT * FROM `ServerDataValue` LIMIT ? OFFSET ?;', [pageSize, offset]);
-
-      if (!res.rows.length) break;
-
-      const sql = 'INSERT INTO `ServerDataValue`(`ID`, `EntryID`, `Type`, `Key`, `Value`) VALUES' + res.rows.map(() => '(?,?,?,?,?)').join(',') + ';';
-      const data = res.rows.reduce((res, row) => [...res, row['ID'], row['EntryID'], row['Type'], row['Key'], row['Value']], []);
-
-      await this.newDb.query(sql, data);
-
-      measure.push((pageSize / (new Date().getTime() - prevTime)) * 1000);
-      if (measure.length > 10) measure.shift();
-      prevTime = new Date().getTime();
-
-      if (measure.length > 0) {
-        const rowsPerSec = measure.reduce((res, meas) => (res += meas), 0) / measure.length;
-        const estSecs = (count - offset) / rowsPerSec;
-        estimate = `${Math.round(rowsPerSec * 10) / 10} rows/s | EST ${moment(0).add(estSecs, 'seconds').format('HH:mm:ss')}`;
-      }
-
-      offset += pageSize;
-      pageSize = Math.min(pageSize, count - offset);
-    }
-  }
-
-  private async importHealthCheckConfig() {
-    Logger.info('[INFO]', 'Importing HealthCheckConfig Table ...');
-    const res = await this.oldDb.stmt('SELECT * FROM `HealthCheckConfig`;', []);
-    for (const row of res.rows) {
-      await this.newDb.query('INSERT INTO `HealthCheckConfig`(`ID`, `ServerID`, `Type`, `Title`) VALUES(?, ?, ?, ?)', [
-        row['ID'],
-        row['ServerID'],
-        row['Type'],
-        row['Title']
-      ]);
-    }
-  }
-
-  private async importHealthCheckParams() {
-    Logger.info('[INFO]', 'Importing HealthCheckParams Table ...');
-    const res = await this.oldDb.stmt('SELECT * FROM `HealthCheckParams`;', []);
-    for (const row of res.rows) {
-      await this.newDb.query('INSERT INTO `HealthCheckParams`(`ID`, `ConfigID`, `Type`, `Key`, `Value`) VALUES (?, ?, ?, ?, ?)', [
-        row['ID'],
-        row['ConfigID'],
-        row['Type'],
-        row['Key'],
-        row['Value']
-      ]);
-    }
-  }
-
-  private async importHealthCheckDataEntry() {
-    Logger.info('[INFO]', 'Importing HealthCheckDataEntry Table ...');
-    let res = await this.oldDb.stmt('SELECT COUNT(*) as Count FROM `HealthCheckDataEntry`;', []);
-    const count = res.rows[0]['Count'] as number;
-    let offset = 0;
-    let pageSize = Math.min(CHUNK_SIZE, count);
-    let measure: number[] = [];
-    let estimate = '-- Rows/s | EST --:--:--';
-    let prevTime = new Date().getTime();
-    while (offset + pageSize <= count) {
-      Logger.info('[INFO]', `Importing HealthCheckDataEntry (${offset}/${count}) - ${estimate} ...`);
-      const res = await this.oldDb.stmt('SELECT * FROM `HealthCheckDataEntry` LIMIT ? OFFSET ?;', [pageSize, offset]);
-
-      if (!res.rows.length) break;
-
-      const sql =
-        'INSERT INTO `HealthCheckDataEntry`(`ID`, `ConfigID`, `Timestamp`, `Status`, `Message`) VALUES ' +
-        res.rows.map(() => '(?, ?, ?, ?, ?)').join(',') +
-        ';';
-      const data = res.rows.reduce((res, row) => [...res, row['ID'], row['ConfigID'], new Date(row['Timestamp']), row['Status'], row['Message']], []);
-
-      await this.newDb.query(sql, data);
-
-      measure.push((pageSize / (new Date().getTime() - prevTime)) * 1000);
-      if (measure.length > 10) measure.shift();
-      prevTime = new Date().getTime();
-
-      if (measure.length > 0) {
-        const rowsPerSec = measure.reduce((res, meas) => (res += meas), 0) / measure.length;
-        const estSecs = (count - offset) / rowsPerSec;
-        estimate = `${Math.round(rowsPerSec * 10) / 10} rows/s | EST ${moment(0).add(estSecs, 'seconds').format('HH:mm:ss')}`;
-      }
-
-      offset += pageSize;
-      pageSize = Math.min(pageSize, count - offset);
-    }
-  }
-
-  public async close(): Promise<void> {
-    await this.newDb.close();
-    await this.oldDb.close();
-  }
-}

+ 0 - 71
server/src/ctrl/sqlite-controller.base.ts

@@ -1,71 +0,0 @@
-import { Database, RunResult, Statement } from 'sqlite3';
-
-export abstract class SQLiteController {
-  protected db?: Database;
-
-  public run(sql: string, params: any): Promise<RunResult> {
-    return new Promise<RunResult>((res, rej) => {
-      if (!this.db) return rej(new Error('Database not opened.'));
-      this.db.run(sql, params, function (err) {
-        if (err) return rej(err);
-        res(this);
-      });
-    });
-  }
-
-  public stmt(sql: string, params: any[]) {
-    return new Promise<{ result: RunResult; rows: any[] }>(async (res, rej) => {
-      if (!this.db) return rej(new Error('Database not opened.'));
-      try {
-        const stmt = await this.prepare(sql);
-        stmt.all(params, function (err, rows) {
-          if (err) return rej(err);
-          res({ result: this, rows });
-        });
-      } catch (err) {
-        rej(err);
-      }
-    });
-  }
-
-  public prepare(sql: string) {
-    return new Promise<Statement>((res, rej) => {
-      try {
-        if (!this.db) return rej(new Error('Database not opened.'));
-        this.db.prepare(sql, function (err) {
-          if (err) return rej(err);
-          res(this);
-        });
-      } catch (err) {
-        rej(err);
-      }
-    });
-  }
-
-  public exec(script: string) {
-    return new Promise<void>((res, rej) => {
-      if (!this.db) return rej(new Error('Database not opened.'));
-      this.db.exec(script, err => (err ? rej(err) : res()));
-    });
-  }
-
-  public async beginTransaction() {
-    await this.run('BEGIN TRANSACTION;', []);
-  }
-
-  public async commit() {
-    await this.run('COMMIT;', []);
-  }
-
-  public async rollback() {
-    await this.run('ROLLBACK;', []);
-  }
-
-  async close() {
-    await new Promise<void>((res, rej) => {
-      if (!this.db) return res();
-      this.db.close(err => (err ? rej(err) : res()));
-    });
-    this.db = undefined;
-  }
-}

+ 0 - 680
server/src/ctrl/sqlite-database.class.ts

@@ -1,680 +0,0 @@
-import fs from 'fs';
-import fsp from 'fs/promises';
-import moment from 'moment';
-import path from 'path';
-import { Database as SQLiteDB, OPEN_CREATE, OPEN_READWRITE } from 'sqlite3';
-
-import defaults from '../../../common/defaults.module';
-import { ServiceConfig, validateParamType } from '../../../common/interfaces/service-config.interface';
-import { HttpCheckData, HttpCheckStatus, ServiceCheckData, ServiceCheckDataEntry } from '../../../common/lib/http-check-data.module';
-import { Logger } from '../../../common/util/logger.class';
-
-import { ServiceChangedStatus } from '../lib/service-changed-status.enum';
-import { ValidationException } from '../lib/validation-exception.class';
-import { DataProvider } from './data-provider.interface';
-import { DBMigration } from './db-migration.class';
-import { SQLiteController } from './sqlite-controller.base';
-
-export class SQLiteDatabase extends SQLiteController implements DataProvider {
-  public set onError(listener: (error: any) => void) {
-    this._onError = listener;
-  }
-
-  private _onError: (error: any) => void = err => console.error('[DB.ONERROR]', err);
-
-  public async open(migrate = false) {
-    try {
-      const DATA_DIR = process.env.DATA_DIR || 'data';
-
-      if (!fs.existsSync(DATA_DIR)) await fsp.mkdir(DATA_DIR);
-
-      const DATA_FILE = path.resolve(DATA_DIR, 'data.db');
-      const exists = fs.existsSync(DATA_FILE);
-
-      await new Promise<void>((res, rej) => {
-        this.db = new SQLiteDB(DATA_FILE, OPEN_READWRITE | OPEN_CREATE, err => (err ? rej(err) : res()));
-        this.db.on('error', this._onError);
-      });
-      Logger.info('[INFO]', exists ? 'Opened' : 'Created', 'SQLite3 Database file', DATA_FILE);
-
-      if (!this.db) throw new Error('Database not opened.');
-
-      if (!exists) {
-        // INITIAL TABLE SETUP
-        await this.run(
-          `CREATE TABLE Server (
-            ID INTEGER PRIMARY KEY AUTOINCREMENT,
-            Title TEXT NOT NULL UNIQUE,
-            FQDN TEXT NOT NULL UNIQUE
-           );`,
-          []
-        );
-
-        await this.run(
-          `CREATE TABLE ServerConfig (
-            ID INTEGER PRIMARY KEY AUTOINCREMENT,
-            ServerID INTEGER NOT NULL,
-            Key TEXT NOT NULL,
-            Value TEXT NOT NULL,
-            FOREIGN KEY(ServerID) REFERENCES Server(ID),
-            UNIQUE(ServerID, Key)
-          )`,
-          []
-        );
-
-        await this.run(
-          `CREATE TABLE ServerDataEntry (
-            ID INTEGER PRIMARY KEY AUTOINCREMENT,
-            ServerID INTEGER NOT NULL,
-            Timestamp INTEGER NOT NULL,
-            FOREIGN KEY(ServerID) REFERENCES Server(ID),
-            UNIQUE(ServerID, Timestamp)
-           );`,
-          []
-        );
-
-        await this.run(
-          `CREATE TABLE ServerDataValue (
-            ID INTEGER PRIMARY KEY AUTOINCREMENT,
-            EntryID INTEGER NOT NULL,
-            Type Text NOT NULL,
-            Key TEXT NOT NULL,
-            Value REAL NOT NULL,
-            FOREIGN KEY(EntryID) REFERENCES ServerDataEntry(ID),
-            UNIQUE(EntryID, Type, Key)
-          );`,
-          []
-        );
-
-        let result = await this.run(`INSERT INTO Server(Title, FQDN) VALUES(?, ?);`, ['Raspi4', '10.8.0.10']);
-        const serverID = result.lastID;
-        Logger.debug(`[DEBUG] Created Server #${serverID}`);
-        result = await this.run(`INSERT INTO ServerConfig(ServerID, Key, Value) VALUES(?, ?, ?);`, [serverID, 'syncInterval', 300]);
-      }
-
-      if (migrate) {
-        // RUN DB MIGRATIONS
-        const mig = new DBMigration(this.db);
-        await mig.update();
-      }
-
-      // DB RUNTIME SETTINGS
-      await this.exec('PRAGMA foreign_keys=on;');
-    } catch (err) {
-      Logger.error('[FATAL] Initializing Database failed:', err);
-      Logger.error('[EXITING]');
-      process.exit(1);
-    }
-  }
-
-  public async getAllServerConfigs(): Promise<Server[]> {
-    const res = await this.stmt(
-      `SELECT 
-        Server.*,
-        ServerConfig.Key,
-        ServerConfig.Value
-        FROM Server
-        LEFT OUTER JOIN ServerConfig ON Server.ID = ServerConfig.ServerID
-        ORDER BY Server.Title, ServerConfig.Key`,
-      []
-    );
-
-    return res.rows.reduce((res: Server[], line, i) => {
-      const serverID = line['ID'];
-      let server: Server;
-      if (i === 0 || res[res.length - 1].id !== serverID) {
-        server = { id: serverID, title: line['Title'], fqdn: line['FQDN'], config: {} };
-        res.push(server);
-      } else {
-        server = res[res.length - 1];
-      }
-
-      if (!!line['Key']) {
-        server.config[line['Key']] = line['Value'];
-      }
-
-      return res;
-    }, [] as Server[]);
-  }
-
-  public async insertServerData(serverID: number, data: ReducedData[]) {
-    if (!data.length) return;
-
-    await this.beginTransaction();
-    try {
-      for (const entry of data) {
-        const result = await this.run('INSERT INTO ServerDataEntry(ServerID, Timestamp) VALUES(?, ?);', [serverID, entry.time.getTime()]);
-        let entryID = result.lastID;
-
-        for (const type of Object.keys(entry).filter(t => !['time', 'hdd'].includes(t))) {
-          for (const key of Object.keys((entry as any)[type])) {
-            await this.run('INSERT INTO ServerDataValue(EntryID, Type, Key, Value) VALUES(?, ?, ?, ?);', [
-              entryID,
-              type,
-              key,
-              (entry as any)[type][key]
-            ]);
-          }
-        }
-
-        if (entry.hdd) {
-          for (const mount of Object.keys(entry.hdd)) {
-            for (const key of Object.keys(entry.hdd[mount])) {
-              await this.run('INSERT INTO ServerDataValue(EntryID, Type, Key, Value) VALUES(?, ?, ?, ?);', [
-                entryID,
-                `hdd:${mount}`,
-                key,
-                (entry.hdd[mount] as any)[key]
-              ]);
-            }
-          }
-        }
-      }
-      await this.commit();
-    } catch (err) {
-      await this.rollback();
-      throw err;
-    }
-  }
-
-  public async getServerDataTypes(serverID: number) {
-    const results = await this.stmt(
-      `
-      SELECT
-        ServerDataValue.Type 
-      FROM ServerDataEntry
-      JOIN ServerDataValue ON ServerDataEntry.ID = ServerDataValue.EntryID
-      WHERE ServerDataEntry.ServerID = ?
-      GROUP BY ServerDataValue.Type
-      ORDER BY ServerDataValue.Type;
-    `,
-      [serverID]
-    );
-
-    return results.rows.reduce((res: Array<ServerDataTypesConfig>, { Type: type }) => {
-      if (!type.startsWith('hdd:')) {
-        res.push({ type });
-      } else {
-        let hdd = res.find(c => c.type === 'hdd');
-        if (!hdd) {
-          hdd = { type: 'hdd', subtypes: [] };
-          res.push(hdd);
-        }
-        hdd.subtypes?.push({ type: type.substring(4) });
-      }
-      return res;
-    }, []) as Array<ServerDataTypesConfig>;
-  }
-
-  public async queryServerData(serverID: number, type: ServerDataType, from: Date, to: Date): Promise<ServerData[]> {
-    const diffMs = moment(to).diff(moment(from));
-    const sectionMs = Math.floor(diffMs / 100);
-    const select_max = type !== 'cpu';
-    const select_types = select_max ? [type, type, type] : [type, type];
-    const result = await this.stmt(
-      `
-      SELECT 
-        CEIL(Timestamp / ?) * ? as 'Timegroup',
-        AVG(VALUE_AVG.Value) as 'avg',
-        MAX(VALUE_PEAK.Value) as 'peak'${
-          select_max
-            ? `,
-        MAX(VALUE_MAX.Value) as 'max'`
-            : ''
-        }
-      FROM ServerDataEntry
-      JOIN ServerDataValue AS VALUE_AVG ON ServerDataEntry.ID = VALUE_AVG.EntryID AND VALUE_AVG.Type = ? AND VALUE_AVG.Key = 'avg'
-      JOIN ServerDataValue AS VALUE_PEAK ON ServerDataEntry.ID = VALUE_PEAK.EntryID AND VALUE_PEAK.Type = ? AND VALUE_PEAK.Key = 'peak'
-      ${
-        select_max
-          ? "JOIN ServerDataValue AS VALUE_MAX ON ServerDataEntry.ID = VALUE_MAX.EntryID AND VALUE_MAX.Type = ? AND VALUE_MAX.Key = 'max'"
-          : ''
-      }
-      WHERE ServerDataEntry.ServerID = ?
-      AND ServerDataEntry.Timestamp BETWEEN ? AND ?
-      GROUP BY Timegroup
-      ORDER BY Timegroup;
-    `,
-      [sectionMs, sectionMs, ...select_types, serverID, from.getTime(), to.getTime()]
-    );
-
-    return result.rows.map(r => ({ time: new Date(r.Timegroup), avg: r.avg, peak: r.peak, max: r.max }));
-  }
-
-  public async queryServerStats(serverID: number, type: ServerDataType, from: Date, to: Date): Promise<ReducedValuesPerc> {
-    const select_max = type !== 'cpu';
-    const select_types = select_max ? [type, type, type] : [type, type];
-    const result = await this.stmt(
-      `
-      SELECT 
-        AVG(VALUE_AVG.Value) as 'avg',
-        AVG(VALUE_PEAK.Value) as 'peak'${
-          select_max
-            ? `,
-        MAX(VALUE_MAX.Value) as 'max'`
-            : ''
-        }
-      FROM ServerDataEntry
-      JOIN ServerDataValue AS VALUE_AVG ON ServerDataEntry.ID = VALUE_AVG.EntryID AND VALUE_AVG.Type = ? AND VALUE_AVG.Key = 'avg'
-      JOIN ServerDataValue AS VALUE_PEAK ON ServerDataEntry.ID = VALUE_PEAK.EntryID AND VALUE_PEAK.Type = ? AND VALUE_PEAK.Key = 'peak'
-      ${
-        select_max
-          ? "JOIN ServerDataValue AS VALUE_MAX ON ServerDataEntry.ID = VALUE_MAX.EntryID AND VALUE_MAX.Type = ? AND VALUE_MAX.Key = 'max'"
-          : ''
-      }
-      WHERE ServerDataEntry.ServerID = ?
-      AND ServerDataEntry.Timestamp BETWEEN ? AND ?;
-    `,
-      [...select_types, serverID, from.getTime(), to.getTime()]
-    );
-
-    const row = result.rows[0];
-    if (Object.keys(row).includes('max')) {
-      return {
-        avg: ((row['avg'] as number) / (row['max'] as number)) * 100,
-        peak: ((row['peak'] as number) / (row['max'] as number)) * 100
-      };
-    } else {
-      return {
-        avg: row['avg'] as number,
-        peak: row['peak'] as number
-      };
-    }
-  }
-
-  private async getHealthCheckConfigs(serverID?: number, type = 'http') {
-    const res = await this.stmt(
-      `SELECT 
-        HealthCheckConfig.*,
-        HealthCheckParams.Type as '_ParamType',
-        HealthCheckParams.Key as '_ParamKey',
-        HealthCheckParams.Value as '_ParamValue'
-        FROM HealthCheckConfig
-        LEFT OUTER JOIN HealthCheckParams ON HealthCheckConfig.ID = HealthCheckParams.ConfigID
-        WHERE HealthCheckConfig.Type = ?
-        ${!!serverID ? 'AND HealthCheckConfig.ServerID = ?' : ''}
-        ORDER BY HealthCheckConfig.Title, _ParamType, _ParamKey`,
-      [type, serverID]
-    );
-
-    return this.configFromResultRows(res.rows);
-  }
-
-  public async getHttpCheckConfigs(serverID?: number) {
-    return (await this.getHealthCheckConfigs(serverID)).map(this.httpCheckConfigFrom);
-  }
-
-  private async getHealthCheckConfigByID(serverID: number, configID: number) {
-    if (!serverID && !configID) return null;
-
-    const res = await this.stmt(
-      `SELECT 
-        HealthCheckConfig.*,
-        HealthCheckParams.Type as '_ParamType',
-        HealthCheckParams.Key as '_ParamKey',
-        HealthCheckParams.Value as '_ParamValue'
-        FROM HealthCheckConfig
-        LEFT OUTER JOIN HealthCheckParams ON HealthCheckConfig.ID = HealthCheckParams.ConfigID
-        WHERE HealthCheckConfig.ID = ?
-        AND HealthCheckConfig.ServerID = ?
-        ORDER BY HealthCheckConfig.Title, _ParamType, _ParamKey`,
-      [configID, serverID]
-    );
-
-    if (!res.rows.length) return null;
-
-    const configs = this.configFromResultRows(res.rows);
-
-    return configs[0];
-  }
-
-  public async getHttpCheckConfigByID(serverID: number, configID: number) {
-    return this.httpCheckConfigFrom(await this.getHealthCheckConfigByID(serverID, configID));
-  }
-
-  public async saveHttpCheckConfig(serverID: number, conf: HttpCheckConfig) {
-    const validationErrors = this.validateHttpCheckConfig(conf);
-    if (validationErrors) throw new ValidationException('Validation of HttpCheckConfig object failed', validationErrors);
-
-    conf.serverId = serverID;
-    let status = ServiceChangedStatus.None;
-
-    const oldConf = await this.getHttpCheckConfigByID(serverID, conf.id);
-    await this.beginTransaction();
-    try {
-      if (oldConf) {
-        // UPDATE
-        Logger.debug('[DEBUG] Updating HealthCheckConfig', conf.title, `(${oldConf.id})`);
-        if (oldConf.title !== conf.title) {
-          await this.stmt('UPDATE HealthCheckConfig SET Title = ? WHERE ID = ?', [conf.title, oldConf.id]);
-        }
-
-        let updValues: any[][] = [];
-        if (oldConf.url !== conf.url) updValues.push([conf.url, conf.id, 'url']);
-        if (oldConf.interval !== conf.interval) {
-          updValues.push([conf.interval, conf.id, 'interval']);
-          status = ServiceChangedStatus.Rescheduled;
-        }
-        if (oldConf.timeout !== conf.timeout) updValues.push([conf.timeout ?? defaults.serviceChecks.httpTimeout, conf.id, 'timeout']);
-        if (oldConf.active !== conf.active) {
-          updValues.push([conf.active ?? defaults.serviceChecks.active ? 1 : 0, conf.id, 'active']);
-          status = conf.active ?? defaults.serviceChecks.active ? ServiceChangedStatus.Activated : ServiceChangedStatus.Deactivated;
-        }
-        if (oldConf.notify !== conf.notify) updValues.push([conf.notify ?? defaults.serviceChecks.notify ? 1 : 0, conf.id, 'notify']);
-        if (oldConf.notifyThreshold !== conf.notifyThreshold)
-          updValues.push([conf.notifyThreshold ?? defaults.serviceChecks.notifyThreshold, conf.id, 'notifyThreshold']);
-        if (updValues.length) {
-          for (const data of updValues) {
-            await this.run(`UPDATE HealthCheckParams SET Value = ? WHERE ConfigID = ? AND Key = ?;`, data);
-          }
-        }
-
-        const res = await this.stmt('SELECT * FROM HealthCheckParams WHERE ConfigID = ? and Key = "check";', [conf.id]);
-        updValues = [];
-        const delIDs: number[] = [];
-        res.rows.forEach((row, i) => {
-          if (i < conf.checks.length) {
-            updValues.push([JSON.stringify(conf.checks[i]), row['ID']]);
-          } else {
-            delIDs.push(row['ID']);
-          }
-        });
-
-        if (delIDs.length) {
-          const delSql = `DELETE FROM HealthCheckParams WHERE ID IN (${delIDs.map(() => '?').join(',')});`;
-          await this.run(delSql, delIDs);
-        }
-
-        if (updValues.length) {
-          for (const data of updValues) {
-            await this.run('UPDATE HealthCheckParams SET Value = ? WHERE ID = ?;', data);
-          }
-        }
-        const insValues = conf.checks.filter((c, i) => i > res.rows.length - 1).map(c => [conf.id, 'regexp', 'check', JSON.stringify(c)]);
-        if (insValues.length) {
-          for (const data of insValues) {
-            await this.run('INSERT INTO HealthCheckParams(ConfigID, Type, Key, Value) VALUES(?, ?, ?, ?);', data);
-          }
-        }
-      } else {
-        // INSERT
-        Logger.debug('[DEBUG] Inserting new HealthCheckConfig', conf.title);
-        const res = await this.run('INSERT INTO HealthCheckConfig(ServerID, Type, Title) VALUES(?, ?, ?);', [serverID, 'http', conf.title]);
-        conf.id = res.lastID;
-        if (conf.active ?? defaults.serviceChecks.active) {
-          status = ServiceChangedStatus.Created;
-        }
-
-        const insCheckValues = conf.checks.map(c => [res.lastID, 'regexp', 'check', c]);
-        await this.run(
-          `INSERT INTO HealthCheckParams(ConfigID, Type, Key, Value) VALUES
-          (?, ?, ?, ?),
-          (?, ?, ?, ?),
-          (?, ?, ?, ?),
-          (?, ?, ?, ?),
-          (?, ?, ?, ?),
-          (?, ?, ?, ?)${conf.checks.length ? `,${insCheckValues.map(() => '(?, ?, ?, ?)').join(',')}` : ''}`,
-          [
-            ...[res.lastID, 'text', 'url', conf.url],
-            ...[res.lastID, 'boolean', 'active', conf.active ?? defaults.serviceChecks.active ? 1 : 0],
-            ...[res.lastID, 'number', 'interval', conf.interval],
-            ...[res.lastID, 'number', 'timeout', conf.timeout ?? defaults.serviceChecks.httpTimeout],
-            ...[res.lastID, 'boolean', 'notify', conf.notify ?? defaults.serviceChecks.notify],
-            ...[res.lastID, 'number', 'notifyThreshold', conf.notifyThreshold ?? defaults.serviceChecks.notifyThreshold],
-            ...conf.checks.reduce((ret, check) => [...ret, res.lastID, 'regexp', 'check', JSON.stringify(check)], [] as any[])
-          ]
-        );
-      }
-
-      await this.commit();
-      return { status, result: conf };
-    } catch (err) {
-      await this.rollback();
-      throw err;
-    }
-  }
-
-  async deleteHealthCheckConfig(serverID: number, confID: number) {
-    const conf = await this.getHealthCheckConfigByID(serverID, confID);
-    if (!conf) return false;
-
-    await this.run('DELETE FROM HealthCheckConfig WHERE ID = ?;', [confID]);
-    return true;
-  }
-
-  async insertHealthCheckData(confID: number, time: Date, status: HttpCheckStatus, message: string) {
-    const res = await this.run('INSERT INTO HealthCheckDataEntry(ConfigID, Timestamp, Status, Message) VALUES(?, ?, ?, ?);', [
-      confID,
-      time.getTime(),
-      status,
-      message
-    ]);
-
-    return {
-      id: res.lastID,
-      configId: confID,
-      time,
-      status,
-      message
-    } as HttpCheckData;
-  }
-
-  async queryServiceCheckData(serverID: number, confID: number, from: Date, to: Date) {
-    const result = await this.stmt(
-      `
-      SELECT DataEntryChanges.*
-      FROM HealthCheckConfig
-      JOIN (
-        SELECT * FROM (
-          SELECT 
-            *
-          FROM HealthCheckDataEntry
-          WHERE ConfigID = ?
-          AND Timestamp BETWEEN ? AND ?
-          ORDER BY ID
-          LIMIT 0, 1
-        ) AS FIRST_STATE
-
-        UNION --+--+--
-
-        SELECT 
-          ID,
-          ConfigID,
-          Timestamp,
-          Status,
-          Message
-        FROM
-        (
-          SELECT 
-            HealthCheckDataEntry.*, 
-            LAG(Status) OVER (ORDER BY ConfigID, Timestamp) AS previous_state, 
-            LAG(Message) OVER (ORDER BY ConfigID, Timestamp) AS previous_msg
-          FROM HealthCheckDataEntry
-          WHERE ConfigID = ?
-        )
-        WHERE Status <> previous_state
-        AND Message <> previous_msg
-        
-        UNION --+--+--
-        
-        SELECT * FROM (
-          SELECT 
-            *
-          FROM HealthCheckDataEntry
-          WHERE ConfigID = ?
-          AND Timestamp BETWEEN ? AND ?
-          ORDER BY ID DESC
-          LIMIT 0, 1
-        ) AS LAST_STATE
-        ORDER BY ConfigID, Timestamp
-      ) AS DataEntryChanges ON DataEntryChanges.ConfigID = HealthCheckConfig.ID
-      WHERE HealthCheckConfig.ServerID = ?
-        AND DataEntryChanges.Timestamp BETWEEN ? AND ?
-      ORDER BY Timestamp, ID;`,
-      [confID, from.getTime(), to.getTime(), confID, confID, from.getTime(), to.getTime(), serverID, from.getTime(), to.getTime()]
-    );
-
-    const mapByTimestamp = this.mapServiceCheckDataByTimestamp(result.rows);
-
-    const arr: ServiceCheckData[] = [];
-    for (const entry of mapByTimestamp.entries()) {
-      arr.push({
-        time: new Date(entry[0]),
-        data: entry[1]
-      });
-    }
-    return arr;
-  }
-
-  public async queryServiceCheckLogs(serverID: number, confID: number, from: Date, to: Date) {
-    const result = await this.stmt(
-      `
-      SELECT HealthCheckDataEntry.*
-      FROM HealthCheckConfig
-      JOIN HealthCheckDataEntry ON HealthCheckDataEntry.ConfigID = HealthCheckConfig.ID
-      WHERE HealthCheckConfig.ID = ?
-        AND HealthCheckConfig.ServerID = ?
-        AND HealthCheckDataEntry.Timestamp BETWEEN ? AND ?
-      ORDER BY Timestamp, ConfigID;`,
-      [confID, serverID, from.getTime(), to.getTime()]
-    );
-
-    const mapByTimestamp = this.mapServiceCheckDataByTimestamp(result.rows);
-
-    const arr: ServiceCheckData[] = [];
-    for (const entry of mapByTimestamp.entries()) {
-      arr.push({
-        time: new Date(entry[0]),
-        data: entry[1]
-      });
-    }
-    return arr;
-  }
-
-  public async getLastErrors(confID: number, threshold: number) {
-    const result = await this.stmt(
-      `SELECT * FROM HealthCheckDataEntry
-        WHERE ConfigID = ?
-        AND Timestamp IN (
-          SELECT Timestamp 
-          FROM HealthCheckDataEntry
-          WHERE ConfigID = ?
-          GROUP BY Timestamp
-          ORDER BY Timestamp DESC
-          LIMIT 0, ?
-        )
-        ORDER BY Timestamp DESC, ID DESC`,
-      [confID, confID, threshold]
-    );
-
-    const mapByTimestamp = this.mapServiceCheckDataByTimestamp(result.rows);
-    const errors: ServiceCheckData[] = [];
-    for (const entry of mapByTimestamp.entries()) {
-      const time = entry[0];
-      const data = entry[1];
-
-      const errorData = data.filter(d => d.status !== HttpCheckStatus.OK);
-      if (!errorData.length) break;
-
-      errors.push({
-        time: new Date(time),
-        data: errorData
-      });
-    }
-
-    return errors;
-  }
-
-  private mapServiceCheckDataByTimestamp(rows: any[]) {
-    return rows.reduce((res: Map<number, ServiceCheckDataEntry[]>, row) => {
-      const time: number = row['Timestamp'];
-      if (!res.has(time)) res.set(time, []);
-      res.get(time)?.push({
-        status: row['Status'] as number,
-        message: row['Message']
-      });
-      return res;
-    }, new Map()) as Map<number, ServiceCheckDataEntry[]>;
-  }
-
-  private configFromResultRows(rows: any[]) {
-    return rows.reduce((res: ServiceConfig[], line, i) => {
-      const configID = line['ID'];
-      let config: ServiceConfig;
-      if (i === 0 || res[res.length - 1].id !== configID) {
-        config = {
-          id: configID,
-          title: line['Title'],
-          type: line['Type'],
-          serverId: line['ServerID'],
-          params: []
-        };
-        res.push(config);
-      } else {
-        config = res[res.length - 1];
-      }
-
-      if (!!line['_ParamKey']) {
-        const type = validateParamType(line['_ParamType']);
-        const key = line['_ParamKey'];
-        if (key === 'check') {
-          let checkParam = config.params.find(c => c.key === 'check');
-          if (!checkParam) {
-            config.params.push(
-              (checkParam = {
-                key: 'check',
-                type: 'regexp',
-                value: []
-              })
-            );
-          }
-          (checkParam.value as string[]).push(line['_ParamValue']);
-        } else {
-          config.params.push({
-            type,
-            key,
-            value: type === 'number' ? Number(line['_ParamValue']) : type === 'boolean' ? Boolean(Number(line['_ParamValue'])) : line['_ParamValue']
-          });
-        }
-      }
-
-      return res;
-    }, [] as ServiceConfig[]);
-  }
-
-  private httpCheckConfigFrom(hcConf: ServiceConfig | null): HttpCheckConfig | null {
-    if (!hcConf) return null;
-    const params = {
-      url: hcConf.params?.find(p => p.key === 'url')?.value as string,
-      active: (hcConf.params?.find(p => p.key === 'active')?.value as boolean) ?? defaults.serviceChecks.active,
-      interval: hcConf.params?.find(p => p.key === 'interval')?.value as number,
-      timeout: (hcConf.params?.find(p => p.key === 'timeout')?.value as number) ?? defaults.serviceChecks.httpTimeout,
-      notify: (hcConf.params?.find(p => p.key === 'notify')?.value as boolean) ?? defaults.serviceChecks.notify,
-      notifyThreshold: (hcConf.params?.find(p => p.key === 'notifyThreshold')?.value as number) ?? defaults.serviceChecks.notifyThreshold,
-      checks: hcConf.params?.reduce(
-        (res, p) => (p.key === 'check' && Array.isArray(p.value) ? [...res, ...p.value.map(c => JSON.parse(c))] : res),
-        [] as string[]
-      )
-    };
-    return {
-      id: hcConf.id,
-      title: hcConf.title,
-      type: hcConf.type,
-      serverId: hcConf.serverId,
-      ...params
-    };
-  }
-
-  private validateHttpCheckConfig(conf: Partial<HttpCheckConfig>): { [key: string]: string } | null {
-    const errors = {} as any;
-    if (!conf) return { null: 'Object was null or undefined' };
-    if (!conf.title?.trim().length) errors['required|title'] = `Field 'title' is required.`;
-    if (!conf.url?.trim().length) errors['required|url'] = `Field 'url' is required.`;
-    if ((!conf.interval && conf.interval !== 0) || Number.isNaN(Number(conf.interval))) errors['required|interval'] = `Field 'interval' is required.`;
-
-    if (!conf.checks || !Array.isArray(conf.checks))
-      errors['required|checks'] = `Field 'checks' is required and must be an array of check expressions.`;
-
-    return Object.keys(errors).length ? errors : null;
-  }
-}

+ 0 - 20
server/src/index.ts

@@ -1,7 +1,3 @@
-import fs from 'fs';
-import fsp from 'fs/promises';
-import path from 'path';
-import moment from 'moment';
 import { Pool } from 'mysql';
 
 import { Logger, LogLevel } from '../../common/util/logger.class';
@@ -9,7 +5,6 @@ import { Logger, LogLevel } from '../../common/util/logger.class';
 import { ControllerPool } from './ctrl/controller-pool.interface';
 import { HttpCheckController } from './ctrl/http-check-controller.class';
 import { MariaDBDatabase } from './ctrl/mariadb-database.class';
-import { MariaDBImporter } from './ctrl/mariadb-importer.class';
 import { MariaDBPoolFactory } from './ctrl/mariadb-poolfactory.class';
 import { ServerConnector } from './ctrl/server-connector.class';
 import { Webserver } from './webserver.class';
@@ -24,19 +19,9 @@ process.on('SIGTERM', exitGracefully);
 
 let pool: ControllerPool;
 let db: MariaDBDatabase;
-let mig: MariaDBImporter;
 let connectionPool: Pool;
 (async () => {
   connectionPool = await MariaDBPoolFactory.createConnectionPool();
-  const sqliteDir = path.resolve(process.cwd(), process.env.DATA_DIR || 'data');
-  const doneFile = path.resolve(sqliteDir, 'import_done.txt');
-
-  if (fs.existsSync(sqliteDir) && !fs.existsSync(doneFile)) {
-    mig = new MariaDBImporter(connectionPool);
-    await mig.connect();
-    await mig.runImport();
-    await fsp.writeFile(doneFile, moment().format('YYYY-MM-DD[T]HH:mm:ss.SSSZZ'), { encoding: 'utf-8' });
-  }
 
   db = new MariaDBDatabase(connectionPool);
   await db.open();
@@ -54,11 +39,6 @@ let connectionPool: Pool;
 async function exitGracefully(...args: any[]) {
   Logger.info(`[EXITING] Graceful exit, received ${JSON.stringify(args)}`);
   try {
-    if (mig) {
-      Logger.info(`[EXITING] Tear down MariaDBImporter instance ...`);
-      await mig.close();
-    }
-
     Logger.info(`[EXITING] Tear down Main Database Controller ...`);
     if (db) await db.close();
 

+ 0 - 3
server/src/lib/migration-runner.interface.ts

@@ -1,3 +0,0 @@
-import { SQLiteController } from '../ctrl/sqlite-controller.base';
-
-export type MigrationRunner = (db: SQLiteController) => Promise<void>;

+ 0 - 28
server/src/migrations/202210032328_website_healthcheck.sql

@@ -1,28 +0,0 @@
-CREATE TABLE HealthCheckConfig(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ServerID INTEGER NOT NULL,
-  Type TEXT NOT NULL,
-  Title TEXT NOT NULL,
-  FOREIGN KEY(ServerID) REFERENCES Server(ID),
-  UNIQUE(ServerID, Type, Title)
-);
-
-CREATE TABLE HealthCheckParams(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ConfigID INTEGER NOT NULL,
-  Type TEXT NOT NULL,
-  Key TEXT NOT NULL,
-  Value TEXT NOT NULL,
-  FOREIGN KEY(ConfigID) REFERENCES HealthCheckConfig(ID),
-  UNIQUE(ConfigID, Type, Key)
-);
-
-CREATE TABLE HealthCheckDataEntry(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ConfigID INTEGER NOT NULL,
-  Timestamp INTEGER NOT NULL,
-  Status INTEGER NOT NULL,
-  Message TEXT,
-  FOREIGN KEY(ConfigID) REFERENCES HealthCheckConfig(ID),
-  UNIQUE(ConfigID, Timestamp)
-);

+ 0 - 11
server/src/migrations/202211072338_website_healthcheck_fix1.sql

@@ -1,11 +0,0 @@
-ALTER TABLE HealthCheckParams RENAME TO HealthCheckParams_OLD;
-CREATE TABLE HealthCheckParams(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ConfigID INTEGER NOT NULL,
-  Type TEXT NOT NULL,
-  Key TEXT NOT NULL,
-  Value TEXT NOT NULL,
-  FOREIGN KEY(ConfigID) REFERENCES HealthCheckConfig(ID)
-);
-INSERT INTO HealthCheckParams SELECT * FROM HealthCheckParams_OLD;
-DROP TABLE HealthCheckParams_OLD;

+ 0 - 92
server/src/migrations/202211190031_cascade_delete.sql

@@ -1,92 +0,0 @@
-ALTER TABLE HealthCheckConfig RENAME TO HealthCheckConfig_OLD;
-
-CREATE TABLE HealthCheckConfig(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ServerID INTEGER NOT NULL,
-  Type TEXT NOT NULL,
-  Title TEXT NOT NULL,
-  CONSTRAINT FK_HealthCheckConfig_Server
-    FOREIGN KEY(ServerID)
-    REFERENCES Server(ID)
-    ON DELETE CASCADE,
-  UNIQUE(ServerID, Type, Title)
-);
-
-INSERT INTO HealthCheckConfig SELECT * FROM HealthCheckConfig_OLD;
-DROP TABLE HealthCheckConfig_OLD;
-
-ALTER TABLE HealthCheckParams RENAME TO HealthCheckParams_OLD;
-CREATE TABLE HealthCheckParams(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ConfigID INTEGER NOT NULL,
-  Type TEXT NOT NULL,
-  Key TEXT NOT NULL,
-  Value TEXT NOT NULL,
-  CONSTRAINT FK_HealthCheckParams_HealthCheckConfig 
-    FOREIGN KEY(ConfigID) 
-    REFERENCES HealthCheckConfig(ID)
-    ON DELETE CASCADE
-);
-INSERT INTO HealthCheckParams SELECT * FROM HealthCheckParams_OLD;
-DROP TABLE HealthCheckParams_OLD;
-
-ALTER TABLE HealthCheckDataEntry RENAME TO HealthCheckDataEntry_OLD;
-CREATE TABLE HealthCheckDataEntry(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ConfigID INTEGER NOT NULL,
-  Timestamp INTEGER NOT NULL,
-  Status INTEGER NOT NULL,
-  Message TEXT,
-  CONSTRAINT FK_HealthCheckDataEntry_HealthCheckConfig
-    FOREIGN KEY(ConfigID) 
-    REFERENCES HealthCheckConfig(ID)
-    ON DELETE CASCADE,
-  UNIQUE(ConfigID, Timestamp)
-);
-INSERT INTO HealthCheckDataEntry SELECT * FROM HealthCheckDataEntry_OLD;
-DROP TABLE HealthCheckDataEntry_OLD;
-
-ALTER TABLE ServerConfig RENAME TO ServerConfig_OLD;
-CREATE TABLE ServerConfig (
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ServerID INTEGER NOT NULL,
-  Key TEXT NOT NULL,
-  Value TEXT NOT NULL,
-  CONSTRAINT FK_ServerConfig_Server
-    FOREIGN KEY(ServerID) 
-    REFERENCES Server(ID)
-    ON DELETE CASCADE,
-  UNIQUE(ServerID, Key)
-);
-INSERT INTO ServerConfig SELECT * FROM ServerConfig_OLD;
-DROP TABLE ServerConfig_OLD;
-
-ALTER TABLE ServerDataEntry RENAME TO ServerDataEntry_OLD;
-CREATE TABLE ServerDataEntry (
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ServerID INTEGER NOT NULL,
-  Timestamp INTEGER NOT NULL,
-  CONSTRAINT FK_ServerDataEntry_Server
-    FOREIGN KEY(ServerID)
-    REFERENCES Server(ID)
-    ON DELETE CASCADE,
-  UNIQUE(ServerID, Timestamp)
-);
-INSERT INTO ServerDataEntry SELECT * FROM ServerDataEntry_OLD;
-DROP TABLE ServerDataEntry_OLD;
-
-ALTER TABLE ServerDataValue RENAME TO ServerDataValue_OLD;
-CREATE TABLE ServerDataValue (
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  EntryID INTEGER NOT NULL,
-  Type Text NOT NULL,
-  Key TEXT NOT NULL,
-  Value REAL NOT NULL,
-  CONSTRAINT FK_ServerDataValue_ServerDataEntry
-    FOREIGN KEY(EntryID)
-    REFERENCES ServerDataEntry(ID)
-    ON DELETE CASCADE,
-  UNIQUE(EntryID, Type, Key)
-);
-INSERT INTO ServerDataValue SELECT * FROM ServerDataValue_OLD;
-DROP TABLE ServerDataValue_OLD;

+ 0 - 7
server/src/migrations/202212301910_website_healthcheck_notification_defaults.sql

@@ -1,7 +0,0 @@
-INSERT INTO HealthCheckParams(ConfigID, Type, Key, Value)
-  SELECT ID, 'boolean', 'notify', '0'
-  FROM HealthCheckConfig;
-
-INSERT INTO HealthCheckParams(ConfigID, Type, Key, Value)
-  SELECT ID, 'number', 'notifyThreshold', '3'
-  FROM HealthCheckConfig;

+ 0 - 30
server/src/migrations/202301302212_website_healtcheck_disjunctive_checks.ts

@@ -1,30 +0,0 @@
-import { SQLiteController } from '../ctrl/sqlite-controller.base';
-
-export default async function (db: SQLiteController) {
-  const result = await db.stmt("SELECT * FROM `HealthCheckParams` WHERE `Type` = 'regexp' AND `Key` = 'check'", []);
-  const idsToDelete: number[] = [];
-  const checksByConfId = result.rows.reduce((res, row) => {
-    idsToDelete.push(row['ID']);
-    const confId = row['ConfigID'];
-    if (!res[confId]) {
-      res[confId] = [];
-    }
-    res[confId].push(row['Value']);
-    return res;
-  }, {}) as { [confID: number]: string[] };
-
-  for (const entry of Object.entries(checksByConfId)) {
-    const confId = entry[0] as unknown as number;
-    const checks = entry[1];
-
-    const conjunction = { and: checks };
-
-    await db.stmt('INSERT INTO `HealthCheckParams`(`ConfigID`, `Type`, `Key`, `Value`) VALUES(?, ?, ?, ?)', [
-      confId,
-      'regexp',
-      'check',
-      JSON.stringify(conjunction)
-    ]);
-  }
-  await db.run(`DELETE FROM HealthCheckParams WHERE ID IN (${idsToDelete.map(() => '?').join(',')});`, idsToDelete);
-}

+ 0 - 15
server/src/migrations/202302131250_website_healthcheck_fix2.sql

@@ -1,15 +0,0 @@
-ALTER TABLE HealthCheckDataEntry RENAME TO HealthCheckDataEntry_OLD;
-CREATE TABLE HealthCheckDataEntry(
-  ID INTEGER PRIMARY KEY AUTOINCREMENT,
-  ConfigID INTEGER NOT NULL,
-  Timestamp INTEGER NOT NULL,
-  Status INTEGER NOT NULL,
-  Message TEXT,
-  CONSTRAINT FK_HealthCheckDataEntry_HealthCheckConfig
-    FOREIGN KEY(ConfigID) 
-    REFERENCES HealthCheckConfig(ID)
-    ON DELETE CASCADE
-    /* REMOVED: UNIQUE(ConfigID, Timestamp) */
-);
-INSERT INTO HealthCheckDataEntry SELECT * FROM HealthCheckDataEntry_OLD;
-DROP TABLE HealthCheckDataEntry_OLD;

+ 0 - 16
server/tsconfig.mig.json

@@ -1,16 +0,0 @@
-{
-  "compilerOptions": {
-    "strict": true,
-    "outDir": "./dist/server/src",
-    "esModuleInterop": true,
-    "moduleResolution": "node",
-    "module": "commonjs",
-    "target": "ES2016",
-    "sourceMap": false,
-    "baseUrl": "./src/migrations",
-    "paths": {
-      "*": ["node_modules/*", "src/*", "../common/*"]
-    }
-  },
-  "include": ["./src/migrations/*"]
-}