diff --git a/api/v1alpha5/conversion.go b/api/v1alpha5/conversion.go index 19397b6956..b5d0cf0ff3 100644 --- a/api/v1alpha5/conversion.go +++ b/api/v1alpha5/conversion.go @@ -456,6 +456,10 @@ func Convert_v1alpha5_Instance_To_v1beta1_BastionStatus(in *Instance, out *infra out.State = infrav1.InstanceState(in.State) out.IP = in.IP out.FloatingIP = in.FloatingIP + + if out.Resolved == nil { + out.Resolved = &infrav1.ResolvedMachineSpec{} + } out.Resolved.ServerGroupID = in.ServerGroupID return nil } @@ -468,7 +472,9 @@ func Convert_v1beta1_BastionStatus_To_v1alpha5_Instance(in *infrav1.BastionStatu out.State = InstanceState(in.State) out.IP = in.IP out.FloatingIP = in.FloatingIP - out.ServerGroupID = in.Resolved.ServerGroupID + if in.Resolved != nil { + out.ServerGroupID = in.Resolved.ServerGroupID + } return nil } diff --git a/api/v1alpha5/conversion_test.go b/api/v1alpha5/conversion_test.go index 7fbf79bda6..cdac7a07be 100644 --- a/api/v1alpha5/conversion_test.go +++ b/api/v1alpha5/conversion_test.go @@ -17,14 +17,20 @@ limitations under the License. package v1alpha5 import ( + "runtime/debug" "testing" "github.com/onsi/gomega" + "github.com/onsi/gomega/format" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/kubernetes/scheme" + utilconversion "sigs.k8s.io/cluster-api/util/conversion" ctrlconversion "sigs.k8s.io/controller-runtime/pkg/conversion" infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" + testhelpers "sigs.k8s.io/cluster-api-provider-openstack/test/helpers" ) func TestConvertFrom(t *testing.T) { @@ -165,3 +171,68 @@ func TestConvert_v1alpha5_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(t }) } } + +type convertiblePointer[T any] interface { + ctrlconversion.Convertible + *T +} + +type hubPointer[T any] interface { + ctrlconversion.Hub + *T +} + +func test_ObjectConvert[SP convertiblePointer[S], HP hubPointer[H], S, H any](t *testing.T) { + t.Helper() + + fuzzerFuncs := func(_ runtimeserializer.CodecFactory) []interface{} { + return testhelpers.InfraV1FuzzerFuncs() + } + f := utilconversion.GetFuzzer(scheme.Scheme, fuzzerFuncs) + + for i := 0; i < 10000; i++ { + var hub HP = new(H) + f.Fuzz(hub) + var spoke SP = new(S) + + func() { + defer func() { + if r := recover(); r != nil { + t.Errorf("PANIC! Down-converting:\n%s\n%s", format.Object(hub, 1), debug.Stack()) + t.FailNow() + } + }() + spoke.ConvertFrom(hub) + }() + + spoke = new(S) + f.Fuzz(spoke) + hub = new(H) + + func() { + defer func() { + if r := recover(); r != nil { + t.Errorf("PANIC! Up-converting:\n%s\n%s", format.Object(spoke, 1), debug.Stack()) + t.FailNow() + } + }() + spoke.ConvertTo(hub) + }() + } +} + +func Test_OpenStackClusterConvert(t *testing.T) { + test_ObjectConvert[*OpenStackCluster, *infrav1.OpenStackCluster](t) +} + +func Test_OpenStackClusterTemplate(t *testing.T) { + test_ObjectConvert[*OpenStackClusterTemplate, *infrav1.OpenStackClusterTemplate](t) +} + +func Test_OpenStackMachineConvert(t *testing.T) { + test_ObjectConvert[*OpenStackMachine, *infrav1.OpenStackMachine](t) +} + +func Test_OpenStackMachineTemplateConvert(t *testing.T) { + test_ObjectConvert[*OpenStackMachineTemplate, *infrav1.OpenStackMachineTemplate](t) +}