From e353ac71fbf02dce19de8e318d3cc4962aaf522e Mon Sep 17 00:00:00 2001 From: Tzif Date: Tue, 4 Aug 2026 10:33:50 +0300 Subject: [PATCH 1/4] OSAC-3160: add GPU columns to InstanceType table rendering Assisted-by: Claude Code Signed-off-by: Tzif --- .../internal/rendering/table_renderer_test.go | 100 +++++++++++++----- .../tables/osac.private.v1.InstanceType.yaml | 9 ++ .../tables/osac.public.v1.InstanceType.yaml | 9 ++ 3 files changed, 93 insertions(+), 25 deletions(-) diff --git a/fulfillment-service/internal/rendering/table_renderer_test.go b/fulfillment-service/internal/rendering/table_renderer_test.go index 34c0a84072..1ab91c875e 100644 --- a/fulfillment-service/internal/rendering/table_renderer_test.go +++ b/fulfillment-service/internal/rendering/table_renderer_test.go @@ -150,33 +150,33 @@ var _ = Describe("Table renderer", func() { }) }) - Describe("Integer columns", func() { - renderInstanceTypes := func(ctx context.Context, items []*publicv1.InstanceType) string { - objectHelper := makeObjectHelper(&publicv1.InstanceType{}) - lookupHelper := makeLookupHelper() + renderInstanceTypes := func(ctx context.Context, items []*publicv1.InstanceType) string { + objectHelper := makeObjectHelper(&publicv1.InstanceType{}) + lookupHelper := makeLookupHelper() - helper := reflection.NewMockHelper(ctrl) - helper.EXPECT(). - Lookup(objectHelper.String()). - Return(objectHelper). - AnyTimes() - helper.EXPECT(). - Lookup(gomock.Any()). - Return(lookupHelper). - AnyTimes() + helper := reflection.NewMockHelper(ctrl) + helper.EXPECT(). + Lookup(objectHelper.String()). + Return(objectHelper). + AnyTimes() + helper.EXPECT(). + Lookup(gomock.Any()). + Return(lookupHelper). + AnyTimes() - buffer := &bytes.Buffer{} - renderer, err := NewTableRenderer(). - SetLogger(logger). - SetHelper(helper). - SetWriter(buffer). - Build() - Expect(err).ToNot(HaveOccurred()) - err = renderer.Render(ctx, items) - Expect(err).ToNot(HaveOccurred()) - return buffer.String() - } + buffer := &bytes.Buffer{} + renderer, err := NewTableRenderer(). + SetLogger(logger). + SetHelper(helper). + SetWriter(buffer). + Build() + Expect(err).ToNot(HaveOccurred()) + err = renderer.Render(ctx, items) + Expect(err).ToNot(HaveOccurred()) + return buffer.String() + } + Describe("Integer columns", func() { It("Renders integer fields as plain numbers", func(ctx context.Context) { output := renderInstanceTypes( ctx, @@ -194,11 +194,61 @@ var _ = Describe("Table renderer", func() { }.Build(), }, ) - Expect(output).To(MatchRegexp(`4\s+16\s+ACTIVE`)) + Expect(output).To(MatchRegexp(`4\s+16\s+.*ACTIVE`)) Expect(output).ToNot(ContainSubstring("%!s")) }) }) + Describe("Optional GPU columns", func() { + It("Renders GPU fields for GPU-enabled InstanceType", func(ctx context.Context) { + output := renderInstanceTypes( + ctx, + []*publicv1.InstanceType{ + publicv1.InstanceType_builder{ + Id: "gpu-a100-8core", + Metadata: publicv1.Metadata_builder{ + Name: "gpu-a100-8core", + }.Build(), + Spec: publicv1.InstanceTypeSpec_builder{ + Cores: 8, + MemoryGib: 64, + State: publicv1.InstanceTypeState_INSTANCE_TYPE_STATE_ACTIVE, + Gpu: publicv1.GpuSpec_builder{ + PciDeviceSelector: "10DE:20B0", + ResourceName: "nvidia.com/A100", + Count: 1, + }.Build(), + }.Build(), + }.Build(), + }, + ) + Expect(output).To(ContainSubstring("10DE:20B0")) + Expect(output).To(ContainSubstring("nvidia.com/A100")) + Expect(output).To(MatchRegexp(`nvidia\.com/A100\s+1\s+ACTIVE`)) + }) + + It("Renders blank GPU columns for non-GPU InstanceType", func(ctx context.Context) { + output := renderInstanceTypes( + ctx, + []*publicv1.InstanceType{ + publicv1.InstanceType_builder{ + Id: "standard-4-16", + Metadata: publicv1.Metadata_builder{ + Name: "standard-4-16", + }.Build(), + Spec: publicv1.InstanceTypeSpec_builder{ + Cores: 4, + MemoryGib: 16, + State: publicv1.InstanceTypeState_INSTANCE_TYPE_STATE_ACTIVE, + }.Build(), + }.Build(), + }, + ) + Expect(output).To(ContainSubstring("GPU DEVICE")) + Expect(output).To(MatchRegexp(`16\s+-\s+-\s+0\s+ACTIVE`)) + }) + }) + It("Compiles CEL expressions successfully for all table definitions", func(ctx context.Context) { // Collect all table definition files: tableFiles, err := filepath.Glob("tables/*.yaml") diff --git a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml index f0eb50b7b7..f25fcfe9fc 100644 --- a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml @@ -22,6 +22,15 @@ columns: - header: MEMORY value: this.spec.memory_gib +- header: GPU DEVICE + value: "has(this.spec.gpu) ? this.spec.gpu.pci_device_selector : '-'" + +- header: GPU RESOURCE + value: "has(this.spec.gpu) ? this.spec.gpu.resource_name : '-'" + +- header: GPU COUNT + value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" + - header: STATE value: this.spec.state type: osac.private.v1.InstanceTypeState diff --git a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml index c433c82f4e..c5c46ce6d4 100644 --- a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml @@ -22,6 +22,15 @@ columns: - header: MEMORY value: this.spec.memory_gib +- header: GPU DEVICE + value: "has(this.spec.gpu) ? this.spec.gpu.pci_device_selector : '-'" + +- header: GPU RESOURCE + value: "has(this.spec.gpu) ? this.spec.gpu.resource_name : '-'" + +- header: GPU COUNT + value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" + - header: STATE value: this.spec.state type: osac.public.v1.InstanceTypeState From 77ff9e19fe21dfe183aeff2f4ed551e8354975e9 Mon Sep 17 00:00:00 2001 From: Tzif Date: Tue, 4 Aug 2026 10:37:14 +0300 Subject: [PATCH 2/4] OSAC-3160: move GPU COUNT column before GPU DEVICE and GPU RESOURCE Assisted-by: Claude Code Signed-off-by: Tzif --- .../internal/rendering/table_renderer_test.go | 4 ++-- .../rendering/tables/osac.private.v1.InstanceType.yaml | 6 +++--- .../rendering/tables/osac.public.v1.InstanceType.yaml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fulfillment-service/internal/rendering/table_renderer_test.go b/fulfillment-service/internal/rendering/table_renderer_test.go index 1ab91c875e..1b4c8e876c 100644 --- a/fulfillment-service/internal/rendering/table_renderer_test.go +++ b/fulfillment-service/internal/rendering/table_renderer_test.go @@ -224,7 +224,7 @@ var _ = Describe("Table renderer", func() { ) Expect(output).To(ContainSubstring("10DE:20B0")) Expect(output).To(ContainSubstring("nvidia.com/A100")) - Expect(output).To(MatchRegexp(`nvidia\.com/A100\s+1\s+ACTIVE`)) + Expect(output).To(MatchRegexp(`1\s+10DE:20B0\s+nvidia\.com/A100\s+ACTIVE`)) }) It("Renders blank GPU columns for non-GPU InstanceType", func(ctx context.Context) { @@ -245,7 +245,7 @@ var _ = Describe("Table renderer", func() { }, ) Expect(output).To(ContainSubstring("GPU DEVICE")) - Expect(output).To(MatchRegexp(`16\s+-\s+-\s+0\s+ACTIVE`)) + Expect(output).To(MatchRegexp(`16\s+0\s+-\s+-\s+ACTIVE`)) }) }) diff --git a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml index f25fcfe9fc..9c793f5909 100644 --- a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml @@ -22,15 +22,15 @@ columns: - header: MEMORY value: this.spec.memory_gib +- header: GPU COUNT + value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" + - header: GPU DEVICE value: "has(this.spec.gpu) ? this.spec.gpu.pci_device_selector : '-'" - header: GPU RESOURCE value: "has(this.spec.gpu) ? this.spec.gpu.resource_name : '-'" -- header: GPU COUNT - value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" - - header: STATE value: this.spec.state type: osac.private.v1.InstanceTypeState diff --git a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml index c5c46ce6d4..2c8f79dfdd 100644 --- a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml @@ -22,15 +22,15 @@ columns: - header: MEMORY value: this.spec.memory_gib +- header: GPU COUNT + value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" + - header: GPU DEVICE value: "has(this.spec.gpu) ? this.spec.gpu.pci_device_selector : '-'" - header: GPU RESOURCE value: "has(this.spec.gpu) ? this.spec.gpu.resource_name : '-'" -- header: GPU COUNT - value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" - - header: STATE value: this.spec.state type: osac.public.v1.InstanceTypeState From 4722c92d777ef65836c7e7380dc1d23103129393 Mon Sep 17 00:00:00 2001 From: Tzif Date: Tue, 4 Aug 2026 15:30:54 +0300 Subject: [PATCH 3/4] OSAC-3160: drop PCI device column, rename GPU headers to GPUs and GPU NAME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the GPU DEVICE column (pci_device_selector) from the InstanceType table — not useful at a glance. Rename GPU COUNT to GPUs and GPU RESOURCE to GPU NAME for clarity. Assisted-by: Claude Code Signed-off-by: Tzif --- .../internal/rendering/table_renderer_test.go | 7 +++---- .../rendering/tables/osac.private.v1.InstanceType.yaml | 7 ++----- .../rendering/tables/osac.public.v1.InstanceType.yaml | 7 ++----- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/fulfillment-service/internal/rendering/table_renderer_test.go b/fulfillment-service/internal/rendering/table_renderer_test.go index 1b4c8e876c..d51b7cdecc 100644 --- a/fulfillment-service/internal/rendering/table_renderer_test.go +++ b/fulfillment-service/internal/rendering/table_renderer_test.go @@ -222,9 +222,8 @@ var _ = Describe("Table renderer", func() { }.Build(), }, ) - Expect(output).To(ContainSubstring("10DE:20B0")) Expect(output).To(ContainSubstring("nvidia.com/A100")) - Expect(output).To(MatchRegexp(`1\s+10DE:20B0\s+nvidia\.com/A100\s+ACTIVE`)) + Expect(output).To(MatchRegexp(`1\s+nvidia\.com/A100\s+ACTIVE`)) }) It("Renders blank GPU columns for non-GPU InstanceType", func(ctx context.Context) { @@ -244,8 +243,8 @@ var _ = Describe("Table renderer", func() { }.Build(), }, ) - Expect(output).To(ContainSubstring("GPU DEVICE")) - Expect(output).To(MatchRegexp(`16\s+0\s+-\s+-\s+ACTIVE`)) + Expect(output).To(ContainSubstring("GPU NAME")) + Expect(output).To(MatchRegexp(`16\s+0\s+-\s+ACTIVE`)) }) }) diff --git a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml index 9c793f5909..f40858f7e1 100644 --- a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml @@ -22,13 +22,10 @@ columns: - header: MEMORY value: this.spec.memory_gib -- header: GPU COUNT +- header: GPUs value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" -- header: GPU DEVICE - value: "has(this.spec.gpu) ? this.spec.gpu.pci_device_selector : '-'" - -- header: GPU RESOURCE +- header: GPU NAME value: "has(this.spec.gpu) ? this.spec.gpu.resource_name : '-'" - header: STATE diff --git a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml index 2c8f79dfdd..098be86ec3 100644 --- a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml @@ -22,13 +22,10 @@ columns: - header: MEMORY value: this.spec.memory_gib -- header: GPU COUNT +- header: GPUs value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" -- header: GPU DEVICE - value: "has(this.spec.gpu) ? this.spec.gpu.pci_device_selector : '-'" - -- header: GPU RESOURCE +- header: GPU NAME value: "has(this.spec.gpu) ? this.spec.gpu.resource_name : '-'" - header: STATE From 281b280279cded18d79bffbd69d51df7c09daae1 Mon Sep 17 00:00:00 2001 From: Tzif Date: Tue, 4 Aug 2026 15:38:12 +0300 Subject: [PATCH 4/4] OSAC-3160: rename GPUs header to GPUS for consistency Assisted-by: Claude Code Signed-off-by: Tzif --- .../internal/rendering/tables/osac.private.v1.InstanceType.yaml | 2 +- .../internal/rendering/tables/osac.public.v1.InstanceType.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml index f40858f7e1..9192ae2cc3 100644 --- a/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.private.v1.InstanceType.yaml @@ -22,7 +22,7 @@ columns: - header: MEMORY value: this.spec.memory_gib -- header: GPUs +- header: GPUS value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" - header: GPU NAME diff --git a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml index 098be86ec3..4e006ae3e5 100644 --- a/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml +++ b/fulfillment-service/internal/rendering/tables/osac.public.v1.InstanceType.yaml @@ -22,7 +22,7 @@ columns: - header: MEMORY value: this.spec.memory_gib -- header: GPUs +- header: GPUS value: "has(this.spec.gpu) ? this.spec.gpu.count : 0" - header: GPU NAME