@nitra/cfr 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -1
- package/bin/cli.mjs +3 -0
- package/lib/{kcc-resources.mjs → get-resources.mjs} +107 -0
- package/lib/kcc-inventory.mjs +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# @nitra/cfr
|
|
2
2
|
|
|
3
3
|
A handful of small k8s/GitOps CLI utilities, one `npx`/`bunx` away — no
|
|
4
|
-
install
|
|
4
|
+
install. Three commands so far:
|
|
5
5
|
|
|
6
6
|
- **`check`** (default) — verify a Kustomize directory's `resources:` list
|
|
7
7
|
matches what's actually on disk
|
|
8
8
|
- **`kcc-inventory`** — diff a GCP Config Connector namespace against the
|
|
9
9
|
live project to find drift
|
|
10
|
+
- **`get-resources`** — the raw resource list `kcc-inventory` diffs,
|
|
11
|
+
without the diff
|
|
10
12
|
|
|
11
13
|
## `check`
|
|
12
14
|
|
|
@@ -146,6 +148,40 @@ already deleted in GCP. Both are cross-checked against a direct Compute
|
|
|
146
148
|
Engine call before being reported, and any stale entry found this way is
|
|
147
149
|
counted and noted separately — never silently folded into DRIFT.
|
|
148
150
|
|
|
151
|
+
## `get-resources`
|
|
152
|
+
|
|
153
|
+
`kcc-inventory` is a diff on top of a fact-finding step: for each KCC
|
|
154
|
+
namespace, list what's live in GCP and what's declared under KCC. That
|
|
155
|
+
step is `get-resources` — same scan, same filtering, no drift/orphan
|
|
156
|
+
comparison. Useful on its own for piping into `jq`, feeding a different
|
|
157
|
+
tool, or just seeing everything a namespace touches without wading
|
|
158
|
+
through a diff.
|
|
159
|
+
|
|
160
|
+
### Usage
|
|
161
|
+
|
|
162
|
+
```sh
|
|
163
|
+
npx @nitra/cfr get-resources <namespace>
|
|
164
|
+
npx @nitra/cfr get-resources --all
|
|
165
|
+
npx @nitra/cfr get-resources <namespace|--all> --json
|
|
166
|
+
npx @nitra/cfr get-resources <namespace|--all> --include-system
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
### namespace nitraai -> проєкт nitraai ###
|
|
171
|
+
== StorageBucket ==
|
|
172
|
+
gcp: 7n-forgejo-lfs
|
|
173
|
+
gcp: old-backups-bucket
|
|
174
|
+
kcc: 7n-forgejo-lfs
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`--json` emits `{resources: [{namespace, project, kind, id, source}, ...],
|
|
178
|
+
diagnostics: [...]}` — `source` is `"gcp"` or `"kcc"`, `diagnostics`
|
|
179
|
+
carries the same stale-cache/GKE-managed notes described above.
|
|
180
|
+
|
|
181
|
+
Same requirements as `kcc-inventory`: `kubectl` on `PATH`, Application
|
|
182
|
+
Default Credentials for the GCP side, `--include-system` to see
|
|
183
|
+
GCP-managed noise.
|
|
184
|
+
|
|
149
185
|
## License
|
|
150
186
|
|
|
151
187
|
MIT
|
package/bin/cli.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { run as runCheck } from '../lib/check.mjs';
|
|
3
3
|
import { run as runKccInventory } from '../lib/kcc-inventory.mjs';
|
|
4
|
+
import { run as runGetResources } from '../lib/get-resources.mjs';
|
|
4
5
|
|
|
5
6
|
const TOP_HELP = `cfr (@nitra/cfr) — a handful of small k8s/GitOps CLI utilities
|
|
6
7
|
|
|
@@ -12,6 +13,7 @@ Commands:
|
|
|
12
13
|
check Verify kustomization.yaml resources: match the directory
|
|
13
14
|
(default when the first argument isn't a known command)
|
|
14
15
|
kcc-inventory GCP Config Connector (KCC) drift inventory
|
|
16
|
+
get-resources Raw KCC/GCP resource list behind kcc-inventory, no diff
|
|
15
17
|
|
|
16
18
|
Run "npx @nitra/cfr <command> --help" for command-specific help.
|
|
17
19
|
`;
|
|
@@ -19,6 +21,7 @@ Run "npx @nitra/cfr <command> --help" for command-specific help.
|
|
|
19
21
|
const COMMANDS = {
|
|
20
22
|
check: runCheck,
|
|
21
23
|
'kcc-inventory': runKccInventory,
|
|
24
|
+
'get-resources': runGetResources,
|
|
22
25
|
};
|
|
23
26
|
|
|
24
27
|
// check is synchronous (local filesystem only); kcc-inventory is async
|
|
@@ -404,3 +404,110 @@ export async function collectNamespace(namespace, { includeSystem = false } = {}
|
|
|
404
404
|
|
|
405
405
|
return { namespace, project, resources, diagnostics };
|
|
406
406
|
}
|
|
407
|
+
|
|
408
|
+
// --- CLI: `cfr get-resources` — collectNamespace() as its own subcommand,
|
|
409
|
+
// no diffing. What kcc-inventory consumes, exposed directly for anyone
|
|
410
|
+
// who wants the raw facts (piping into jq, feeding a different tool).
|
|
411
|
+
|
|
412
|
+
export const HELP = `cfr get-resources — raw KCC/GCP resource list, no diff
|
|
413
|
+
|
|
414
|
+
Usage:
|
|
415
|
+
npx @nitra/cfr get-resources <namespace>
|
|
416
|
+
npx @nitra/cfr get-resources --all
|
|
417
|
+
npx @nitra/cfr get-resources <namespace|--all> [--json] [--include-system]
|
|
418
|
+
|
|
419
|
+
The mechanism kcc-inventory is built on, callable on its own: per KCC
|
|
420
|
+
namespace (namespace carrying the annotation
|
|
421
|
+
cnrm.cloud.google.com/project-id), lists every resource found live in the
|
|
422
|
+
GCP project (source: gcp) and every one declared as a Config Connector
|
|
423
|
+
custom resource in that namespace (source: kcc), for IAMServiceAccount,
|
|
424
|
+
IAMServiceAccountKey, ArtifactRegistryRepository, ContainerCluster,
|
|
425
|
+
ContainerNodePool, StorageBucket, ComputeAddress, DNSManagedZone,
|
|
426
|
+
DNSRecordSet, and IAMPolicyMember. No drift/orphan diff — that's
|
|
427
|
+
\`cfr kcc-inventory\`.
|
|
428
|
+
|
|
429
|
+
By default GCP-managed system noise is filtered out (Google-owned service
|
|
430
|
+
accounts, gcr.io shims, GKE-managed node pools/DNS zones, legacy bucket
|
|
431
|
+
ACL entries, ...) — pass --include-system to see it anyway.
|
|
432
|
+
|
|
433
|
+
Requires \`kubectl\` on PATH, pointed at the target cluster (set KUBE_CONTEXT
|
|
434
|
+
to target a specific kubeconfig context explicitly instead of relying on
|
|
435
|
+
the current one). The GCP side talks to Cloud Asset Inventory, IAM, and
|
|
436
|
+
Compute Engine directly over REST via Application Default Credentials —
|
|
437
|
+
no \`gcloud\` CLI needed.
|
|
438
|
+
|
|
439
|
+
Options:
|
|
440
|
+
--json Emit {resources, diagnostics} as JSON instead of the
|
|
441
|
+
human-readable listing.
|
|
442
|
+
--include-system Don't filter out GCP-managed system resources.
|
|
443
|
+
-h, --help Show this help and exit.
|
|
444
|
+
|
|
445
|
+
Exits 0 on a completed scan, 2 on a usage error.
|
|
446
|
+
`;
|
|
447
|
+
|
|
448
|
+
function printHuman(namespace, collected) {
|
|
449
|
+
console.log(`### namespace ${namespace} -> проєкт ${collected.project} ###`);
|
|
450
|
+
const byKind = new Map(KIND_ORDER.map((k) => [k, []]));
|
|
451
|
+
for (const r of collected.resources) byKind.get(r.kind)?.push(r);
|
|
452
|
+
for (const kind of KIND_ORDER) {
|
|
453
|
+
const entries = byKind.get(kind);
|
|
454
|
+
if (!entries.length) continue;
|
|
455
|
+
console.log(`== ${kind} ==`);
|
|
456
|
+
for (const { source, id } of [...entries].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
457
|
+
console.log(` ${source}: ${id}`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if (collected.diagnostics.length) {
|
|
461
|
+
console.log('== diagnostics ==');
|
|
462
|
+
for (const d of collected.diagnostics) {
|
|
463
|
+
if (d.type === 'stale-cache') console.log(` ${d.kind}: застарілий кеш Asset Inventory, ${d.count} запис(ів)`);
|
|
464
|
+
else if (d.type === 'gke-managed-skip') console.log(` ${d.kind}: керує сам GKE — ${d.zones.join(', ')}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
console.log('');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export async function run(argv) {
|
|
471
|
+
if (argv.includes('-h') || argv.includes('--help')) {
|
|
472
|
+
process.stdout.write(HELP);
|
|
473
|
+
return 0;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const target = argv[0];
|
|
477
|
+
if (!target) {
|
|
478
|
+
console.error('usage: cfr get-resources <namespace|--all> [--json] [--include-system] (KUBE_CONTEXT=... для явного контексту)');
|
|
479
|
+
return 2;
|
|
480
|
+
}
|
|
481
|
+
const jsonMode = argv.includes('--json');
|
|
482
|
+
const includeSystem = argv.includes('--include-system');
|
|
483
|
+
|
|
484
|
+
let namespaces;
|
|
485
|
+
if (target === '--all') {
|
|
486
|
+
namespaces = listKccNamespaces();
|
|
487
|
+
if (!namespaces.length) {
|
|
488
|
+
console.error('жоден namespace не має cnrm.cloud.google.com/project-id');
|
|
489
|
+
return 2;
|
|
490
|
+
}
|
|
491
|
+
} else {
|
|
492
|
+
namespaces = [target];
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const resources = [];
|
|
496
|
+
const diagnostics = [];
|
|
497
|
+
for (const namespace of namespaces) {
|
|
498
|
+
const collected = await collectNamespace(namespace, { includeSystem });
|
|
499
|
+
if (!collected.project) {
|
|
500
|
+
console.error(`namespace ${namespace} не має cnrm.cloud.google.com/project-id`);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
if (jsonMode) {
|
|
504
|
+
for (const r of collected.resources) resources.push({ namespace, project: collected.project, ...r });
|
|
505
|
+
for (const d of collected.diagnostics) diagnostics.push({ namespace, project: collected.project, ...d });
|
|
506
|
+
} else {
|
|
507
|
+
printHuman(namespace, collected);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (jsonMode) console.log(JSON.stringify({ resources, diagnostics }, null, 2));
|
|
512
|
+
return 0;
|
|
513
|
+
}
|
package/lib/kcc-inventory.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// Diff і звіт над сирим списком з
|
|
1
|
+
// Diff і звіт над сирим списком з get-resources.mjs: що з GCP-ресурсів
|
|
2
2
|
// проєкту реально живе під KCC (описано в git), а що — "чуже" (створено
|
|
3
3
|
// повз KCC). Суто читання, нічого не видаляє — вхідний контракт для
|
|
4
4
|
// окремого cleanup-рішення, яке вирішує, що з DRIFT можна прибрати.
|
|
5
|
-
import { collectNamespace, listKccNamespaces, KIND_ORDER } from './
|
|
5
|
+
import { collectNamespace, listKccNamespaces, KIND_ORDER } from './get-resources.mjs';
|
|
6
6
|
|
|
7
7
|
export const HELP = `cfr kcc-inventory — GCP Config Connector (KCC) drift inventory
|
|
8
8
|
|
|
@@ -93,7 +93,7 @@ function printDiagnostic(diag, jsonMode, results, project) {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
// Groups the flat resources list from
|
|
96
|
+
// Groups the flat resources list from get-resources.mjs back into
|
|
97
97
|
// per-kind {live, kcc} arrays, diffs and prints each kind in KIND_ORDER,
|
|
98
98
|
// interleaving each kind's diagnostics (if any) right before its report —
|
|
99
99
|
// same order a human reading top to bottom expects.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitra/cfr",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A handful of small k8s/GitOps CLI utilities: `check` verifies every YAML file in a Kustomize directory is listed in kustomization.yaml's explicit resources: (and vice versa); `kcc-inventory` diffs a GCP Config Connector namespace against the live project to find drift.",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "A handful of small k8s/GitOps CLI utilities: `check` verifies every YAML file in a Kustomize directory is listed in kustomization.yaml's explicit resources: (and vice versa); `kcc-inventory` diffs a GCP Config Connector namespace against the live project to find drift; `get-resources` is that same scan without the diff.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kustomize",
|
|
7
7
|
"flux",
|