Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8b86252
migrate mcm provider from openstack to stackit
aniruddha2000 Aug 26, 2026
01a1b39
add feature gates
aniruddha2000 Aug 27, 2026
1837d0f
add worker migrated annotation
aniruddha2000 Aug 27, 2026
c47646a
add small check to not trigger migration when done
aniruddha2000 Aug 27, 2026
504056b
minor nits
aniruddha2000 Aug 27, 2026
462effd
add diagnosis
aniruddha2000 Aug 31, 2026
952006b
trigger build
aniruddha2000 Aug 31, 2026
6a753b1
run ci
aniruddha2000 Aug 31, 2026
a67922d
add nil stackit client to the tests
aniruddha2000 Sep 2, 2026
8f4dd16
remove diagnosis
aniruddha2000 Sep 2, 2026
5241e32
add poc test for the machine migration
aniruddha2000 Sep 2, 2026
b32b095
fix mocks in the tests
aniruddha2000 Sep 2, 2026
a73bc4b
add improvements to the test
aniruddha2000 Sep 3, 2026
385baa8
fix the test and its running
aniruddha2000 Sep 3, 2026
51b27e6
add iaas failure tolerance testing
aniruddha2000 Sep 4, 2026
320d8bf
make fmt
aniruddha2000 Sep 7, 2026
ec219a7
make check fix<
aniruddha2000 Sep 7, 2026
0733734
make check fix
aniruddha2000 Sep 9, 2026
95619d8
fix test
aniruddha2000 Sep 9, 2026
2b1a268
fix test
aniruddha2000 Sep 9, 2026
a712745
resolve review
aniruddha2000 Sep 10, 2026
c44e976
fix test
aniruddha2000 Sep 10, 2026
f66ecdc
use named capture groups in the regex
aniruddha2000 Sep 11, 2026
84dd68b
move regex compile to init func
aniruddha2000 Sep 11, 2026
49091b3
resolve AI suggestions
aniruddha2000 Sep 17, 2026
1624513
resolve AI suggestions
aniruddha2000 Sep 17, 2026
84af27b
revert provider id is empty review
aniruddha2000 Sep 17, 2026
88d9ba2
update labels and make nits
aniruddha2000 Sep 18, 2026
183cd32
fix test
aniruddha2000 Sep 18, 2026
6b9e45a
fix review
aniruddha2000 Sep 23, 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
12 changes: 12 additions & 0 deletions pkg/controller/worker/actuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/apis/stackit/helper"
stackitv1alpha1 "github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/apis/stackit/v1alpha1"
openstackclient "github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/openstack/client"
"github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/stackit"
stackitclient "github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/stackit/client"
)

