Files
Reloader/pkg/metadata/publisher.go
T

113 lines
3.6 KiB
Go

package metadata
import (
"context"
"fmt"
"os"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/stakater/Reloader/internal/pkg/workload"
"github.com/stakater/Reloader/pkg/config"
)
// Publisher handles creating and updating the metadata ConfigMap.
type Publisher struct {
client client.Client
cfg *config.Config
log logr.Logger
}
// NewPublisher creates a new Publisher.
func NewPublisher(c client.Client, cfg *config.Config, log logr.Logger) *Publisher {
return &Publisher{
client: c,
cfg: cfg,
log: log,
}
}
// Publish creates or updates the metadata ConfigMap.
func (p *Publisher) Publish(ctx context.Context) error {
namespace := os.Getenv(EnvReloaderNamespace)
if namespace == "" {
p.log.Info("RELOADER_NAMESPACE is not set, skipping meta info configmap creation")
return nil
}
metaInfo := NewMetaInfo(p.cfg)
configMap := metaInfo.ToConfigMap()
existing := &corev1.ConfigMap{}
err := p.client.Get(
ctx, client.ObjectKey{
Name: ConfigMapName,
Namespace: namespace,
}, existing,
)
if err != nil {
if !errors.IsNotFound(err) {
return fmt.Errorf("failed to get existing meta info configmap: %w", err)
}
p.log.Info("Creating meta info configmap")
if err := p.client.Create(ctx, configMap, client.FieldOwner(workload.FieldManager)); err != nil {
return fmt.Errorf("failed to create meta info configmap: %w", err)
}
p.log.Info("Meta info configmap created successfully")
return nil
}
p.log.Info("Meta info configmap already exists, updating it")
existing.Data = configMap.Data
existing.Labels = configMap.Labels
if err := p.client.Update(ctx, existing, client.FieldOwner(workload.FieldManager)); err != nil {
return fmt.Errorf("failed to update meta info configmap: %w", err)
}
p.log.Info("Meta info configmap updated successfully")
return nil
}
// PublishMetaInfoConfigMap is a convenience function that creates a Publisher and calls Publish.
func PublishMetaInfoConfigMap(ctx context.Context, c client.Client, cfg *config.Config, log logr.Logger) error {
publisher := NewPublisher(c, cfg, log)
return publisher.Publish(ctx)
}
// Runnable returns a controller-runtime Runnable that publishes the meta-info
// ConfigMap when the manager starts. It builds its own uncached client from the
// given rest config and scheme: the ConfigMap lives in Reloader's own namespace,
// which the manager cache does not cover in scoped mode, so a cache-backed client
// cannot read or write it there. Meta-info is internal instance metadata and is
// always published regardless of which resources are watched.
func Runnable(restConfig *rest.Config, scheme *runtime.Scheme, cfg *config.Config, log logr.Logger) RunnableFunc {
return func(ctx context.Context) error {
c, err := client.New(restConfig, client.Options{Scheme: scheme})
if err != nil {
log.Error(err, "Failed to create client for meta info configmap publisher")
// Non-fatal, don't return error to avoid crashing the manager
<-ctx.Done()
return nil
}
if err := PublishMetaInfoConfigMap(ctx, c, cfg, log); err != nil {
log.Error(err, "Failed to create metadata ConfigMap")
// Non-fatal, don't return error to avoid crashing the manager
}
<-ctx.Done()
return nil
}
}
// RunnableFunc is a function that implements the controller-runtime Runnable interface.
type RunnableFunc func(context.Context) error
// Start implements the Runnable interface.
func (r RunnableFunc) Start(ctx context.Context) error {
return r(ctx)
}