Skip to content

Commit

Permalink
Add time triggered Server polling (#114)
Browse files Browse the repository at this point in the history
* Add time triggered `Server` polling

Currently we are missing e.g. PowerState changes on a `Server` if they
are manually performed. In order to check periodically for the correct
`Server` status we introduce a new flag `resync-interval` (default: 30
sec) which will trigger a `Server` reconciliation according to this
value.

* Rename `resyn-interval` flag to `server-resync-interval`
  • Loading branch information
afritzler authored Aug 23, 2024
1 parent 58c3779 commit a4264ab
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 36 deletions.
27 changes: 16 additions & 11 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,15 @@ func main() {
var registryPort int
var registryProtocol string
var registryURL string
var requeueInterval time.Duration
var registryResyncInterval time.Duration
var webhookPort int
var enforceFirstBoot bool
var serverResyncInterval time.Duration

flag.DurationVar(&requeueInterval, "requeue-interval", 10*time.Second, "Reconciler requeue interval.")
flag.DurationVar(&registryResyncInterval, "registry-resync-interval", 10*time.Second,
"Defines the interval at which the registry is polled for new server information.")
flag.DurationVar(&serverResyncInterval, "server-resync-interval", 30*time.Second,
"Defines the interval at which the server is polled.")
flag.StringVar(&registryURL, "registry-url", "", "The URL of the registry.")
flag.StringVar(&registryProtocol, "registry-protocol", "http", "The protocol to use for the registry.")
flag.IntVar(&registryPort, "registry-port", 10000, "The port to use for the registry.")
Expand Down Expand Up @@ -193,15 +197,16 @@ func main() {
os.Exit(1)
}
if err = (&controller.ServerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Insecure: insecure,
ManagerNamespace: managerNamespace,
ProbeImage: probeImage,
ProbeOSImage: probeOSImage,
RegistryURL: registryURL,
RequeueInterval: requeueInterval,
EnforceFirstBoot: enforceFirstBoot,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Insecure: insecure,
ManagerNamespace: managerNamespace,
ProbeImage: probeImage,
ProbeOSImage: probeOSImage,
RegistryURL: registryURL,
RegistryResyncInterval: registryResyncInterval,
ResyncInterval: serverResyncInterval,
EnforceFirstBoot: enforceFirstBoot,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Server")
os.Exit(1)
Expand Down
58 changes: 42 additions & 16 deletions internal/controller/server_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,23 @@ import (
"sort"
"time"

"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/handler"

apierrors "k8s.io/apimachinery/pkg/api/errors"

"github.com/ironcore-dev/metal-operator/internal/api/registry"

"github.com/go-logr/logr"
"github.com/ironcore-dev/controller-utils/clientutils"
metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
"github.com/ironcore-dev/metal-operator/internal/api/registry"
"github.com/ironcore-dev/metal-operator/internal/ignition"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
meta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/source"
)

const (
Expand All @@ -50,14 +49,15 @@ const (
// ServerReconciler reconciles a Server object
type ServerReconciler struct {
client.Client
Scheme *runtime.Scheme
Insecure bool
ManagerNamespace string
ProbeImage string
RegistryURL string
ProbeOSImage string
RequeueInterval time.Duration
EnforceFirstBoot bool
Scheme *runtime.Scheme
Insecure bool
ManagerNamespace string
ProbeImage string
RegistryURL string
ProbeOSImage string
RegistryResyncInterval time.Duration
EnforceFirstBoot bool
ResyncInterval time.Duration
}

//+kubebuilder:rbac:groups=metal.ironcore.dev,resources=bmcs,verbs=get;list;watch
Expand Down Expand Up @@ -162,7 +162,7 @@ func (r *ServerReconciler) reconcile(ctx context.Context, log logr.Logger, serve

requeue, err := r.ensureServerStateTransition(ctx, log, server)
if requeue && err == nil {
return ctrl.Result{Requeue: requeue, RequeueAfter: r.RequeueInterval}, nil
return ctrl.Result{Requeue: requeue, RequeueAfter: r.RegistryResyncInterval}, nil
}
if err != nil && !apierrors.IsNotFound(err) {
return ctrl.Result{}, fmt.Errorf("failed to ensure server state transition: %w", err)
Expand Down Expand Up @@ -814,12 +814,38 @@ func (r *ServerReconciler) applyBiosSettings(ctx context.Context, log logr.Logge

// SetupWithManager sets up the controller with the Manager.
func (r *ServerReconciler) SetupWithManager(mgr ctrl.Manager) error {
// Create a channel to send periodic events
ch := make(chan event.TypedGenericEvent[*metalv1alpha1.Server])

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Start a goroutine to send events to the channel at the specified interval
go func() {
ticker := time.NewTicker(r.RegistryResyncInterval)
defer ticker.Stop()

for {
select {
case <-ticker.C:
// Emit an event to trigger reconciliation
ch <- event.TypedGenericEvent[*metalv1alpha1.Server]{
Object: &metalv1alpha1.Server{},
}
case <-ctx.Done():
close(ch)
return
}
}
}()

return ctrl.NewControllerManagedBy(mgr).
For(&metalv1alpha1.Server{}).
Watches(
&metalv1alpha1.ServerBootConfiguration{},
r.enqueueServerByServerBootConfiguration(),
).
WatchesRawSource(source.Channel(ch, &handler.TypedEnqueueRequestForObject[*metalv1alpha1.Server]{})).
Complete(r)
}

Expand Down
19 changes: 10 additions & 9 deletions internal/controller/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,16 @@ func SetupTest() *corev1.Namespace {
}).SetupWithManager(k8sManager)).To(Succeed())

Expect((&ServerReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Insecure: true,
ManagerNamespace: ns.Name,
ProbeImage: "foo:latest",
ProbeOSImage: "fooOS:latest",
RegistryURL: registryURL,
RequeueInterval: 50 * time.Millisecond,
EnforceFirstBoot: true,
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Insecure: true,
ManagerNamespace: ns.Name,
ProbeImage: "foo:latest",
ProbeOSImage: "fooOS:latest",
RegistryURL: registryURL,
RegistryResyncInterval: 50 * time.Millisecond,
ResyncInterval: 100 * time.Millisecond,
EnforceFirstBoot: true,
}).SetupWithManager(k8sManager)).To(Succeed())

Expect((&ServerClaimReconciler{
Expand Down

0 comments on commit a4264ab

Please sign in to comment.