type delegateFactory struct {
Expand Down Expand Up @@ -71,6 +73,12 @@ func (d *delegateFactory) WorkerDelegate(ctx context.Context, worker *extensions
return nil, err
}

stackitClient := stackitclient.New(stackit.DetermineRegion(cluster), cluster)
iaasClient, err := stackitClient.IaaS(ctx, d.seedClient, worker.Spec.SecretRef)
if err != nil {
return nil, err
}

return NewWorkerDelegate(
d.seedClient,
d.scheme,
Expand All @@ -81,6 +89,7 @@ func (d *delegateFactory) WorkerDelegate(ctx context.Context, worker *extensions
worker,
cluster,
d.customLabelDomain,
iaasClient,
)
}

Expand All @@ -102,6 +111,7 @@ type workerDelegate struct {
machineImages []stackitv1alpha1.MachineImage

openstackClient openstackclient.Factory
iaaSClient stackitclient.IaaSClient
}

// NewWorkerDelegate creates a new context for a worker reconciliation.
Expand All @@ -115,6 +125,7 @@ func NewWorkerDelegate(
worker *extensionsv1alpha1.Worker,
cluster *extensionscontroller.Cluster,
customLabelDomain string,
iaaSClient stackitclient.IaaSClient,
) (genericactuator.WorkerDelegate, error) {
config, err := helper.CloudProfileConfigFromCluster(cluster)
if err != nil {
Expand All @@ -133,5 +144,6 @@ func NewWorkerDelegate(
cluster: cluster,
worker: worker,
customLabelDomain: customLabelDomain,
iaaSClient: iaaSClient,
}, nil
}
131 changes: 130 additions & 1 deletion pkg/controller/worker/machines.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"

extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller"
Expand All @@ -24,6 +25,7 @@ import (
"github.com/gardener/gardener/pkg/client/kubernetes"
gardenutils "github.com/gardener/gardener/pkg/utils"
machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
iaas "github.com/stackitcloud/stackit-sdk-go/services/iaas/v2api"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand All @@ -36,6 +38,14 @@ import (
stackitutils "github.com/stackitcloud/gardener-extension-provider-stackit/v2/pkg/utils"
)

const (
shouldMigrateMachineAnnotation = "stackit.cloud/machine-should-be-migrated"
migratedMachineAnnotation = "stackit.cloud/migrated-machine"
workerMigratedAnnotation = "stackit.cloud/machine-controller-manager-migrated"

stackitProviderID = "stackit://"
)

// MachineClassKind yields the name of the machine class kind used by OpenStack provider.
func (w *workerDelegate) MachineClassKind() string {
return "MachineClass"
Expand Down Expand Up @@ -63,7 +73,19 @@ func (w *workerDelegate) DeployMachineClasses(ctx context.Context) error {
if feature.UseStackitMachineControllerManager(w.cluster) {
chartPath = "machineclass-stackit"
}
return w.seedChartApplier.ApplyFromEmbeddedFS(ctx, charts.InternalChart, filepath.Join(charts.InternalChartsPath, chartPath), w.worker.Namespace, "machineclass", kubernetes.Values(map[string]any{"machineClasses": w.machineClasses}))
err := w.seedChartApplier.ApplyFromEmbeddedFS(ctx, charts.InternalChart, filepath.Join(charts.InternalChartsPath, chartPath), w.worker.Namespace, "machineclass", kubernetes.Values(map[string]any{"machineClasses": w.machineClasses}))
if err != nil {
return err
}

if feature.MigrateStackitMachineControllerManager(w.cluster) && w.worker.Annotations[workerMigratedAnnotation] != "true" {
err = w.migrateMachines(ctx)
if err != nil {
return err
}
Comment thread
breuerfelix marked this conversation as resolved.
Outdated
}

return nil
}

// GenerateMachineDeployments generates the configuration for the desired machine deployments.
Expand Down Expand Up @@ -406,3 +428,110 @@ func EnsureUniformMachineImages(images []stackitv1alpha1.MachineImage, definitio
}
return uniformMachineImages
}

func (w *workerDelegate) migrateMachines(ctx context.Context) error {
var (
allMachines machinev1alpha1.MachineList
migrateMachines []machinev1alpha1.Machine
)

err := w.seedClient.List(ctx, &allMachines, &client.ListOptions{Namespace: w.worker.Namespace})
if err != nil {
return err
Comment thread
aniruddha2000 marked this conversation as resolved.
Outdated
}

for i := range allMachines.Items {
// ignore error as default is false
migrateAnnotation, _ := strconv.ParseBool(allMachines.Items[i].Annotations[shouldMigrateMachineAnnotation])
if !strings.HasPrefix(allMachines.Items[i].Spec.ProviderID, "stackit://") || migrateAnnotation {
migrateMachines = append(migrateMachines, allMachines.Items[i])
}
}

if len(migrateMachines) == 0 {
// no old openstack machine
return w.markWorkerAsMigrated(ctx)
}

for _, m := range migrateMachines {
patchAnnotations := client.MergeFrom(m.DeepCopy())
if m.Annotations == nil {
m.Annotations = make(map[string]string)
}
m.Annotations[shouldMigrateMachineAnnotation] = "true"
m.Annotations[migratedMachineAnnotation] = "true"
Comment thread
breuerfelix marked this conversation as resolved.
err = w.seedClient.Patch(ctx, &m, patchAnnotations)
if err != nil {
return err
}

if m.Spec.ProviderID != "" {
Comment thread
breuerfelix marked this conversation as resolved.
serverID, err := serverIDFromProviderID(m.Spec.ProviderID)
if err != nil {
return fmt.Errorf("migrateMachines: %w", err)
}
Comment thread
aniruddha2000 marked this conversation as resolved.

patch := client.MergeFrom(m.DeepCopy())
m.Spec.ProviderID = fmt.Sprintf("%s%s/%s", stackitProviderID, w.iaaSClient.ProjectID(), serverID)
err = w.seedClient.Patch(ctx, &m, patch)
if err != nil {
return err
}

_, err = w.iaaSClient.UpdateServer(ctx, serverID, iaas.UpdateServerPayload{
Labels: map[string]any{
// TODO refine labels
Comment thread
breuerfelix marked this conversation as resolved.
"mcm.gardener.cloud/machine": m.Name,
"mcm.gardener.cloud/machineclass": m.Spec.Class.Name,
"mcm.gardener.cloud/role": "node",
Comment thread
breuerfelix marked this conversation as resolved.
Outdated
},
Comment thread
aniruddha2000 marked this conversation as resolved.
})
if err != nil {
return err
}
}

patchRemoveMigrationAnnotation := client.MergeFrom(m.DeepCopy())
delete(m.Annotations, shouldMigrateMachineAnnotation)
err = w.seedClient.Patch(ctx, &m, patchRemoveMigrationAnnotation)
if err != nil {
return err
}
}

return w.markWorkerAsMigrated(ctx)
}

func (w *workerDelegate) markWorkerAsMigrated(ctx context.Context) error {
patchWorker := client.MergeFrom(w.worker.DeepCopy())

if w.worker.Annotations == nil {
w.worker.Annotations = make(map[string]string)
}

w.worker.Annotations[workerMigratedAnnotation] = "true"

return w.seedClient.Patch(ctx, w.worker, patchWorker)
}

func serverIDFromProviderID(providerID string) (string, error) {
patterns := []*regexp.Regexp{
regexp.MustCompile(`^openstack:///[^/]+/(?P<serverID>[^/]+)$`),
regexp.MustCompile(`^stackit://[^/]+/(?P<serverID>[^/]+)$`),
Comment thread
breuerfelix marked this conversation as resolved.
}

for _, pattern := range patterns {
match := pattern.FindStringSubmatch(providerID)
if len(match) == 0 {
continue
}

for i, name := range pattern.SubexpNames() {
if name == "serverID" {
return match[i], nil
}
}
Comment thread
aniruddha2000 marked this conversation as resolved.
Outdated
}

return "", fmt.Errorf("malformed machine provider ID: %s", providerID)
}
Loading