From 29dcb7d0f088937cefc5158055f48680e86e5c36 Mon Sep 17 00:00:00 2001 From: Pujit Mehrotra Date: Tue, 15 Jul 2025 09:48:12 -0400 Subject: [PATCH] fix: rm short-circuit in `rc.unraid-api` if plugin config dir is absent (#1515) This short-circuit causes any/all `rc.unraid-api` invocations to immediately fail on fresh 7.2 images (because `/boot/config/dynamix.my.servers` doesn't exist). ## Summary by CodeRabbit * **Refactor** * Removed initial checks and setup for a plugin directory and default environment file in the startup script. * Simplified environment switching with streamlined commands and improved error handling. * Removed deprecated environment path references and updated related tests. * **Documentation** * Added descriptive comments clarifying build and environment settings. * **Tests** * Updated test cases by removing assertions related to deprecated environment paths. * **Maintenance** * Updated timestamp fixtures for consistency. --- .../modules/__snapshots__/paths.test.ts.snap | 1 - api/src/__test__/store/modules/paths.test.ts | 1 - api/src/environment.ts | 2 + api/src/store/modules/paths.ts | 1 - api/src/unraid-api/cli/switch-env.command.ts | 79 ++++++++----------- .../downloaded/.login.php.last-download-time | 2 +- .../DefaultPageLayout.php.last-download-time | 2 +- .../Notifications.page.last-download-time | 2 +- .../auth-request.php.last-download-time | 2 +- .../downloaded/rc.nginx.last-download-time | 2 +- .../dynamix.unraid.net/etc/rc.d/rc.unraid-api | 3 - 11 files changed, 38 insertions(+), 59 deletions(-) diff --git a/api/src/__test__/store/modules/__snapshots__/paths.test.ts.snap b/api/src/__test__/store/modules/__snapshots__/paths.test.ts.snap index e34dd1e54..2bd80788c 100644 --- a/api/src/__test__/store/modules/__snapshots__/paths.test.ts.snap +++ b/api/src/__test__/store/modules/__snapshots__/paths.test.ts.snap @@ -17,7 +17,6 @@ exports[`Returns paths 1`] = ` "myservers-base", "myservers-config", "myservers-config-states", - "myservers-env", "myservers-keepalive", "keyfile-base", "machine-id", diff --git a/api/src/__test__/store/modules/paths.test.ts b/api/src/__test__/store/modules/paths.test.ts index 78b7b788c..0fae0dabc 100644 --- a/api/src/__test__/store/modules/paths.test.ts +++ b/api/src/__test__/store/modules/paths.test.ts @@ -24,7 +24,6 @@ test('Returns paths', async () => { 'myservers-base': '/boot/config/plugins/dynamix.my.servers/', 'myservers-config': expect.stringContaining('api/dev/Unraid.net/myservers.cfg'), 'myservers-config-states': expect.stringContaining('api/dev/states/myservers.cfg'), - 'myservers-env': '/boot/config/plugins/dynamix.my.servers/env', 'myservers-keepalive': './dev/Unraid.net/fb_keepalive', 'keyfile-base': expect.stringContaining('api/dev/Unraid.net'), 'machine-id': expect.stringContaining('api/dev/data/machine-id'), diff --git a/api/src/environment.ts b/api/src/environment.ts index f418bd8a6..13bdc8495 100644 --- a/api/src/environment.ts +++ b/api/src/environment.ts @@ -67,6 +67,7 @@ export const getPackageJsonDependencies = (): string[] | undefined => { export const API_VERSION = process.env.npm_package_version ?? getPackageJson().version; +/** Controls how the app is built/run (i.e. in terms of optimization) */ export const NODE_ENV = (process.env.NODE_ENV as 'development' | 'test' | 'staging' | 'production') ?? 'production'; export const environment = { @@ -76,6 +77,7 @@ export const CHOKIDAR_USEPOLLING = process.env.CHOKIDAR_USEPOLLING === 'true'; export const IS_DOCKER = process.env.IS_DOCKER === 'true'; export const DEBUG = process.env.DEBUG === 'true'; export const INTROSPECTION = process.env.INTROSPECTION === 'true'; +/** Determines the app-level & business logic environment (i.e. what data & infrastructure is used) */ export const ENVIRONMENT = process.env.ENVIRONMENT ? (process.env.ENVIRONMENT as 'production' | 'staging' | 'development') : 'production'; diff --git a/api/src/store/modules/paths.ts b/api/src/store/modules/paths.ts index 3a70d38e7..e42e4d83a 100644 --- a/api/src/store/modules/paths.ts +++ b/api/src/store/modules/paths.ts @@ -49,7 +49,6 @@ const initialState = { resolvePath(process.env.PATHS_STATES ?? ('/usr/local/emhttp/state/' as const)), 'myservers.cfg' as const ), - 'myservers-env': '/boot/config/plugins/dynamix.my.servers/env' as const, 'myservers-keepalive': process.env.PATHS_MY_SERVERS_FB ?? ('/boot/config/plugins/dynamix.my.servers/fb_keepalive' as const), diff --git a/api/src/unraid-api/cli/switch-env.command.ts b/api/src/unraid-api/cli/switch-env.command.ts index 7c4a7b0ea..18c53b51c 100644 --- a/api/src/unraid-api/cli/switch-env.command.ts +++ b/api/src/unraid-api/cli/switch-env.command.ts @@ -1,13 +1,13 @@ -import { copyFile, readFile, writeFile } from 'fs/promises'; +import { copyFile } from 'fs/promises'; import { join } from 'path'; import { Command, CommandRunner, Option } from 'nest-commander'; -import { cliLogger } from '@app/core/log.js'; +import { fileExistsSync } from '@app/core/utils/files/file-exists.js'; +import { ENVIRONMENT } from '@app/environment.js'; import { getters } from '@app/store/index.js'; import { LogService } from '@app/unraid-api/cli/log.service.js'; -import { StartCommand } from '@app/unraid-api/cli/start.command.js'; -import { StopCommand } from '@app/unraid-api/cli/stop.command.js'; +import { RestartCommand } from '@app/unraid-api/cli/restart.command.js'; interface SwitchEnvOptions { environment?: 'staging' | 'production'; @@ -31,60 +31,43 @@ export class SwitchEnvCommand extends CommandRunner { constructor( private readonly logger: LogService, - private readonly stopCommand: StopCommand, - private readonly startCommand: StartCommand + private readonly restartCommand: RestartCommand ) { super(); } - private async getEnvironmentFromFile(path: string): Promise<'production' | 'staging'> { - const envFile = await readFile(path, 'utf-8').catch(() => ''); - this.logger.debug(`Checking ${path} for current ENV, found ${envFile}`); - - // Match the env file env="production" which would be [0] = env="production", [1] = env and [2] = production - const matchArray = /([a-zA-Z]+)=["]*([a-zA-Z]+)["]*/.exec(envFile); - // Get item from index 2 of the regex match or return production - const [, , currentEnvInFile] = matchArray && matchArray.length === 3 ? matchArray : []; - return this.parseStringToEnv(currentEnvInFile); - } - - private switchToOtherEnv(environment: 'production' | 'staging'): 'production' | 'staging' { - if (environment === 'production') { - return 'staging'; - } - return 'production'; - } - async run(_, options: SwitchEnvOptions): Promise { const paths = getters.paths(); const basePath = paths['unraid-api-base']; - const envFlashFilePath = paths['myservers-env']; + const currentEnvPath = join(basePath, '.env'); - this.logger.warn('Stopping the Unraid API'); - try { - await this.stopCommand.run([], { delete: false }); - } catch (err) { - this.logger.warn('Failed to stop the Unraid API (maybe already stopped?)'); + // Determine target environment + const currentEnv = ENVIRONMENT; + const targetEnv = options.environment ?? 'production'; + + this.logger.info(`Switching environment from ${currentEnv} to ${targetEnv}`); + + // Check if target environment file exists + const sourceEnvPath = join(basePath, `.env.${targetEnv}`); + if (!fileExistsSync(sourceEnvPath)) { + this.logger.error( + `Environment file ${sourceEnvPath} does not exist. Cannot switch to ${targetEnv} environment.` + ); + process.exit(1); } - const newEnv = - options.environment ?? - this.switchToOtherEnv(await this.getEnvironmentFromFile(envFlashFilePath)); - this.logger.info(`Setting environment to ${newEnv}`); + // Copy the target environment file to .env + this.logger.debug(`Copying ${sourceEnvPath} to ${currentEnvPath}`); + try { + await copyFile(sourceEnvPath, currentEnvPath); + this.logger.info(`Successfully switched to ${targetEnv} environment`); + } catch (error) { + this.logger.error(`Failed to copy environment file: ${error}`); + process.exit(1); + } - // Write new env to flash - const newEnvLine = `env="${newEnv}"`; - this.logger.debug('Writing %s to %s', newEnvLine, envFlashFilePath); - await writeFile(envFlashFilePath, newEnvLine); - - // Copy the new env over to live location before restarting - const source = join(basePath, `.env.${newEnv}`); - const destination = join(basePath, '.env'); - - cliLogger.debug('Copying %s to %s', source, destination); - await copyFile(source, destination); - - cliLogger.info('Now using %s', newEnv); - await this.startCommand.run([], {}); + // Restart the API to pick up the new environment + this.logger.info('Restarting Unraid API to apply environment changes...'); + await this.restartCommand.run(); } } diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time index 83193e350..57c42a2ef 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time @@ -1 +1 @@ -1751630630443 \ No newline at end of file +1752524464371 \ No newline at end of file diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time index 125d1dfd8..c25e06d50 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time @@ -1 +1 @@ -1751630630198 \ No newline at end of file +1752524464066 \ No newline at end of file diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time index c7db09181..478d8e7f7 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time @@ -1 +1 @@ -1751630630343 \ No newline at end of file +1752524464213 \ No newline at end of file diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time index c2f1dd9f4..e8c55463f 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time @@ -1 +1 @@ -1751630630571 \ No newline at end of file +1752524464631 \ No newline at end of file diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/rc.nginx.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/rc.nginx.last-download-time index 0e9029449..d3a765f5b 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/rc.nginx.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/rc.nginx.last-download-time @@ -1 +1 @@ -1751630630810 \ No newline at end of file +1752524464761 \ No newline at end of file diff --git a/plugin/source/dynamix.unraid.net/etc/rc.d/rc.unraid-api b/plugin/source/dynamix.unraid.net/etc/rc.d/rc.unraid-api index 885d5dcbc..d2685ba4f 100755 --- a/plugin/source/dynamix.unraid.net/etc/rc.d/rc.unraid-api +++ b/plugin/source/dynamix.unraid.net/etc/rc.d/rc.unraid-api @@ -4,9 +4,6 @@ # shellcheck source=/dev/null source /etc/profile -flash="/boot/config/plugins/dynamix.my.servers" -[[ ! -d "${flash}" ]] && echo "Please reinstall the Unraid Connect plugin" && exit 1 -[[ ! -f "${flash}/env" ]] && echo 'env=production' >"${flash}/env" unraid_binary_path="/usr/local/bin/unraid-api" api_base_dir="/usr/local/unraid-api" scripts_dir="/usr/local/share/dynamix.unraid.net/scripts"