Skip to content
Merged
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
19 changes: 19 additions & 0 deletions api/common/v1alpha1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,25 @@ const (
DefaultEphemeralManager = "ephemeral-manager"
)

// TopologyLabel represents a topology label that can be configured on machinepoollet, volumepoollet, and bucketpoollet,
// which set them on MachinePool, VolumePool, and BucketPool resources.
// These labels are managed exclusively by the respective poollet controllers (machinepoollet, volumepoollet, bucketpoollet).
// Any manual changes to these labels will be overwritten by the poollet controllers.
// The intent is similar to Kubernetes' topology labels.
type TopologyLabel string

const (
// TopologyLabelRegion is a label applied to MachinePool, VolumePool, and BucketPool resources.
// Machines, Volumes, and Buckets can use this label in their pool selectors.
// The intent is similar to Kubernetes' topology labels (e.g., `topology.kubernetes.io/region`).
TopologyLabelRegion TopologyLabel = "topology.ironcore.dev/region"

// TopologyLabelZone is a label applied to MachinePool, VolumePool, and BucketPool resources.
// Machines, Volumes, and Buckets can use this label in their pool selectors.
// The intent is similar to Kubernetes' topology labels (e.g., `topology.kubernetes.io/zone`).
TopologyLabelZone TopologyLabel = "topology.ironcore.dev/zone"
)

// ConfigMapKeySelector is a reference to a specific 'key' within a ConfigMap resource.
// In some instances, `key` is a required field.
// +structType=atomic
Expand Down
28 changes: 28 additions & 0 deletions docs/api-reference/common.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,34 @@ When specified, allowed values are NoSchedule.</p>
<td></td>
</tr></tbody>
</table>
<h3 id="common.ironcore.dev/v1alpha1.TopologyLabel">TopologyLabel
(<code>string</code> alias)</h3>
<div>
<p>TopologyLabel represents a topology label that can be configured on machinepoollet, volumepoollet, and bucketpoollet,
which set them on MachinePool, VolumePool, and BucketPool resources.
These labels are managed exclusively by the respective poollet controllers (machinepoollet, volumepoollet, bucketpoollet).
Any manual changes to these labels will be overwritten by the poollet controllers.
The intent is similar to Kubernetes&rsquo; topology labels.</p>
</div>
<table>
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr><td><p>&#34;topology.ironcore.dev/region&#34;</p></td>
<td><p>TopologyLabelRegion is a label applied to MachinePool, VolumePool, and BucketPool resources.
Machines, Volumes, and Buckets can use this label in their pool selectors.
The intent is similar to Kubernetes&rsquo; topology labels (e.g., <code>topology.kubernetes.io/region</code>).</p>
</td>
</tr><tr><td><p>&#34;topology.ironcore.dev/zone&#34;</p></td>
<td><p>TopologyLabelZone is a label applied to MachinePool, VolumePool, and BucketPool resources.
Machines, Volumes, and Buckets can use this label in their pool selectors.
The intent is similar to Kubernetes&rsquo; topology labels (e.g., <code>topology.kubernetes.io/zone</code>).</p>
</td>
</tr></tbody>
</table>
<h3 id="common.ironcore.dev/v1alpha1.UIDReference">UIDReference
</h3>
<div>
Expand Down
15 changes: 15 additions & 0 deletions poollet/bucketpoollet/cmd/bucketpoollet/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"

commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
ipamv1alpha1 "github.com/ironcore-dev/ironcore/api/ipam/v1alpha1"
networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1"
storagev1alpha1 "github.com/ironcore-dev/ironcore/api/storage/v1alpha1"
Expand Down Expand Up @@ -66,6 +67,8 @@ type Options struct {
BucketDownwardAPILabels map[string]string
BucketDownwardAPIAnnotations map[string]string
BucketPoolName string
TopologyRegionLabel string
TopologyZoneLabel string
ProviderID string
BucketRuntimeEndpoint string
DialTimeout time.Duration
Expand Down Expand Up @@ -104,6 +107,8 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) {
fs.StringToStringVar(&o.BucketDownwardAPILabels, "bucket-downward-api-label", o.BucketDownwardAPILabels, "Downward-API labels to set on the IRI bucket.")
fs.StringToStringVar(&o.BucketDownwardAPIAnnotations, "bucket-downward-api-annotation", o.BucketDownwardAPIAnnotations, "Downward-API annotations to set on the IRI bucket.")
fs.StringVar(&o.BucketPoolName, "bucket-pool-name", o.BucketPoolName, "Name of the bucket pool to announce / watch")
fs.StringVar(&o.TopologyRegionLabel, "topology-region-label", "", "Label to use for the region topology information.")
fs.StringVar(&o.TopologyZoneLabel, "topology-zone-label", "", "Label to use for the zone topology information.")
fs.StringVar(&o.ProviderID, "provider-id", "", "Provider id to announce on the bucket pool.")
fs.StringVar(&o.BucketRuntimeEndpoint, "bucket-runtime-endpoint", o.BucketRuntimeEndpoint, "Endpoint of the remote bucket runtime service.")
fs.DurationVar(&o.DialTimeout, "dial-timeout", 1*time.Second, "Timeout for dialing to the bucket runtime endpoint.")
Expand Down Expand Up @@ -157,6 +162,14 @@ func Run(ctx context.Context, opts Options) error {
logger := ctrl.LoggerFrom(ctx)
setupLog := ctrl.Log.WithName("setup")

topologyLabels := map[commonv1alpha1.TopologyLabel]string{}
if opts.TopologyRegionLabel != "" {
topologyLabels[commonv1alpha1.TopologyLabelRegion] = opts.TopologyRegionLabel
}
if opts.TopologyZoneLabel != "" {
topologyLabels[commonv1alpha1.TopologyLabelZone] = opts.TopologyZoneLabel
}

getter, err := bucketpoolletconfig.NewGetter(opts.BucketPoolName)
if err != nil {
setupLog.Error(err, "Error creating new getter")
Expand Down Expand Up @@ -342,6 +355,7 @@ func Run(ctx context.Context, opts Options) error {
BucketPoolName: opts.BucketPoolName,
BucketClassMapper: bucketClassMapper,
BucketRuntime: bucketRuntime,
TopologyLabels: topologyLabels,
}).SetupWithManager(mgr); err != nil {
return fmt.Errorf("error setting up bucket pool reconciler with manager: %w", err)
}
Expand All @@ -353,6 +367,7 @@ func Run(ctx context.Context, opts Options) error {
Client: mgr.GetClient(),
BucketPoolName: opts.BucketPoolName,
ProviderID: opts.ProviderID,
TopologyLabels: topologyLabels,
OnInitialized: onInitialized,
}).SetupWithManager(mgr); err != nil {
return fmt.Errorf("error setting up bucket pool init with manager: %w", err)
Expand Down
17 changes: 17 additions & 0 deletions poollet/bucketpoollet/controllers/bucketpool_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import (
"fmt"

"github.com/go-logr/logr"
commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
storagev1alpha1 "github.com/ironcore-dev/ironcore/api/storage/v1alpha1"
iriBucket "github.com/ironcore-dev/ironcore/iri/apis/bucket"
"github.com/ironcore-dev/ironcore/poollet/bucketpoollet/bcm"
poolletutils "github.com/ironcore-dev/ironcore/poollet/common/utils"
corev1 "k8s.io/api/core/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
Expand All @@ -25,6 +27,8 @@ type BucketPoolReconciler struct {
BucketPoolName string
BucketRuntime iriBucket.RuntimeService
BucketClassMapper bcm.BucketClassMapper

TopologyLabels map[commonv1alpha1.TopologyLabel]string
}

//+kubebuilder:rbac:groups=storage.ironcore.dev,resources=bucketpools,verbs=get;list;watch;update;patch
Expand Down Expand Up @@ -70,6 +74,11 @@ func (r *BucketPoolReconciler) supportsBucketClass(ctx context.Context, bucketCl
func (r *BucketPoolReconciler) reconcile(ctx context.Context, log logr.Logger, bucketPool *storagev1alpha1.BucketPool) (ctrl.Result, error) {
log.V(1).Info("Reconcile")

log.V(1).Info("Enforcing configured topology labels")
if err := r.enforceOriginalTopologyLabels(ctx, log, bucketPool); err != nil {
return ctrl.Result{}, fmt.Errorf("error enforcing original topology labels: %w", err)
}

log.V(1).Info("Listing bucket classes")
bucketClassList := &storagev1alpha1.BucketClassList{}
if err := r.List(ctx, bucketClassList); err != nil {
Expand Down Expand Up @@ -101,6 +110,14 @@ func (r *BucketPoolReconciler) reconcile(ctx context.Context, log logr.Logger, b
return ctrl.Result{}, nil
}

func (r *BucketPoolReconciler) enforceOriginalTopologyLabels(ctx context.Context, log logr.Logger, bucketPool *storagev1alpha1.BucketPool) error {
base := bucketPool.DeepCopy()

poolletutils.SetTopologyLabels(log, &bucketPool.ObjectMeta, r.TopologyLabels)

return r.Patch(ctx, bucketPool, client.MergeFrom(base))
}

func (r *BucketPoolReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(
Expand Down
17 changes: 17 additions & 0 deletions poollet/bucketpoollet/controllers/bucketpool_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,21 @@ var _ = Describe("BucketPoolController", func() {
})),
))
})

It("should enforce topology labels", func(ctx SpecContext) {
By("patching the bucket pool with incorrect topology labels")
Eventually(Update(bucketPool, func() {
if bucketPool.Labels == nil {
bucketPool.Labels = make(map[string]string)
}
bucketPool.Labels["topology.ironcore.dev/region"] = "wrong-region"
bucketPool.Labels["topology.ironcore.dev/zone"] = "wrong-zone"
})).Should(Succeed())

By("checking if the reconciler resets the topology labels to its original values")
Eventually(Object(bucketPool)).Should(SatisfyAll(
HaveField("ObjectMeta.Labels", HaveKeyWithValue("topology.ironcore.dev/region", "test-region-1")),
HaveField("ObjectMeta.Labels", HaveKeyWithValue("topology.ironcore.dev/zone", "test-zone-1")),
))
})
})
8 changes: 8 additions & 0 deletions poollet/bucketpoollet/controllers/bucketpool_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"context"
"fmt"

commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
storagev1alpha1 "github.com/ironcore-dev/ironcore/api/storage/v1alpha1"
bucketpoolletv1alpha1 "github.com/ironcore-dev/ironcore/poollet/bucketpoollet/api/v1alpha1"
poolletutils "github.com/ironcore-dev/ironcore/poollet/common/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -20,6 +22,8 @@ type BucketPoolInit struct {
BucketPoolName string
ProviderID string

TopologyLabels map[commonv1alpha1.TopologyLabel]string

OnInitialized func(ctx context.Context) error
OnFailed func(ctx context.Context, reason error) error
}
Expand All @@ -42,6 +46,10 @@ func (i *BucketPoolInit) Start(ctx context.Context) error {
ProviderID: i.ProviderID,
},
}

