mirror of
https://github.com/tale/headplane.git
synced 2026-08-28 07:57:03 +00:00
feat(TALE-33): add debug logging with DEBUG env
This commit is contained in:
@@ -13,6 +13,7 @@ import { HeadscaleConfig, loadConfig } from '~/utils/config/headscale'
|
||||
import log from '~/utils/log'
|
||||
|
||||
export interface HeadplaneContext {
|
||||
debug: boolean
|
||||
headscaleUrl: string
|
||||
cookieSecret: string
|
||||
integration: IntegrationFactory | undefined
|
||||
@@ -38,6 +39,12 @@ export async function loadContext(): Promise<HeadplaneContext> {
|
||||
return context
|
||||
}
|
||||
|
||||
const debug = process.env.DEBUG === 'true'
|
||||
if (debug) {
|
||||
log.info('CTXT', 'Debug mode is enabled! Logs will spam a lot.')
|
||||
log.info('CTXT', 'Please disable debug mode in production.')
|
||||
}
|
||||
|
||||
const path = resolve(process.env.CONFIG_FILE ?? '/etc/headscale/config.yaml')
|
||||
const { config, contextData } = await checkConfig(path)
|
||||
|
||||
@@ -60,6 +67,7 @@ export async function loadContext(): Promise<HeadplaneContext> {
|
||||
}
|
||||
|
||||
context = {
|
||||
debug,
|
||||
headscaleUrl,
|
||||
cookieSecret,
|
||||
integration: await loadIntegration(),
|
||||
@@ -80,10 +88,13 @@ export async function loadContext(): Promise<HeadplaneContext> {
|
||||
}
|
||||
|
||||
async function checkConfig(path: string) {
|
||||
log.debug('CTXT', 'Checking config at %s', path)
|
||||
|
||||
let config: HeadscaleConfig | undefined
|
||||
try {
|
||||
config = await loadConfig(path)
|
||||
} catch {
|
||||
log.debug('CTXT', 'Config at %s failed to load', path)
|
||||
return {
|
||||
config: undefined,
|
||||
contextData: {
|
||||
@@ -95,9 +106,12 @@ async function checkConfig(path: string) {
|
||||
|
||||
let write = false
|
||||
try {
|
||||
log.debug('CTXT', 'Checking write access to %s', path)
|
||||
await access(path, constants.W_OK)
|
||||
write = true
|
||||
} catch {}
|
||||
} catch {
|
||||
log.debug('CTXT', 'No write access to %s', path)
|
||||
}
|
||||
|
||||
return {
|
||||
config,
|
||||
@@ -109,7 +123,12 @@ async function checkConfig(path: string) {
|
||||
}
|
||||
|
||||
async function checkOidc(config?: HeadscaleConfig) {
|
||||
log.debug('CTXT', 'Checking OIDC configuration')
|
||||
|
||||
const disableKeyLogin = process.env.DISABLE_API_KEY_LOGIN === 'true'
|
||||
log.debug('CTXT', 'API Key Login Enabled: %s', !disableKeyLogin)
|
||||
|
||||
log.debug('CTXT', 'Checking ROOT_API_KEY and falling back to API_KEY')
|
||||
const rootKey = process.env.ROOT_API_KEY ?? process.env.API_KEY
|
||||
if (!rootKey) {
|
||||
throw new Error('ROOT_API_KEY or API_KEY not set')
|
||||
@@ -119,6 +138,10 @@ async function checkOidc(config?: HeadscaleConfig) {
|
||||
let client = process.env.OIDC_CLIENT_ID
|
||||
let secret = process.env.OIDC_CLIENT_SECRET
|
||||
|
||||
log.debug('CTXT', 'Checking OIDC environment variables')
|
||||
log.debug('CTXT', 'Issuer: %s', issuer)
|
||||
log.debug('CTXT', 'Client: %s', client)
|
||||
|
||||
if (
|
||||
(issuer ?? client ?? secret)
|
||||
&& !(issuer && client && secret)
|
||||
@@ -143,6 +166,7 @@ async function checkOidc(config?: HeadscaleConfig) {
|
||||
secret = config.oidc?.client_secret
|
||||
|
||||
if (!secret && config.oidc?.client_secret_path) {
|
||||
log.debug('CTXT', 'Trying to read OIDC client secret from %s', config.oidc.client_secret_path)
|
||||
try {
|
||||
const data = await readFile(
|
||||
config.oidc.client_secret_path,
|
||||
@@ -152,7 +176,9 @@ async function checkOidc(config?: HeadscaleConfig) {
|
||||
if (data && data.length > 0) {
|
||||
secret = data.trim()
|
||||
}
|
||||
} catch {}
|
||||
} catch {
|
||||
log.error('CTXT', 'Failed to read OIDC client secret from %s', config.oidc.client_secret_path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,10 +187,12 @@ export async function loadConfig(path?: string) {
|
||||
throw new Error('Path is required to lazy load config')
|
||||
}
|
||||
|
||||
log.debug('CFGX', 'Loading Headscale configuration from %s', path)
|
||||
const data = await readFile(path, 'utf8')
|
||||
configYaml = parseDocument(data)
|
||||
|
||||
if (process.env.HEADSCALE_CONFIG_UNSTRICT === 'true') {
|
||||
log.debug('CFGX', 'Loaded Headscale configuration in non-strict mode')
|
||||
const loaded = configYaml.toJSON() as Record<string, unknown>
|
||||
config = {
|
||||
...loaded,
|
||||
@@ -249,8 +251,10 @@ export async function loadConfig(path?: string) {
|
||||
}
|
||||
|
||||
try {
|
||||
log.debug('CFGX', 'Attempting to parse Headscale configuration')
|
||||
config = await HeadscaleConfig.parseAsync(configYaml.toJSON())
|
||||
} catch (error) {
|
||||
log.debug('CFGX', 'Failed to load Headscale configuration')
|
||||
if (error instanceof z.ZodError) {
|
||||
log.error('CFGX', 'Recieved invalid configuration file')
|
||||
log.error('CFGX', 'The following schema issues were found:')
|
||||
@@ -279,7 +283,9 @@ export async function patchConfig(partial: Record<string, unknown>) {
|
||||
throw new Error('Config not loaded')
|
||||
}
|
||||
|
||||
log.debug('CFGX', 'Patching Headscale configuration')
|
||||
for (const [key, value] of Object.entries(partial)) {
|
||||
log.debug('CFGX', 'Patching %s with %s', key, value)
|
||||
// If the key is something like `test.bar."foo.bar"`, then we treat
|
||||
// the foo.bar as a single key, and not as two keys, so that needs
|
||||
// to be split correctly.
|
||||
@@ -321,5 +327,6 @@ export async function patchConfig(partial: Record<string, unknown>) {
|
||||
: (await HeadscaleConfig.parseAsync(configYaml.toJSON()))
|
||||
|
||||
const path = resolve(process.env.CONFIG_FILE ?? '/etc/headscale/config.yaml')
|
||||
log.debug('CFGX', 'Writing patched configuration to %s', path)
|
||||
await writeFile(path, configYaml.toString(), 'utf8')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user