diff --git a/apps/cli/src/command/diff.command.ts b/apps/cli/src/command/diff.command.ts index 788102e7..e06651d9 100644 --- a/apps/cli/src/command/diff.command.ts +++ b/apps/cli/src/command/diff.command.ts @@ -69,6 +69,7 @@ export const DiffCommand = new BackendCommand( opts.labelSelector, opts.includeResourceType, opts.excludeResourceType, + opts.managedByLabel, ), opts.lint ? LintTask() : { task: () => undefined }, !opts.remoteStateFile diff --git a/apps/cli/src/command/helper.ts b/apps/cli/src/command/helper.ts index 0862d07c..8ea2ed8b 100644 --- a/apps/cli/src/command/helper.ts +++ b/apps/cli/src/command/helper.ts @@ -207,6 +207,12 @@ export class BackendCommand< ) .env('ADC_TLS_SKIP_VERIFY') .default(false), + ) + .addOption( + new Option( + '--no-managed-by-label', + 'disable injecting the "managed-by=adc" label into synced resources', + ), ); } } diff --git a/apps/cli/src/command/ingress-sync.command.ts b/apps/cli/src/command/ingress-sync.command.ts index 27992830..9344f22d 100644 --- a/apps/cli/src/command/ingress-sync.command.ts +++ b/apps/cli/src/command/ingress-sync.command.ts @@ -31,6 +31,7 @@ export const IngressSyncCommand = new BackendCommand('sync') opts.labelSelector, opts.includeResourceType, opts.excludeResourceType, + opts.managedByLabel, ), LintTask(), !opts.remoteStateFile diff --git a/apps/cli/src/command/lint.command.ts b/apps/cli/src/command/lint.command.ts index ca7f1d16..54582ea3 100644 --- a/apps/cli/src/command/lint.command.ts +++ b/apps/cli/src/command/lint.command.ts @@ -28,7 +28,10 @@ export const LintCommand = new BaseCommand('lint') const opts = LintCommand.optsWithGlobals(); const tasks = new Listr( - [LoadLocalConfigurationTask(opts.file, {}), LintTask()], + [ + LoadLocalConfigurationTask(opts.file, {}, undefined, undefined, false), + LintTask(), + ], { renderer: SignaleRenderer, rendererOptions: { verbose: opts.verbose }, diff --git a/apps/cli/src/command/sync.command.ts b/apps/cli/src/command/sync.command.ts index 2ed80eca..4a417ccd 100644 --- a/apps/cli/src/command/sync.command.ts +++ b/apps/cli/src/command/sync.command.ts @@ -85,6 +85,7 @@ export const SyncCommand = new BackendCommand( opts.labelSelector, opts.includeResourceType, opts.excludeResourceType, + opts.managedByLabel, ), opts.lint ? LintTask() : { task: () => undefined }, !opts.remoteStateFile diff --git a/apps/cli/src/command/typing.d.ts b/apps/cli/src/command/typing.d.ts index 636b7400..f6c1d738 100644 --- a/apps/cli/src/command/typing.d.ts +++ b/apps/cli/src/command/typing.d.ts @@ -16,6 +16,7 @@ export type BackendOptions = { labelSelector?: Record; includeResourceType?: Array; excludeResourceType?: Array; + managedByLabel?: boolean; } & GlobalOptions; export interface KVConfiguration { diff --git a/apps/cli/src/command/utils.spec.ts b/apps/cli/src/command/utils.spec.ts index 5e3e5c1c..ccd7d1fa 100644 --- a/apps/cli/src/command/utils.spec.ts +++ b/apps/cli/src/command/utils.spec.ts @@ -1,6 +1,8 @@ import * as ADCSDK from '@api7/adc-sdk'; import { + MANAGED_BY_LABEL_KEY, + MANAGED_BY_LABEL_VALUE, fillLabels, recursiveRemoveIdField, recursiveReplaceEnvVars, @@ -254,6 +256,120 @@ describe('CLI utils', () => { }); }); + it('should label local resources as managed by ADC, the same way fillLabels does for --label-selector', () => { + expect( + fillLabels( + { + services: [ + { + name: 'Test Service', + routes: [ + { + name: 'Test Nested Route', + uris: ['/test-nested'], + }, + ], + stream_routes: [ + { + name: 'Test Nested Stream Route', + }, + ], + }, + ], + consumers: [{ username: 'alice', labels: { team: 'a' } }], + } as ADCSDK.Configuration, + { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + ), + ).toEqual({ + services: [ + { + name: 'Test Service', + labels: { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + routes: [ + { + name: 'Test Nested Route', + uris: ['/test-nested'], + labels: { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + }, + ], + stream_routes: [ + { + name: 'Test Nested Stream Route', + labels: { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + }, + ], + }, + ], + consumers: [ + { + username: 'alice', + labels: { team: 'a', [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + }, + ], + }); + }); + + it('should overwrite an existing managed-by label with a different value, keeping other labels', () => { + expect( + fillLabels( + { + services: [ + { + name: 'Test Service', + labels: { team: 'a', [MANAGED_BY_LABEL_KEY]: 'something-else' }, + routes: [ + { + name: 'Test Nested Route', + uris: ['/test-nested'], + labels: { [MANAGED_BY_LABEL_KEY]: 'something-else' }, + }, + ], + stream_routes: [ + { + name: 'Test Nested Stream Route', + labels: { [MANAGED_BY_LABEL_KEY]: 'something-else' }, + }, + ], + }, + ], + consumers: [ + { + username: 'alice', + labels: { [MANAGED_BY_LABEL_KEY]: 'something-else' }, + }, + ], + } as ADCSDK.Configuration, + { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + ), + ).toEqual({ + services: [ + { + name: 'Test Service', + labels: { team: 'a', [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + routes: [ + { + name: 'Test Nested Route', + uris: ['/test-nested'], + labels: { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + }, + ], + stream_routes: [ + { + name: 'Test Nested Stream Route', + labels: { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + }, + ], + }, + ], + consumers: [ + { + username: 'alice', + labels: { [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE }, + }, + ], + }); + }); + describe('Environment Variables', () => { it('mock config', () => { const config: ADCSDK.Configuration = { diff --git a/apps/cli/src/command/utils.ts b/apps/cli/src/command/utils.ts index fca4b9b8..a797c38b 100644 --- a/apps/cli/src/command/utils.ts +++ b/apps/cli/src/command/utils.ts @@ -200,6 +200,12 @@ export const fillLabels = ( return configuration; }; +// Injected into local resources the same way --label-selector's fillLabels() +// works, so it flows into every CREATE/UPDATE payload naturally without any +// special-casing in the differ or the backend. +export const MANAGED_BY_LABEL_KEY = 'managed-by'; +export const MANAGED_BY_LABEL_VALUE = 'adc'; + export const filterResourceType = ( config: ADCSDK.Configuration = {}, includes?: Array, diff --git a/apps/cli/src/command/validate.command.ts b/apps/cli/src/command/validate.command.ts index 4e9c3b3f..65bc9857 100644 --- a/apps/cli/src/command/validate.command.ts +++ b/apps/cli/src/command/validate.command.ts @@ -56,6 +56,7 @@ export const ValidateCommand = new BackendCommand( opts.labelSelector, opts.includeResourceType, opts.excludeResourceType, + opts.managedByLabel, ), opts.lint ? LintTask() : { task: () => undefined }, DiffResourceTask(), diff --git a/apps/cli/src/tasks/load_local.ts b/apps/cli/src/tasks/load_local.ts index 93ece411..9294e33d 100644 --- a/apps/cli/src/tasks/load_local.ts +++ b/apps/cli/src/tasks/load_local.ts @@ -7,8 +7,9 @@ import { ListrTask } from 'listr2'; import path from 'node:path'; import type { TaskContext } from '../command/diff.command'; - import { + MANAGED_BY_LABEL_KEY, + MANAGED_BY_LABEL_VALUE, fillLabels, filterResourceType, mergeKVConfigurations, @@ -22,6 +23,7 @@ export const LoadLocalConfigurationTask = ( labelSelector?: ADCSDK.BackendOptions['labelSelector'], includeResourceType?: Array, excludeResourceType?: Array, + managedByLabel = true, ): ListrTask => ({ title: `Load local configuration`, task: async (ctx, task) => { @@ -87,7 +89,8 @@ export const LoadLocalConfigurationTask = ( { title: 'Filter configuration resource type', enabled: () => - (includeResourceType?.length ?? 0) > 0 || (excludeResourceType?.length ?? 0) > 0, + (includeResourceType?.length ?? 0) > 0 || + (excludeResourceType?.length ?? 0) > 0, task: () => { ctx.local = filterResourceType( ctx.local, @@ -104,6 +107,14 @@ export const LoadLocalConfigurationTask = ( fillLabels(ctx.local, labelSelector); }, }, + { + enabled: managedByLabel, + task: async () => { + fillLabels(ctx.local, { + [MANAGED_BY_LABEL_KEY]: MANAGED_BY_LABEL_VALUE, + }); + }, + }, ], { ctx: subCtx, diff --git a/libs/sdk/tsconfig.json b/libs/sdk/tsconfig.json index dc7dc215..62ebbd94 100644 --- a/libs/sdk/tsconfig.json +++ b/libs/sdk/tsconfig.json @@ -2,5 +2,12 @@ "extends": "../../tsconfig.base.json", "files": [], "include": [], - "references": [] + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] } diff --git a/libs/sdk/tsconfig.spec.json b/libs/sdk/tsconfig.spec.json index aa4a5fa4..779b9d2f 100644 --- a/libs/sdk/tsconfig.spec.json +++ b/libs/sdk/tsconfig.spec.json @@ -30,5 +30,9 @@ "src/**/*.spec.jsx", "src/**/*.d.ts" ], - "references": [] + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] }