log.V(1).Info("Initially setting topology labels")
poolletutils.SetTopologyLabels(log, &bucketPool.ObjectMeta, i.TopologyLabels)

if err := i.Patch(ctx, bucketPool, client.Apply, client.ForceOwnership, client.FieldOwner(bucketpoolletv1alpha1.FieldOwner)); err != nil {
if i.OnFailed != nil {
log.V(1).Info("Failed applying, calling OnFailed callback", "Error", err)
Expand Down
54 changes: 54 additions & 0 deletions poollet/bucketpoollet/controllers/bucketpool_init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

package controllers_test

import (
"context"

commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
storagev1alpha1 "github.com/ironcore-dev/ironcore/api/storage/v1alpha1"
"github.com/ironcore-dev/ironcore/poollet/bucketpoollet/controllers"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
. "sigs.k8s.io/controller-runtime/pkg/envtest/komega"
)

var _ = Describe("BucketPoolInit", func() {
It("should set topology labels", func(ctx SpecContext) {
initializedCalled := false

bpi := &controllers.BucketPoolInit{
Client: k8sClient,
BucketPoolName: "test-pool",
ProviderID: "provider-123",
TopologyLabels: map[commonv1alpha1.TopologyLabel]string{
commonv1alpha1.TopologyLabelRegion: "foo-region-1",
commonv1alpha1.TopologyLabelZone: "foo-zone-1",
},
OnInitialized: func(ctx context.Context) error {
initializedCalled = true
return nil
},
}

Expect(bpi.Start(ctx)).To(Succeed())

pool := &storagev1alpha1.BucketPool{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pool",
},
}
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(pool), pool)).To(Succeed())
DeferCleanup(k8sClient.Delete, pool)

Expect(initializedCalled).To(BeTrue(), "OnInitialized should have been called")

Eventually(Object(pool)).Should(SatisfyAll(
HaveField("ObjectMeta.Labels", HaveKeyWithValue("topology.ironcore.dev/region", "foo-region-1")),
HaveField("ObjectMeta.Labels", HaveKeyWithValue("topology.ironcore.dev/zone", "foo-zone-1")),
))
})
})
9 changes: 9 additions & 0 deletions poollet/bucketpoollet/controllers/controllers_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"testing"
"time"

commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
corev1alpha1 "github.com/ironcore-dev/ironcore/api/core/v1alpha1"
storagev1alpha1 "github.com/ironcore-dev/ironcore/api/storage/v1alpha1"
storageclient "github.com/ironcore-dev/ironcore/internal/client/storage"
Expand Down Expand Up @@ -158,6 +159,10 @@ func SetupTest() (*corev1.Namespace, *storagev1alpha1.BucketPool, *storagev1alph
*bp = storagev1alpha1.BucketPool{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-bp-",
Labels: map[string]string{
string(commonv1alpha1.TopologyLabelRegion): "test-region-1",
string(commonv1alpha1.TopologyLabelZone): "test-zone-1",
},
},
}
Expect(k8sClient.Create(ctx, bp)).To(Succeed(), "failed to create test bucket pool")
Expand Down Expand Up @@ -239,6 +244,10 @@ func SetupTest() (*corev1.Namespace, *storagev1alpha1.BucketPool, *storagev1alph
BucketRuntime: srv,
BucketClassMapper: bucketClassMapper,
BucketPoolName: bp.Name,
TopologyLabels: map[commonv1alpha1.TopologyLabel]string{
commonv1alpha1.TopologyLabelRegion: "test-region-1",
commonv1alpha1.TopologyLabelZone: "test-zone-1",
},
}).SetupWithManager(k8sManager)).To(Succeed())

