Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
969138b
docs: add cluster-api v1.9.11 upgrade design spec
schegi Apr 1, 2026
a02cd77
Merge branch 'main' of https://github.com/ionos-cloud/cluster-api-pro…
schegi Apr 1, 2026
80cae03
docs: add cluster-api v1.9.11 upgrade implementation plan
schegi Apr 1, 2026
91a5f62
Merge branch 'main' of https://github.com/ionos-cloud/cluster-api-pro…
schegi Apr 13, 2026
6346fd8
docs: add cluster-api v1.10.10 upgrade design spec
schegi Apr 13, 2026
ece600d
docs: add README compatibility table update to upgrade spec
schegi Apr 13, 2026
1d957bb
docs: add cluster-api v1.10.10 upgrade implementation plan
schegi Apr 13, 2026
c2017f9
chore(deps): bump cluster-api v1.8.12 -> v1.10.10 and dependencies
schegi Apr 13, 2026
18c3a18
fix: update predicate signatures for CAPI v1.9+ (scheme argument)
schegi Apr 13, 2026
16a513c
fix(e2e): rename GetVariable to MustGetVariable for CAPI v1.10
schegi Apr 13, 2026
ea31ae4
fix(e2e): update addons import path (graduated from experimental)
schegi Apr 13, 2026
d73ded6
chore: update golangci-lint config for CAPI v1.10 markers
schegi Apr 13, 2026
ccee414
chore(e2e): update CAPI component URLs to v1.10.10
schegi Apr 13, 2026
9cac7c6
docs: update compatibility table for CAPI v1.10
schegi Apr 13, 2026
0b25bdd
feat: add CRDMigrator controller per CAPI v1.10 migration guide
schegi Apr 13, 2026
43bcc89
chore: regenerate manifests, deepcopy, and mocks for CAPI v1.10.10
schegi Apr 13, 2026
70e71a8
fix: upgrade go.opentelemetry.io/otel/sdk to v1.43.0 for CVE-2026-39883
schegi Apr 13, 2026
41d7027
fix: bump Go builder image to 1.25.9 for CVE-2026-32282
schegi Apr 13, 2026
97d5ed3
chore: remove agent-generated plan and spec docs
schegi Apr 13, 2026
e05e980
fix: address PR #358 review comments
schegi Apr 29, 2026
30657db
Merge branch 'main' into feat/upgrade-capi-v1.10.10
schegi Jun 8, 2026
c911b12
make CI happy
gauravgahlot Jun 11, 2026
cb2a064
update Go from v1.25.10 to v1.25.11
gauravgahlot Jun 11, 2026
09785f5
fix: align CRDMigrator RBAC with v1.10 migration guide
schegi Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .codespellignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
capi
capic
decorder
pulish
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.25.8 AS builder
FROM golang:1.25.11 AS builder
ARG TARGETOS
ARG TARGETARCH

Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,11 @@ This provider requires **Go 1.25 or newer**. The exact version is specified in `

This provider's versions are compatible with the following versions of Cluster API:

| | Cluster API v1beta1 (v1.7) | Cluster API v1beta1 (v1.8) |
|-----------------------|:--------------------------:|:--------------------------:|
| CAPIC v1alpha1 (v0.2) | ✓ | ☓ |
| CAPIC v1alpha1 (v0.3) | ✓ | ☓ |
| CAPIC v1alpha1 (v0.4) | ✓ | ✓ |
| CAPIC v1alpha1 (v0.5) | ✓ | ✓ |
| CAPIC v1alpha1 (v0.6) | ✓ | ✓ |
| | Cluster API v1beta1 (v1.8) | Cluster API v1beta1 (v1.9) | Cluster API v1beta1 (v1.10) |
|-----------------------|:--------------------------:|:--------------------------:|:---------------------------:|
| CAPIC v1alpha1 (v0.4) | ✓ | ☓ | ☓ |
| CAPIC v1alpha1 (v0.5) | ✓ | ☓ | ☓ |
| CAPIC v1alpha1 (v0.6) | ✓ | ✓ | ✓ |

### Kubernetes Versions

Expand Down
39 changes: 0 additions & 39 deletions api/v1alpha1/ionoscloudmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/errors"

"github.com/ionos-cloud/cluster-api-provider-ionoscloud/internal/util/ptr"
)
Expand Down Expand Up @@ -296,44 +295,6 @@ type IonosCloudMachineStatus struct {
//+optional
MachineNetworkInfo *MachineNetworkInfo `json:"machineNetworkInfo,omitempty"`

// FailureReason will be set in the event that there is a terminal problem
// reconciling the Machine and will contain a succinct value suitable
// for machine interpretation.
//
// This field should not be set for transitive errors that a controller
// faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the Machine's spec or the configuration of
// the controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the controller, or the
// responsible controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of IonosCloudMachines
// can be added as events to the IonosCloudMachine object and/or logged in the
// controller's output.
//+optional
FailureReason *errors.MachineStatusError `json:"failureReason,omitempty"`

// FailureMessage will be set in the event that there is a terminal problem
// reconciling the Machine and will contain a more verbose string suitable
// for logging and human consumption.
//
// This field should not be set for transitive errors that a controller
// faces that are expected to be fixed automatically over
// time (like service outages), but instead indicate that something is
// fundamentally wrong with the Machine's spec or the configuration of
// the controller, and that manual intervention is required. Examples
// of terminal errors would be invalid combinations of settings in the
// spec, values that are unsupported by the controller, or the
// responsible controller itself being critically misconfigured.
//
// Any transient errors that occur during the reconciliation of IonosCloudMachines
// can be added as events to the IonosCloudMachine object and/or logged in the
// controller's output.
//+optional
FailureMessage *string `json:"failureMessage,omitempty"`

// Conditions defines current service state of the IonosCloudMachine.
//+optional
Conditions clusterv1.Conditions `json:"conditions,omitempty"`
Expand Down
3 changes: 0 additions & 3 deletions api/v1alpha1/ionoscloudmachine_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
sdk "github.com/ionos-cloud/sdk-go/v6"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/cluster-api/errors"
"sigs.k8s.io/cluster-api/util/conditions"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand Down Expand Up @@ -562,8 +561,6 @@ var _ = Describe("IonosCloudMachine Tests", func() {
RequestPath: "path/to/resource",
State: sdk.RequestStatusRunning,
}
m.Status.FailureReason = ptr.To(errors.InvalidConfigurationMachineError)
m.Status.FailureMessage = ptr.To("Failure message")
m.Status.Location = "de/fra"

m.Status.MachineNetworkInfo = &MachineNetworkInfo{
Expand Down
11 changes: 0 additions & 11 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 58 additions & 18 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@ limitations under the License.
package main

import (
"context"
"flag"
"fmt"
"os"

"github.com/spf13/pflag"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/klog/v2"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/controllers/crdmigrator"
ipamv1 "sigs.k8s.io/cluster-api/exp/ipam/api/v1beta1"
"sigs.k8s.io/cluster-api/util/flags"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/healthz"

Expand All @@ -39,18 +44,20 @@ import (
)

var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
healthProbeAddr string
enableLeaderElection bool
managerOptions = flags.ManagerOptions{}
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
healthProbeAddr string
enableLeaderElection bool
managerOptions = flags.ManagerOptions{}
skipCRDMigrationPhases []string

icClusterConcurrency int
icMachineConcurrency int
)

func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(apiextensionsv1.AddToScheme(scheme))

utilruntime.Must(clusterv1.AddToScheme(scheme))
utilruntime.Must(infrav1.AddToScheme(scheme))
Expand All @@ -63,6 +70,13 @@ func init() {
// +kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create
// +kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create

// Add CRD RBAC for CRD Migrator.
// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch
// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions;customresourcedefinitions/status,verbs=update;patch,resourceNames=ionoscloudclusters.infrastructure.cluster.x-k8s.io;ionoscloudclustertemplates.infrastructure.cluster.x-k8s.io;ionoscloudmachines.infrastructure.cluster.x-k8s.io;ionoscloudmachinetemplates.infrastructure.cluster.x-k8s.io

// Add CR RBAC for CRD Migrator.
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=ionoscloudclustertemplates;ionoscloudmachinetemplates,verbs=get;list;watch;patch;update

func main() {
ctrl.SetLogger(klog.Background())
initFlags()
Expand Down Expand Up @@ -99,19 +113,8 @@ func main() {

ctx := ctrl.SetupSignalHandler()

if err = iccontroller.NewIonosCloudClusterReconciler(mgr).SetupWithManager(
ctx,
mgr,
controller.Options{MaxConcurrentReconciles: icClusterConcurrency},
); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "IonosCloudCluster")
os.Exit(1)
}
if err = iccontroller.NewIonosCloudMachineReconciler(mgr).SetupWithManager(
mgr,
controller.Options{MaxConcurrentReconciles: icMachineConcurrency},
); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "IonosCloudMachine")
if err = setUpControllers(ctx, mgr); err != nil {
setupLog.Error(err, "unable to set up controllers")
os.Exit(1)
}
//+kubebuilder:scaffold:builder
Expand All @@ -132,6 +135,41 @@ func main() {
}
}

func setUpControllers(ctx context.Context, mgr ctrl.Manager) error {
skipPhases := make([]crdmigrator.Phase, 0, len(skipCRDMigrationPhases))
for _, p := range skipCRDMigrationPhases {
skipPhases = append(skipPhases, crdmigrator.Phase(p))
}
if err := (&crdmigrator.CRDMigrator{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
SkipCRDMigrationPhases: skipPhases,
Config: map[client.Object]crdmigrator.ByObjectConfig{
&infrav1.IonosCloudCluster{}: {UseCache: true},
&infrav1.IonosCloudClusterTemplate{}: {UseCache: false},
&infrav1.IonosCloudMachine{}: {UseCache: true},
&infrav1.IonosCloudMachineTemplate{}: {UseCache: false},
},
}).SetupWithManager(ctx, mgr, controller.Options{}); err != nil {
return fmt.Errorf("unable to create CRDMigrator controller: %w", err)
}

if err := iccontroller.NewIonosCloudClusterReconciler(mgr).SetupWithManager(
ctx,
mgr,
controller.Options{MaxConcurrentReconciles: icClusterConcurrency},
); err != nil {
return fmt.Errorf("unable to create IonosCloudCluster controller: %w", err)
}
if err := iccontroller.NewIonosCloudMachineReconciler(mgr).SetupWithManager(
mgr,
controller.Options{MaxConcurrentReconciles: icMachineConcurrency},
); err != nil {
return fmt.Errorf("unable to create IonosCloudMachine controller: %w", err)
}
return nil
}

// initFlags parses the command line flags.
func initFlags() {
klog.InitFlags(nil)
Expand All @@ -142,6 +180,8 @@ func initFlags() {
pflag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
pflag.StringArrayVar(&skipCRDMigrationPhases, "skip-crd-migration-phases", []string{},
"CRD migration phases to skip. Valid values are: StorageVersionMigration, CleanupManagedFields.")
pflag.IntVar(&icClusterConcurrency, "ionoscloudcluster-concurrency", 1,
"Number of IonosCloudClusters to process simultaneously")
pflag.IntVar(&icMachineConcurrency, "ionoscloudmachine-concurrency", 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ spec:
provider-provided block IP into the kube-vip manifest.
properties:
host:
description: The hostname on which the API server is serving.
description: host is the hostname on which the API server is serving.
maxLength: 512
type: string
port:
description: The port on which the API server is serving.
description: port is the port on which the API server is serving.
format: int32
type: integer
required:
Expand Down Expand Up @@ -138,36 +139,43 @@ spec:
properties:
lastTransitionTime:
description: |-
Last time the condition transitioned from one status to another.
lastTransitionTime is the last time the condition transitioned from one status to another.
This should be when the underlying condition changed. If that is not known, then using the time when
the API field changed is acceptable.
format: date-time
type: string
message:
description: |-
A human readable message indicating details about the transition.
message is a human readable message indicating details about the transition.
This field may be empty.
Comment thread
schegi marked this conversation as resolved.
maxLength: 10240
minLength: 1
type: string
reason:
description: |-
The reason for the condition's last transition in CamelCase.
reason is the reason for the condition's last transition in CamelCase.
The specific API may choose whether or not this field is considered a guaranteed API.
This field may not be empty.
This field may be empty.
maxLength: 256
minLength: 1
Comment thread
schegi marked this conversation as resolved.
type: string
severity:
description: |-
Severity provides an explicit classification of Reason code, so the users or machines can immediately
severity provides an explicit classification of Reason code, so the users or machines can immediately
understand the current situation and act accordingly.
The Severity field MUST be set only when Status=False.
maxLength: 32
type: string
status:
description: Status of the condition, one of True, False, Unknown.
description: status of the condition, one of True, False, Unknown.
type: string
type:
description: |-
Type of condition in CamelCase or in foo.example.com/CamelCase.
type of condition in CamelCase or in foo.example.com/CamelCase.
Many .condition.type values are consistent across resources like Available, but because arbitrary conditions
can be useful (see .node.status.conditions), the ability to deconflict is important.
maxLength: 256
minLength: 1
type: string
required:
- lastTransitionTime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,13 @@ spec:
provider-provided block IP into the kube-vip manifest.
properties:
host:
description: The hostname on which the API server is serving.
description: host is the hostname on which the API server
is serving.
maxLength: 512
type: string
port:
description: The port on which the API server is serving.
description: port is the port on which the API server
is serving.
format: int32
type: integer
required:
Expand Down
Loading
Loading