Skip to content

Commit 2ea40fe

Browse files
committed
fix(api): Add custom JSON marshaling for InstancePrototype interface fields
Instance provisioning fails with "Expected only one oneOf fields to be set: got 0" errors when using InstancePrototype types with interface-typed fields. Go's default JSON marshaling omits interface-typed fields in certain contexts. oneOf discriminator fields (image, zone, vpc, primary_network_attachment) are missing from the JSON payload, causing VPC API validation to fail. This commit add custom MarshalJSON methods to 8 InstancePrototype variant types that explicitly serialize all fields including interface types. Fixes: #133 Signed-off-by: Josephine Pfeiffer <[email protected]>
1 parent 166095d commit 2ea40fe

File tree

3 files changed

+674
-3
lines changed

3 files changed

+674
-3
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package vpcv1_test
2+
3+
import (
4+
"encoding/json"
5+
"strings"
6+
"testing"
7+
8+
"github.com/IBM/vpc-go-sdk/vpcv1"
9+
)
10+
11+
func TestInstancePrototypeMarshalBug(t *testing.T) {
12+
// Create the prototype exactly like Karpenter does
13+
imageID := "r010-test-image-id"
14+
zoneName := "eu-de-2"
15+
profileName := "bx2-2x8"
16+
vpcID := "r010-test-vpc-id"
17+
instanceName := "test-instance"
18+
subnetID := "test-subnet-id"
19+
20+
// Create VNI prototype
21+
vniPrototype := &vpcv1.InstanceNetworkAttachmentPrototypeVirtualNetworkInterfaceVirtualNetworkInterfacePrototypeInstanceNetworkAttachmentContext{
22+
Subnet: &vpcv1.SubnetIdentityByID{
23+
ID: &subnetID,
24+
},
25+
}
26+
27+
primaryNetworkAttachment := &vpcv1.InstanceNetworkAttachmentPrototype{
28+
VirtualNetworkInterface: vniPrototype,
29+
}
30+
31+
// Create instance prototype
32+
instancePrototype := &vpcv1.InstancePrototypeInstanceByImageInstanceByImageInstanceByNetworkAttachment{
33+
Image: &vpcv1.ImageIdentityByID{ID: &imageID},
34+
Zone: &vpcv1.ZoneIdentityByName{Name: &zoneName},
35+
Profile: &vpcv1.InstanceProfileIdentityByName{Name: &profileName},
36+
VPC: &vpcv1.VPCIdentityByID{ID: &vpcID},
37+
Name: &instanceName,
38+
PrimaryNetworkAttachment: primaryNetworkAttachment,
39+
}
40+
41+
// Verify fields are set
42+
if instancePrototype.Image == nil {
43+
t.Fatal("Image field should not be nil")
44+
}
45+
if instancePrototype.Zone == nil {
46+
t.Fatal("Zone field should not be nil")
47+
}
48+
if instancePrototype.VPC == nil {
49+
t.Fatal("VPC field should not be nil")
50+
}
51+
if instancePrototype.Profile == nil {
52+
t.Fatal("Profile field should not be nil")
53+
}
54+
55+
// Marshal to JSON
56+
jsonBytes, err := json.MarshalIndent(instancePrototype, "", " ")
57+
if err != nil {
58+
t.Fatalf("JSON marshaling failed: %v", err)
59+
}
60+
61+
jsonString := string(jsonBytes)
62+
t.Logf("Marshaled JSON:\n%s\n", jsonString)
63+
64+
// These assertions will FAIL if the bug exists
65+
if !strings.Contains(jsonString, `"image"`) {
66+
t.Error("JSON should contain image field - BUG CONFIRMED")
67+
}
68+
if !strings.Contains(jsonString, `"zone"`) {
69+
t.Error("JSON should contain zone field - BUG CONFIRMED")
70+
}
71+
if !strings.Contains(jsonString, `"vpc"`) {
72+
t.Error("JSON should contain vpc field - BUG CONFIRMED")
73+
}
74+
if !strings.Contains(jsonString, `"profile"`) {
75+
t.Error("JSON should contain profile field - BUG CONFIRMED")
76+
}
77+
78+
// Verify actual values
79+
if !strings.Contains(jsonString, imageID) {
80+
t.Error("JSON should contain image ID value")
81+
}
82+
if !strings.Contains(jsonString, zoneName) {
83+
t.Error("JSON should contain zone name value")
84+
}
85+
if !strings.Contains(jsonString, vpcID) {
86+
t.Error("JSON should contain VPC ID value")
87+
}
88+
if !strings.Contains(jsonString, profileName) {
89+
t.Error("JSON should contain profile name value")
90+
}
91+
}

0 commit comments

Comments
 (0)