go func() {
Expand Down
25 changes: 25 additions & 0 deletions poollet/common/utils/topology.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

package utils

import (
"github.com/go-logr/logr"
commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func SetTopologyLabels(log logr.Logger, om *v1.ObjectMeta, labels map[commonv1alpha1.TopologyLabel]string) {
if len(labels) == 0 {
return
}

if om.Labels == nil {
om.Labels = make(map[string]string)
}

for key, val := range labels {
log.V(1).Info("Setting topology label", "Label", key, "Value", val)
om.Labels[string(key)] = val
}
}
17 changes: 17 additions & 0 deletions poollet/machinepoollet/cmd/machinepoollet/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"

commonv1alpha1 "github.com/ironcore-dev/ironcore/api/common/v1alpha1"
computev1alpha1 "github.com/ironcore-dev/ironcore/api/compute/v1alpha1"
ipamv1alpha1 "github.com/ironcore-dev/ironcore/api/ipam/v1alpha1"
networkingv1alpha1 "github.com/ironcore-dev/ironcore/api/networking/v1alpha1"
Expand Down Expand Up @@ -87,6 +88,9 @@ type Options struct {
NetworkDownwardAPILabels map[string]string
NetworkDownwardAPIAnnotations map[string]string

TopologyRegionLabel string
TopologyZoneLabel string

ProviderID string
MachineRuntimeEndpoint string
MachineRuntimeSocketDiscoveryTimeout time.Duration
Expand Down Expand Up @@ -136,6 +140,9 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) {
fs.StringToStringVar(&o.NetworkDownwardAPILabels, "network-downward-api-label", o.NetworkDownwardAPILabels, "Downward-API labels to set on the iri network.")
fs.StringToStringVar(&o.NetworkDownwardAPIAnnotations, "network-downward-api-annotation", o.NetworkDownwardAPIAnnotations, "Downward-API annotations to set on the iri network.")

fs.StringVar(&o.TopologyRegionLabel, "topology-region-label", "", "Label to use for the region topology information.")
fs.StringVar(&o.TopologyZoneLabel, "topology-zone-label", "", "Label to use for the zone topology information.")

fs.StringVar(&o.ProviderID, "provider-id", "", "Provider id to announce on the machine pool.")
fs.StringVar(&o.MachineRuntimeEndpoint, "machine-runtime-endpoint", o.MachineRuntimeEndpoint, "Endpoint of the remote machine runtime service.")
fs.DurationVar(&o.MachineRuntimeSocketDiscoveryTimeout, "machine-runtime-socket-discovery-timeout", 20*time.Second, "Timeout for discovering the machine runtime socket.")
Expand Down Expand Up @@ -320,6 +327,14 @@ func Run(ctx context.Context, opts Options) error {
})
}

topologyLabels := map[commonv1alpha1.TopologyLabel]string{}
if opts.TopologyRegionLabel != "" {
topologyLabels[commonv1alpha1.TopologyLabelRegion] = opts.TopologyRegionLabel
}
if opts.TopologyZoneLabel != "" {
topologyLabels[commonv1alpha1.TopologyLabelZone] = opts.TopologyZoneLabel
}

mgr, err := ctrl.NewManager(cfg, ctrl.Options{
Logger: logger,
Scheme: scheme,
Expand Down Expand Up @@ -462,6 +477,7 @@ func Run(ctx context.Context, opts Options) error {
Port: port,
MachineRuntime: machineRuntime,
MachineClassMapper: machineClassMapper,
TopologyLabels: topologyLabels,
}).SetupWithManager(mgr); err != nil {
return fmt.Errorf("error setting up machine pool reconciler with manager: %w", err)
}
Expand All @@ -481,6 +497,7 @@ func Run(ctx context.Context, opts Options) error {
Client: mgr.GetClient(),
MachinePoolName: opts.MachinePoolName,
ProviderID: opts.ProviderID,
TopologyLabels: topologyLabels,
OnInitialized: onInitialized,
}).SetupWithManager(mgr); err != nil {
return fmt.Errorf("error setting up machine pool init with manager: %w", err)
Expand Down
Loading
Loading