diff --git a/api/v1alpha3/azuremachine_conversion.go b/api/v1alpha3/azuremachine_conversion.go index d242c93bed3..5f48457cec2 100644 --- a/api/v1alpha3/azuremachine_conversion.go +++ b/api/v1alpha3/azuremachine_conversion.go @@ -50,6 +50,10 @@ func (src *AzureMachine) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Image.SharedGallery.SKU = restored.Spec.Image.SharedGallery.SKU } + if dst.Spec.Image != nil && restored.Spec.Image.ComputeGallery != nil { + dst.Spec.Image.ComputeGallery = restored.Spec.Image.ComputeGallery + } + dst.Spec.SubnetName = restored.Spec.SubnetName dst.Status.LongRunningOperationStates = restored.Status.LongRunningOperationStates @@ -144,3 +148,23 @@ func Convert_v1beta1_ManagedDiskParameters_To_v1alpha3_ManagedDisk(in *v1beta1.M out.DiskEncryptionSet = (*DiskEncryptionSetParameters)(in.DiskEncryptionSet) return nil } + +func Convert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(in *v1beta1.AzureMarketplaceImage, out *AzureMarketplaceImage, s apiconversion.Scope) error { + out.Offer = in.ImagePlan.Offer + out.Publisher = in.ImagePlan.Publisher + out.SKU = in.ImagePlan.SKU + + return autoConvert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(in, out, s) +} + +func Convert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in *AzureMarketplaceImage, out *v1beta1.AzureMarketplaceImage, s apiconversion.Scope) error { + out.ImagePlan.Offer = in.Offer + out.ImagePlan.Publisher = in.Publisher + out.ImagePlan.SKU = in.SKU + + return autoConvert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in, out, s) +} + +func Convert_v1beta1_Image_To_v1alpha3_Image(in *v1beta1.Image, out *Image, s apiconversion.Scope) error { + return autoConvert_v1beta1_Image_To_v1alpha3_Image(in, out, s) +} diff --git a/api/v1alpha3/azuremachinetemplate_conversion.go b/api/v1alpha3/azuremachinetemplate_conversion.go index 12eca0d6208..f2ceb54ddbd 100644 --- a/api/v1alpha3/azuremachinetemplate_conversion.go +++ b/api/v1alpha3/azuremachinetemplate_conversion.go @@ -50,6 +50,10 @@ func (src *AzureMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Template.Spec.Image.SharedGallery.SKU = restored.Spec.Template.Spec.Image.SharedGallery.SKU } + if dst.Spec.Template.Spec.Image != nil && restored.Spec.Template.Spec.Image.ComputeGallery != nil { + dst.Spec.Template.Spec.Image.ComputeGallery = restored.Spec.Template.Spec.Image.ComputeGallery + } + dst.Spec.Template.Spec.SubnetName = restored.Spec.Template.Spec.SubnetName dst.Spec.Template.ObjectMeta = restored.Spec.Template.ObjectMeta diff --git a/api/v1alpha3/zz_generated.conversion.go b/api/v1alpha3/zz_generated.conversion.go index e704622644e..0325968d850 100644 --- a/api/v1alpha3/zz_generated.conversion.go +++ b/api/v1alpha3/zz_generated.conversion.go @@ -156,16 +156,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*AzureMarketplaceImage)(nil), (*v1beta1.AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(a.(*AzureMarketplaceImage), b.(*v1beta1.AzureMarketplaceImage), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta1.AzureMarketplaceImage)(nil), (*AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(a.(*v1beta1.AzureMarketplaceImage), b.(*AzureMarketplaceImage), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*AzureSharedGalleryImage)(nil), (*v1beta1.AzureSharedGalleryImage)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_AzureSharedGalleryImage_To_v1beta1_AzureSharedGalleryImage(a.(*AzureSharedGalleryImage), b.(*v1beta1.AzureSharedGalleryImage), scope) }); err != nil { @@ -216,11 +206,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta1.Image)(nil), (*Image)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_Image_To_v1alpha3_Image(a.(*v1beta1.Image), b.(*Image), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*PublicIPSpec)(nil), (*v1beta1.PublicIPSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_PublicIPSpec_To_v1beta1_PublicIPSpec(a.(*PublicIPSpec), b.(*v1beta1.PublicIPSpec), scope) }); err != nil { @@ -296,6 +281,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*AzureMarketplaceImage)(nil), (*v1beta1.AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(a.(*AzureMarketplaceImage), b.(*v1beta1.AzureMarketplaceImage), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*FrontendIP)(nil), (*v1beta1.FrontendIP)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha3_FrontendIP_To_v1beta1_FrontendIP(a.(*FrontendIP), b.(*v1beta1.FrontendIP), scope) }); err != nil { @@ -376,6 +366,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.AzureMarketplaceImage)(nil), (*AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(a.(*v1beta1.AzureMarketplaceImage), b.(*AzureMarketplaceImage), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.AzureSharedGalleryImage)(nil), (*AzureSharedGalleryImage)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_AzureSharedGalleryImage_To_v1alpha3_AzureSharedGalleryImage(a.(*v1beta1.AzureSharedGalleryImage), b.(*AzureSharedGalleryImage), scope) }); err != nil { @@ -391,6 +386,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.Image)(nil), (*Image)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_Image_To_v1alpha3_Image(a.(*v1beta1.Image), b.(*Image), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.LoadBalancerSpec)(nil), (*LoadBalancerSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_LoadBalancerSpec_To_v1alpha3_LoadBalancerSpec(a.(*v1beta1.LoadBalancerSpec), b.(*LoadBalancerSpec), scope) }); err != nil { @@ -1062,33 +1062,21 @@ func Convert_v1beta1_AzureMachineTemplateSpec_To_v1alpha3_AzureMachineTemplateSp } func autoConvert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in *AzureMarketplaceImage, out *v1beta1.AzureMarketplaceImage, s conversion.Scope) error { - out.Publisher = in.Publisher - out.Offer = in.Offer - out.SKU = in.SKU + // WARNING: in.Publisher requires manual conversion: does not exist in peer-type + // WARNING: in.Offer requires manual conversion: does not exist in peer-type + // WARNING: in.SKU requires manual conversion: does not exist in peer-type out.Version = in.Version out.ThirdPartyImage = in.ThirdPartyImage return nil } -// Convert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage is an autogenerated conversion function. -func Convert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in *AzureMarketplaceImage, out *v1beta1.AzureMarketplaceImage, s conversion.Scope) error { - return autoConvert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in, out, s) -} - func autoConvert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(in *v1beta1.AzureMarketplaceImage, out *AzureMarketplaceImage, s conversion.Scope) error { - out.Publisher = in.Publisher - out.Offer = in.Offer - out.SKU = in.SKU + // WARNING: in.ImagePlan requires manual conversion: does not exist in peer-type out.Version = in.Version out.ThirdPartyImage = in.ThirdPartyImage return nil } -// Convert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage is an autogenerated conversion function. -func Convert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(in *v1beta1.AzureMarketplaceImage, out *AzureMarketplaceImage, s conversion.Scope) error { - return autoConvert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(in, out, s) -} - func autoConvert_v1alpha3_AzureSharedGalleryImage_To_v1beta1_AzureSharedGalleryImage(in *AzureSharedGalleryImage, out *v1beta1.AzureSharedGalleryImage, s conversion.Scope) error { out.SubscriptionID = in.SubscriptionID out.ResourceGroup = in.ResourceGroup @@ -1271,7 +1259,15 @@ func autoConvert_v1alpha3_Image_To_v1beta1_Image(in *Image, out *v1beta1.Image, } else { out.SharedGallery = nil } - out.Marketplace = (*v1beta1.AzureMarketplaceImage)(unsafe.Pointer(in.Marketplace)) + if in.Marketplace != nil { + in, out := &in.Marketplace, &out.Marketplace + *out = new(v1beta1.AzureMarketplaceImage) + if err := Convert_v1alpha3_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(*in, *out, s); err != nil { + return err + } + } else { + out.Marketplace = nil + } return nil } @@ -1291,15 +1287,19 @@ func autoConvert_v1beta1_Image_To_v1alpha3_Image(in *v1beta1.Image, out *Image, } else { out.SharedGallery = nil } - out.Marketplace = (*AzureMarketplaceImage)(unsafe.Pointer(in.Marketplace)) + if in.Marketplace != nil { + in, out := &in.Marketplace, &out.Marketplace + *out = new(AzureMarketplaceImage) + if err := Convert_v1beta1_AzureMarketplaceImage_To_v1alpha3_AzureMarketplaceImage(*in, *out, s); err != nil { + return err + } + } else { + out.Marketplace = nil + } + // WARNING: in.ComputeGallery requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_Image_To_v1alpha3_Image is an autogenerated conversion function. -func Convert_v1beta1_Image_To_v1alpha3_Image(in *v1beta1.Image, out *Image, s conversion.Scope) error { - return autoConvert_v1beta1_Image_To_v1alpha3_Image(in, out, s) -} - func autoConvert_v1alpha3_LoadBalancerSpec_To_v1beta1_LoadBalancerSpec(in *LoadBalancerSpec, out *v1beta1.LoadBalancerSpec, s conversion.Scope) error { out.ID = in.ID out.Name = in.Name diff --git a/api/v1alpha4/azuremachine_conversion.go b/api/v1alpha4/azuremachine_conversion.go index b1103a78a41..c8cf37e76fa 100644 --- a/api/v1alpha4/azuremachine_conversion.go +++ b/api/v1alpha4/azuremachine_conversion.go @@ -17,20 +17,41 @@ limitations under the License. package v1alpha4 import ( + apiconversion "k8s.io/apimachinery/pkg/conversion" "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" + utilconversion "sigs.k8s.io/cluster-api/util/conversion" "sigs.k8s.io/controller-runtime/pkg/conversion" ) // ConvertTo converts this AzureMachine to the Hub version (v1beta1). func (src *AzureMachine) ConvertTo(dstRaw conversion.Hub) error { dst := dstRaw.(*v1beta1.AzureMachine) - return Convert_v1alpha4_AzureMachine_To_v1beta1_AzureMachine(src, dst, nil) + if err := Convert_v1alpha4_AzureMachine_To_v1beta1_AzureMachine(src, dst, nil); err != nil { + return err + } + + // Manually restore data from annotations + restored := &v1beta1.AzureMachine{} + if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { + return err + } + + if restored.Spec.Image != nil && restored.Spec.Image.ComputeGallery != nil { + dst.Spec.Image.ComputeGallery = restored.Spec.Image.ComputeGallery + } + + return nil } // ConvertFrom converts from the Hub version (v1beta1) to this version. func (dst *AzureMachine) ConvertFrom(srcRaw conversion.Hub) error { src := srcRaw.(*v1beta1.AzureMachine) - return Convert_v1beta1_AzureMachine_To_v1alpha4_AzureMachine(src, dst, nil) + if err := Convert_v1beta1_AzureMachine_To_v1alpha4_AzureMachine(src, dst, nil); err != nil { + return err + } + + // Preserve Hub data on down-conversion. + return utilconversion.MarshalData(src, dst) } // ConvertTo converts this AzureMachineList to the Hub version (v1beta1). @@ -44,3 +65,23 @@ func (dst *AzureMachineList) ConvertFrom(srcRaw conversion.Hub) error { src := srcRaw.(*v1beta1.AzureMachineList) return Convert_v1beta1_AzureMachineList_To_v1alpha4_AzureMachineList(src, dst, nil) } + +func Convert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(in *v1beta1.AzureMarketplaceImage, out *AzureMarketplaceImage, s apiconversion.Scope) error { + out.Offer = in.ImagePlan.Offer + out.Publisher = in.ImagePlan.Publisher + out.SKU = in.ImagePlan.SKU + + return autoConvert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(in, out, s) +} + +func Convert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in *AzureMarketplaceImage, out *v1beta1.AzureMarketplaceImage, s apiconversion.Scope) error { + out.ImagePlan.Offer = in.Offer + out.ImagePlan.Publisher = in.Publisher + out.ImagePlan.SKU = in.SKU + + return autoConvert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in, out, s) +} + +func Convert_v1beta1_Image_To_v1alpha4_Image(in *v1beta1.Image, out *Image, s apiconversion.Scope) error { + return autoConvert_v1beta1_Image_To_v1alpha4_Image(in, out, s) +} diff --git a/api/v1alpha4/azuremachinetemplate_conversion.go b/api/v1alpha4/azuremachinetemplate_conversion.go index 995aa2d425c..3b7e4e8ce9d 100644 --- a/api/v1alpha4/azuremachinetemplate_conversion.go +++ b/api/v1alpha4/azuremachinetemplate_conversion.go @@ -36,6 +36,10 @@ func (src *AzureMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { return err } + if dst.Spec.Template.Spec.Image != nil && restored.Spec.Template.Spec.Image.ComputeGallery != nil { + dst.Spec.Template.Spec.Image.ComputeGallery = restored.Spec.Template.Spec.Image.ComputeGallery + } + dst.Spec.Template.ObjectMeta = restored.Spec.Template.ObjectMeta return nil diff --git a/api/v1alpha4/zz_generated.conversion.go b/api/v1alpha4/zz_generated.conversion.go index 01e4eb9e6b8..daed97869ed 100644 --- a/api/v1alpha4/zz_generated.conversion.go +++ b/api/v1alpha4/zz_generated.conversion.go @@ -217,16 +217,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*AzureMarketplaceImage)(nil), (*v1beta1.AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(a.(*AzureMarketplaceImage), b.(*v1beta1.AzureMarketplaceImage), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta1.AzureMarketplaceImage)(nil), (*AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(a.(*v1beta1.AzureMarketplaceImage), b.(*AzureMarketplaceImage), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*AzureSharedGalleryImage)(nil), (*v1beta1.AzureSharedGalleryImage)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha4_AzureSharedGalleryImage_To_v1beta1_AzureSharedGalleryImage(a.(*AzureSharedGalleryImage), b.(*v1beta1.AzureSharedGalleryImage), scope) }); err != nil { @@ -322,11 +312,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta1.Image)(nil), (*Image)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_Image_To_v1alpha4_Image(a.(*v1beta1.Image), b.(*Image), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*ManagedDiskParameters)(nil), (*v1beta1.ManagedDiskParameters)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha4_ManagedDiskParameters_To_v1beta1_ManagedDiskParameters(a.(*ManagedDiskParameters), b.(*v1beta1.ManagedDiskParameters), scope) }); err != nil { @@ -432,6 +417,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*AzureMarketplaceImage)(nil), (*v1beta1.AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(a.(*AzureMarketplaceImage), b.(*v1beta1.AzureMarketplaceImage), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*FrontendIP)(nil), (*v1beta1.FrontendIP)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha4_FrontendIP_To_v1beta1_FrontendIP(a.(*FrontendIP), b.(*v1beta1.FrontendIP), scope) }); err != nil { @@ -477,11 +467,21 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.AzureMarketplaceImage)(nil), (*AzureMarketplaceImage)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(a.(*v1beta1.AzureMarketplaceImage), b.(*AzureMarketplaceImage), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.FrontendIP)(nil), (*FrontendIP)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_FrontendIP_To_v1alpha4_FrontendIP(a.(*v1beta1.FrontendIP), b.(*FrontendIP), scope) }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.Image)(nil), (*Image)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_Image_To_v1alpha4_Image(a.(*v1beta1.Image), b.(*Image), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.LoadBalancerSpec)(nil), (*LoadBalancerSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_LoadBalancerSpec_To_v1alpha4_LoadBalancerSpec(a.(*v1beta1.LoadBalancerSpec), b.(*LoadBalancerSpec), scope) }); err != nil { @@ -992,7 +992,15 @@ func autoConvert_v1alpha4_AzureMachineSpec_To_v1beta1_AzureMachineSpec(in *Azure out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID)) out.VMSize = in.VMSize out.FailureDomain = (*string)(unsafe.Pointer(in.FailureDomain)) - out.Image = (*v1beta1.Image)(unsafe.Pointer(in.Image)) + if in.Image != nil { + in, out := &in.Image, &out.Image + *out = new(v1beta1.Image) + if err := Convert_v1alpha4_Image_To_v1beta1_Image(*in, *out, s); err != nil { + return err + } + } else { + out.Image = nil + } out.Identity = v1beta1.VMIdentity(in.Identity) out.UserAssignedIdentities = *(*[]v1beta1.UserAssignedIdentity)(unsafe.Pointer(&in.UserAssignedIdentities)) out.RoleAssignmentName = in.RoleAssignmentName @@ -1020,7 +1028,15 @@ func autoConvert_v1beta1_AzureMachineSpec_To_v1alpha4_AzureMachineSpec(in *v1bet out.ProviderID = (*string)(unsafe.Pointer(in.ProviderID)) out.VMSize = in.VMSize out.FailureDomain = (*string)(unsafe.Pointer(in.FailureDomain)) - out.Image = (*Image)(unsafe.Pointer(in.Image)) + if in.Image != nil { + in, out := &in.Image, &out.Image + *out = new(Image) + if err := Convert_v1beta1_Image_To_v1alpha4_Image(*in, *out, s); err != nil { + return err + } + } else { + out.Image = nil + } out.Identity = VMIdentity(in.Identity) out.UserAssignedIdentities = *(*[]UserAssignedIdentity)(unsafe.Pointer(&in.UserAssignedIdentities)) out.RoleAssignmentName = in.RoleAssignmentName @@ -1209,33 +1225,21 @@ func Convert_v1beta1_AzureMachineTemplateSpec_To_v1alpha4_AzureMachineTemplateSp } func autoConvert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in *AzureMarketplaceImage, out *v1beta1.AzureMarketplaceImage, s conversion.Scope) error { - out.Publisher = in.Publisher - out.Offer = in.Offer - out.SKU = in.SKU + // WARNING: in.Publisher requires manual conversion: does not exist in peer-type + // WARNING: in.Offer requires manual conversion: does not exist in peer-type + // WARNING: in.SKU requires manual conversion: does not exist in peer-type out.Version = in.Version out.ThirdPartyImage = in.ThirdPartyImage return nil } -// Convert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage is an autogenerated conversion function. -func Convert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in *AzureMarketplaceImage, out *v1beta1.AzureMarketplaceImage, s conversion.Scope) error { - return autoConvert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(in, out, s) -} - func autoConvert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(in *v1beta1.AzureMarketplaceImage, out *AzureMarketplaceImage, s conversion.Scope) error { - out.Publisher = in.Publisher - out.Offer = in.Offer - out.SKU = in.SKU + // WARNING: in.ImagePlan requires manual conversion: does not exist in peer-type out.Version = in.Version out.ThirdPartyImage = in.ThirdPartyImage return nil } -// Convert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage is an autogenerated conversion function. -func Convert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(in *v1beta1.AzureMarketplaceImage, out *AzureMarketplaceImage, s conversion.Scope) error { - return autoConvert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(in, out, s) -} - func autoConvert_v1alpha4_AzureSharedGalleryImage_To_v1beta1_AzureSharedGalleryImage(in *AzureSharedGalleryImage, out *v1beta1.AzureSharedGalleryImage, s conversion.Scope) error { out.SubscriptionID = in.SubscriptionID out.ResourceGroup = in.ResourceGroup @@ -1503,7 +1507,15 @@ func Convert_v1beta1_Future_To_v1alpha4_Future(in *v1beta1.Future, out *Future, func autoConvert_v1alpha4_Image_To_v1beta1_Image(in *Image, out *v1beta1.Image, s conversion.Scope) error { out.ID = (*string)(unsafe.Pointer(in.ID)) out.SharedGallery = (*v1beta1.AzureSharedGalleryImage)(unsafe.Pointer(in.SharedGallery)) - out.Marketplace = (*v1beta1.AzureMarketplaceImage)(unsafe.Pointer(in.Marketplace)) + if in.Marketplace != nil { + in, out := &in.Marketplace, &out.Marketplace + *out = new(v1beta1.AzureMarketplaceImage) + if err := Convert_v1alpha4_AzureMarketplaceImage_To_v1beta1_AzureMarketplaceImage(*in, *out, s); err != nil { + return err + } + } else { + out.Marketplace = nil + } return nil } @@ -1515,15 +1527,19 @@ func Convert_v1alpha4_Image_To_v1beta1_Image(in *Image, out *v1beta1.Image, s co func autoConvert_v1beta1_Image_To_v1alpha4_Image(in *v1beta1.Image, out *Image, s conversion.Scope) error { out.ID = (*string)(unsafe.Pointer(in.ID)) out.SharedGallery = (*AzureSharedGalleryImage)(unsafe.Pointer(in.SharedGallery)) - out.Marketplace = (*AzureMarketplaceImage)(unsafe.Pointer(in.Marketplace)) + if in.Marketplace != nil { + in, out := &in.Marketplace, &out.Marketplace + *out = new(AzureMarketplaceImage) + if err := Convert_v1beta1_AzureMarketplaceImage_To_v1alpha4_AzureMarketplaceImage(*in, *out, s); err != nil { + return err + } + } else { + out.Marketplace = nil + } + // WARNING: in.ComputeGallery requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_Image_To_v1alpha4_Image is an autogenerated conversion function. -func Convert_v1beta1_Image_To_v1alpha4_Image(in *v1beta1.Image, out *Image, s conversion.Scope) error { - return autoConvert_v1beta1_Image_To_v1alpha4_Image(in, out, s) -} - func autoConvert_v1alpha4_LoadBalancerSpec_To_v1beta1_LoadBalancerSpec(in *LoadBalancerSpec, out *v1beta1.LoadBalancerSpec, s conversion.Scope) error { out.ID = in.ID out.Name = in.Name diff --git a/api/v1beta1/azureimage_validation.go b/api/v1beta1/azureimage_validation.go index ac6d14dcb94..42eba08b1c6 100644 --- a/api/v1beta1/azureimage_validation.go +++ b/api/v1beta1/azureimage_validation.go @@ -40,6 +40,9 @@ func ValidateImage(image *Image, fldPath *field.Path) field.ErrorList { if image.ID != nil { allErrs = append(allErrs, validateSpecificImage(image, fldPath)...) } + if image.ComputeGallery != nil { + allErrs = append(allErrs, validateComputeGalleryImage(image, fldPath)...) + } return allErrs } @@ -62,14 +65,35 @@ func validateSingleDetailsOnly(image *Image, fldPath *field.Path) field.ErrorLis if image.SharedGallery != nil { if imageDetailsFound { - allErrs = append(allErrs, field.Forbidden(fldPath.Child("SharedGallery"), "SharedGallery cannot be used as an image ID or Marketplace images has been specified")) + allErrs = append(allErrs, field.Forbidden(fldPath.Child("SharedGallery"), "SharedGallery cannot be used as an image ID. Marketplace or ComputeGallery images has been specified")) + } else { + imageDetailsFound = true + } + } + + if image.ComputeGallery != nil { + if imageDetailsFound { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("ComputeGallery"), "ComputeGallery cannot be used as an image ID. Marketplace or SharedGallery images has been specified")) } else { imageDetailsFound = true } } if !imageDetailsFound { - allErrs = append(allErrs, field.Required(fldPath, "You must supply a ID, Marketplace or SharedGallery image details")) + allErrs = append(allErrs, field.Required(fldPath, "You must supply an ID, Marketplace or ComputeGallery image details")) + } + + return allErrs +} + +func validateComputeGalleryImage(image *Image, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if image.ComputeGallery.SubscriptionID != nil && image.ComputeGallery.ResourceGroup == nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("ResourceGroup"), "", "ResourceGroup cannot be empty when SubscriptionID is specified")) + } + if image.ComputeGallery.ResourceGroup != nil && image.ComputeGallery.SubscriptionID == nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("SubscriptionID"), "", "SubscriptionID cannot be empty when ResourceGroup is specified")) } return allErrs diff --git a/api/v1beta1/azureimage_validation_test.go b/api/v1beta1/azureimage_validation_test.go index 06fe263d898..b22bbff2d0e 100644 --- a/api/v1beta1/azureimage_validation_test.go +++ b/api/v1beta1/azureimage_validation_test.go @@ -19,6 +19,7 @@ package v1beta1 import ( "testing" + "github.com/Azure/go-autorest/autorest/to" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/util/validation/field" ) @@ -41,10 +42,12 @@ func TestImageTooManyDetails(t *testing.T) { image := &Image{ Marketplace: &AzureMarketplaceImage{ - Offer: "OFFER", - Publisher: "PUBLISHER", - SKU: "SKU", - Version: "1.0.0.", + ImagePlan: ImagePlan{ + Offer: "OFFER", + Publisher: "PUBLISHER", + SKU: "SKU", + }, + Version: "1.0.0.", }, SharedGallery: &AzureSharedGalleryImage{ Gallery: "GALLERY", @@ -58,6 +61,36 @@ func TestImageTooManyDetails(t *testing.T) { g.Expect(ValidateImage(image, field.NewPath("image"))).To(HaveLen(1)) } +func TestComputeImageGalleryValid(t *testing.T) { + g := NewWithT(t) + + testCases := map[string]struct { + image *Image + expectedErrors int + }{ + "AzureComputeGalleryImage - fully specified community image": { + expectedErrors: 0, + image: createTestComputeImage(nil, nil), + }, + "AzureComputeGalleryImage - fully specified private image": { + expectedErrors: 0, + image: createTestComputeImage(to.StringPtr("SUB1234"), to.StringPtr("RG1234")), + }, + "AzureComputeGalleryImage - private image with missing subscription": { + expectedErrors: 1, + image: createTestComputeImage(nil, to.StringPtr("RG1234")), + }, + "AzureComputeGalleryImage - private image with missing resource group": { + expectedErrors: 1, + image: createTestComputeImage(to.StringPtr("SUB1234"), nil), + }, + } + + for _, tc := range testCases { + g.Expect(ValidateImage(tc.image, field.NewPath("image"))).To(HaveLen(tc.expectedErrors)) + } +} + func TestSharedImageGalleryValid(t *testing.T) { g := NewWithT(t) @@ -152,6 +185,18 @@ func TestImageByIDValid(t *testing.T) { } } +func createTestComputeImage(subscriptionID, resourceGroup *string) *Image { + return &Image{ + ComputeGallery: &AzureComputeGalleryImage{ + Name: "IMAGENAME", + Gallery: "GALLERY9876", + Version: "1.0.0", + SubscriptionID: subscriptionID, + ResourceGroup: resourceGroup, + }, + } +} + func createTestSharedImage(subscriptionID, resourceGroup, name, gallery, version string) *Image { return &Image{ SharedGallery: &AzureSharedGalleryImage{ @@ -167,10 +212,12 @@ func createTestSharedImage(subscriptionID, resourceGroup, name, gallery, version func createTestMarketPlaceImage(publisher, offer, sku, version string) *Image { return &Image{ Marketplace: &AzureMarketplaceImage{ - Publisher: publisher, - Offer: offer, - SKU: sku, - Version: version, + ImagePlan: ImagePlan{ + Publisher: publisher, + Offer: offer, + SKU: sku, + }, + Version: version, }, } } diff --git a/api/v1beta1/azuremachine_webhook_test.go b/api/v1beta1/azuremachine_webhook_test.go index a278ec92b45..75a5815f212 100644 --- a/api/v1beta1/azuremachine_webhook_test.go +++ b/api/v1beta1/azuremachine_webhook_test.go @@ -40,12 +40,12 @@ func TestAzureMachine_ValidateCreate(t *testing.T) { }{ { name: "azuremachine with marketplace image - full", - machine: createMachineWithtMarketPlaceImage("PUB1234", "OFFER1234", "SKU1234", "1.0.0"), + machine: createMachineWithMarketPlaceImage("PUB1234", "OFFER1234", "SKU1234", "1.0.0"), wantErr: false, }, { name: "azuremachine with marketplace image - missing publisher", - machine: createMachineWithtMarketPlaceImage("", "OFFER1235", "SKU1235", "2.0.0"), + machine: createMachineWithMarketPlaceImage("", "OFFER1235", "SKU1235", "2.0.0"), wantErr: true, }, { @@ -570,13 +570,15 @@ func createMachineWithSharedImage(subscriptionID, resourceGroup, name, gallery, } } -func createMachineWithtMarketPlaceImage(publisher, offer, sku, version string) *AzureMachine { +func createMachineWithMarketPlaceImage(publisher, offer, sku, version string) *AzureMachine { image := &Image{ Marketplace: &AzureMarketplaceImage{ - Publisher: publisher, - Offer: offer, - SKU: sku, - Version: version, + ImagePlan: ImagePlan{ + Publisher: publisher, + Offer: offer, + SKU: sku, + }, + Version: version, }, } diff --git a/api/v1beta1/azuremachinetemplate_webhook_test.go b/api/v1beta1/azuremachinetemplate_webhook_test.go index 843fbb06aae..7e462f2378f 100644 --- a/api/v1beta1/azuremachinetemplate_webhook_test.go +++ b/api/v1beta1/azuremachinetemplate_webhook_test.go @@ -36,14 +36,14 @@ func TestAzureMachineTemplate_ValidateCreate(t *testing.T) { { name: "azuremachinetemplate with marketplane image - full", machineTemplate: createAzureMachineTemplateFromMachine( - createMachineWithtMarketPlaceImage("PUB1234", "OFFER1234", "SKU1234", "1.0.0"), + createMachineWithMarketPlaceImage("PUB1234", "OFFER1234", "SKU1234", "1.0.0"), ), wantErr: false, }, { name: "azuremachinetemplate with marketplace image - missing publisher", machineTemplate: createAzureMachineTemplateFromMachine( - createMachineWithtMarketPlaceImage("", "OFFER1234", "SKU1234", "1.0.0"), + createMachineWithMarketPlaceImage("", "OFFER1234", "SKU1234", "1.0.0"), ), wantErr: true, }, diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index 55db677cf5a..7907eecf493 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -318,16 +318,46 @@ type Image struct { ID *string `json:"id,omitempty"` // SharedGallery specifies an image to use from an Azure Shared Image Gallery + // Deprecated: use ComputeGallery instead. // +optional SharedGallery *AzureSharedGalleryImage `json:"sharedGallery,omitempty"` // Marketplace specifies an image to use from the Azure Marketplace // +optional Marketplace *AzureMarketplaceImage `json:"marketplace,omitempty"` + + // ComputeGallery specifies an image to use from the Azure Compute Gallery + // +optional + ComputeGallery *AzureComputeGalleryImage `json:"computeGallery,omitempty"` } -// AzureMarketplaceImage defines an image in the Azure Marketplace to use for VM creation. -type AzureMarketplaceImage struct { +// AzureComputeGalleryImage defines an image in the Azure Compute Gallery to use for VM creation. +type AzureComputeGalleryImage struct { + // Gallery specifies the name of the compute image gallery that contains the image + // +kubebuilder:validation:MinLength=1 + Gallery string `json:"gallery"` + // Name is the name of the image + // +kubebuilder:validation:MinLength=1 + Name string `json:"name"` + // Version specifies the version of the marketplace image. The allowed formats + // are Major.Minor.Build or 'latest'. Major, Minor, and Build are decimal numbers. + // Specify 'latest' to use the latest version of an image available at deploy time. + // Even if you use 'latest', the VM image will not automatically update after deploy + // time even if a new version becomes available. + // +kubebuilder:validation:MinLength=1 + Version string `json:"version"` + // SubscriptionID is the identifier of the subscription that contains the private compute gallery. + // +optional + SubscriptionID *string `json:"subscriptionID,omitempty"` + // ResourceGroup specifies the resource group containing the private compute gallery. + // +optional + ResourceGroup *string `json:"resourceGroup,omitempty"` + // Plan contains plan information. + // +optional + Plan *ImagePlan `json:"plan,omitempty"` +} + +type ImagePlan struct { // Publisher is the name of the organization that created the image // +kubebuilder:validation:MinLength=1 Publisher string `json:"publisher"` @@ -339,6 +369,12 @@ type AzureMarketplaceImage struct { // For example, 18.04-LTS, 2019-Datacenter // +kubebuilder:validation:MinLength=1 SKU string `json:"sku"` +} + +// AzureMarketplaceImage defines an image in the Azure Marketplace to use for VM creation. +type AzureMarketplaceImage struct { + ImagePlan `json:",inline"` + // Version specifies the version of an image sku. The allowed formats // are Major.Minor.Build or 'latest'. Major, Minor, and Build are decimal numbers. // Specify 'latest' to use the latest version of an image available at deploy time. diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index dc9893816b2..2516b5c557b 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -456,6 +456,36 @@ func (in *AzureClusterTemplateSpec) DeepCopy() *AzureClusterTemplateSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureComputeGalleryImage) DeepCopyInto(out *AzureComputeGalleryImage) { + *out = *in + if in.SubscriptionID != nil { + in, out := &in.SubscriptionID, &out.SubscriptionID + *out = new(string) + **out = **in + } + if in.ResourceGroup != nil { + in, out := &in.ResourceGroup, &out.ResourceGroup + *out = new(string) + **out = **in + } + if in.Plan != nil { + in, out := &in.Plan, &out.Plan + *out = new(ImagePlan) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureComputeGalleryImage. +func (in *AzureComputeGalleryImage) DeepCopy() *AzureComputeGalleryImage { + if in == nil { + return nil + } + out := new(AzureComputeGalleryImage) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureMachine) DeepCopyInto(out *AzureMachine) { *out = *in @@ -721,6 +751,7 @@ func (in *AzureMachineTemplateSpec) DeepCopy() *AzureMachineTemplateSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureMarketplaceImage) DeepCopyInto(out *AzureMarketplaceImage) { *out = *in + out.ImagePlan = in.ImagePlan } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureMarketplaceImage. @@ -1026,6 +1057,11 @@ func (in *Image) DeepCopyInto(out *Image) { *out = new(AzureMarketplaceImage) **out = **in } + if in.ComputeGallery != nil { + in, out := &in.ComputeGallery, &out.ComputeGallery + *out = new(AzureComputeGalleryImage) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image. @@ -1038,6 +1074,21 @@ func (in *Image) DeepCopy() *Image { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImagePlan) DeepCopyInto(out *ImagePlan) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePlan. +func (in *ImagePlan) DeepCopy() *ImagePlan { + if in == nil { + return nil + } + out := new(ImagePlan) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LoadBalancerClassSpec) DeepCopyInto(out *LoadBalancerClassSpec) { *out = *in diff --git a/azure/converters/image.go b/azure/converters/image.go index 5526d66d4d2..5e32334ce66 100644 --- a/azure/converters/image.go +++ b/azure/converters/image.go @@ -33,8 +33,8 @@ func ImageToSDK(image *infrav1.Image) (*compute.ImageReference, error) { if image.Marketplace != nil { return mpImageToSDK(image) } - if image.SharedGallery != nil { - return sigImageToSDK(image) + if image.ComputeGallery != nil || image.SharedGallery != nil { + return computeImageToSDK(image) } return nil, errors.New("unable to convert image as no options set") @@ -49,16 +49,40 @@ func mpImageToSDK(image *infrav1.Image) (*compute.ImageReference, error) { }, nil } -func sigImageToSDK(image *infrav1.Image) (*compute.ImageReference, error) { - imageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/%s/images/%s/versions/%s", - image.SharedGallery.SubscriptionID, - image.SharedGallery.ResourceGroup, - image.SharedGallery.Gallery, - image.SharedGallery.Name, - image.SharedGallery.Version) +func computeImageToSDK(image *infrav1.Image) (*compute.ImageReference, error) { + idTemplate := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/%s/images/%s/versions/%s" + + if image.SharedGallery != nil { + return &compute.ImageReference{ + ID: to.StringPtr(fmt.Sprintf(idTemplate, + image.SharedGallery.SubscriptionID, + image.SharedGallery.ResourceGroup, + image.SharedGallery.Gallery, + image.SharedGallery.Name, + image.SharedGallery.Version, + )), + }, nil + } + + // For private Azure Compute Gallery consumption both resource group and subscription ID must be provided. + // If they are not, we assume use of community gallery. + if image.ComputeGallery.ResourceGroup != nil && image.ComputeGallery.SubscriptionID != nil { + return &compute.ImageReference{ + ID: to.StringPtr(fmt.Sprintf(idTemplate, + image.ComputeGallery.SubscriptionID, + image.ComputeGallery.ResourceGroup, + image.ComputeGallery.Gallery, + image.ComputeGallery.Name, + image.ComputeGallery.Version, + )), + }, nil + } return &compute.ImageReference{ - ID: &imageID, + CommunityGalleryImageID: to.StringPtr(fmt.Sprintf("/CommunityGalleries/%s/Images/%s/Versions/%s", + image.ComputeGallery.Gallery, + image.ComputeGallery.Name, + image.ComputeGallery.Version)), }, nil } @@ -88,6 +112,15 @@ func ImageToPlan(image *infrav1.Image) *compute.Plan { } } + // Plan is needed when using a Azure Compute Gallery image with Plan details. + if image.ComputeGallery != nil && image.ComputeGallery.Plan != nil { + return &compute.Plan{ + Publisher: to.StringPtr(image.ComputeGallery.Plan.Publisher), + Name: to.StringPtr(image.ComputeGallery.Plan.SKU), + Product: to.StringPtr(image.ComputeGallery.Plan.Offer), + } + } + // Otherwise return nil. return nil } diff --git a/azure/converters/image_test.go b/azure/converters/image_test.go index b80bbd21173..abe985bf6ca 100644 --- a/azure/converters/image_test.go +++ b/azure/converters/image_test.go @@ -31,6 +31,25 @@ func Test_ImageToPlan(t *testing.T) { image *infrav1.Image expect func(*GomegaWithT, *compute.Plan) }{ + { + name: "Should return a plan for a Community Gallery image with plan details", + image: &infrav1.Image{ + ComputeGallery: &infrav1.AzureComputeGalleryImage{ + Plan: &infrav1.ImagePlan{ + Publisher: "my-publisher", + Offer: "my-offer", + SKU: "my-sku", + }, + }, + }, + expect: func(g *GomegaWithT, result *compute.Plan) { + g.Expect(result).To(Equal(&compute.Plan{ + Name: to.StringPtr("my-sku"), + Publisher: to.StringPtr("my-publisher"), + Product: to.StringPtr("my-offer"), + })) + }, + }, { name: "Should return a plan for a SIG image with plan details", image: &infrav1.Image{ @@ -72,9 +91,11 @@ func Test_ImageToPlan(t *testing.T) { name: "Should return nil for a Marketplace first party image", image: &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "my-publisher", - Offer: "my-offer", - SKU: "my-sku", + ImagePlan: infrav1.ImagePlan{ + Publisher: "my-publisher", + Offer: "my-offer", + SKU: "my-sku", + }, Version: "v0.5.0", ThirdPartyImage: false, }, @@ -87,9 +108,11 @@ func Test_ImageToPlan(t *testing.T) { name: "Should return a plan for a Marketplace third party image", image: &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "my-publisher", - Offer: "my-offer", - SKU: "my-sku", + ImagePlan: infrav1.ImagePlan{ + Publisher: "my-publisher", + Offer: "my-offer", + SKU: "my-sku", + }, Version: "v0.5.0", ThirdPartyImage: true, }, diff --git a/azure/converters/vmss.go b/azure/converters/vmss.go index 41f16c8db8f..78aeb4fe253 100644 --- a/azure/converters/vmss.go +++ b/azure/converters/vmss.go @@ -99,9 +99,11 @@ func SDKImageToImage(sdkImageRef *compute.ImageReference, isThirdPartyImage bool return infrav1.Image{ ID: sdkImageRef.ID, Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: to.String(sdkImageRef.Publisher), - Offer: to.String(sdkImageRef.Offer), - SKU: to.String(sdkImageRef.Sku), + ImagePlan: infrav1.ImagePlan{ + Publisher: to.String(sdkImageRef.Publisher), + Offer: to.String(sdkImageRef.Offer), + SKU: to.String(sdkImageRef.Sku), + }, Version: to.String(sdkImageRef.Version), ThirdPartyImage: isThirdPartyImage, }, diff --git a/azure/scope/machinepool_test.go b/azure/scope/machinepool_test.go index a9ee7d14773..4fc5c144573 100644 --- a/azure/scope/machinepool_test.go +++ b/azure/scope/machinepool_test.go @@ -284,9 +284,11 @@ func TestMachinePoolScope_SaveVMImageToStatus(t *testing.T) { } image = &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "cncf-upstream", - Offer: "capi", - SKU: "k8s-1dot19dot11-ubuntu-1804", + ImagePlan: infrav1.ImagePlan{ + Publisher: "cncf-upstream", + Offer: "capi", + SKU: "k8s-1dot19dot11-ubuntu-1804", + }, Version: "latest", ThirdPartyImage: false, }, @@ -322,9 +324,11 @@ func TestMachinePoolScope_GetVMImage(t *testing.T) { g.Expect(err).NotTo(HaveOccurred()) image := &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "cncf-upstream", - Offer: "capi", - SKU: "k8s-1dot19dot11-ubuntu-1804", + ImagePlan: infrav1.ImagePlan{ + Publisher: "cncf-upstream", + Offer: "capi", + SKU: "k8s-1dot19dot11-ubuntu-1804", + }, Version: "latest", ThirdPartyImage: false, }, @@ -339,9 +343,11 @@ func TestMachinePoolScope_GetVMImage(t *testing.T) { mp.Spec.Template.Spec.Version = to.StringPtr("v1.19.11") amp.Spec.Template.Image = &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "cncf-upstream", - Offer: "capi", - SKU: "k8s-1dot19dot19-ubuntu-1804", + ImagePlan: infrav1.ImagePlan{ + Publisher: "cncf-upstream", + Offer: "capi", + SKU: "k8s-1dot19dot19-ubuntu-1804", + }, Version: "latest", ThirdPartyImage: false, }, @@ -351,9 +357,11 @@ func TestMachinePoolScope_GetVMImage(t *testing.T) { g.Expect(err).NotTo(HaveOccurred()) image := &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "cncf-upstream", - Offer: "capi", - SKU: "k8s-1dot19dot19-ubuntu-1804", + ImagePlan: infrav1.ImagePlan{ + Publisher: "cncf-upstream", + Offer: "capi", + SKU: "k8s-1dot19dot19-ubuntu-1804", + }, Version: "latest", ThirdPartyImage: false, }, diff --git a/azure/scope/machinepoolmachine_test.go b/azure/scope/machinepoolmachine_test.go index bb1c2329d88..ea4d4ae91a9 100644 --- a/azure/scope/machinepoolmachine_test.go +++ b/azure/scope/machinepoolmachine_test.go @@ -249,10 +249,12 @@ func TestMachineScope_UpdateStatus(t *testing.T) { State: v1beta1.Succeeded, Image: v1beta1.Image{ Marketplace: &v1beta1.AzureMarketplaceImage{ - Publisher: "cncf-upstream", - Offer: "capi", - SKU: "k8s-1dot19dot11-ubuntu-1804", - Version: "latest", + ImagePlan: v1beta1.ImagePlan{ + Publisher: "cncf-upstream", + Offer: "capi", + SKU: "k8s-1dot19dot11-ubuntu-1804", + }, + Version: "latest", }, }, }, ampm diff --git a/azure/services/scalesets/scalesets_test.go b/azure/services/scalesets/scalesets_test.go index 283dc81bc8f..b252c5e77a1 100644 --- a/azure/services/scalesets/scalesets_test.go +++ b/azure/services/scalesets/scalesets_test.go @@ -699,7 +699,7 @@ func getFakeSkus() []compute.ResourceSku { { Location: to.StringPtr("test-location"), Zones: &[]string{"1", "3"}, - //ZoneDetails: &[]compute.ResourceSkuZoneDetails{ + // ZoneDetails: &[]compute.ResourceSkuZoneDetails{ // { // Capabilities: &[]compute.ResourceSkuCapabilities{ // { @@ -1190,10 +1190,12 @@ func setupDefaultVMSSExpectations(s *mock_scalesets.MockScaleSetScopeMockRecorde setupVMSSExpectationsWithoutVMImage(s) image := &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "fake-publisher", - Offer: "my-offer", - SKU: "sku-id", - Version: "1.0", + ImagePlan: infrav1.ImagePlan{ + Publisher: "fake-publisher", + Offer: "my-offer", + SKU: "sku-id", + }, + Version: "1.0", }, } s.GetVMImage(gomockinternal.AContext()).Return(image, nil).AnyTimes() @@ -1204,10 +1206,12 @@ func setupUpdateVMSSExpectations(s *mock_scalesets.MockScaleSetScopeMockRecorder setupVMSSExpectationsWithoutVMImage(s) image := &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "fake-publisher", - Offer: "my-offer", - SKU: "sku-id", - Version: "2.0", + ImagePlan: infrav1.ImagePlan{ + Publisher: "fake-publisher", + Offer: "my-offer", + SKU: "sku-id", + }, + Version: "2.0", }, } s.GetVMImage(gomockinternal.AContext()).Return(image, nil).AnyTimes() diff --git a/azure/services/virtualmachineimages/images.go b/azure/services/virtualmachineimages/images.go index ff6d8870b06..bd88849c969 100644 --- a/azure/services/virtualmachineimages/images.go +++ b/azure/services/virtualmachineimages/images.go @@ -60,10 +60,12 @@ func (s *Service) GetDefaultUbuntuImage(ctx context.Context, location, k8sVersio defaultImage := &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: publisher, - Offer: offer, - SKU: skuID, - Version: version, + ImagePlan: infrav1.ImagePlan{ + Publisher: publisher, + Offer: offer, + SKU: skuID, + }, + Version: version, }, } @@ -101,10 +103,12 @@ func (s *Service) GetDefaultWindowsImage(ctx context.Context, location, k8sVersi defaultImage := &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: publisher, - Offer: offer, - SKU: skuID, - Version: version, + ImagePlan: infrav1.ImagePlan{ + Publisher: publisher, + Offer: offer, + SKU: skuID, + }, + Version: version, }, } diff --git a/azure/services/virtualmachines/spec_test.go b/azure/services/virtualmachines/spec_test.go index 7495a75732b..60e03345843 100644 --- a/azure/services/virtualmachines/spec_test.go +++ b/azure/services/virtualmachines/spec_test.go @@ -483,9 +483,11 @@ func TestParameters(t *testing.T) { Size: "Standard_D2v3", Image: &infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: "fake-publisher", - Offer: "my-offer", - SKU: "sku-id", + ImagePlan: infrav1.ImagePlan{ + Publisher: "fake-publisher", + Offer: "my-offer", + SKU: "sku-id", + }, Version: "1.0", ThirdPartyImage: true, }, diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinepools.yaml index 628f593ed0e..a45716ba497 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinepools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinepools.yaml @@ -1532,6 +1532,67 @@ spec: default the Azure Marketplace "capi" offer, which is based on Ubuntu. properties: + computeGallery: + description: ComputeGallery specifies an image to use from + the Azure Compute Gallery + properties: + gallery: + description: Gallery specifies the name of the compute + image gallery that contains the image + minLength: 1 + type: string + name: + description: Name is the name of the image + minLength: 1 + type: string + plan: + description: Plan contains plan information. + properties: + offer: + description: Offer specifies the name of a group of + related images created by the publisher. For example, + UbuntuServer, WindowsServer + minLength: 1 + type: string + publisher: + description: Publisher is the name of the organization + that created the image + minLength: 1 + type: string + sku: + description: SKU specifies an instance of an offer, + such as a major release of a distribution. For example, + 18.04-LTS, 2019-Datacenter + minLength: 1 + type: string + required: + - offer + - publisher + - sku + type: object + resourceGroup: + description: ResourceGroup specifies the resource group + containing the private compute gallery. + type: string + subscriptionID: + description: SubscriptionID is the identifier of the subscription + that contains the private compute gallery. + type: string + version: + description: Version specifies the version of the marketplace + image. The allowed formats are Major.Minor.Build or + 'latest'. Major, Minor, and Build are decimal numbers. + Specify 'latest' to use the latest version of an image + available at deploy time. Even if you use 'latest', + the VM image will not automatically update after deploy + time even if a new version becomes available. + minLength: 1 + type: string + required: + - gallery + - name + - version + type: object id: description: ID specifies an image to use by ID type: string @@ -1579,8 +1640,9 @@ spec: - version type: object sharedGallery: - description: SharedGallery specifies an image to use from - an Azure Shared Image Gallery + description: 'SharedGallery specifies an image to use from + an Azure Shared Image Gallery Deprecated: use ComputeGallery + instead.' properties: gallery: description: Gallery specifies the name of the shared @@ -1845,6 +1907,66 @@ spec: When the spec image is nil, this image is populated with the details of the defaulted Azure Marketplace "capi" offer. properties: + computeGallery: + description: ComputeGallery specifies an image to use from the + Azure Compute Gallery + properties: + gallery: + description: Gallery specifies the name of the compute image + gallery that contains the image + minLength: 1 + type: string + name: + description: Name is the name of the image + minLength: 1 + type: string + plan: + description: Plan contains plan information. + properties: + offer: + description: Offer specifies the name of a group of related + images created by the publisher. For example, UbuntuServer, + WindowsServer + minLength: 1 + type: string + publisher: + description: Publisher is the name of the organization + that created the image + minLength: 1 + type: string + sku: + description: SKU specifies an instance of an offer, such + as a major release of a distribution. For example, 18.04-LTS, + 2019-Datacenter + minLength: 1 + type: string + required: + - offer + - publisher + - sku + type: object + resourceGroup: + description: ResourceGroup specifies the resource group containing + the private compute gallery. + type: string + subscriptionID: + description: SubscriptionID is the identifier of the subscription + that contains the private compute gallery. + type: string + version: + description: Version specifies the version of the marketplace + image. The allowed formats are Major.Minor.Build or 'latest'. + Major, Minor, and Build are decimal numbers. Specify 'latest' + to use the latest version of an image available at deploy + time. Even if you use 'latest', the VM image will not automatically + update after deploy time even if a new version becomes available. + minLength: 1 + type: string + required: + - gallery + - name + - version + type: object id: description: ID specifies an image to use by ID type: string @@ -1891,8 +2013,8 @@ spec: - version type: object sharedGallery: - description: SharedGallery specifies an image to use from an Azure - Shared Image Gallery + description: 'SharedGallery specifies an image to use from an + Azure Shared Image Gallery Deprecated: use ComputeGallery instead.' properties: gallery: description: Gallery specifies the name of the shared image diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml index 325dc7c9583..f7fa1fcc67f 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml @@ -1144,6 +1144,66 @@ spec: VM creation. If image details are omitted the image will default the Azure Marketplace "capi" offer, which is based on Ubuntu. properties: + computeGallery: + description: ComputeGallery specifies an image to use from the + Azure Compute Gallery + properties: + gallery: + description: Gallery specifies the name of the compute image + gallery that contains the image + minLength: 1 + type: string + name: + description: Name is the name of the image + minLength: 1 + type: string + plan: + description: Plan contains plan information. + properties: + offer: + description: Offer specifies the name of a group of related + images created by the publisher. For example, UbuntuServer, + WindowsServer + minLength: 1 + type: string + publisher: + description: Publisher is the name of the organization + that created the image + minLength: 1 + type: string + sku: + description: SKU specifies an instance of an offer, such + as a major release of a distribution. For example, 18.04-LTS, + 2019-Datacenter + minLength: 1 + type: string + required: + - offer + - publisher + - sku + type: object + resourceGroup: + description: ResourceGroup specifies the resource group containing + the private compute gallery. + type: string + subscriptionID: + description: SubscriptionID is the identifier of the subscription + that contains the private compute gallery. + type: string + version: + description: Version specifies the version of the marketplace + image. The allowed formats are Major.Minor.Build or 'latest'. + Major, Minor, and Build are decimal numbers. Specify 'latest' + to use the latest version of an image available at deploy + time. Even if you use 'latest', the VM image will not automatically + update after deploy time even if a new version becomes available. + minLength: 1 + type: string + required: + - gallery + - name + - version + type: object id: description: ID specifies an image to use by ID type: string @@ -1190,8 +1250,8 @@ spec: - version type: object sharedGallery: - description: SharedGallery specifies an image to use from an Azure - Shared Image Gallery + description: 'SharedGallery specifies an image to use from an + Azure Shared Image Gallery Deprecated: use ComputeGallery instead.' properties: gallery: description: Gallery specifies the name of the shared image diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml index b309771742c..12fe01ab8d6 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml @@ -916,6 +916,68 @@ spec: the image will default the Azure Marketplace "capi" offer, which is based on Ubuntu. properties: + computeGallery: + description: ComputeGallery specifies an image to use + from the Azure Compute Gallery + properties: + gallery: + description: Gallery specifies the name of the compute + image gallery that contains the image + minLength: 1 + type: string + name: + description: Name is the name of the image + minLength: 1 + type: string + plan: + description: Plan contains plan information. + properties: + offer: + description: Offer specifies the name of a group + of related images created by the publisher. + For example, UbuntuServer, WindowsServer + minLength: 1 + type: string + publisher: + description: Publisher is the name of the organization + that created the image + minLength: 1 + type: string + sku: + description: SKU specifies an instance of an offer, + such as a major release of a distribution. For + example, 18.04-LTS, 2019-Datacenter + minLength: 1 + type: string + required: + - offer + - publisher + - sku + type: object + resourceGroup: + description: ResourceGroup specifies the resource + group containing the private compute gallery. + type: string + subscriptionID: + description: SubscriptionID is the identifier of the + subscription that contains the private compute gallery. + type: string + version: + description: Version specifies the version of the + marketplace image. The allowed formats are Major.Minor.Build + or 'latest'. Major, Minor, and Build are decimal + numbers. Specify 'latest' to use the latest version + of an image available at deploy time. Even if you + use 'latest', the VM image will not automatically + update after deploy time even if a new version becomes + available. + minLength: 1 + type: string + required: + - gallery + - name + - version + type: object id: description: ID specifies an image to use by ID type: string @@ -964,8 +1026,9 @@ spec: - version type: object sharedGallery: - description: SharedGallery specifies an image to use from - an Azure Shared Image Gallery + description: 'SharedGallery specifies an image to use + from an Azure Shared Image Gallery Deprecated: use ComputeGallery + instead.' properties: gallery: description: Gallery specifies the name of the shared diff --git a/docs/book/src/topics/custom-images.md b/docs/book/src/topics/custom-images.md index 706f3388956..c9814001c57 100644 --- a/docs/book/src/topics/custom-images.md +++ b/docs/book/src/topics/custom-images.md @@ -63,20 +63,20 @@ See [Upgrading workload clusters][upgrading-workload-clusters] for more details. To use a custom image, it needs to be referenced in an `image:` section of your `AzureMachineTemplate`. See below for more specific examples. -### Using Shared Image Gallery (Recommended) +### Using Azure Compute Gallery (Recommended) -To use an image from the [Shared Image Gallery][shared-image-gallery], fill in the `resourceGroup`, `name`, `subscriptionID`, `gallery`, and `version` fields: +To use an image from the [Azure Compute Gallery][azure-compute-gallery], previously known as Shared Image Gallery (SIG), fill in the `resourceGroup`, `name`, `subscriptionID`, `gallery`, and `version` fields: ```yaml apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: AzureMachineTemplate metadata: - name: capz-shared-gallery-example + name: capz-compute-gallery-example spec: template: spec: image: - sharedGallery: + computeGallery: resourceGroup: "cluster-api-images" name: "capi-1234567890" subscriptionID: "01234567-89ab-cdef-0123-4567890abcde" @@ -103,29 +103,30 @@ ManagedImageLocation: southcentralus ManagedImageSharedImageGalleryId: /subscriptions/01234567-89ab-cdef-0123-4567890abcde/resourceGroups/cluster-api-images/providers/Microsoft.Compute/galleries/ClusterAPI/images/capi-ubuntu-1804/versions/0.3.1234567890 ``` -Please also see the [replication recommendations][replication-recommendations] for the Shared Image Gallery. +Please also see the [replication recommendations][replication-recommendations] for the Azure Compute Gallery. -If the image you want to use is based on an image released by a third party publisher such as for example +If the image you want to use is based on an image released by a third party publisher such as for example `Flatcar Linux` by `Kinvolk`, then you need to specify the `publisher`, `offer`, and `sku` fields as well: ```yaml apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: AzureMachineTemplate metadata: - name: capz-shared-gallery-example + name: capz-compute-gallery-example spec: template: spec: image: - sharedGallery: + computeGallery: resourceGroup: "cluster-api-images" name: "capi-1234567890" subscriptionID: "01234567-89ab-cdef-0123-4567890abcde" gallery: "ClusterAPI" version: "0.3.1234567890" - publisher: "kinvolk" - offer: "flatcar-container-linux-free" - sku: "stable" + plan: + publisher: "kinvolk" + offer: "flatcar-container-linux-free" + sku: "stable" ``` This will make API calls to create Virtual Machines or Virtual Machine Scale Sets to have the `Plan` correctly set. @@ -148,7 +149,7 @@ spec: A managed image resource can be created from a Virtual Machine. Please refer to Azure documentation on [creating a managed image][creating-managed-image] for more detail. -Managed images support only 20 simultaneous deployments, so for most use cases Shared Image Gallery is recommended. +Managed images support only 20 simultaneous deployments, so for most use cases Azure Compute Gallery is recommended. ### Using Azure Marketplace @@ -171,8 +172,56 @@ spec: thirdPartyImage: true ``` +### Using Azure Community Gallery + +To use an image from [Azure Community Gallery][azure-community-gallery], set `name` field to gallery's public name and don't set `subscriptionID` and `resourceGroup` fields: + +```yaml +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: AzureMachineTemplate +metadata: + name: capz-community-gallery-example +spec: + template: + spec: + image: + computeGallery: + gallery: testGallery-3282f15c-906a-4c4b-b206-eb3c51adb5be + name: capi-flatcar-stable-3139.2.0 + version: 0.3.1651499183 +``` + +If the image you want to use is based on an image released by a third party publisher such as for example +`Flatcar Linux` by `Kinvolk`, then you need to specify the `publisher`, `offer`, and `sku` fields as well: + +```yaml +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: AzureMachineTemplate +metadata: + name: capz-community-gallery-example +spec: + template: + spec: + image: + computeGallery: + gallery: testGallery-3282f15c-906a-4c4b-b206-eb3c51adb5be + name: capi-flatcar-stable-3139.2.0 + version: 0.3.1651499183 + plan: + publisher: kinvolk + offer: flatcar-container-linux-free + sku: stable +``` + +This will make API calls to create Virtual Machines or Virtual Machine Scale Sets to have the `Plan` correctly set. + +In the case of a third party image, you must accept the license terms with the [Azure CLI][azure-cli] before consuming it. + +[azure-cli]: https://docs.microsoft.com/en-us/cli/azure/vm/image/terms?view=azure-cli-latest +[azure-community-gallery]: https://docs.microsoft.com/en-us/azure/virtual-machines/azure-compute-gallery#community [azure-marketplace]: https://docs.microsoft.com/azure/marketplace/marketplace-publishers-guide [azure-capi-images]: https://image-builder.sigs.k8s.io/capi/providers/azure.html +[azure-compute-gallery]: https://docs.microsoft.com/azure/virtual-machines/linux/shared-image-galleries [capi-images]: https://image-builder.sigs.k8s.io/capi/capi.html [creating-managed-image]: https://docs.microsoft.com/azure/virtual-machines/linux/capture-image [creating-vm-offer]: https://docs.azure.cn/en-us/articles/azure-marketplace/imagepublishguide#5-azure- @@ -180,7 +229,6 @@ spec: [image-builder-azure]: https://github.com/kubernetes-sigs/image-builder/tree/master/images/capi/packer/azure [kubeadm-preflight-checks]: https://github.com/kubernetes/kubeadm/blob/master/docs/design/design_v1.10.md#preflight-checks [replication-recommendations]: https://docs.microsoft.com/azure/virtual-machines/linux/shared-image-galleries#scaling -[shared-image-gallery]: https://docs.microsoft.com/azure/virtual-machines/linux/shared-image-galleries [supported-capi]: https://cluster-api.sigs.k8s.io/reference/versions.html#supported-kubernetes-versions [supported-k8s]: https://kubernetes.io/releases/version-skew-policy/#supported-versions [upgrading-workload-clusters]: https://cluster-api.sigs.k8s.io/tasks/kubeadm-control-plane.html#upgrading-workload-clusters diff --git a/exp/api/v1alpha3/azuremachinepool_conversion.go b/exp/api/v1alpha3/azuremachinepool_conversion.go index 297e6304633..20d115c4a04 100644 --- a/exp/api/v1alpha3/azuremachinepool_conversion.go +++ b/exp/api/v1alpha3/azuremachinepool_conversion.go @@ -72,6 +72,10 @@ func (src *AzureMachinePool) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Template.Image.SharedGallery.SKU = restored.Spec.Template.Image.SharedGallery.SKU } + if dst.Spec.Template.Image != nil && restored.Spec.Template.Image.ComputeGallery != nil { + dst.Spec.Template.Image.ComputeGallery = restored.Spec.Template.Image.ComputeGallery + } + if len(dst.Annotations) == 0 { dst.Annotations = nil } diff --git a/exp/api/v1alpha4/azuremachinepool_conversion.go b/exp/api/v1alpha4/azuremachinepool_conversion.go index d43babb5a82..e96c9aa6dc3 100644 --- a/exp/api/v1alpha4/azuremachinepool_conversion.go +++ b/exp/api/v1alpha4/azuremachinepool_conversion.go @@ -18,19 +18,43 @@ package v1alpha4 import ( expv1beta1 "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1" + utilconversion "sigs.k8s.io/cluster-api/util/conversion" "sigs.k8s.io/controller-runtime/pkg/conversion" ) // ConvertTo converts this AzureMachinePool to the Hub version (v1beta1). func (src *AzureMachinePool) ConvertTo(dstRaw conversion.Hub) error { dst := dstRaw.(*expv1beta1.AzureMachinePool) - return Convert_v1alpha4_AzureMachinePool_To_v1beta1_AzureMachinePool(src, dst, nil) + if err := Convert_v1alpha4_AzureMachinePool_To_v1beta1_AzureMachinePool(src, dst, nil); err != nil { + return err + } + + // Manually restore data. + restored := &expv1beta1.AzureMachinePool{} + if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { + return err + } + + if restored.Spec.Template.Image != nil && restored.Spec.Template.Image.ComputeGallery != nil { + dst.Spec.Template.Image.ComputeGallery = restored.Spec.Template.Image.ComputeGallery + } + + if restored.Status.Image != nil && restored.Status.Image.ComputeGallery != nil { + dst.Status.Image.ComputeGallery = restored.Status.Image.ComputeGallery + } + + return nil } // ConvertFrom converts from the Hub version (v1beta1) to this version. func (dst *AzureMachinePool) ConvertFrom(srcRaw conversion.Hub) error { src := srcRaw.(*expv1beta1.AzureMachinePool) - return Convert_v1beta1_AzureMachinePool_To_v1alpha4_AzureMachinePool(src, dst, nil) + if err := Convert_v1beta1_AzureMachinePool_To_v1alpha4_AzureMachinePool(src, dst, nil); err != nil { + return err + } + + // Preserve Hub data on down-conversion. + return utilconversion.MarshalData(src, dst) } // ConvertTo converts this AzureMachinePool to the Hub version (v1beta1). diff --git a/exp/api/v1beta1/azuremachinepool_test.go b/exp/api/v1beta1/azuremachinepool_test.go index 8ead3958e31..c6d1c27f442 100644 --- a/exp/api/v1beta1/azuremachinepool_test.go +++ b/exp/api/v1beta1/azuremachinepool_test.go @@ -79,7 +79,7 @@ func TestAzureMachinePool_Validate(t *testing.T) { }, Expect: func(g *gomega.GomegaWithT, actual error) { g.Expect(actual).To(gomega.HaveOccurred()) - g.Expect(actual.Error()).To(gomega.ContainSubstring("You must supply a ID, Marketplace or SharedGallery image details")) + g.Expect(actual.Error()).To(gomega.ContainSubstring("You must supply an ID, Marketplace or ComputeGallery image details")) }, }, { diff --git a/exp/api/v1beta1/azuremachinepool_webhook_test.go b/exp/api/v1beta1/azuremachinepool_webhook_test.go index 002e1ee0e55..77e5bc1bf25 100644 --- a/exp/api/v1beta1/azuremachinepool_webhook_test.go +++ b/exp/api/v1beta1/azuremachinepool_webhook_test.go @@ -57,12 +57,12 @@ func TestAzureMachinePool_ValidateCreate(t *testing.T) { }{ { name: "azuremachinepool with marketplace image - full", - amp: createMachinePoolWithtMarketPlaceImage("PUB1234", "OFFER1234", "SKU1234", "1.0.0", to.IntPtr(10)), + amp: createMachinePoolWithMarketPlaceImage("PUB1234", "OFFER1234", "SKU1234", "1.0.0", to.IntPtr(10)), wantErr: false, }, { name: "azuremachinepool with marketplace image - missing publisher", - amp: createMachinePoolWithtMarketPlaceImage("", "OFFER1234", "SKU1234", "1.0.0", to.IntPtr(10)), + amp: createMachinePoolWithMarketPlaceImage("", "OFFER1234", "SKU1234", "1.0.0", to.IntPtr(10)), wantErr: true, }, { @@ -275,13 +275,15 @@ func TestAzureMachinePool_Default(t *testing.T) { g.Expect(publicKeyNotExistTest.amp.Spec.Template.SSHPublicKey).NotTo(BeEmpty()) } -func createMachinePoolWithtMarketPlaceImage(publisher, offer, sku, version string, terminateNotificationTimeout *int) *AzureMachinePool { +func createMachinePoolWithMarketPlaceImage(publisher, offer, sku, version string, terminateNotificationTimeout *int) *AzureMachinePool { image := infrav1.Image{ Marketplace: &infrav1.AzureMarketplaceImage{ - Publisher: publisher, - Offer: offer, - SKU: sku, - Version: version, + ImagePlan: infrav1.ImagePlan{ + Publisher: publisher, + Offer: offer, + SKU: sku, + }, + Version: version, }, }