diff --git a/README.md b/README.md index 97471feb..c7b9cd23 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ This provider's versions are compatible with the following versions of Cluster A | | Cluster API v1beta1 (v1.7) | |------------------------|:--------------------------:| | CAPIC v1alpha1 (v0.2) | ✓ | +| CAPIC v1alpha1 (v0.3) | ✓ | +| CAPIC v1alpha1 (v0.4) | ✓ | ### Kubernetes Versions diff --git a/api/v1alpha1/ionoscloudcluster_types.go b/api/v1alpha1/ionoscloudcluster_types.go index 2bee17ba..d772009f 100644 --- a/api/v1alpha1/ionoscloudcluster_types.go +++ b/api/v1alpha1/ionoscloudcluster_types.go @@ -34,6 +34,8 @@ const ( IonosCloudClusterKind = "IonosCloudCluster" ) +//+kubebuilder:validation:XValidation:rule="self.controlPlaneEndpoint.host == '' || has(self.location)",message="location is required when controlPlaneEndpoint.host is set" + // IonosCloudClusterSpec defines the desired state of IonosCloudCluster. type IonosCloudClusterSpec struct { // ControlPlaneEndpoint represents the endpoint used to communicate with the control plane. @@ -44,10 +46,12 @@ type IonosCloudClusterSpec struct { ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint,omitempty"` // Location is the location where the data centers should be located. + // //+kubebuilder:validation:XValidation:rule="self == oldSelf",message="location is immutable" //+kubebuilder:example=de/txl //+kubebuilder:validation:MinLength=1 - Location string `json:"location"` + //+optional + Location string `json:"location,omitempty"` // CredentialsRef is a reference to the secret containing the credentials to access the IONOS Cloud API. //+kubebuilder:validation:XValidation:rule="has(self.name) && self.name != ''",message="credentialsRef.name must be provided" diff --git a/api/v1alpha1/ionoscloudcluster_types_test.go b/api/v1alpha1/ionoscloudcluster_types_test.go index a7c99c72..f3add433 100644 --- a/api/v1alpha1/ionoscloudcluster_types_test.go +++ b/api/v1alpha1/ionoscloudcluster_types_test.go @@ -86,11 +86,17 @@ var _ = Describe("IonosCloudCluster", func() { Expect(k8sClient.Create(context.Background(), cluster)). Should(MatchError(ContainSubstring("credentialsRef.name must be provided"))) }) - It("should not allow creating clusters with empty location", func() { + It("should not allow creating clusters with empty location when ControlPlaneEndpoint host is set", func() { cluster := defaultCluster() cluster.Spec.Location = "" Expect(k8sClient.Create(context.Background(), cluster)). - Should(MatchError(ContainSubstring("spec.location in body should be at least 1 chars long"))) + Should(MatchError(ContainSubstring("location is required when controlPlaneEndpoint.host is set"))) + }) + It("should allow creating clusters with empty location when ControlPlaneEndpoint host is not set", func() { + cluster := defaultCluster() + cluster.Spec.Location = "" + cluster.Spec.ControlPlaneEndpoint.Host = "" + Expect(k8sClient.Create(context.Background(), cluster)).To(Succeed()) }) }) diff --git a/api/v1alpha1/ionoscloudmachine_types.go b/api/v1alpha1/ionoscloudmachine_types.go index bc9fb709..3494079e 100644 --- a/api/v1alpha1/ionoscloudmachine_types.go +++ b/api/v1alpha1/ionoscloudmachine_types.go @@ -151,7 +151,6 @@ type IonosCloudMachineSpec struct { Disk *Volume `json:"disk"` // AdditionalNetworks defines the additional network configurations for the VM. - // NOTE(lubedacht): We currently only support networks with DHCP enabled. //+optional AdditionalNetworks Networks `json:"additionalNetworks,omitempty"` @@ -188,6 +187,16 @@ type Network struct { //+kubebuilder:validation:Minimum=1 NetworkID int32 `json:"networkID"` + // VNET is solely used for internal purposes and requires elevated permissions. + //+optional + VNET *string `json:"vnet,omitempty"` + + // DHCP indicates whether DHCP is enabled for the LAN. + // The primary NIC will always have DHCP enabled. + //+kubebuilder:default=true + //+optional + DHCP *bool `json:"dhcp,omitempty"` + // IPAMConfig allows to obtain IP Addresses from existing IP pools instead of using DHCP. IPAMConfig `json:",inline"` } diff --git a/api/v1alpha1/ionoscloudmachine_types_test.go b/api/v1alpha1/ionoscloudmachine_types_test.go index 893436a3..ae986c28 100644 --- a/api/v1alpha1/ionoscloudmachine_types_test.go +++ b/api/v1alpha1/ionoscloudmachine_types_test.go @@ -405,6 +405,11 @@ var _ = Describe("IonosCloudMachine Tests", func() { Entry("invalid IPv4PoolRef with invalid apiGroup", "IPv4", "InClusterIPPool", "SomeWrongAPIGroup", "ipv4-pool"), Entry("invalid IPv4PoolRef with empty name", "IPv4", "InClusterIPPool", "ipam.cluster.x-k8s.io", ""), ) + It("DHCP should default to true", func() { + m := defaultMachine() + Expect(k8sClient.Create(context.Background(), m)).To(Succeed()) + Expect(*m.Spec.AdditionalNetworks[0].DHCP).To(BeTrue()) + }) }) }) Context("FailoverIP", func() { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 27ecac92..03121d12 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -590,6 +590,16 @@ func (in *NICInfo) DeepCopy() *NICInfo { func (in *Network) DeepCopyInto(out *Network) { *out = *in in.IPAMConfig.DeepCopyInto(&out.IPAMConfig) + if in.VNET != nil { + in, out := &in.VNET, &out.VNET + *out = new(string) + **out = **in + } + if in.DHCP != nil { + in, out := &in.DHCP, &out.DHCP + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network. diff --git a/clusterctl-settings.json b/clusterctl-settings.json index 917b8b75..32bcec33 100644 --- a/clusterctl-settings.json +++ b/clusterctl-settings.json @@ -2,6 +2,6 @@ "name": "infrastructure-ionoscloud", "config": { "componentsFile": "infrastructure-components.yaml", - "nextVersion": "v0.2.0" + "nextVersion": "v0.4.0" } } diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclusters.yaml index da2fbd77..f42c22d6 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclusters.yaml @@ -119,8 +119,10 @@ spec: rule: self == oldSelf required: - credentialsRef - - location type: object + x-kubernetes-validations: + - message: location is required when controlPlaneEndpoint.host is set + rule: self.controlPlaneEndpoint.host == '' || has(self.location) status: description: IonosCloudClusterStatus defines the observed state of IonosCloudCluster. properties: diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml index 24b5b6d3..2bef6c68 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudclustertemplates.yaml @@ -111,8 +111,11 @@ spec: rule: self == oldSelf required: - credentialsRef - - location type: object + x-kubernetes-validations: + - message: location is required when controlPlaneEndpoint.host + is set + rule: self.controlPlaneEndpoint.host == '' || has(self.location) required: - spec type: object diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachines.yaml index d515c9a4..bd1105b8 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachines.yaml @@ -64,9 +64,8 @@ spec: description: IonosCloudMachineSpec defines the desired state of IonosCloudMachine. properties: additionalNetworks: - description: |- - AdditionalNetworks defines the additional network configurations for the VM. - NOTE(lubedacht): We currently only support networks with DHCP enabled. + description: AdditionalNetworks defines the additional network configurations + for the VM. items: description: Network contains the config for additional LANs. properties: @@ -128,6 +127,12 @@ spec: rule: self.kind == 'InClusterIPPool' || self.kind == 'GlobalInClusterIPPool' - message: ipv6PoolRef.name is required rule: self.name != '' + dhcp: + default: true + description: |- + DHCP indicates whether DHCP is enabled for the LAN. + The primary NIC will always have DHCP enabled. + type: boolean networkID: description: |- NetworkID represents an ID an existing LAN in the data center. @@ -135,6 +140,10 @@ spec: format: int32 minimum: 1 type: integer + vnet: + description: VNET is solely used for internal purposes and requires + elevated permissions. + type: string required: - networkID type: object diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachinetemplates.yaml index 4dbe4cc2..cb3e74c4 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ionoscloudmachinetemplates.yaml @@ -73,9 +73,8 @@ spec: description: Spec is the IonosCloudMachineSpec for the IonosCloudMachineTemplate. properties: additionalNetworks: - description: |- - AdditionalNetworks defines the additional network configurations for the VM. - NOTE(lubedacht): We currently only support networks with DHCP enabled. + description: AdditionalNetworks defines the additional network + configurations for the VM. items: description: Network contains the config for additional LANs. @@ -148,6 +147,12 @@ spec: == 'GlobalInClusterIPPool' - message: ipv6PoolRef.name is required rule: self.name != '' + dhcp: + default: true + description: |- + DHCP indicates whether DHCP is enabled for the LAN. + The primary NIC will always have DHCP enabled. + type: boolean networkID: description: |- NetworkID represents an ID an existing LAN in the data center. @@ -155,6 +160,10 @@ spec: format: int32 minimum: 1 type: integer + vnet: + description: VNET is solely used for internal purposes + and requires elevated permissions. + type: string required: - networkID type: object diff --git a/go.mod b/go.mod index 90587dd7..52bbae0e 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,10 @@ require ( github.com/go-logr/logr v1.4.2 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 - github.com/ionos-cloud/sdk-go/v6 v6.1.11 + github.com/ionos-cloud/sdk-go/v6 v6.2.1 github.com/jarcoal/httpmock v1.3.1 - github.com/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.33.1 + github.com/onsi/ginkgo/v2 v2.19.1 + github.com/onsi/gomega v1.34.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 k8s.io/api v0.29.7 @@ -41,7 +41,7 @@ require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.5.0 // indirect - github.com/docker/docker v25.0.5+incompatible // indirect + github.com/docker/docker v25.0.6+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 // indirect @@ -116,22 +116,21 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.21.0 // indirect + golang.org/x/tools v0.23.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/grpc v1.60.1 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index d89993df..97fdcf3e 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE= -github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg= +github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -102,8 +102,6 @@ github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= @@ -114,7 +112,6 @@ github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvR github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -151,8 +148,8 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ionos-cloud/sdk-go/v6 v6.1.11 h1:J/uRN4UWO3wCyGOeDdMKv8LWRzKu6UIkLEaes38Kzh8= -github.com/ionos-cloud/sdk-go/v6 v6.1.11/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= +github.com/ionos-cloud/sdk-go/v6 v6.2.1 h1:mxxN+frNVmbFrmmFfXnBC3g2USYJrl6mc1LW2iNYbFY= +github.com/ionos-cloud/sdk-go/v6 v6.2.1/go.mod h1:SXrO9OGyWjd2rZhAhEpdYN6VUAODzzqRdqA9BCviQtI= github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -199,10 +196,10 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= @@ -327,10 +324,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -341,10 +338,10 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -364,20 +361,19 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -385,16 +381,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= @@ -403,10 +397,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/controller/ionoscloudmachine_controller.go b/internal/controller/ionoscloudmachine_controller.go index a3dedf0a..16e4c8e2 100644 --- a/internal/controller/ionoscloudmachine_controller.go +++ b/internal/controller/ionoscloudmachine_controller.go @@ -134,9 +134,6 @@ func (r *IonosCloudMachineReconciler) Reconcile( return ctrl.Result{}, fmt.Errorf("failed to create ionos client: %w", err) } - if err != nil { - return ctrl.Result{}, errors.New("could not create machine service") - } if !ionosCloudMachine.ObjectMeta.DeletionTimestamp.IsZero() { return r.reconcileDelete(ctx, machineScope, cloudService) } @@ -343,7 +340,7 @@ func (r *IonosCloudMachineReconciler) SetupWithManager(mgr ctrl.Manager, options &clusterv1.Machine{}, handler.EnqueueRequestsFromMapFunc( util.MachineToInfrastructureMapFunc(infrav1.GroupVersion.WithKind(infrav1.IonosCloudMachineType)))). - Complete(reconcile.AsReconciler[*infrav1.IonosCloudMachine](r.Client, r)) + Complete(reconcile.AsReconciler(r.Client, r)) } func (r *IonosCloudMachineReconciler) getClusterScope( diff --git a/internal/ionoscloud/client.go b/internal/ionoscloud/client.go index 72c1a2e6..0212815c 100644 --- a/internal/ionoscloud/client.go +++ b/internal/ionoscloud/client.go @@ -41,7 +41,7 @@ type Client interface { DeleteVolume(ctx context.Context, datacenterID, volumeID string) (string, error) // CreateLAN creates a new LAN with the provided properties in the specified data center, // returning the request path. - CreateLAN(ctx context.Context, datacenterID string, properties sdk.LanPropertiesPost) (string, error) + CreateLAN(ctx context.Context, datacenterID string, properties sdk.LanProperties) (string, error) // PatchLAN patches the LAN that matches lanID in the specified data center with the provided properties, // returning the request location. PatchLAN(ctx context.Context, datacenterID, lanID string, properties sdk.LanProperties) (string, error) diff --git a/internal/ionoscloud/client/client.go b/internal/ionoscloud/client/client.go index f5bf5eab..76e021f3 100644 --- a/internal/ionoscloud/client/client.go +++ b/internal/ionoscloud/client/client.go @@ -219,12 +219,12 @@ func (c *IonosCloudClient) DeleteVolume(ctx context.Context, datacenterID, volum // CreateLAN creates a new LAN with the provided properties in the specified data center, // returning the request location. -func (c *IonosCloudClient) CreateLAN(ctx context.Context, datacenterID string, properties sdk.LanPropertiesPost, +func (c *IonosCloudClient) CreateLAN(ctx context.Context, datacenterID string, properties sdk.LanProperties, ) (string, error) { if datacenterID == "" { return "", errDatacenterIDIsEmpty } - lanPost := sdk.LanPost{ + lanPost := sdk.Lan{ Properties: &properties, } _, req, err := c.API.LANsApi.DatacentersLansPost(ctx, datacenterID).Lan(lanPost).Execute() diff --git a/internal/ionoscloud/clienttest/mock_client.go b/internal/ionoscloud/clienttest/mock_client.go index 0a9b6d08..000077ce 100644 --- a/internal/ionoscloud/clienttest/mock_client.go +++ b/internal/ionoscloud/clienttest/mock_client.go @@ -98,7 +98,7 @@ func (_c *MockClient_CheckRequestStatus_Call) RunAndReturn(run func(context.Cont } // CreateLAN provides a mock function with given fields: ctx, datacenterID, properties -func (_m *MockClient) CreateLAN(ctx context.Context, datacenterID string, properties ionoscloud.LanPropertiesPost) (string, error) { +func (_m *MockClient) CreateLAN(ctx context.Context, datacenterID string, properties ionoscloud.LanProperties) (string, error) { ret := _m.Called(ctx, datacenterID, properties) if len(ret) == 0 { @@ -107,16 +107,16 @@ func (_m *MockClient) CreateLAN(ctx context.Context, datacenterID string, proper var r0 string var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, ionoscloud.LanPropertiesPost) (string, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, string, ionoscloud.LanProperties) (string, error)); ok { return rf(ctx, datacenterID, properties) } - if rf, ok := ret.Get(0).(func(context.Context, string, ionoscloud.LanPropertiesPost) string); ok { + if rf, ok := ret.Get(0).(func(context.Context, string, ionoscloud.LanProperties) string); ok { r0 = rf(ctx, datacenterID, properties) } else { r0 = ret.Get(0).(string) } - if rf, ok := ret.Get(1).(func(context.Context, string, ionoscloud.LanPropertiesPost) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, string, ionoscloud.LanProperties) error); ok { r1 = rf(ctx, datacenterID, properties) } else { r1 = ret.Error(1) @@ -133,14 +133,14 @@ type MockClient_CreateLAN_Call struct { // CreateLAN is a helper method to define mock.On call // - ctx context.Context // - datacenterID string -// - properties ionoscloud.LanPropertiesPost +// - properties ionoscloud.LanProperties func (_e *MockClient_Expecter) CreateLAN(ctx interface{}, datacenterID interface{}, properties interface{}) *MockClient_CreateLAN_Call { return &MockClient_CreateLAN_Call{Call: _e.mock.On("CreateLAN", ctx, datacenterID, properties)} } -func (_c *MockClient_CreateLAN_Call) Run(run func(ctx context.Context, datacenterID string, properties ionoscloud.LanPropertiesPost)) *MockClient_CreateLAN_Call { +func (_c *MockClient_CreateLAN_Call) Run(run func(ctx context.Context, datacenterID string, properties ionoscloud.LanProperties)) *MockClient_CreateLAN_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(ionoscloud.LanPropertiesPost)) + run(args[0].(context.Context), args[1].(string), args[2].(ionoscloud.LanProperties)) }) return _c } @@ -150,7 +150,7 @@ func (_c *MockClient_CreateLAN_Call) Return(_a0 string, _a1 error) *MockClient_C return _c } -func (_c *MockClient_CreateLAN_Call) RunAndReturn(run func(context.Context, string, ionoscloud.LanPropertiesPost) (string, error)) *MockClient_CreateLAN_Call { +func (_c *MockClient_CreateLAN_Call) RunAndReturn(run func(context.Context, string, ionoscloud.LanProperties) (string, error)) *MockClient_CreateLAN_Call { _c.Call.Return(run) return _c } diff --git a/internal/service/cloud/network.go b/internal/service/cloud/network.go index 30653b44..0c39ab40 100644 --- a/internal/service/cloud/network.go +++ b/internal/service/cloud/network.go @@ -180,7 +180,7 @@ func (s *Service) getLAN(ctx context.Context, ms *scope.Machine) (*sdk.Lan, erro func (s *Service) createLAN(ctx context.Context, ms *scope.Machine) error { log := s.logger.WithName("createLAN") - lanProperties := sdk.LanPropertiesPost{ + lanProperties := sdk.LanProperties{ Name: ptr.To(s.lanName(ms.ClusterScope.Cluster)), Public: ptr.To(true), Ipv6CidrBlock: ptr.To("AUTO"), // IPv6 is enabled by default. diff --git a/internal/service/cloud/network_test.go b/internal/service/cloud/network_test.go index 2eab32cd..d0eb3e5a 100644 --- a/internal/service/cloud/network_test.go +++ b/internal/service/cloud/network_test.go @@ -629,7 +629,7 @@ func (s *lanSuite) examplePatchRequest(status string) sdk.Request { } func (s *lanSuite) mockCreateLANCall() *clienttest.MockClient_CreateLAN_Call { - return s.ionosClient.EXPECT().CreateLAN(s.ctx, s.machineScope.DatacenterID(), sdk.LanPropertiesPost{ + return s.ionosClient.EXPECT().CreateLAN(s.ctx, s.machineScope.DatacenterID(), sdk.LanProperties{ Name: ptr.To(s.service.lanName(s.clusterScope.Cluster)), Public: ptr.To(true), Ipv6CidrBlock: ptr.To("AUTO"), diff --git a/internal/service/cloud/server.go b/internal/service/cloud/server.go index 83b6c416..1856c5ab 100644 --- a/internal/service/cloud/server.go +++ b/internal/service/cloud/server.go @@ -443,7 +443,9 @@ func (s *Service) buildServerEntities(ms *scope.Machine, params serverEntityPara nic := sdk.Nic{ Properties: &sdk.NicProperties{ Lan: &nw.NetworkID, - }, + Vnet: nw.VNET, + Dhcp: nw.DHCP, + }, } if ms.IonosMachine.Status.MachineNetworkInfo != nil { diff --git a/internal/service/cloud/server_test.go b/internal/service/cloud/server_test.go index 8db3f89a..7799e4c7 100644 --- a/internal/service/cloud/server_test.go +++ b/internal/service/cloud/server_test.go @@ -150,6 +150,45 @@ func (s *serverSuite) TestReconcileServerRequestDoneStateAvailableTurnedOff() { s.True(requeue) } +func (s *serverSuite) TestReconcileServerAdditionalNetworks() { + s.machineScope.IonosMachine.Spec.AdditionalNetworks = []infrav1.Network{{ + NetworkID: 43, + DHCP: ptr.To(false), + }, { + NetworkID: 44, + DHCP: ptr.To(true), + }} + + s.prepareReconcileServerRequestTest() + s.mockGetServerCreationRequestCall().Return([]sdk.Request{}, nil) + s.mockListLANsCall().Return(&sdk.Lans{Items: &[]sdk.Lan{{ + Id: ptr.To(exampleLANID), + Properties: &sdk.LanProperties{ + Name: ptr.To(s.service.lanName(s.clusterScope.Cluster)), + Public: ptr.To(true), + }, + }}}, nil) + + properties, entities := s.defaultServerComponents() + *entities.Nics.Items = append(*entities.Nics.Items, sdk.Nic{ + Properties: &sdk.NicProperties{ + Lan: ptr.To[int32](43), + Dhcp: ptr.To(false), + }, + }, sdk.Nic{ + Properties: &sdk.NicProperties{ + Lan: ptr.To[int32](44), + Dhcp: ptr.To(true), + }, + }) + s.mockCreateServerCall(properties, entities).Return(&sdk.Server{Id: ptr.To("12345")}, "location/to/server", nil) + + requeue, err := s.service.ReconcileServer(s.ctx, s.machineScope) + s.Equal("ionos://12345", ptr.Deref(s.machineScope.IonosMachine.Spec.ProviderID, "")) + s.NoError(err) + s.True(requeue) +} + func (s *serverSuite) TestReconcileEnterpriseServerNoRequest() { s.prepareReconcileServerRequestTest() s.mockGetServerCreationRequestCall().Return([]sdk.Request{}, nil) diff --git a/internal/util/locker/locker.go b/internal/util/locker/locker.go index 178b99d0..a902d85c 100644 --- a/internal/util/locker/locker.go +++ b/internal/util/locker/locker.go @@ -67,8 +67,8 @@ func (lwc *lockWithCounter) inc() { } // dec decrements the number of waiters. -func (lwc *lockWithCounter) dec() { - lwc.waiters.Add(-1) +func (lwc *lockWithCounter) dec() int32 { + return lwc.waiters.Add(-1) } // count gets the current number of waiters. @@ -109,10 +109,9 @@ func (l *Locker) Lock(ctx context.Context, key string) error { return nil case <-ctx.Done(): // Locking aborted, so we can decrement the number of waiters for this lock. - lwc.dec() - // If there are no more waiters, we can delete the lock. + // If there are no more waiters and the lock is not held, we can delete the lock. l.mu.Lock() - if lwc.count() == 0 { + if lwc.dec() == 0 && len(lwc.ch) == 0 { delete(l.locks, key) } l.mu.Unlock() @@ -129,10 +128,12 @@ func (l *Locker) Unlock(key string) { if !exists { panic("no such lock: " + key) } - <-lwc.ch // If there are no more waiters, we can delete the lock. if lwc.count() == 0 { delete(l.locks, key) } + + // Release key lock + <-lwc.ch } diff --git a/internal/util/locker/locker_test.go b/internal/util/locker/locker_test.go index 7bfa2fdf..c4946d0b 100644 --- a/internal/util/locker/locker_test.go +++ b/internal/util/locker/locker_test.go @@ -158,5 +158,5 @@ func TestLockerContextDeadlineExceeded(t *testing.T) { require.ErrorIs(t, context.DeadlineExceeded, err) }) - require.Empty(t, l.locks) + require.NotPanics(t, func() { l.Unlock("test") }) } diff --git a/metadata.yaml b/metadata.yaml index c229ac26..cfc48364 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -2,6 +2,12 @@ apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3 kind: Metadata releaseSeries: +- major: 0 + minor: 4 + contract: v1beta1 +- major: 0 + minor: 3 + contract: v1beta1 - major: 0 minor: 2 contract: v1beta1 diff --git a/test/e2e/config/ionoscloud.yaml b/test/e2e/config/ionoscloud.yaml index 49208d8a..1d77653b 100644 --- a/test/e2e/config/ionoscloud.yaml +++ b/test/e2e/config/ionoscloud.yaml @@ -54,7 +54,7 @@ providers: - name: ionoscloud type: InfrastructureProvider versions: - - name: v0.2.99 + - name: v0.4.99 value: "../../../config/default" replacements: - old: ghcr.io/ionos-cloud/cluster-api-provider-ionoscloud:dev