Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.vscode
bin/
test/
!test/extension/
**/*.yaml
hack/
docs/
Expand Down
19 changes: 17 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,10 @@ ORG ?= rancher
CONTROLLER_IMAGE_NAME := cluster-api-provider-rke2
BOOTSTRAP_IMAGE_NAME := $(CONTROLLER_IMAGE_NAME)-bootstrap
CONTROLPLANE_IMAGE_NAME = $(CONTROLLER_IMAGE_NAME)-controlplane
TEST_EXTENSION_IMAGE_NAME := $(CONTROLLER_IMAGE_NAME)-test-extension
BOOTSTRAP_IMG ?= $(REGISTRY)/$(ORG)/$(BOOTSTRAP_IMAGE_NAME)
CONTROLPLANE_IMG ?= $(REGISTRY)/$(ORG)/$(CONTROLPLANE_IMAGE_NAME)
TEST_EXTENSION_IMG ?= $(REGISTRY)/$(ORG)/$(TEST_EXTENSION_IMAGE_NAME)
IID_FILE ?= $(shell mktemp)
LOCAL_IMAGES = $(shell pwd)/out/images

Expand Down Expand Up @@ -351,6 +353,18 @@ docker-build-rke2-control-plane:
$(MAKE) set-manifest-image MANIFEST_IMG=$(CONTROLPLANE_IMG) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="./controlplane/config/default/manager_image_patch.yaml"
$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./controlplane/config/default/manager_pull_policy.yaml"

.PHONY: docker-build-test-extension
docker-build-test-extension: buildx-machine docker-pull-prerequisites ## Build the e2e test Runtime Extension image
DOCKER_BUILDKIT=1 BUILDX_BUILDER=$(MACHINE) docker buildx build \
--platform $(ARCH) \
--load \
--build-arg builder_image=$(GO_CONTAINER_IMAGE) \
--build-arg goproxy=$(GOPROXY) \
--build-arg package=./test/extension \
--build-arg ldflags="$(LDFLAGS)" . -t $(TEST_EXTENSION_IMG):$(TAG)
$(MAKE) set-manifest-image MANIFEST_IMG=$(TEST_EXTENSION_IMG) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="./test/extension/config/default/manager_image_patch.yaml"
$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./test/extension/config/default/manager_pull_policy.yaml"

## --------------------------------------
## Testing
## --------------------------------------
Expand Down Expand Up @@ -427,16 +441,17 @@ test-e2e: ## Run the end-to-end tests
# https://www.suse.com/support/kb/doc/?id=000020048
.PHONY: inotify-check
inotify-check:
@if [ `cat /proc/sys/fs/inotify/max_user_instances` -le 256 ]; then \
@if [ -r /proc/sys/fs/inotify/max_user_instances ] && [ `cat /proc/sys/fs/inotify/max_user_instances` -le 256 ]; then \
echo -e "\033[0;31mfs.inotify.max_user_instances is too low, test may fail (sudo sysctl fs.inotify.max_user_instances=8192)\033[0m";\
fi
@if [ `cat /proc/sys/fs/inotify/max_user_watches` -le 8192 ]; then \
@if [ -r /proc/sys/fs/inotify/max_user_watches ] && [ `cat /proc/sys/fs/inotify/max_user_watches` -le 8192 ]; then \
echo -e "\033[0;31mfs.inotify.max_user_watches is too low, tests may fail (sudo sysctl fs.inotify.max_user_watches=1048576)\033[0m"; \
fi

.PHONY: e2e-image
e2e-image:
TAG=$(TAG) $(MAKE) docker-build
TAG=$(TAG) $(MAKE) docker-build-test-extension

.PHONY: compile-e2e
compile-e2e: ## Test e2e compilation
Expand Down
8 changes: 8 additions & 0 deletions controlplane/config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ rules:
- patch
- update
- watch
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
- watch
- apiGroups:
- apiextensions.k8s.io
resources:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,14 @@ import (
)

const (
// rke2ManagerName is the name of the RKE2 manager deployment.
// rke2ManagerName is the SSA field manager used for the main RKE2 control-plane
// objects (Machine spec, InfraMachine, RKE2Config).
rke2ManagerName = "rke2controlplane"

// rke2MetadataManagerName is a separate SSA field manager used for the
// labels and annotations only patches written every reconcile by syncMachines.
rke2MetadataManagerName = "rke2controlplane-metadata"

// rke2ControlPlaneKind is the kind of the RKE2 control plane.
rke2ControlPlaneKind = "RKE2ControlPlane"

Expand Down Expand Up @@ -119,6 +124,7 @@ type RKE2ControlPlaneReconciler struct {
// +kubebuilder:rbac:groups="infrastructure.cluster.x-k8s.io",resources=*,verbs=get;list;watch;create;patch;delete
// +kubebuilder:rbac:groups="apiextensions.k8s.io",resources=customresourcedefinitions,verbs=get;list;watch
// +kubebuilder:rbac:groups=runtime.cluster.x-k8s.io,resources=extensionconfigs,verbs=get;list;watch
// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
Expand Down
6 changes: 5 additions & 1 deletion controlplane/internal/controllers/scale.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,11 @@ func (r *RKE2ControlPlaneReconciler) UpdateExternalObject(
// Update annotations
updatedObject.SetAnnotations(rcp.Spec.MachineTemplate.ObjectMeta.Annotations)

if err := ssa.Patch(ctx, r.Client, rke2ManagerName, updatedObject, ssa.WithCachingProxy{Cache: r.ssaCache, Original: obj}); err != nil {
// Use the metadata only field manager so we only own the labels/annotations
// that were derived from RCP.MachineTemplate metadata. This avoids stripping
// other annotations (e.g. UpdateInProgressAnnotation) that triggerInPlaceUpdate
// wrote under the main rke2ManagerName.
if err := ssa.Patch(ctx, r.Client, rke2MetadataManagerName, updatedObject, ssa.WithCachingProxy{Cache: r.ssaCache, Original: obj}); err != nil {
return fmt.Errorf("failed to update %s: %w", obj.GetObjectKind().GroupVersionKind().Kind, err)
}

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ require (
go.etcd.io/etcd/api/v3 v3.6.10
go.etcd.io/etcd/client/v3 v3.6.10
go.uber.org/zap v1.28.0
gomodules.xyz/jsonpatch/v2 v2.5.0
google.golang.org/grpc v1.80.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.35.4
k8s.io/apiextensions-apiserver v0.35.4
k8s.io/apimachinery v0.35.4
k8s.io/apiserver v0.35.4
k8s.io/client-go v0.35.4
k8s.io/component-base v0.35.4
k8s.io/klog/v2 v2.140.0
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
sigs.k8s.io/cluster-api v1.13.1
Expand Down Expand Up @@ -156,14 +158,12 @@ require (
golang.org/x/text v0.36.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.44.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/cluster-bootstrap v0.35.4 // indirect
k8s.io/component-base v0.35.4 // indirect
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
Expand Down
66 changes: 59 additions & 7 deletions pkg/rke2/control_plane.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
controlplanev1 "github.com/rancher/cluster-api-provider-rke2/controlplane/api/v1beta2"
"github.com/rancher/cluster-api-provider-rke2/pkg/capi/hooks"
"github.com/rancher/cluster-api-provider-rke2/pkg/capi/inplace"
"github.com/rancher/cluster-api-provider-rke2/pkg/rke2/desiredstate"
)

// UpToDateResult is the result of calling the UpToDate func for a Machine.
Expand Down Expand Up @@ -141,7 +142,7 @@ func NewControlPlane(
machinesUpToDateResults := map[string]UpToDateResult{}

for _, m := range ownedMachines {
upToDate, result, err := UpToDate(ctx, m, rcp, infraObjects, rke2Configs)
upToDate, result, err := UpToDate(ctx, client, cluster, m, rcp, infraObjects, rke2Configs)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -628,8 +629,14 @@ func (c *ControlPlane) UsesEmbeddedEtcd() bool {

// UpToDate checks if a Machine is up to date with the control plane's configuration.
// If not, messages explaining why are provided with different level of detail for logs and conditions.
func UpToDate(ctx context.Context, machine *clusterv1.Machine, rcp *controlplanev1.RKE2ControlPlane,
infraConfigs map[string]*unstructured.Unstructured, machineConfigs map[string]*bootstrapv1.RKE2Config,
func UpToDate(
ctx context.Context,
c client.Client,
cluster *clusterv1.Cluster,
machine *clusterv1.Machine,
rcp *controlplanev1.RKE2ControlPlane,
infraConfigs map[string]*unstructured.Unstructured,
machineConfigs map[string]*bootstrapv1.RKE2Config,
) (bool, *UpToDateResult, error) {
res := &UpToDateResult{
EligibleForInPlaceUpdate: true,
Expand All @@ -655,7 +662,11 @@ func UpToDate(ctx context.Context, machine *clusterv1.Machine, rcp *controlplane
}

// Machines that do not match with rcp config.
matches, specLogMessages, specConditionMessages := matchesMachineSpec(ctx, infraConfigs, machineConfigs, rcp, machine)
matches, specLogMessages, specConditionMessages, err := matchesMachineSpec(ctx, c, cluster, infraConfigs, machineConfigs, rcp, machine, res)
if err != nil {
return false, nil, err
}

if !matches {
res.LogMessages = append(res.LogMessages, specLogMessages...)
res.ConditionMessages = append(res.ConditionMessages, specConditionMessages...)
Expand All @@ -681,14 +692,55 @@ func UpToDate(ctx context.Context, machine *clusterv1.Machine, rcp *controlplane
// - are not relevant for the rollout decision (ex: failureDomain).
func matchesMachineSpec(
ctx context.Context,
c client.Client,
cluster *clusterv1.Cluster,
infraConfigs map[string]*unstructured.Unstructured,
machineConfigs map[string]*bootstrapv1.RKE2Config,
rcp *controlplanev1.RKE2ControlPlane,
machine *clusterv1.Machine,
) (bool, []string, []string) {
res *UpToDateResult,
) (bool, []string, []string, error) {
logMessages := []string{}
conditionMessages := []string{}

if cluster != nil {
desiredMachine, err := desiredstate.ComputeDesiredMachine(
rcp, cluster,
machine.Spec.InfrastructureRef, machine.Spec.Bootstrap.ConfigRef,
machine.Spec.FailureDomain, machine,
)
if err != nil {
return false, nil, nil, fmt.Errorf("failed to compute desired Machine for %s: %w", machine.Name, err)
}

// Note: spec.version is not mutated in-place by syncMachines and accordingly
// not updated by desiredstate.ComputeDesiredMachine, so we have to update it here.
// Note: spec.failureDomain is in general only changed on delete/create, so we don't have to update it here for in-place.
desiredMachine.Spec.Version = rcp.Spec.Version
res.DesiredMachine = desiredMachine
// Note: Intentionally not storing currentMachine as it can change later, e.g. through syncMachines.

if res.CurrentRKE2Config != nil {
desiredRKE2Config, err := desiredstate.ComputeDesiredRKE2Config(rcp, cluster, res.CurrentRKE2Config.Name, res.CurrentRKE2Config)
if err != nil {
return false, nil, nil, fmt.Errorf("failed to compute desired RKE2Config for %s: %w", machine.Name, err)
}

res.DesiredRKE2Config = desiredRKE2Config
}

if res.CurrentInfraMachine != nil {
desiredInfraMachine, err := desiredstate.ComputeDesiredInfraMachine(
ctx, c, rcp, cluster, res.CurrentInfraMachine.GetName(), res.CurrentInfraMachine,
)
if err != nil {
return false, nil, nil, fmt.Errorf("failed to compute desired InfraMachine for %s: %w", machine.Name, err)
}

res.DesiredInfraMachine = desiredInfraMachine
}
}

if !collections.MatchesKubernetesVersion(rcp.Spec.Version)(machine) {
machineVersion := ""
if machine != nil && machine.Spec.Version != "" {
Expand All @@ -711,8 +763,8 @@ func matchesMachineSpec(
}

if len(logMessages) > 0 || len(conditionMessages) > 0 {
return false, logMessages, conditionMessages
return false, logMessages, conditionMessages, nil
}

return true, nil, nil
return true, nil, nil, nil
}
Loading