Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 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
0e5ae23
feat(api): remove deprecated FailureReason/FailureMessage fields
schegi Apr 13, 2026
0d5d8f2
refactor(scope): remove HasFailed method (deprecated fields removed)
schegi Apr 13, 2026
8bd072f
test: remove tests for deprecated FailureReason/FailureMessage
schegi Apr 13, 2026
b882a63
chore: regenerate deepcopy and CRDs after FailureReason removal
schegi Apr 13, 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
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ issues:
- linters:
- revive
text: "comment-spacings: no space between comment delimiter and comment text"
source: "//(\\+(kubebuilder|optional|required)|#nosec)"
source: "//(\\+(kubebuilder|optional|required|list)|#nosec)"
- linters:
- revive
text: "exported: exported method .*\\.(Reconcile|SetupWithManager|SetupWebhookWithManager) should have comment or be unexported"
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ 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.7) | Cluster API v1beta1 (v1.8) | Cluster API v1beta1 (v1.10) |
|-----------------------|:--------------------------:|:--------------------------:|:---------------------------:|
| CAPIC v1alpha1 (v0.2) | ✓ | ☓ | ☓ |
| CAPIC v1alpha1 (v0.3) | ✓ | ☓ | ☓ |
| CAPIC v1alpha1 (v0.4) | ✓ | ✓ | ☓ |
| CAPIC v1alpha1 (v0.5) | ✓ | ✓ | ☓ |
| CAPIC v1alpha1 (v0.6) | ✓ | ✓ | ☓ |
| CAPIC v1alpha1 (v0.7) | ☓ | ☓ | ✓ |

### 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.

73 changes: 55 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,10 @@ func init() {
// +kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create
// +kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create

// Add RBAC for CRDMigrator controller.
// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch;patch
// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions/status,verbs=get;patch

func main() {
ctrl.SetLogger(klog.Background())
initFlags()
Expand Down Expand Up @@ -99,19 +110,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 setup controllers")
os.Exit(1)
}
//+kubebuilder:scaffold:builder
Expand All @@ -132,6 +132,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 +177,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. Use when the CAPI CRDMigrator handles migration.")
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.
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
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