From 87eea102f44e7d06f540bf5de272d0e2ec0cb22f Mon Sep 17 00:00:00 2001 From: Aditya Choudhari Date: Mon, 20 Jan 2025 22:09:18 -0800 Subject: [PATCH 1/2] fix: Vm v1 schema --- .../src/resource-scan/google/vm.ts | 24 ++++++++----- packages/validators/src/resources/index.ts | 1 + packages/validators/src/resources/vm-v1.ts | 35 +++++++++++++++++++ 3 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 packages/validators/src/resources/vm-v1.ts diff --git a/apps/event-worker/src/resource-scan/google/vm.ts b/apps/event-worker/src/resource-scan/google/vm.ts index 2d22046e7..b1673dd50 100644 --- a/apps/event-worker/src/resource-scan/google/vm.ts +++ b/apps/event-worker/src/resource-scan/google/vm.ts @@ -1,4 +1,5 @@ import type * as SCHEMA from "@ctrlplane/db/schema"; +import type { VmV1 } from "@ctrlplane/validators/resources"; import type { google } from "@google-cloud/compute/build/protos/protos.js"; import { InstancesClient } from "@google-cloud/compute"; import _ from "lodash"; @@ -19,7 +20,7 @@ const instanceToResource = ( workspaceId: string, providerId: string, projectId: string, -): SCHEMA.InsertResource & { metadata: Record } => { +): VmV1 => { const instanceZone = instance.zone != null ? instance.zone.split("/").pop() : null; const appUrl = `https://console.cloud.google.com/compute/instancesDetail/zones/${instanceZone}/instances/${instance.name}?project=${projectId}`; @@ -28,17 +29,21 @@ const instanceToResource = ( name: String(instance.name ?? instance.id ?? ""), providerId, identifier: `${projectId}/${instance.name}`, - version: "compute/v1", + version: "vm/v1", kind: "VM", config: { - name: instance.name ?? instance.id ?? "", - auth: { - method: "google/gce", - project: projectId, - zone: instanceZone, - instance: instance.name ?? instance.id ?? "", - }, + name: String(instance.name ?? instance.id ?? ""), status: instance.status ?? "STATUS_UNSPECIFIED", + id: String(instance.id ?? ""), + machineType: instance.machineType?.split("/").pop() ?? "", + type: { type: "google", project: projectId, zone: instanceZone ?? "" }, + disks: + instance.disks?.map((disk) => ({ + name: disk.deviceName ?? "", + size: Number(disk.diskSizeGb), + type: disk.type ?? "", + encrypted: disk.diskEncryptionKey?.rawKey != null, + })) ?? [], }, metadata: omitNullUndefined({ [ReservedMetadataKey.Links]: JSON.stringify({ @@ -53,6 +58,7 @@ const instanceToResource = ( "vm/cpu-platform": instance.cpuPlatform, "vm/deletion-protection": instance.deletionProtection, "vm/description": instance.description, + "vm/status": instance.status, "vm/disk-count": instance.disks?.length ?? 0, "vm/disk-size-gb": _.sumBy(instance.disks, (disk) => disk.diskSizeGb != null ? Number(disk.diskSizeGb) : 0, diff --git a/packages/validators/src/resources/index.ts b/packages/validators/src/resources/index.ts index f890055dd..58952e283 100644 --- a/packages/validators/src/resources/index.ts +++ b/packages/validators/src/resources/index.ts @@ -1,3 +1,4 @@ export * from "./kubernetes-v1.js"; export * from "./conditions/index.js"; export * from "./cloud-v1.js"; +export * from "./vm-v1.js"; diff --git a/packages/validators/src/resources/vm-v1.ts b/packages/validators/src/resources/vm-v1.ts new file mode 100644 index 000000000..898ce50bc --- /dev/null +++ b/packages/validators/src/resources/vm-v1.ts @@ -0,0 +1,35 @@ +import { z } from "zod"; + +const diskV1 = z.object({ + name: z.string(), + size: z.number(), + type: z.string(), + encrypted: z.boolean(), +}); + +export const vmV1 = z.object({ + workspaceId: z.string(), + providerId: z.string(), + version: z.literal("vm/v1"), + kind: z.literal("VM"), + identifier: z.string(), + name: z.string(), + config: z + .object({ + name: z.string(), + id: z.string(), + machineType: z.string(), + disks: z.array(diskV1), + type: z.discriminatedUnion("type", [ + z.object({ + type: z.literal("google"), + project: z.string(), + zone: z.string(), + }), + ]), + }) + .passthrough(), + metadata: z.record(z.string()).and(z.object({}).partial()), +}); + +export type VmV1 = z.infer; From 2c7578a9214e42d208d1cb7bd2692b13689102c2 Mon Sep 17 00:00:00 2001 From: Aditya Choudhari Date: Mon, 20 Jan 2025 22:43:06 -0800 Subject: [PATCH 2/2] cleanup --- .../src/resource-scan/google/vm.ts | 23 ++++++++++++++----- packages/validators/src/resources/vm-v1.ts | 5 ++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/event-worker/src/resource-scan/google/vm.ts b/apps/event-worker/src/resource-scan/google/vm.ts index b1673dd50..261e07754 100644 --- a/apps/event-worker/src/resource-scan/google/vm.ts +++ b/apps/event-worker/src/resource-scan/google/vm.ts @@ -15,6 +15,20 @@ const log = logger.child({ module: "resource-scan/gke/vm" }); const getVMClient = (targetPrincipal?: string | null) => getGoogleClient(InstancesClient, targetPrincipal, "VM Client"); +const getFlattenedMetadata = (metadata?: google.cloud.compute.v1.IMetadata) => { + if (metadata == null) return {}; + const { items } = metadata; + return _.fromPairs( + items?.map(({ key, value }) => [`vm/metadata/${key}`, value ?? ""]) ?? [], + ); +}; + +const getFlattenedTags = (tags?: google.cloud.compute.v1.ITags) => { + if (tags == null) return {}; + const { items } = tags; + return _.fromPairs(items?.map((value) => [`vm/tag/${value}`, true]) ?? []); +}; + const instanceToResource = ( instance: google.cloud.compute.v1.IInstance, workspaceId: string, @@ -53,7 +67,7 @@ const instanceToResource = ( "google/self-link": instance.selfLink, "google/project": projectId, "google/zone": instance.zone, - "vm/machine-type": instance.machineType, + "vm/machine-type": instance.machineType?.split("/").pop() ?? null, "vm/can-ip-forward": instance.canIpForward, "vm/cpu-platform": instance.cpuPlatform, "vm/deletion-protection": instance.deletionProtection, @@ -74,10 +88,7 @@ const instanceToResource = ( "vm/last-start-timestamp": instance.lastStartTimestamp, "vm/last-stop-timestamp": instance.lastStopTimestamp, "vm/last-suspended-timestamp": instance.lastSuspendedTimestamp, - ..._.mapKeys( - instance.metadata ?? {}, - (_value, key) => `vm/metadata/${key}`, - ), + ...getFlattenedMetadata(instance.metadata ?? undefined), "vm/min-cpu-platform": instance.minCpuPlatform, "vm/network-performance-config/total-egress-bandwith-tier": instance.networkPerformanceConfig?.totalEgressBandwidthTier, @@ -110,7 +121,7 @@ const instanceToResource = ( "vm/service-accounts": instance.serviceAccounts?.map((account) => account.email).join(", ") ?? null, - ..._.mapKeys(instance.tags ?? {}, (_value, key) => `vm/tag/${key}`), + ...getFlattenedTags(instance.tags ?? undefined), }), }; }; diff --git a/packages/validators/src/resources/vm-v1.ts b/packages/validators/src/resources/vm-v1.ts index 898ce50bc..31f35914c 100644 --- a/packages/validators/src/resources/vm-v1.ts +++ b/packages/validators/src/resources/vm-v1.ts @@ -18,7 +18,6 @@ export const vmV1 = z.object({ .object({ name: z.string(), id: z.string(), - machineType: z.string(), disks: z.array(diskV1), type: z.discriminatedUnion("type", [ z.object({ @@ -29,7 +28,9 @@ export const vmV1 = z.object({ ]), }) .passthrough(), - metadata: z.record(z.string()).and(z.object({}).partial()), + metadata: z + .record(z.string()) + .and(z.object({ "vm/machine-type": z.string().optional() })), }); export type VmV1 = z.infer;