diff --git a/api/src/core/utils/misc/parse-config.ts b/api/src/core/utils/misc/parse-config.ts index a0b70fbb2..3a5f82f1e 100644 --- a/api/src/core/utils/misc/parse-config.ts +++ b/api/src/core/utils/misc/parse-config.ts @@ -75,6 +75,7 @@ export const fileExists = async (path: string) => access(path, F_OK) .then(() => true) .catch(() => false); + export const fileExistsSync = (path: string) => { try { accessSync(path, F_OK); diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/log-rotate.modification.ts b/api/src/unraid-api/unraid-file-modifier/modifications/log-rotate.modification.ts new file mode 100644 index 000000000..1d43396fb --- /dev/null +++ b/api/src/unraid-api/unraid-file-modifier/modifications/log-rotate.modification.ts @@ -0,0 +1,50 @@ +import { Logger } from '@nestjs/common'; +import { rm, writeFile } from 'node:fs/promises'; + +import { execa } from 'execa'; + +import { fileExists } from '@app/core/utils/misc/parse-config'; +import { + FileModification, + ShouldApplyWithReason, +} from '@app/unraid-api/unraid-file-modifier/unraid-file-modifier.service'; + +export class LogRotateModification implements FileModification { + id: string = 'log-rotate'; + filePath: string = '/etc/logrotate.d/unraid-api' as const; + logger: Logger; + logRotateConfig: string = ` +/var/log/unraid-api/*.log { + rotate 1 + missingok + size 1M + su root root + compress + delaycompress + copytruncate + create 0640 root root +} + `; + + constructor(logger: Logger) { + this.logger = logger; + } + + async apply(): Promise { + await writeFile(this.filePath, this.logRotateConfig, { mode: '644' }); + // Ensure file is owned by root:root + await execa('chown', ['root:root', this.filePath]).catch((err) => this.logger.error(err)); + } + + async rollback(): Promise { + await rm(this.filePath); + } + + async shouldApply(): Promise { + const alreadyConfigured = await fileExists(this.filePath); + if (alreadyConfigured) { + return { shouldApply: false, reason: 'LogRotate configuration already exists' }; + } + return { shouldApply: true, reason: 'No LogRotate config for the API configured yet' }; + } +} diff --git a/api/src/unraid-api/unraid-file-modifier/unraid-file-modifier.service.ts b/api/src/unraid-api/unraid-file-modifier/unraid-file-modifier.service.ts index 232c108c7..0c449e37e 100644 --- a/api/src/unraid-api/unraid-file-modifier/unraid-file-modifier.service.ts +++ b/api/src/unraid-api/unraid-file-modifier/unraid-file-modifier.service.ts @@ -2,6 +2,7 @@ import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/commo import AuthRequestModification from '@app/unraid-api/unraid-file-modifier/modifications/auth-request.modification'; import SSOFileModification from '@app/unraid-api/unraid-file-modifier/modifications/sso.modification'; +import { LogRotateModification } from '@app/unraid-api/unraid-file-modifier/modifications/log-rotate.modification'; export interface ShouldApplyWithReason { shouldApply: boolean; @@ -42,6 +43,7 @@ export class UnraidFileModificationService implements OnModuleInit, OnModuleDest async loadModifications(): Promise { const modifications: FileModification[] = []; const modificationClasses: Array FileModification> = [ + LogRotateModification, AuthRequestModification, SSOFileModification, ];