diff --git a/api/api.go b/api/api.go deleted file mode 100644 index 5c64cfb0..00000000 --- a/api/api.go +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package api - -import "time" - -type Metadata struct { - ID string `json:"id"` - Annotations map[string]string `json:"annotations"` - Labels map[string]string `json:"labels"` - - CreatedAt time.Time `json:"createdAt"` - DeletedAt *time.Time `json:"deletedAt,omitempty"` - Generation int64 `json:"generation"` - ResourceVersion uint64 `json:"resourceVersion"` - - Finalizers []string `json:"finalizers,omitempty"` -} - -func (m *Metadata) GetID() string { - return m.ID -} - -func (m *Metadata) GetAnnotations() map[string]string { - return m.Annotations -} - -func (m *Metadata) GetLabels() map[string]string { - return m.Labels -} - -func (m *Metadata) GetCreatedAt() time.Time { - return m.CreatedAt -} - -func (m *Metadata) GetDeletedAt() *time.Time { - return m.DeletedAt -} - -func (m *Metadata) GetGeneration() int64 { - return m.Generation -} - -func (m *Metadata) GetFinalizers() []string { - return m.Finalizers -} - -func (m *Metadata) GetResourceVersion() uint64 { - return m.ResourceVersion -} - -func (m *Metadata) SetID(id string) { - m.ID = id -} - -func (m *Metadata) SetAnnotations(annotations map[string]string) { - m.Annotations = annotations -} - -func (m *Metadata) SetLabels(labels map[string]string) { - m.Labels = labels -} - -func (m *Metadata) SetCreatedAt(createdAt time.Time) { - m.CreatedAt = createdAt -} - -func (m *Metadata) SetDeletedAt(deleted *time.Time) { - m.DeletedAt = deleted -} - -func (m *Metadata) SetGeneration(generation int64) { - m.Generation = generation -} - -func (m *Metadata) SetFinalizers(finalizers []string) { - m.Finalizers = finalizers -} - -func (m *Metadata) IncrementResourceVersion() { - m.ResourceVersion++ -} - -type Object interface { - GetID() string - GetAnnotations() map[string]string - GetLabels() map[string]string - GetCreatedAt() time.Time - GetDeletedAt() *time.Time - GetGeneration() int64 - GetFinalizers() []string - GetResourceVersion() uint64 - - SetID(id string) - SetAnnotations(annotations map[string]string) - SetLabels(labels map[string]string) - SetCreatedAt(createdAt time.Time) - SetDeletedAt(deleted *time.Time) - SetGeneration(generation int64) - SetFinalizers(finalizers []string) - IncrementResourceVersion() -} diff --git a/api/apiutils.go b/api/apiutils.go index 79cc48fd..17b76272 100644 --- a/api/apiutils.go +++ b/api/apiutils.go @@ -4,20 +4,18 @@ package api import ( - "encoding/json" - "fmt" - "github.com/ironcore-dev/controller-utils/metautils" irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" + apiutils "github.com/ironcore-dev/provider-utils/apiutils/api" ) -func GetObjectMetadata(o Metadata) (*irimeta.ObjectMetadata, error) { - annotations, err := GetAnnotationsAnnotation(o) +func GetObjectMetadata(o apiutils.Metadata) (*irimeta.ObjectMetadata, error) { + annotations, err := apiutils.GetAnnotationsAnnotation(o, AnnotationsAnnotation) if err != nil { return nil, err } - labels, err := GetLabelsAnnotation(o) + labels, err := apiutils.GetLabelsAnnotation(o, LabelsAnnotation) if err != nil { return nil, err } @@ -37,77 +35,30 @@ func GetObjectMetadata(o Metadata) (*irimeta.ObjectMetadata, error) { }, nil } -func SetObjectMetadata(o Object, metadata *irimeta.ObjectMetadata) error { - if err := SetAnnotationsAnnotation(o, metadata.Annotations); err != nil { +func SetObjectMetadata(o apiutils.Object, metadata *irimeta.ObjectMetadata) error { + if err := apiutils.SetAnnotationsAnnotation(o, AnnotationsAnnotation, metadata.Annotations); err != nil { return err } - if err := SetLabelsAnnotation(o, metadata.Labels); err != nil { + if err := apiutils.SetLabelsAnnotation(o, LabelsAnnotation, metadata.Labels); err != nil { return err } return nil } -func SetLabelsAnnotation(o Object, labels map[string]string) error { - data, err := json.Marshal(labels) - if err != nil { - return fmt.Errorf("error marshalling labels: %w", err) - } - metautils.SetAnnotation(o, LabelsAnnotation, string(data)) - return nil -} - -func GetLabelsAnnotation(o Metadata) (map[string]string, error) { - data, ok := o.GetAnnotations()[LabelsAnnotation] - if !ok { - return nil, fmt.Errorf("object has no labels at %s", LabelsAnnotation) - } - - var labels map[string]string - if err := json.Unmarshal([]byte(data), &labels); err != nil { - return nil, err - } - - return labels, nil -} - -func SetAnnotationsAnnotation(o Object, annotations map[string]string) error { - data, err := json.Marshal(annotations) - if err != nil { - return fmt.Errorf("error marshalling annotations: %w", err) - } - metautils.SetAnnotation(o, AnnotationsAnnotation, string(data)) - - return nil -} - -func GetAnnotationsAnnotation(o Metadata) (map[string]string, error) { - data, ok := o.GetAnnotations()[AnnotationsAnnotation] - if !ok { - return nil, fmt.Errorf("object has no annotations at %s", AnnotationsAnnotation) - } - - var annotations map[string]string - if err := json.Unmarshal([]byte(data), &annotations); err != nil { - return nil, err - } - - return annotations, nil -} - -func SetManagerLabel(o Object, manager string) { +func SetManagerLabel(o apiutils.Object, manager string) { metautils.SetLabel(o, ManagerLabel, manager) } -func SetClassLabel(o Object, class string) { +func SetClassLabel(o apiutils.Object, class string) { metautils.SetLabel(o, ClassLabel, class) } -func GetClassLabel(o Object) (string, bool) { +func GetClassLabel(o apiutils.Object) (string, bool) { class, found := o.GetLabels()[ClassLabel] return class, found } -func IsManagedBy(o Object, manager string) bool { +func IsManagedBy(o apiutils.Object, manager string) bool { actual, ok := o.GetLabels()[ManagerLabel] return ok && actual == manager } diff --git a/api/machine.go b/api/machine.go index add01feb..a19e1b88 100644 --- a/api/machine.go +++ b/api/machine.go @@ -5,10 +5,12 @@ package api import ( "time" + + apiutils "github.com/ironcore-dev/provider-utils/apiutils/api" ) type Machine struct { - Metadata `json:"metadata,omitempty"` + apiutils.Metadata `json:"metadata,omitempty"` Spec MachineSpec `json:"spec"` Status MachineStatus `json:"status"` diff --git a/cmd/libvirt-provider/app/app.go b/cmd/libvirt-provider/app/app.go index eb84b352..4a947c23 100644 --- a/cmd/libvirt-provider/app/app.go +++ b/cmd/libvirt-provider/app/app.go @@ -18,14 +18,13 @@ import ( "github.com/go-logr/logr" "github.com/ironcore-dev/ironcore-image/oci/remote" + ocistore "github.com/ironcore-dev/ironcore-image/oci/store" "github.com/ironcore-dev/ironcore/broker/common" commongrpc "github.com/ironcore-dev/ironcore/broker/common/grpc" iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" "github.com/ironcore-dev/libvirt-provider/api" "github.com/ironcore-dev/libvirt-provider/internal/console" "github.com/ironcore-dev/libvirt-provider/internal/controllers" - "github.com/ironcore-dev/libvirt-provider/internal/event" - "github.com/ironcore-dev/libvirt-provider/internal/event/machineevent" "github.com/ironcore-dev/libvirt-provider/internal/healthcheck" "github.com/ironcore-dev/libvirt-provider/internal/host" "github.com/ironcore-dev/libvirt-provider/internal/libvirt/guest" @@ -36,10 +35,12 @@ import ( volumeplugin "github.com/ironcore-dev/libvirt-provider/internal/plugins/volume" "github.com/ironcore-dev/libvirt-provider/internal/plugins/volume/ceph" "github.com/ironcore-dev/libvirt-provider/internal/plugins/volume/emptydisk" - "github.com/ironcore-dev/libvirt-provider/internal/qcow2" "github.com/ironcore-dev/libvirt-provider/internal/raw" "github.com/ironcore-dev/libvirt-provider/internal/server" "github.com/ironcore-dev/libvirt-provider/internal/strategy" + "github.com/ironcore-dev/provider-utils/eventutils/event" + "github.com/ironcore-dev/provider-utils/eventutils/recorder" + hostutils "github.com/ironcore-dev/provider-utils/storeutils/host" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -79,7 +80,7 @@ type Options struct { GCVMGracefulShutdownTimeout time.Duration ResyncIntervalGarbageCollector time.Duration - MachineEventStore machineevent.EventStoreOptions + MachineEventStore recorder.EventStoreOptions VolumeCachePolicy string } @@ -134,15 +135,13 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.StringSliceVar(&o.Libvirt.PreferredDomainTypes, "preferred-domain-types", []string{"kvm", "qemu"}, "Ordered list of preferred domain types to use.") fs.StringSliceVar(&o.Libvirt.PreferredMachineTypes, "preferred-machine-types", []string{"pc-q35"}, "Ordered list of preferred machine types to use.") - fs.StringVar(&o.Libvirt.Qcow2Type, "qcow2-type", qcow2.Default(), fmt.Sprintf("qcow2 implementation to use. Available: %v", qcow2.Available())) - fs.DurationVar(&o.GCVMGracefulShutdownTimeout, "gc-vm-graceful-shutdown-timeout", 5*time.Minute, "Duration to wait for the VM to gracefully shut down. If the VM does not shut down within this period, it will be forcibly destroyed by garbage collector.") fs.DurationVar(&o.ResyncIntervalGarbageCollector, "gc-resync-interval", 1*time.Minute, "Interval for resynchronizing the garbage collector.") // Machine event store options - fs.IntVar(&o.MachineEventStore.MachineEventMaxEvents, "machine-event-max-events", 100, "Maximum number of machine events that can be stored.") - fs.DurationVar(&o.MachineEventStore.MachineEventTTL, "machine-event-ttl", 5*time.Minute, "Time to live for machine events.") - fs.DurationVar(&o.MachineEventStore.MachineEventResyncInterval, "machine-event-resync-interval", 1*time.Minute, "Interval for resynchronizing the machine events.") + fs.IntVar(&o.MachineEventStore.MaxEvents, "machine-event-max-events", 100, "Maximum number of machine events that can be stored.") + fs.DurationVar(&o.MachineEventStore.TTL, "machine-event-ttl", 5*time.Minute, "Time to live for machine events.") + fs.DurationVar(&o.MachineEventStore.ResyncInterval, "machine-event-resync-interval", 1*time.Minute, "Interval for resynchronizing the machine events.") // Volume cache policy option fs.StringVar(&o.VolumeCachePolicy, "volume-cache-policy", "none", @@ -227,15 +226,15 @@ func Run(ctx context.Context, opts Options) error { return err } - imgCache, err := oci.NewLocalCache(log, reg, providerHost.OCIStore()) + ociStore, err := ocistore.New(providerHost.ImagesDir()) if err != nil { - setupLog.Error(err, "failed to initialize oci manager") + setupLog.Error(err, "error creating oci store") return err } - qcow2Inst, err := qcow2.Instance(opts.Libvirt.Qcow2Type) + imgCache, err := oci.NewLocalCache(log, reg, ociStore) if err != nil { - setupLog.Error(err, "failed to initialize qcow2 instance") + setupLog.Error(err, "failed to initialize oci manager") return err } @@ -258,7 +257,7 @@ func Run(ctx context.Context, opts Options) error { volumePlugins := volumeplugin.NewPluginManager() if err := volumePlugins.InitPlugins(providerHost, []volumeplugin.Plugin{ ceph.NewPlugin(), - emptydisk.NewPlugin(qcow2Inst, rawInst), + emptydisk.NewPlugin(rawInst), }); err != nil { setupLog.Error(err, "failed to initialize volume plugin manager") return err @@ -281,7 +280,7 @@ func Run(ctx context.Context, opts Options) error { } setupLog.Info("Configuring machine store", "Directory", providerHost.MachineStoreDir()) - machineStore, err := host.NewStore(host.Options[*api.Machine]{ + machineStore, err := hostutils.NewStore[*api.Machine](hostutils.Options[*api.Machine]{ NewFunc: func() *api.Machine { return &api.Machine{} }, CreateStrategy: strategy.MachineStrategy, Dir: providerHost.MachineStoreDir(), @@ -301,11 +300,11 @@ func Run(ctx context.Context, opts Options) error { return err } - eventStore := machineevent.NewEventStore(log, opts.MachineEventStore) + eventStore := recorder.NewEventStore(log, opts.MachineEventStore) machineReconciler, err := controllers.NewMachineReconciler( log.WithName("machine-reconciler"), - libvirt, + providerHost, machineStore, machineEvents, eventStore, @@ -313,7 +312,6 @@ func Run(ctx context.Context, opts Options) error { GuestCapabilities: caps, ImageCache: imgCache, Raw: rawInst, - Host: providerHost, VolumePluginManager: volumePlugins, NetworkInterfacePlugin: nicPlugin, ResyncIntervalVolumeSize: opts.ResyncIntervalVolumeSize, diff --git a/go.mod b/go.mod index 4846c230..7981252e 100644 --- a/go.mod +++ b/go.mod @@ -2,29 +2,31 @@ module github.com/ironcore-dev/libvirt-provider go 1.24.0 +toolchain go1.24.1 + require ( github.com/blang/semver/v4 v4.0.0 - github.com/ceph/go-ceph v0.32.0 + github.com/ceph/go-ceph v0.33.0 github.com/containerd/containerd v1.7.27 - github.com/digitalocean/go-libvirt v0.0.0-20250317183548-13bf9b43b50b + github.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6 github.com/go-chi/chi/v5 v5.2.1 github.com/go-logr/logr v1.4.2 - github.com/gogo/protobuf v1.3.2 github.com/google/uuid v1.6.0 - github.com/ironcore-dev/controller-utils v0.9.8 - github.com/ironcore-dev/ironcore v0.2.2 + github.com/ironcore-dev/controller-utils v0.9.9 + github.com/ironcore-dev/ironcore v0.2.3 github.com/ironcore-dev/ironcore-image v0.2.4 - github.com/ironcore-dev/ironcore-net v0.2.2 + github.com/ironcore-dev/ironcore-net v0.2.3 + github.com/ironcore-dev/provider-utils v0.0.0-20250409071032-ef57cc16e3c6 github.com/moby/term v0.5.2 - github.com/onsi/ginkgo/v2 v2.23.3 - github.com/onsi/gomega v1.36.3 + github.com/onsi/ginkgo/v2 v2.23.4 + github.com/onsi/gomega v1.37.0 github.com/opencontainers/image-spec v1.1.1 - github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/client_golang v1.22.0 github.com/shirou/gopsutil/v3 v3.24.5 github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.6 - golang.org/x/sync v0.12.0 - google.golang.org/grpc v1.71.0 + golang.org/x/sync v0.13.0 + google.golang.org/grpc v1.72.0 k8s.io/api v0.32.3 k8s.io/apimachinery v0.32.3 k8s.io/client-go v0.32.3 @@ -37,11 +39,15 @@ require ( require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/Microsoft/hcsshim v0.12.9 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/containerd/cgroups/v3 v3.0.5 // indirect + github.com/containerd/continuity v0.4.5 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect + github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/creack/pty v1.1.21 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect @@ -50,25 +56,28 @@ require ( github.com/docker/docker v28.0.1+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.2 // indirect github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.8.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // indirect + github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -81,6 +90,7 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -88,9 +98,9 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.62.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.63.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect @@ -102,31 +112,33 @@ require ( go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel/metric v1.35.0 // indirect go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/net v0.37.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/oauth2 v0.29.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/term v0.31.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.31.0 // indirect + golang.org/x/tools v0.32.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/protobuf v1.36.5 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250421163800-61c742ae3ef0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect - k8s.io/apiextensions-apiserver v0.32.2 // indirect - k8s.io/apiserver v0.32.2 // indirect + k8s.io/apiextensions-apiserver v0.32.3 // indirect + k8s.io/apiserver v0.32.3 // indirect k8s.io/cli-runtime v0.32.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect oras.land/oras-go v1.2.6 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index ee0a0461..a577266f 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= -github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= +github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6lLg= +github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -20,22 +20,26 @@ github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuP github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/ceph/go-ceph v0.32.0 h1:iXRUGdPmH7h9Vf/WA1Dg3Wo1tgL7gcUbylfpbxrlGLs= -github.com/ceph/go-ceph v0.32.0/go.mod h1:42eoJzyLS3VREzqrg2ot44NtuluQZi55hFRSoLF36GQ= +github.com/ceph/go-ceph v0.33.0 h1:xT9v/MAa+DIBmflyITyFkGRgWngATghGegKJguEOInQ= +github.com/ceph/go-ceph v0.33.0/go.mod h1:6ef0lIyDHnwArykqfWZDWCfbbJAVTXL1tOYrM1M4bAE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo= +github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII= github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0= -github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII= -github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= +github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= +github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -47,8 +51,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/digitalocean/go-libvirt v0.0.0-20250317183548-13bf9b43b50b h1:LqD7kE8wQRMPjjRAzg9ENwDwJKlapDpuiG1ix5QQcps= -github.com/digitalocean/go-libvirt v0.0.0-20250317183548-13bf9b43b50b/go.mod h1:s7Tz3AmcoxYalhSQXZ2dzHanRebh35PeetRkYfhda3c= +github.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6 h1:jk2z9emvvDmaTwTdVOvQCK3POtH6+fEvWUtqMBjvnq0= +github.com/digitalocean/go-libvirt v0.0.0-20250417173424-a6a66ef779d6/go.mod h1:vumyuXRJJvjCdabRsu/BvoCirqGHC5bakkC9G0V3Mgw= github.com/distribution/distribution/v3 v3.0.0-beta.1 h1:X+ELTxPuZ1Xe5MsD3kp2wfGUhc8I+MPfRis8dZ818Ic= github.com/distribution/distribution/v3 v3.0.0-beta.1/go.mod h1:O9O8uamhHzWWQVTjuQpyYUVm/ShPHPUDgvQMpHGVBDs= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= @@ -63,8 +67,8 @@ github.com/docker/docker-credential-helpers v0.9.2 h1:50JF7ADQiHdAVBRtg/vy883Y4U github.com/docker/docker-credential-helpers v0.9.2/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 h1:EHZfspsnLAz8Hzccd67D5abwLiqoqym2jz/jOS39mCk= +github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= @@ -77,10 +81,10 @@ github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjT github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= +github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -96,22 +100,22 @@ github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= -github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0= +github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -128,8 +132,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 h1:+J3r2e8+RsmN3vKfo75g0YSY61ms37qzPglu4p0sGro= -github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 h1:b/8HpQhvKLSNzH5oTXN2WkNcMl6YB5K3FRbb+i+Ml34= +github.com/google/pprof v0.0.0-20250418163039-24c5476c6587/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= @@ -147,14 +151,16 @@ github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvH github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ironcore-dev/controller-utils v0.9.8 h1:A7cd/n368xBh83cu7AEHaXYXnW37ICe4YKLXWsPRWW4= -github.com/ironcore-dev/controller-utils v0.9.8/go.mod h1:fBA4gnfrneJzuEtL+jJj2A+YE8KmgQ4ot3A/eNRd5P0= -github.com/ironcore-dev/ironcore v0.2.2 h1:c23smdbxcoSKOir/jQvCIyWuj3HfF7T6t6tN2h7pqQ8= -github.com/ironcore-dev/ironcore v0.2.2/go.mod h1:r4p2CGWnzk8/0UTXUgDTT9AvA6hkvRmPHZ/oHKn7Fl8= +github.com/ironcore-dev/controller-utils v0.9.9 h1:SRVMjj+jh9yDZj//1hGG7U7S4fRuUVICAiXu7JBHJyo= +github.com/ironcore-dev/controller-utils v0.9.9/go.mod h1:hNqQjd6JkRmKYH1MY1XkfT4Eew3P7etHTJjaHj+vK9Y= +github.com/ironcore-dev/ironcore v0.2.3 h1:me2LuScaoekxSRtV7KhCqGZ/jOsU7fCuqt6LBxcx+ts= +github.com/ironcore-dev/ironcore v0.2.3/go.mod h1:u39dlr8d3RfPCK4FLBLvFfmbDdh8Tu7a3R06nXkIJug= github.com/ironcore-dev/ironcore-image v0.2.4 h1:yzmnXnXPKXCfJIL8TmyapyHfK6gup8zA+WV9Kq9pYqA= github.com/ironcore-dev/ironcore-image v0.2.4/go.mod h1:ZwUrZ+pZumYAu6F9RJYe04824Leylma3tvIkNANwiyE= -github.com/ironcore-dev/ironcore-net v0.2.2 h1:9JjDfDvKONsap7LFJKTcgyW7yCqElpEq/VkwXyCV1Qc= -github.com/ironcore-dev/ironcore-net v0.2.2/go.mod h1:RB6aKSX10tExYXfg3Jf64E1IHJqz1H20PocDSCmzy2c= +github.com/ironcore-dev/ironcore-net v0.2.3 h1:xn8+oFr7aQSmnMYymUoU/SCVTF7eeVPKQf5RPPPpU5I= +github.com/ironcore-dev/ironcore-net v0.2.3/go.mod h1:1aj8WV/4HcBjYApvhHPgEjAY16Vpzvj8MMChhx2v0Zs= +github.com/ironcore-dev/provider-utils v0.0.0-20250409071032-ef57cc16e3c6 h1:LOwltmAO/c3YeqG+aRTXUnSto52Ox9FHzNEEMSae8cw= +github.com/ironcore-dev/provider-utils v0.0.0-20250409071032-ef57cc16e3c6/go.mod h1:YJtzgDeOCQqDoUO0pwxczW23lv9dT0x/6SnjLkAPv/I= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -187,8 +193,8 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= @@ -205,10 +211,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= -github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= -github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= -github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -223,24 +229,26 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho= github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U= github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc= @@ -316,6 +324,8 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= @@ -328,8 +338,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -338,17 +348,17 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= +golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -360,37 +370,36 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= -google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24= -google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e h1:UdXH7Kzbj+Vzastr5nVfccbmFsmYNygVLSPk1pEfDoY= +google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250421163800-61c742ae3ef0 h1:l7lvb5BMqtbmd7fibSq7fi956Fv9/sqiwI9qOw8ltCo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250421163800-61c742ae3ef0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -409,20 +418,20 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4= -k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA= +k8s.io/apiextensions-apiserver v0.32.3 h1:4D8vy+9GWerlErCwVIbcQjsWunF9SUGNu7O7hiQTyPY= +k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss= k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw= -k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM= +k8s.io/apiserver v0.32.3 h1:kOw2KBuHOA+wetX1MkmrxgBr648ksz653j26ESuWNY8= +k8s.io/apiserver v0.32.3/go.mod h1:q1x9B8E/WzShF49wh3ADOh6muSfpmFL0I2t+TG0Zdgc= k8s.io/cli-runtime v0.32.3 h1:khLF2ivU2T6Q77H97atx3REY9tXiA3OLOjWJxUrdvss= k8s.io/cli-runtime v0.32.3/go.mod h1:vZT6dZq7mZAca53rwUfdFSZjdtLyfF61mkf/8q+Xjak= k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 h1:t0huyHnz6HsokckRxAF1bY0cqPFwzINKCL7yltEjZQc= -k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/kubectl v0.32.3 h1:VMi584rbboso+yjfv0d8uBHwwxbC438LKq+dXd5tOAI= k8s.io/kubectl v0.32.3/go.mod h1:6Euv2aso5GKzo/UVMacV6C7miuyevpfI91SvBvV9Zdg= k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= @@ -438,7 +447,7 @@ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/controllers/machine_controller.go b/internal/controllers/machine_controller.go index 2f0c2fa2..fcef52d0 100644 --- a/internal/controllers/machine_controller.go +++ b/internal/controllers/machine_controller.go @@ -19,8 +19,6 @@ import ( "github.com/digitalocean/go-libvirt" "github.com/go-logr/logr" "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/event" - machineEvent "github.com/ironcore-dev/libvirt-provider/internal/event/machineevent" providerhost "github.com/ironcore-dev/libvirt-provider/internal/host" "github.com/ironcore-dev/libvirt-provider/internal/libvirt/guest" libvirtmeta "github.com/ironcore-dev/libvirt-provider/internal/libvirt/meta" @@ -30,8 +28,10 @@ import ( providernetworkinterface "github.com/ironcore-dev/libvirt-provider/internal/plugins/networkinterface" providervolume "github.com/ironcore-dev/libvirt-provider/internal/plugins/volume" "github.com/ironcore-dev/libvirt-provider/internal/raw" - "github.com/ironcore-dev/libvirt-provider/internal/store" "github.com/ironcore-dev/libvirt-provider/internal/utils" + "github.com/ironcore-dev/provider-utils/eventutils/event" + "github.com/ironcore-dev/provider-utils/eventutils/recorder" + "github.com/ironcore-dev/provider-utils/storeutils/store" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/util/workqueue" @@ -70,7 +70,6 @@ type MachineReconcilerOptions struct { TCMallocLibPath string ImageCache providerimage.Cache Raw raw.Raw - Host providerhost.Host VolumePluginManager *providervolume.PluginManager NetworkInterfacePlugin providernetworkinterface.Plugin VolumeEvents event.Source[*api.Machine] @@ -83,14 +82,14 @@ type MachineReconcilerOptions struct { func NewMachineReconciler( log logr.Logger, - libvirt *libvirt.Libvirt, + host providerhost.LibvirtHost, machines store.Store[*api.Machine], machineEvents event.Source[*api.Machine], - eventRecorder machineEvent.EventRecorder, + eventRecorder recorder.EventRecorder, opts MachineReconcilerOptions, ) (*MachineReconciler, error) { - if libvirt == nil { - return nil, fmt.Errorf("must specify libvirt client") + if host == nil { + return nil, fmt.Errorf("must specify libvirt host") } if machines == nil { @@ -104,13 +103,12 @@ func NewMachineReconciler( return &MachineReconciler{ log: log, queue: workqueue.NewTypedRateLimitingQueue[string](workqueue.DefaultTypedControllerRateLimiter[string]()), - libvirt: libvirt, machines: machines, machineEvents: machineEvents, EventRecorder: eventRecorder, guestCapabilities: opts.GuestCapabilities, tcMallocLibPath: opts.TCMallocLibPath, - host: opts.Host, + host: host, imageCache: opts.ImageCache, raw: opts.Raw, volumePluginManager: opts.VolumePluginManager, @@ -127,10 +125,9 @@ type MachineReconciler struct { log logr.Logger queue workqueue.TypedRateLimitingInterface[string] - libvirt *libvirt.Libvirt guestCapabilities guest.Capabilities tcMallocLibPath string - host providerhost.Host + host providerhost.LibvirtHost imageCache providerimage.Cache raw raw.Raw @@ -141,7 +138,7 @@ type MachineReconciler struct { machines store.Store[*api.Machine] machineEvents event.Source[*api.Machine] - machineEvent.EventRecorder + recorder.EventRecorder resyncIntervalVolumeSize time.Duration @@ -167,7 +164,7 @@ func (r *MachineReconciler) Start(ctx context.Context) error { for _, machine := range machines { if ptr.Deref(machine.Spec.Image, "") == evt.Ref { - r.Eventf(log, machine.Metadata, corev1.EventTypeNormal, "PulledImage", "Pulled image %s", *machine.Spec.Image) + r.Eventf(machine.Metadata, corev1.EventTypeNormal, "PulledImage", "Pulled image %s", *machine.Spec.Image) log.V(1).Info("Image pulled: Requeue machines", "Image", evt.Ref, "Machine", machine.ID) r.queue.Add(machine.ID) } @@ -264,7 +261,7 @@ func (r *MachineReconciler) startCheckAndEnqueueVolumeResize(ctx context.Context } if lastVolumeSize := getLastVolumeSize(machine, GetUniqueVolumeName(plugin.Name(), volumeID)); volumeSize != lastVolumeSize { - r.Eventf(log, machine.Metadata, corev1.EventTypeNormal, "SizeChangedVolume", "Volume size changed %s, lastVolumeSize: %d bytes, volumeSize: %d bytes", volume.Name, lastVolumeSize, volumeSize) + r.Eventf(machine.Metadata, corev1.EventTypeNormal, "SizeChangedVolume", "Volume size changed %s, lastVolumeSize: %d bytes, volumeSize: %d bytes", volume.Name, lastVolumeSize, volumeSize) log.V(1).Info("Volume size changed", "volumeName", volume.Name, "volumeID", volumeID, "machineID", machine.ID, "lastSize", lastVolumeSize, "volumeSize", volumeSize) shouldEnqueue = true break @@ -279,7 +276,7 @@ func (r *MachineReconciler) startCheckAndEnqueueVolumeResize(ctx context.Context } func (r *MachineReconciler) startEnqueueMachineByLibvirtEvent(ctx context.Context, log logr.Logger) { - lifecycleEvents, err := r.libvirt.LifecycleEvents(ctx) + lifecycleEvents, err := r.host.Libvirt().LifecycleEvents(ctx) if err != nil { log.Error(err, "failed to subscribe to libvirt lifecycle events") return @@ -371,7 +368,7 @@ func (r *MachineReconciler) processMachineDeletion(ctx context.Context, log logr if _, err := r.machines.Update(ctx, machine); store.IgnoreErrNotFound(err) != nil { return fmt.Errorf("failed to update machine metadata: %w", err) } - r.Eventf(log, machine.Metadata, corev1.EventTypeNormal, "CompletedDeletion", "Deletion completed") + r.Eventf(machine.Metadata, corev1.EventTypeNormal, "CompletedDeletion", "Deletion completed") log.V(1).Info("Removed Finalizer. Deletion completed") return nil @@ -403,14 +400,14 @@ func (r *MachineReconciler) deleteMachine(ctx context.Context, log logr.Logger, func (r *MachineReconciler) destroyDomain(log logr.Logger, machine *api.Machine, domain libvirt.Domain) error { // DomainDestroyFlags is a blocking operation, and its synchronous nature may pose potential performance issues in the future. // During test involving 26 empty disks, the function call took a maximum of 1 second to complete. - if err := r.libvirt.DomainDestroyFlags(domain, libvirt.DomainDestroyGraceful); err != nil { + if err := r.host.Libvirt().DomainDestroyFlags(domain, libvirt.DomainDestroyGraceful); err != nil { if libvirt.IsNotFound(err) { return nil } return fmt.Errorf("failed to initiate forceful shutdown: %w", err) } - r.Eventf(log, machine.Metadata, corev1.EventTypeWarning, "DestroyedDomain", "Domain Destroyed") + r.Eventf(machine.Metadata, corev1.EventTypeWarning, "DestroyedDomain", "Domain Destroyed") log.V(1).Info("Destroyed domain") return nil @@ -418,13 +415,13 @@ func (r *MachineReconciler) destroyDomain(log logr.Logger, machine *api.Machine, func (r *MachineReconciler) shutdownMachine(log logr.Logger, machine *api.Machine, domain libvirt.Domain) (bool, error) { log.V(1).Info("Triggering shutdown", "ShutdownAt", machine.Spec.ShutdownAt) - r.Eventf(log, machine.Metadata, corev1.EventTypeNormal, "TriggeringShutdown", "Shutdown Triggered") + r.Eventf(machine.Metadata, corev1.EventTypeNormal, "TriggeringShutdown", "Shutdown Triggered") shutdownMode := libvirt.DomainShutdownAcpiPowerBtn if machine.Spec.GuestAgent == api.GuestAgentQemu { shutdownMode = libvirt.DomainShutdownGuestAgent } - if err := r.libvirt.DomainShutdownFlags(domain, shutdownMode); err != nil { + if err := r.host.Libvirt().DomainShutdownFlags(domain, shutdownMode); err != nil { if libvirt.IsNotFound(err) { return false, nil } @@ -509,7 +506,7 @@ func (r *MachineReconciler) reconcileDomain( machine *api.Machine, ) (api.MachineState, []api.VolumeStatus, []api.NetworkInterfaceStatus, error) { log.V(1).Info("Looking up domain") - if _, err := r.libvirt.DomainLookupByUUID(libvirtutils.UUIDStringToBytes(machine.ID)); err != nil { + if _, err := r.host.Libvirt().DomainLookupByUUID(libvirtutils.UUIDStringToBytes(machine.ID)); err != nil { if !libvirt.IsNotFound(err) { return "", nil, nil, fmt.Errorf("error getting domain %s: %w", machine.ID, err) } @@ -548,20 +545,20 @@ func (r *MachineReconciler) updateDomain( return nil, nil, fmt.Errorf("error getting domain description: %w", err) } - attacher, err := NewLibvirtVolumeAttacher(domainDesc, NewRunningDomainExecutor(r.libvirt, machine.ID), r.volumeCachePolicy) + attacher, err := NewLibvirtVolumeAttacher(domainDesc, NewRunningDomainExecutor(r.host.Libvirt(), machine.ID), r.volumeCachePolicy) if err != nil { return nil, nil, fmt.Errorf("error construction volume attacher: %w", err) } volumeStates, err := r.attachDetachVolumes(ctx, log, machine, attacher) if err != nil { - r.Eventf(log, machine.Metadata, corev1.EventTypeWarning, "AttchDetachVolume", "Volume attach/detach failed with error: %s", err) + r.Eventf(machine.Metadata, corev1.EventTypeWarning, "AttchDetachVolume", "Volume attach/detach failed with error: %s", err) return nil, nil, fmt.Errorf("[volumes] %w", err) } nicStates, err := r.attachDetachNetworkInterfaces(ctx, log, machine, domainDesc) if err != nil { - r.Eventf(log, machine.Metadata, corev1.EventTypeWarning, "AttchDetachNIC", "NIC attach/detach failed with error: %s", err) + r.Eventf(machine.Metadata, corev1.EventTypeWarning, "AttchDetachNIC", "NIC attach/detach failed with error: %s", err) return nil, nil, fmt.Errorf("[network interfaces] %w", err) } @@ -569,7 +566,7 @@ func (r *MachineReconciler) updateDomain( } func (r *MachineReconciler) getMachineState(machineID string) (api.MachineState, error) { - domainState, _, err := r.libvirt.DomainGetState(machineDomain(machineID), 0) + domainState, _, err := r.host.Libvirt().DomainGetState(machineDomain(machineID), 0) if err != nil { return "", fmt.Errorf("error getting domain state: %w", err) } @@ -597,7 +594,7 @@ func (r *MachineReconciler) createDomain( log.V(1).Info("Creating domain") log.V(2).Info("Domain", "XML", domainXMLData) - if _, err := r.libvirt.DomainCreateXML(domainXMLData, libvirt.DomainNone); err != nil { + if _, err := r.host.Libvirt().DomainCreateXML(domainXMLData, libvirt.DomainNone); err != nil { return nil, nil, err } @@ -768,30 +765,30 @@ func (r *MachineReconciler) domainFor( return nil, nil, nil, err } } else { - r.Eventf(log, machine.Metadata, corev1.EventTypeWarning, "NoIgnitionData", "Machine does not have ignition data") + r.Eventf(machine.Metadata, corev1.EventTypeWarning, "NoIgnitionData", "Machine does not have ignition data") } - attacher, err := NewLibvirtVolumeAttacher(domainDesc, NewCreateDomainExecutor(r.libvirt), r.volumeCachePolicy) + attacher, err := NewLibvirtVolumeAttacher(domainDesc, NewCreateDomainExecutor(r.host.Libvirt()), r.volumeCachePolicy) if err != nil { return nil, nil, nil, err } volumeStates, err := r.attachDetachVolumes(ctx, log, machine, attacher) if err != nil { - r.Eventf(log, machine.Metadata, corev1.EventTypeWarning, "AttchDetachVolume", "Volume attach/detach failed with error: %s", err) + r.Eventf(machine.Metadata, corev1.EventTypeWarning, "AttchDetachVolume", "Volume attach/detach failed with error: %s", err) return nil, nil, nil, err } if machine.Spec.Volumes != nil { - r.Eventf(log, machine.Metadata, corev1.EventTypeNormal, "AttchedVolume", "Successfully attached volumes") + r.Eventf(machine.Metadata, corev1.EventTypeNormal, "AttchedVolume", "Successfully attached volumes") } nicStates, err := r.setDomainNetworkInterfaces(ctx, machine, domainDesc) if err != nil { - r.Eventf(log, machine.Metadata, corev1.EventTypeWarning, "AttchDetachNIC", "Setting domain network interface failed with error: %s", err) + r.Eventf(machine.Metadata, corev1.EventTypeWarning, "AttchDetachNIC", "Setting domain network interface failed with error: %s", err) return nil, nil, nil, err } if machine.Spec.NetworkInterfaces != nil { - r.Eventf(log, machine.Metadata, corev1.EventTypeNormal, "AttchedNIC", "Successfully attached network interfaces") + r.Eventf(machine.Metadata, corev1.EventTypeNormal, "AttchedNIC", "Successfully attached network interfaces") } return domainDesc, volumeStates, nicStates, nil @@ -920,7 +917,7 @@ func (r *MachineReconciler) setDomainImage( return err } - r.Eventf(log, machine.Metadata, corev1.EventTypeNormal, "PullingImage", "Pulling image %s", machineImgRef) + r.Eventf(machine.Metadata, corev1.EventTypeNormal, "PullingImage", "Pulling image %s", machineImgRef) return err } @@ -988,7 +985,7 @@ func (r *MachineReconciler) setDomainIgnition(machine *api.Machine, domain *libv } func (r *MachineReconciler) getDomainDesc(machineID string) (*libvirtxml.Domain, error) { - domainXMLData, err := r.libvirt.DomainGetXMLDesc(libvirt.Domain{UUID: libvirtutils.UUIDStringToBytes(machineID)}, 0) + domainXMLData, err := r.host.Libvirt().DomainGetXMLDesc(libvirt.Domain{UUID: libvirtutils.UUIDStringToBytes(machineID)}, 0) if err != nil { return nil, err } diff --git a/internal/controllers/machine_controller_nics.go b/internal/controllers/machine_controller_nics.go index 27266308..3a155461 100644 --- a/internal/controllers/machine_controller_nics.go +++ b/internal/controllers/machine_controller_nics.go @@ -352,7 +352,7 @@ func (r *MachineReconciler) attachDomainDevice(domain libvirt.Domain, dev libvir if err != nil { return err } - return r.libvirt.DomainAttachDevice(domain, data) + return r.host.Libvirt().DomainAttachDevice(domain, data) } func (r *MachineReconciler) detachDomainDevice(domain libvirt.Domain, dev libvirtxml.Document) error { @@ -360,7 +360,7 @@ func (r *MachineReconciler) detachDomainDevice(domain libvirt.Domain, dev libvir if err != nil { return err } - return r.libvirt.DomainDetachDevice(domain, data) + return r.host.Libvirt().DomainDetachDevice(domain, data) } func parseNetworkInterfaceAlias(alias string) (string, error) { diff --git a/internal/controllers/machine_controller_volumes.go b/internal/controllers/machine_controller_volumes.go index 17a98cb6..869a73af 100644 --- a/internal/controllers/machine_controller_volumes.go +++ b/internal/controllers/machine_controller_volumes.go @@ -475,7 +475,7 @@ func (a *libvirtVolumeAttacher) GetVolume(name string) (*AttachVolume, error) { type MountVolume = providerhost.MachineVolume type volumeMounter struct { - host providerhost.Host + host providerhost.LibvirtHost pluginManager *providervolume.PluginManager machine *api.Machine } diff --git a/internal/event/event.go b/internal/event/event.go deleted file mode 100644 index c591a1c7..00000000 --- a/internal/event/event.go +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package event - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/go-logr/logr" - "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/store" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" -) - -type Handler[e api.Object] interface { - Handle(event Event[e]) -} - -type HandlerFunc[E api.Object] func(event Event[E]) - -func (f HandlerFunc[E]) Handle(event Event[E]) { - f(event) -} - -type HandlerRegistration interface{} - -type Source[E api.Object] interface { - AddHandler(handler Handler[E]) (HandlerRegistration, error) - RemoveHandler(registration HandlerRegistration) error -} - -type Type string - -const ( - TypeCreated Type = "Created" - TypeUpdated Type = "Updated" - TypeDeleted Type = "Deleted" - TypeGeneric Type = "Generic" -) - -type Event[E api.Object] struct { - Type Type - Object E -} - -type ListWatchSourceOptions struct { - ResyncDuration time.Duration -} - -func setListWatchSourceOptionsDefaults(o *ListWatchSourceOptions) { - if o.ResyncDuration == 0 { - o.ResyncDuration = 1 * time.Hour - } -} - -func NewListWatchSource[E api.Object](listFunc func(ctx context.Context) ([]E, error), watchFunc func(ctx context.Context) (store.Watch[E], error), opts ListWatchSourceOptions) (*ListWatchSource[E], error) { - setListWatchSourceOptionsDefaults(&opts) - - return &ListWatchSource[E]{ - listFunc: listFunc, - watchFunc: watchFunc, - handles: sets.New[*handle[E]](), - resyncDuration: opts.ResyncDuration, - }, nil -} - -type ListWatchSource[E api.Object] struct { - listFunc func(ctx context.Context) ([]E, error) - watchFunc func(ctx context.Context) (store.Watch[E], error) - - handlesMu sync.RWMutex - handles sets.Set[*handle[E]] - - resyncDuration time.Duration -} - -func (s *ListWatchSource[E]) Start(ctx context.Context) error { - log := logr.FromContextOrDiscard(ctx) - var wg sync.WaitGroup - - watch, err := s.watchFunc(ctx) - if err != nil { - return fmt.Errorf("failed to start watch: %w", err) - } - - wg.Add(1) - go func() { - defer wg.Done() - defer watch.Stop() - - for { - select { - case <-ctx.Done(): - return - case evt := <-watch.Events(): - eventType, err := typeFromWatchType(evt.Type) - if err != nil { - log.Error(err, "error converting watch event type") - continue - } - - s.enqueue(Event[E]{ - Type: eventType, - Object: evt.Object, - }) - } - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - - wait.UntilWithContext(ctx, func(ctx context.Context) { - objs, err := s.listFunc(ctx) - if err != nil { - log.Error(err, "failed to list objects") - return - } - - for _, obj := range objs { - s.enqueue(Event[E]{ - Type: TypeGeneric, - Object: obj, - }) - } - }, s.resyncDuration) - }() - - return nil -} - -func (s *ListWatchSource[E]) AddHandler(handler Handler[E]) (HandlerRegistration, error) { - s.handlesMu.Lock() - defer s.handlesMu.Unlock() - - reg := &handle[E]{ - handler: handler, - } - - s.handles.Insert(reg) - - return reg, nil -} - -func (s *ListWatchSource[E]) RemoveHandler(registration HandlerRegistration) error { - s.handlesMu.Lock() - defer s.handlesMu.Unlock() - - h, ok := registration.(*handle[E]) - if !ok { - return fmt.Errorf("invalid handler registration") - } - - s.handles.Delete(h) - - return nil -} - -func (s *ListWatchSource[E]) enqueue(evt Event[E]) { - for _, handler := range s.handlers() { - handler.Handle(evt) - } -} - -func (s *ListWatchSource[E]) handlers() []Handler[E] { - s.handlesMu.RLock() - defer s.handlesMu.RUnlock() - - handlers := make([]Handler[E], 0, s.handles.Len()) - for hdl := range s.handles { - handlers = append(handlers, hdl.handler) - } - - return handlers -} - -type handle[E api.Object] struct { - handler Handler[E] -} - -func typeFromWatchType(eventType store.WatchEventType) (Type, error) { - switch eventType { - case store.WatchEventTypeCreated: - return TypeCreated, nil - case store.WatchEventTypeUpdated: - return TypeUpdated, nil - case store.WatchEventTypeDeleted: - return TypeDeleted, nil - default: - return "", fmt.Errorf("unknown watch event type %q", eventType) - } -} diff --git a/internal/event/machineevent/machineevent.go b/internal/event/machineevent/machineevent.go deleted file mode 100644 index 90c33f8e..00000000 --- a/internal/event/machineevent/machineevent.go +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package machineevent - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/go-logr/logr" - "github.com/gogo/protobuf/proto" - irievent "github.com/ironcore-dev/ironcore/iri/apis/event/v1alpha1" - irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1" - "github.com/ironcore-dev/libvirt-provider/api" - "k8s.io/apimachinery/pkg/util/wait" -) - -// EventRecorder defines an interface for recording events -type EventRecorder interface { - Eventf(log logr.Logger, apiMetadata api.Metadata, eventType string, reason string, messageFormat string, args ...any) -} - -// EventStore defines an interface for listing events -type EventStore interface { - ListEvents() []*irievent.Event -} - -// EventStoreOptions defines options to initialize the machine event store -type EventStoreOptions struct { - MachineEventMaxEvents int - MachineEventTTL time.Duration - MachineEventResyncInterval time.Duration -} - -// Store implements the EventRecorder and EventStore interface and represents an in-memory event store with TTL for events. -type Store struct { - maxEvents int // Maximum number of events in the store - events []*irievent.Event // Slice of events - mutex sync.Mutex // Mutex for thread safety - eventTTL time.Duration // TTL for events - eventResyncInterval time.Duration // Resync interval for event store's TTL expiration check - head int // Index of the oldest event - count int // Current number of events in the store - log logr.Logger // Logger for logging overridden events -} - -// NewEventStore creates a new EventStore with a fixed number of events and set TTL for events. -func NewEventStore(log logr.Logger, opts EventStoreOptions) *Store { - return &Store{ - maxEvents: opts.MachineEventMaxEvents, - events: make([]*irievent.Event, opts.MachineEventMaxEvents), - eventTTL: opts.MachineEventTTL, - eventResyncInterval: opts.MachineEventResyncInterval, - head: 0, - count: 0, - log: log, - } -} - -// Eventf logs and records an event with formatted message. -func (es *Store) Eventf(log logr.Logger, apiMetadata api.Metadata, eventType, reason, messageFormat string, args ...any) { - metadata, err := api.GetObjectMetadata(apiMetadata) - if err != nil { - log.Error(err, "error getting iri metadata") - return - } - - // Format the message using the provided format and arguments - message := fmt.Sprintf(messageFormat, args...) - - es.recordEvent(metadata, eventType, reason, message) -} - -// recordEvent adds a new Event to the store. Implements the EventRecorder interface. -func (es *Store) recordEvent(metadata *irimeta.ObjectMetadata, eventType, reason, message string) { - es.mutex.Lock() - defer es.mutex.Unlock() - - // Calculate the index where the new event will be inserted - index := (es.head + es.count) % es.maxEvents - - // If the store is full, log and overwrite the oldest event and move the head - if es.count == es.maxEvents { - es.log.V(1).Info("Overriding event", "event", es.events[es.head]) - es.head = (es.head + 1) % es.maxEvents - } else { - es.count++ - } - - event := &irievent.Event{ - Spec: &irievent.EventSpec{ - InvolvedObjectMeta: metadata, - Type: eventType, - Reason: reason, - Message: message, - EventTime: time.Now().Unix(), - }, - } - - es.events[index] = event -} - -// removeExpiredEvents checks and removes events whose TTL has expired. -func (es *Store) removeExpiredEvents() { - es.mutex.Lock() - defer es.mutex.Unlock() - - now := time.Now() - - for es.count > 0 { - index := es.head % es.maxEvents - event := es.events[index] - eventTime := time.Unix(event.Spec.EventTime, 0) - eventTimeWithDuration := eventTime.Add(es.eventTTL) - - if eventTimeWithDuration.After(now) { - break - } - - // Clear the reference to the expired event - es.events[index] = nil - es.head = (es.head + 1) % es.maxEvents - es.count-- - } -} - -// Start initializes and starts the event store's TTL expiration check. -func (es *Store) Start(ctx context.Context) { - wait.UntilWithContext(ctx, func(ctx context.Context) { - es.removeExpiredEvents() - }, es.eventResyncInterval) -} - -// ListEvents returns a copy of all events currently in the store. -func (es *Store) ListEvents() []*irievent.Event { - es.mutex.Lock() - defer es.mutex.Unlock() - - result := make([]*irievent.Event, 0, es.count) - for i := 0; i < es.count; i++ { - index := (es.head + i) % es.maxEvents - // Create a deep copy of the event to break the reference - clone, ok := proto.Clone(es.events[index]).(*irievent.Event) - if !ok { - es.log.Error(fmt.Errorf("failed to clone event: %s", es.events[index]), "assertion error") - continue - } - result = append(result, clone) - } - - return result -} diff --git a/internal/event/machineevent/machineevent_test.go b/internal/event/machineevent/machineevent_test.go deleted file mode 100644 index a54d8d6e..00000000 --- a/internal/event/machineevent/machineevent_test.go +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package machineevent_test - -import ( - "context" - "fmt" - "strings" - "testing" - "time" - - "github.com/ironcore-dev/libvirt-provider/api" - - "github.com/go-logr/logr" - "github.com/go-logr/logr/funcr" - . "github.com/ironcore-dev/libvirt-provider/internal/event/machineevent" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestHandler(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Machine Event Suite") -} - -const ( - maxEvents = 5 - eventTTL = 2 * time.Second - eventType = "TestType" - reason = "TestReason" - message = "TestMessage" - resyncInterval = 2 * time.Second -) - -var ( - logOutput strings.Builder - log logr.Logger - es *Store - apiMetadata = api.Metadata{ - ID: "test-id-1234", - Annotations: map[string]string{ - "libvirt-provider.ironcore.dev/annotations": "{\"key1\":\"value1\", \"key2\":\"value2\"}", - "libvirt-provider.ironcore.dev/labels": "{\"downward-api.machinepoollet.ironcore.dev/root-machine-namespace\":\"default\", \"downward-api.machinepoollet.ironcore.dev/root-machine-name\":\"machine1\"}", - }} - opts = EventStoreOptions{ - MachineEventMaxEvents: maxEvents, - MachineEventTTL: eventTTL, - MachineEventResyncInterval: resyncInterval, - } -) - -var _ = Describe("Machine EventStore", func() { - BeforeEach(func() { - logOutput.Reset() - log = funcr.New(func(prefix, args string) { - logOutput.WriteString(args) - }, funcr.Options{}) - - es = NewEventStore(log, opts) - }) - - Context("Initialization", func() { - It("should initialize events slice with no elements", func() { - Expect(es.ListEvents()).To(BeEmpty()) - }) - }) - - Context("AddEvent", func() { - It("should add an event to the store", func() { - es.Eventf(log, apiMetadata, eventType, reason, message) - Expect(logOutput.String()).To(BeEmpty()) - Expect(es.ListEvents()).To(HaveLen(1)) - }) - - It("should handle error when retrieving metadata", func() { - badMetadata := api.Metadata{ - ID: "test-id-1234"} - es.Eventf(log, badMetadata, eventType, reason, message) - Expect(logOutput.String()).To(ContainSubstring("error getting iri metadata")) - Expect(es.ListEvents()).To(HaveLen(0)) - }) - - It("should override the oldest event when the store is full", func() { - for i := 0; i < maxEvents; i++ { - es.Eventf(log, apiMetadata, eventType, reason, "%s %d", message, i) - Expect(logOutput.String()).To(BeEmpty()) - Expect(es.ListEvents()).To(HaveLen(i + 1)) - } - - es.Eventf(log, apiMetadata, eventType, reason, "New Event") - Expect(logOutput.String()).To(BeEmpty()) - - events := es.ListEvents() - Expect(events).To(HaveLen(maxEvents)) - - for i := 0; i < maxEvents-1; i++ { - Expect(events[i].Spec.Message).To(Equal(fmt.Sprintf("%s %d", message, i+1))) - } - - Expect(events[maxEvents-1].Spec.Message).To(Equal("New Event")) - }) - }) - - Context("removeExpiredEvents", func() { - It("should remove events whose TTL has expired", func() { - es.Eventf(log, apiMetadata, eventType, reason, message) - Expect(logOutput.String()).To(BeEmpty()) - Expect(es.ListEvents()).To(HaveLen(1)) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - go es.Start(ctx) - - Eventually(func(g Gomega) bool { - return g.Expect(es.ListEvents()).To(HaveLen(0)) - }).WithTimeout(eventTTL + 1*time.Second).WithPolling(100 * time.Millisecond).Should(BeTrue()) - }) - - It("should not remove events whose TTL has not expired", func() { - es.Eventf(log, apiMetadata, eventType, reason, message) - Expect(logOutput.String()).To(BeEmpty()) - Expect(es.ListEvents()).To(HaveLen(1)) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - go es.Start(ctx) - - Expect(es.ListEvents()).To(HaveLen(1)) - }) - }) - - Context("Start", func() { - It("should periodically remove expired events", func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - go es.Start(ctx) - - es.Eventf(log, apiMetadata, eventType, reason, message) - Expect(logOutput.String()).To(BeEmpty()) - Expect(es.ListEvents()).To(HaveLen(1)) - - Eventually(func(g Gomega) bool { - return g.Expect(es.ListEvents()).To(HaveLen(0)) - }).WithTimeout(resyncInterval + 1*time.Second).WithPolling(100 * time.Millisecond).Should(BeTrue()) - }) - }) - - Context("ListEvents", func() { - It("should return all current events", func() { - es.Eventf(log, apiMetadata, eventType, reason, message) - Expect(logOutput.String()).To(BeEmpty()) - - events := es.ListEvents() - Expect(events).To(HaveLen(1)) - Expect(events[0].Spec.Message).To(Equal(message)) - }) - - It("should return a copy of events", func() { - es.Eventf(log, apiMetadata, eventType, reason, message) - Expect(logOutput.String()).To(BeEmpty()) - events := es.ListEvents() - Expect(events).To(HaveLen(1)) - - events[0].Spec.Message = "Changed Message" - - storedEvents := es.ListEvents() - Expect(storedEvents[0].Spec.Message).ToNot(Equal(events[0].Spec.Message)) - }) - }) -}) diff --git a/internal/host/host.go b/internal/host/host.go index 05fea40b..f6046a93 100644 --- a/internal/host/host.go +++ b/internal/host/host.go @@ -9,7 +9,6 @@ import ( "path/filepath" "github.com/digitalocean/go-libvirt" - ocistore "github.com/ironcore-dev/ironcore-image/oci/store" ) const ( @@ -136,58 +135,36 @@ func (p *paths) MachineIgnitionFile(machineUID string) string { return filepath.Join(p.MachineIgnitionsDir(machineUID), DefaultMachineIgnitionFile) } -type Host interface { - Paths - OCIStore() *ocistore.Store -} - type LibvirtHost interface { - Host - Libvirt() *libvirt.Libvirt -} - -type host struct { Paths - ociStore *ocistore.Store -} - -func (h *host) OCIStore() *ocistore.Store { - return h.ociStore + Libvirt() *libvirt.Libvirt } func PathsAt(rootDir string) (Paths, error) { p := &paths{rootDir} - if err := os.MkdirAll(p.RootDir(), perm); err != nil { + if err := os.MkdirAll(p.RootDir(), os.ModePerm); err != nil { return nil, fmt.Errorf("error creating root directory: %w", err) } - if err := os.MkdirAll(p.ImagesDir(), perm); err != nil { + if err := os.MkdirAll(p.ImagesDir(), os.ModePerm); err != nil { return nil, fmt.Errorf("error creating images directory: %w", err) } - if err := os.MkdirAll(p.MachinesDir(), perm); err != nil { + if err := os.MkdirAll(p.MachinesDir(), os.ModePerm); err != nil { return nil, fmt.Errorf("error creating machines directory: %w", err) } return p, nil } -func NewAt(rootDir string) (Host, error) { +func NewAt(rootDir string) (Paths, error) { p, err := PathsAt(rootDir) if err != nil { return nil, err } - ociStore, err := ocistore.New(p.ImagesDir()) - if err != nil { - return nil, fmt.Errorf("error creating oci store: %w", err) - } - - return &host{ - Paths: p, - ociStore: ociStore, - }, nil + return p, nil } type libvirtHost struct { - Host + Paths libvirt *libvirt.Libvirt } @@ -196,12 +173,12 @@ func (h *libvirtHost) Libvirt() *libvirt.Libvirt { } func NewLibvirtAt(rootDir string, libvirt *libvirt.Libvirt) (LibvirtHost, error) { - host, err := NewAt(rootDir) + p, err := NewAt(rootDir) if err != nil { return nil, err } - return &libvirtHost{host, libvirt}, nil + return &libvirtHost{p, libvirt}, nil } type MachineVolume struct { @@ -213,55 +190,6 @@ type MachineNetworkInterface struct { NetworkInterfaceName string } -func ReadMachineUIDs(paths Paths) ([]string, error) { - var res []string - if err := IterateMachines(paths, func(machineUID string) error { - res = append(res, machineUID) - return nil - }); err != nil { - return nil, err - } - return res, nil -} - -func IterateMachines(paths Paths, f func(machineUID string) error) error { - entries, err := os.ReadDir(paths.MachinesDir()) - if err != nil { - return err - } - - for _, entry := range entries { - if !entry.IsDir() { - continue - } - - machineUID := string(entry.Name()) - if err := f(machineUID); err != nil { - return fmt.Errorf("[machine uid %s] %w", machineUID, err) - } - } - return nil -} - -func IterateMachineNetworkInterfaces(paths Paths, machineUID string, f func(networkInterfaceName string) error) error { - entries, err := os.ReadDir(paths.MachineNetworkInterfacesDir(machineUID)) - if err != nil { - return err - } - - for _, entry := range entries { - if !entry.IsDir() { - continue - } - - networkInterfaceName := entry.Name() - if err := f(networkInterfaceName); err != nil { - return fmt.Errorf("[network interface %s] %w", networkInterfaceName, err) - } - } - return nil -} - func ReadMachineNetworkInterfaces(paths Paths, machineUID string) ([]MachineNetworkInterface, error) { entries, err := os.ReadDir(paths.MachineNetworkInterfacesDir(machineUID)) if err != nil { @@ -282,19 +210,19 @@ func ReadMachineNetworkInterfaces(paths Paths, machineUID string) ([]MachineNetw } func MakeMachineDirs(paths Paths, machineUID string) error { - if err := os.MkdirAll(paths.MachineDir(machineUID), perm); err != nil { + if err := os.MkdirAll(paths.MachineDir(machineUID), os.ModePerm); err != nil { return fmt.Errorf("error creating machine directory: %w", err) } - if err := os.MkdirAll(paths.MachineRootFSDir(machineUID), perm); err != nil { + if err := os.MkdirAll(paths.MachineRootFSDir(machineUID), os.ModePerm); err != nil { return fmt.Errorf("error creating machine rootfs directory: %w", err) } - if err := os.MkdirAll(paths.MachineVolumesDir(machineUID), perm); err != nil { + if err := os.MkdirAll(paths.MachineVolumesDir(machineUID), os.ModePerm); err != nil { return fmt.Errorf("error creating machine disks directory: %w", err) } - if err := os.MkdirAll(paths.MachineIgnitionsDir(machineUID), perm); err != nil { + if err := os.MkdirAll(paths.MachineIgnitionsDir(machineUID), os.ModePerm); err != nil { return fmt.Errorf("error creating machine ignitions directory: %w", err) } - if err := os.MkdirAll(paths.MachineNetworkInterfacesDir(machineUID), perm); err != nil { + if err := os.MkdirAll(paths.MachineNetworkInterfacesDir(machineUID), os.ModePerm); err != nil { return fmt.Errorf("error creating machine network interfaces directory: %w", err) } return nil diff --git a/internal/host/host_suite_test.go b/internal/host/host_suite_test.go deleted file mode 100644 index 6b35cb21..00000000 --- a/internal/host/host_suite_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package host_test - -import ( - "testing" - "time" - - "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/host" - "github.com/ironcore-dev/libvirt-provider/internal/store" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" -) - -var ( - tmpDir string - machineStore store.Store[*api.Machine] -) - -const ( - eventuallyTimeout = 5 * time.Second - pollingInterval = 250 * time.Millisecond - consistentlyDuration = 1 * time.Second -) - -func TestServer(t *testing.T) { - SetDefaultConsistentlyPollingInterval(pollingInterval) - SetDefaultEventuallyPollingInterval(pollingInterval) - SetDefaultEventuallyTimeout(eventuallyTimeout) - SetDefaultConsistentlyDuration(consistentlyDuration) - - RegisterFailHandler(Fail) - RunSpecs(t, "Server Suite") -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - var err error - - tmpDir = GinkgoT().TempDir() - - machineStore, err = host.NewStore[*api.Machine](host.Options[*api.Machine]{ - Dir: tmpDir, - NewFunc: func() *api.Machine { - return &api.Machine{} - }, - }) - Expect(err).NotTo(HaveOccurred()) -}) diff --git a/internal/host/store.go b/internal/host/store.go deleted file mode 100644 index a922488d..00000000 --- a/internal/host/store.go +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package host - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "reflect" - "sync" - "time" - - "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/store" - utilssync "github.com/ironcore-dev/libvirt-provider/internal/sync" - "github.com/ironcore-dev/libvirt-provider/internal/utils" - "k8s.io/apimachinery/pkg/util/json" - "k8s.io/apimachinery/pkg/util/sets" -) - -const perm = 0777 - -type Options[E api.Object] struct { - //TODO - Dir string - NewFunc func() E - CreateStrategy CreateStrategy[E] -} - -func NewStore[E api.Object](opts Options[E]) (*Store[E], error) { - - if opts.NewFunc == nil { - return nil, fmt.Errorf("must specify opts.NewFunc") - } - - if err := os.MkdirAll(opts.Dir, perm); err != nil { - return nil, fmt.Errorf("error creating store directory: %w", err) - } - - return &Store[E]{ - dir: opts.Dir, - - idMu: utilssync.NewMutexMap[string](), - - newFunc: opts.NewFunc, - createStrategy: opts.CreateStrategy, - - watches: sets.New[*watch[E]](), - }, nil -} - -type Store[E api.Object] struct { - dir string - - idMu *utilssync.MutexMap[string] - - newFunc func() E - createStrategy CreateStrategy[E] - - watchesMu sync.RWMutex - watches sets.Set[*watch[E]] -} - -type CreateStrategy[E api.Object] interface { - PrepareForCreate(obj E) -} - -func (s *Store[E]) Create(_ context.Context, obj E) (E, error) { - s.idMu.Lock(obj.GetID()) - defer s.idMu.Unlock(obj.GetID()) - - _, err := s.get(obj.GetID()) - switch { - case err == nil: - return utils.Zero[E](), fmt.Errorf("object with id %q %w", obj.GetID(), store.ErrAlreadyExists) - case errors.Is(err, store.ErrNotFound): - default: - return utils.Zero[E](), fmt.Errorf("failed to get object with id %q %w", obj.GetID(), err) - } - - if s.createStrategy != nil { - s.createStrategy.PrepareForCreate(obj) - } - - obj.SetCreatedAt(time.Now()) - obj.IncrementResourceVersion() - - obj, err = s.set(obj) - if err != nil { - return utils.Zero[E](), err - } - - s.enqueue(store.WatchEvent[E]{ - Type: store.WatchEventTypeCreated, - Object: obj, - }) - - return obj, nil -} - -func (s *Store[E]) Get(_ context.Context, id string) (E, error) { - s.idMu.Lock(id) - defer s.idMu.Unlock(id) - - object, err := s.get(id) - if err != nil { - return utils.Zero[E](), fmt.Errorf("failed to read object: %w", err) - } - - return object, nil -} - -func (s *Store[E]) Update(_ context.Context, obj E) (E, error) { - s.idMu.Lock(obj.GetID()) - defer s.idMu.Unlock(obj.GetID()) - - oldObj, err := s.get(obj.GetID()) - if err != nil { - return utils.Zero[E](), err - } - - if obj.GetDeletedAt() != nil && len(obj.GetFinalizers()) == 0 { - if err := s.delete(obj.GetID()); err != nil { - return utils.Zero[E](), fmt.Errorf("failed to delete object metadata: %w", err) - } - return obj, nil - } - - if oldObj.GetResourceVersion() != obj.GetResourceVersion() { - return utils.Zero[E](), fmt.Errorf("failed to update object: %w", store.ErrResourceVersionNotLatest) - } - - if reflect.DeepEqual(oldObj, obj) { - return obj, nil - } - - obj.IncrementResourceVersion() - - obj, err = s.set(obj) - if err != nil { - return utils.Zero[E](), err - } - - s.enqueue(store.WatchEvent[E]{ - Type: store.WatchEventTypeUpdated, - Object: obj, - }) - - return obj, nil -} - -func (s *Store[E]) Delete(_ context.Context, id string) error { - s.idMu.Lock(id) - defer s.idMu.Unlock(id) - - obj, err := s.get(id) - if err != nil { - return err - } - - if len(obj.GetFinalizers()) == 0 { - return s.delete(id) - } - - if obj.GetDeletedAt() != nil { - return nil - } - - now := time.Now() - obj.SetDeletedAt(&now) - obj.IncrementResourceVersion() - - if _, err := s.set(obj); err != nil { - return fmt.Errorf("failed to set object metadata: %w", err) - } - - s.enqueue(store.WatchEvent[E]{ - Type: store.WatchEventTypeDeleted, - Object: obj, - }) - - return nil -} - -func (s *Store[E]) List(ctx context.Context) ([]E, error) { - entries, err := os.ReadDir(s.dir) - if err != nil { - return nil, fmt.Errorf("failed to list objects: %w", err) - } - - var objs []E - for _, entry := range entries { - if entry.IsDir() { - continue - } - - object, err := s.Get(ctx, entry.Name()) - if err != nil { - return nil, fmt.Errorf("failed to read object: %w", err) - } - - objs = append(objs, object) - } - - return objs, nil -} - -func (s *Store[E]) Watch(_ context.Context) (store.Watch[E], error) { - //TODO make configurable - const bufferSize = 10 - s.watchesMu.Lock() - defer s.watchesMu.Unlock() - - w := &watch[E]{ - store: s, - events: make(chan store.WatchEvent[E], bufferSize), - } - - s.watches.Insert(w) - - return w, nil -} - -func (s *Store[E]) get(id string) (E, error) { - file, err := os.ReadFile(filepath.Join(s.dir, id)) - if err != nil { - if !os.IsNotExist(err) { - return utils.Zero[E](), fmt.Errorf("failed to read file: %w", err) - } - - return utils.Zero[E](), fmt.Errorf("object with id %q %w", id, store.ErrNotFound) - } - - obj := s.newFunc() - if err := json.Unmarshal(file, &obj); err != nil { - return utils.Zero[E](), fmt.Errorf("failed to unmarshal object from file %s: %w", id, err) - } - - return obj, err -} - -func (s *Store[E]) set(obj E) (E, error) { - data, err := json.Marshal(obj) - if err != nil { - return utils.Zero[E](), fmt.Errorf("failed to marshal obj: %w", err) - } - - if err := os.WriteFile(filepath.Join(s.dir, obj.GetID()), data, 0666); err != nil { - return utils.Zero[E](), nil - } - - return obj, nil -} - -func (s *Store[E]) delete(id string) error { - if err := os.Remove(filepath.Join(s.dir, id)); err != nil { - return fmt.Errorf("failed to delete object from store: %w", err) - } - - return nil -} - -func (s *Store[E]) watchHandlers() []*watch[E] { - s.watchesMu.RLock() - defer s.watchesMu.RUnlock() - - return s.watches.UnsortedList() -} - -func (s *Store[E]) enqueue(evt store.WatchEvent[E]) { - for _, handler := range s.watchHandlers() { - select { - case handler.events <- evt: - default: - } - } -} diff --git a/internal/host/store_test.go b/internal/host/store_test.go deleted file mode 100644 index 49f2f9bf..00000000 --- a/internal/host/store_test.go +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package host_test - -import ( - "os" - "path/filepath" - - "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/store" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = Describe("Store", func() { - - It("should correctly create a object", func(ctx SpecContext) { - By("creating a watch") - watch, err := machineStore.Watch(ctx) - Expect(err).NotTo(HaveOccurred()) - DeferCleanup(watch.Stop) - - By("creating a machine object") - machine, err := machineStore.Create(ctx, &api.Machine{ - Metadata: api.Metadata{ - ID: "test-id", - }, - Spec: api.MachineSpec{}, - Status: api.MachineStatus{}, - }) - Expect(err).NotTo(HaveOccurred()) - Expect(machine).NotTo(BeNil()) - - By("checking that the store object exists") - data, err := os.ReadFile(filepath.Join(tmpDir, machine.ID)) - Expect(err).NotTo(HaveOccurred()) - Expect(data).NotTo(BeNil()) - - By("checking that the event got fired") - event := &store.WatchEvent[*api.Machine]{ - Type: store.WatchEventTypeCreated, - Object: machine, - } - Eventually(watch.Events()).Should(Receive(event)) - }) -}) diff --git a/internal/host/watch.go b/internal/host/watch.go deleted file mode 100644 index 32f877eb..00000000 --- a/internal/host/watch.go +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package host - -import ( - "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/store" -) - -type watch[E api.Object] struct { - store *Store[E] - events chan store.WatchEvent[E] -} - -func (w *watch[E]) Stop() { - w.store.watchesMu.Lock() - defer w.store.watchesMu.Unlock() - - w.store.watches.Delete(w) -} - -func (w *watch[E]) Events() <-chan store.WatchEvent[E] { - return w.events -} diff --git a/internal/plugins/networkinterface/apinet/apinet.go b/internal/plugins/networkinterface/apinet/apinet.go index 479faaeb..c8c14331 100644 --- a/internal/plugins/networkinterface/apinet/apinet.go +++ b/internal/plugins/networkinterface/apinet/apinet.go @@ -41,7 +41,7 @@ const ( type Plugin struct { nodeName string - host providerhost.Host + host providerhost.LibvirtHost apinetClient client.Client } @@ -52,7 +52,7 @@ func NewPlugin(nodeName string, client client.Client) providernetworkinterface.P } } -func (p *Plugin) Init(host providerhost.Host) error { +func (p *Plugin) Init(host providerhost.LibvirtHost) error { p.host = host return nil } diff --git a/internal/plugins/networkinterface/isolated/isolated.go b/internal/plugins/networkinterface/isolated/isolated.go index 5fce1f86..c18e3a6c 100644 --- a/internal/plugins/networkinterface/isolated/isolated.go +++ b/internal/plugins/networkinterface/isolated/isolated.go @@ -18,14 +18,14 @@ const ( ) type plugin struct { - host providerhost.Host + host providerhost.LibvirtHost } func NewPlugin() providernetworkinterface.Plugin { return &plugin{} } -func (p *plugin) Init(host providerhost.Host) error { +func (p *plugin) Init(host providerhost.LibvirtHost) error { p.host = host return nil } diff --git a/internal/plugins/networkinterface/plugins.go b/internal/plugins/networkinterface/plugins.go index 92297d82..83ff03f3 100644 --- a/internal/plugins/networkinterface/plugins.go +++ b/internal/plugins/networkinterface/plugins.go @@ -12,7 +12,7 @@ import ( type Plugin interface { Name() string - Init(host providerhost.Host) error + Init(host providerhost.LibvirtHost) error Apply(ctx context.Context, spec *api.NetworkInterfaceSpec, machine *api.Machine) (*NetworkInterface, error) Delete(ctx context.Context, computeNicName string, machineID string) error diff --git a/internal/plugins/networkinterface/providernetwork/providernetwork.go b/internal/plugins/networkinterface/providernetwork/providernetwork.go index d5099782..632b2b0d 100644 --- a/internal/plugins/networkinterface/providernetwork/providernetwork.go +++ b/internal/plugins/networkinterface/providernetwork/providernetwork.go @@ -18,14 +18,14 @@ const ( ) type plugin struct { - host providerhost.Host + host providerhost.LibvirtHost } func NewPlugin() providernetworkinterface.Plugin { return &plugin{} } -func (p *plugin) Init(host providerhost.Host) error { +func (p *plugin) Init(host providerhost.LibvirtHost) error { p.host = host return nil } diff --git a/internal/plugins/volume/emptydisk/emptydisk.go b/internal/plugins/volume/emptydisk/emptydisk.go index 12454290..6b354b06 100644 --- a/internal/plugins/volume/emptydisk/emptydisk.go +++ b/internal/plugins/volume/emptydisk/emptydisk.go @@ -14,7 +14,6 @@ import ( "github.com/ironcore-dev/libvirt-provider/api" "github.com/ironcore-dev/libvirt-provider/internal/plugins/volume" - "github.com/ironcore-dev/libvirt-provider/internal/qcow2" "github.com/ironcore-dev/libvirt-provider/internal/raw" utilstrings "k8s.io/utils/strings" ) @@ -29,15 +28,13 @@ const ( ) type plugin struct { - host volume.Host - qcow2 qcow2.QCow2 - raw raw.Raw + host volume.Host + raw raw.Raw } -func NewPlugin(qcow2 qcow2.QCow2, raw raw.Raw) volume.Plugin { +func NewPlugin(raw raw.Raw) volume.Plugin { return &plugin{ - qcow2: qcow2, - raw: raw, + raw: raw, } } diff --git a/internal/qcow2/qcow2.go b/internal/qcow2/qcow2.go deleted file mode 100644 index 882b3785..00000000 --- a/internal/qcow2/qcow2.go +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package qcow2 - -import ( - "fmt" - "sort" -) - -type QCow2 interface { - Create(filename string, opts ...CreateOption) error -} - -type CreateOption interface { - ApplyToCreate(o *CreateOptions) -} - -type WithSize int64 - -func (s WithSize) ApplyToCreate(o *CreateOptions) { - o.Size = (*int64)(&s) -} - -type WithSourceFile string - -func (s WithSourceFile) ApplyToCreate(o *CreateOptions) { - o.SourceFile = string(s) -} - -type CreateOptions struct { - Size *int64 - SourceFile string -} - -func (o *CreateOptions) ApplyToCreate(o2 *CreateOptions) { - if o.Size != nil { - o2.Size = o.Size - } - if o.SourceFile != "" { - o2.SourceFile = o.SourceFile - } -} - -func (o *CreateOptions) ApplyOptions(opts []CreateOption) { - for _, opt := range opts { - opt.ApplyToCreate(o) - } -} - -type qcow2AndPriority struct { - qcow2 QCow2 - priority int -} - -type implsRegistry struct { - entries map[string]qcow2AndPriority -} - -func (r *implsRegistry) Add(name string, priority int, qcow2 QCow2) error { - if _, ok := r.entries[name]; ok { - return fmt.Errorf("implementation %q already registered", name) - } - - if r.entries == nil { - r.entries = make(map[string]qcow2AndPriority) - } - - r.entries[name] = qcow2AndPriority{qcow2, priority} - return nil -} - -func (r *implsRegistry) Instance(name string) (QCow2, error) { - entry, ok := r.entries[name] - if !ok { - return nil, fmt.Errorf("unknown implementation %q", name) - } - return entry.qcow2, nil -} - -func (r *implsRegistry) Available() []string { - res := make([]string, 0, len(r.entries)) - for name := range r.entries { - res = append(res, name) - } - sort.Slice(res, func(i, j int) bool { - return r.entries[res[i]].priority < r.entries[res[j]].priority - }) - return res -} - -func (r *implsRegistry) Default() string { - return r.Available()[0] -} - -var ( - impls implsRegistry - - Instance = impls.Instance - Available = impls.Available - Default = impls.Default -) diff --git a/internal/qcow2/qcow2_exec.go b/internal/qcow2/qcow2_exec.go deleted file mode 100644 index 95eb7ad5..00000000 --- a/internal/qcow2/qcow2_exec.go +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package qcow2 - -import ( - "fmt" - "os/exec" - "strconv" - - utilruntime "k8s.io/apimachinery/pkg/util/runtime" -) - -type Exec struct { -} - -func (Exec) Create(filename string, opts ...CreateOption) error { - o := &CreateOptions{} - o.ApplyOptions(opts) - - if o.SourceFile == "" && o.Size == nil { - return fmt.Errorf("must specify Size when creating without source file") - } - - args := []string{"create", "-f", "qcow2"} - - if o.SourceFile != "" { - args = append(args, - "-b", o.SourceFile, - "-F", "raw", - ) - } - - args = append(args, filename) - - if o.Size != nil { - args = append(args, strconv.FormatInt(*o.Size, 10)) - } - - res, err := exec.Command("qemu-img", args...).CombinedOutput() - if err != nil { - return fmt.Errorf("error running qemu-img: %s, exit error %w", string(res), err) - } - return nil -} - -func init() { - utilruntime.Must(impls.Add("exec", 0, Exec{})) -} diff --git a/internal/server/event_list.go b/internal/server/event_list.go index f9851f65..adef4bc4 100644 --- a/internal/server/event_list.go +++ b/internal/server/event_list.go @@ -5,28 +5,39 @@ package server import ( "context" + "fmt" + "github.com/go-logr/logr" irievent "github.com/ironcore-dev/ironcore/iri/apis/event/v1alpha1" iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" + "github.com/ironcore-dev/libvirt-provider/api" + apiutils "github.com/ironcore-dev/provider-utils/apiutils/api" + "github.com/ironcore-dev/provider-utils/eventutils/recorder" "k8s.io/apimachinery/pkg/labels" ) -func (s *Server) filterEvents(events []*irievent.Event, filter *iri.EventFilter) []*irievent.Event { +func (s *Server) filterEvents(log logr.Logger, events []*recorder.Event, filter *iri.EventFilter) []*recorder.Event { if filter == nil { return events } var ( - res []*irievent.Event + res []*recorder.Event sel = labels.SelectorFromSet(filter.LabelSelector) ) for _, iriEvent := range events { - if !sel.Matches(labels.Set(iriEvent.Spec.InvolvedObjectMeta.Labels)) { + originLabels, err := apiutils.GetLabelsAnnotation(iriEvent.InvolvedObjectMeta, api.LabelsAnnotation) + if err != nil { + log.V(1).Info("failed to labels from involved object", "err", err.Error()) + continue + } + + if !sel.Matches(labels.Set(originLabels)) { continue } if filter.EventsFromTime > 0 && filter.EventsToTime > 0 { - if iriEvent.Spec.EventTime < filter.EventsFromTime || iriEvent.Spec.EventTime > filter.EventsToTime { + if iriEvent.EventTime < filter.EventsFromTime || iriEvent.EventTime > filter.EventsToTime { continue } } @@ -36,8 +47,39 @@ func (s *Server) filterEvents(events []*irievent.Event, filter *iri.EventFilter) return res } +func (s *Server) convertEventToIRIEvent(events []*recorder.Event) ([]*irievent.Event, error) { + var ( + res []*irievent.Event + ) + for _, event := range events { + metadata, err := api.GetObjectMetadata(event.InvolvedObjectMeta) + if err != nil { + return nil, fmt.Errorf("failed to get object metadata: %w", err) + } + + res = append(res, &irievent.Event{ + Spec: &irievent.EventSpec{ + InvolvedObjectMeta: metadata, + Reason: event.Reason, + Message: event.Message, + Type: event.Type, + EventTime: event.EventTime, + }, + }) + } + return res, nil +} + func (s *Server) ListEvents(ctx context.Context, req *iri.ListEventsRequest) (*iri.ListEventsResponse, error) { - iriEvents := s.filterEvents(s.eventStore.ListEvents(), req.Filter) + log := s.loggerFrom(ctx) + + events := s.eventStore.ListEvents() + filteredEvents := s.filterEvents(log, events, req.Filter) + + iriEvents, err := s.convertEventToIRIEvent(filteredEvents) + if err != nil { + return nil, err + } return &iri.ListEventsResponse{ Events: iriEvents, diff --git a/internal/server/exec.go b/internal/server/exec.go index 49b1801c..b56eac0a 100644 --- a/internal/server/exec.go +++ b/internal/server/exec.go @@ -19,7 +19,7 @@ import ( remotecommandserver "github.com/ironcore-dev/ironcore/poollet/machinepoollet/iri/streaming/remotecommand" "github.com/ironcore-dev/libvirt-provider/api" libvirtutils "github.com/ironcore-dev/libvirt-provider/internal/libvirt/utils" - "github.com/ironcore-dev/libvirt-provider/internal/store" + "github.com/ironcore-dev/provider-utils/storeutils/store" "github.com/moby/term" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" diff --git a/internal/server/machine_annotations_update.go b/internal/server/machine_annotations_update.go index 608de5d7..fa21d31d 100644 --- a/internal/server/machine_annotations_update.go +++ b/internal/server/machine_annotations_update.go @@ -10,13 +10,14 @@ import ( iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/store" + apiutils "github.com/ironcore-dev/provider-utils/apiutils/api" + "github.com/ironcore-dev/provider-utils/storeutils/store" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func (s *Server) updateAnnotations(ctx context.Context, machine *api.Machine, annotations map[string]string) error { - if err := api.SetAnnotationsAnnotation(machine, annotations); err != nil { + if err := apiutils.SetAnnotationsAnnotation(machine, api.AnnotationsAnnotation, annotations); err != nil { return fmt.Errorf("failed to set machine annotations: %w", err) } diff --git a/internal/server/machine_create.go b/internal/server/machine_create.go index 141f16b8..5a75b0e3 100644 --- a/internal/server/machine_create.go +++ b/internal/server/machine_create.go @@ -9,7 +9,8 @@ import ( "github.com/go-logr/logr" iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" - api "github.com/ironcore-dev/libvirt-provider/api" + "github.com/ironcore-dev/libvirt-provider/api" + apiutils "github.com/ironcore-dev/provider-utils/apiutils/api" ) func calcResources(class *iri.MachineClass) (int64, int64) { @@ -64,7 +65,7 @@ func (s *Server) createMachineFromIRIMachine(ctx context.Context, log logr.Logge } machine := &api.Machine{ - Metadata: api.Metadata{ + Metadata: apiutils.Metadata{ ID: s.idGen.Generate(), }, Spec: api.MachineSpec{ diff --git a/internal/server/machine_delete.go b/internal/server/machine_delete.go index 7a5fff37..c0abb4fa 100644 --- a/internal/server/machine_delete.go +++ b/internal/server/machine_delete.go @@ -9,7 +9,7 @@ import ( "fmt" iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" - "github.com/ironcore-dev/libvirt-provider/internal/store" + "github.com/ironcore-dev/provider-utils/storeutils/store" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/internal/server/machine_list.go b/internal/server/machine_list.go index 5eeb4f55..2e33eee1 100644 --- a/internal/server/machine_list.go +++ b/internal/server/machine_list.go @@ -11,7 +11,7 @@ import ( "github.com/go-logr/logr" iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/store" + "github.com/ironcore-dev/provider-utils/storeutils/store" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "k8s.io/apimachinery/pkg/labels" diff --git a/internal/server/machine_powerstate_update.go b/internal/server/machine_powerstate_update.go index 052390c3..3600c8b9 100644 --- a/internal/server/machine_powerstate_update.go +++ b/internal/server/machine_powerstate_update.go @@ -10,7 +10,7 @@ import ( iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/store" + "github.com/ironcore-dev/provider-utils/storeutils/store" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/internal/server/server.go b/internal/server/server.go index 7a0adca7..feca5a6b 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -17,11 +17,11 @@ import ( "github.com/ironcore-dev/ironcore/broker/common/request" iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1" "github.com/ironcore-dev/libvirt-provider/api" - "github.com/ironcore-dev/libvirt-provider/internal/event/machineevent" providernetworkinterface "github.com/ironcore-dev/libvirt-provider/internal/plugins/networkinterface" "github.com/ironcore-dev/libvirt-provider/internal/plugins/volume" - "github.com/ironcore-dev/libvirt-provider/internal/store" "github.com/ironcore-dev/libvirt-provider/internal/utils" + "github.com/ironcore-dev/provider-utils/eventutils/recorder" + "github.com/ironcore-dev/provider-utils/storeutils/store" ctrl "sigs.k8s.io/controller-runtime" ) @@ -33,7 +33,7 @@ type Server struct { idGen idgen.IDGen machineStore store.Store[*api.Machine] - eventStore machineevent.EventStore + eventStore recorder.EventStore networkInterfacePlugin providernetworkinterface.Plugin @@ -58,7 +58,7 @@ type Options struct { IDGen idgen.IDGen MachineStore store.Store[*api.Machine] - EventStore machineevent.EventStore + EventStore recorder.EventStore MachineClasses MachineClassRegistry diff --git a/internal/server/server_suite_test.go b/internal/server/server_suite_test.go index 989c5654..5e1825b6 100644 --- a/internal/server/server_suite_test.go +++ b/internal/server/server_suite_test.go @@ -18,8 +18,8 @@ import ( "github.com/ironcore-dev/ironcore/iri/remote/machine" "github.com/ironcore-dev/libvirt-provider/api" "github.com/ironcore-dev/libvirt-provider/cmd/libvirt-provider/app" - "github.com/ironcore-dev/libvirt-provider/internal/event/machineevent" "github.com/ironcore-dev/libvirt-provider/internal/networkinterfaceplugin" + "github.com/ironcore-dev/provider-utils/eventutils/recorder" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "google.golang.org/grpc" @@ -44,7 +44,7 @@ const ( streamingAddress = "127.0.0.1:20251" healthCheckAddress = "127.0.0.1:20252" metricsAddress = "" // disable metrics server for integration tests - machineEventMaxEvents = 10 + machineEventMaxEvents = 1000 machineEventTTL = 10 * time.Second machineEventResyncInterval = 2 * time.Second ) @@ -131,10 +131,10 @@ var _ = BeforeSuite(func() { ResyncIntervalGarbageCollector: resyncGarbageCollectorInterval, ResyncIntervalVolumeSize: resyncVolumeSizeInterval, GuestAgent: app.GuestAgentOption(api.GuestAgentNone), - MachineEventStore: machineevent.EventStoreOptions{ - MachineEventMaxEvents: machineEventMaxEvents, - MachineEventTTL: machineEventTTL, - MachineEventResyncInterval: machineEventResyncInterval, + MachineEventStore: recorder.EventStoreOptions{ + MaxEvents: machineEventMaxEvents, + TTL: machineEventTTL, + ResyncInterval: machineEventResyncInterval, }, } diff --git a/internal/store/store.go b/internal/store/store.go deleted file mode 100644 index 3b40b156..00000000 --- a/internal/store/store.go +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors -// SPDX-License-Identifier: Apache-2.0 - -package store - -import ( - "context" - "errors" - - "github.com/ironcore-dev/libvirt-provider/api" -) - -var ( - ErrNotFound = errors.New("not found") - ErrAlreadyExists = errors.New("already exists") - ErrResourceVersionNotLatest = errors.New("resourceVersion is not latest") -) - -func IgnoreErrNotFound(err error) error { - if errors.Is(err, ErrNotFound) { - return nil - } - - return err -} - -type Watch[E api.Object] interface { - Stop() - Events() <-chan WatchEvent[E] -} - -type WatchEvent[E api.Object] struct { - Type WatchEventType - Object E -} - -type WatchEventType string - -const ( - WatchEventTypeCreated WatchEventType = "Created" - WatchEventTypeUpdated WatchEventType = "Updated" - WatchEventTypeDeleted WatchEventType = "Deleted" -) - -type Store[E api.Object] interface { - Create(ctx context.Context, obj E) (E, error) - Get(ctx context.Context, id string) (E, error) - Update(ctx context.Context, obj E) (E, error) - Delete(ctx context.Context, id string) error - List(ctx context.Context) ([]E, error) - - Watch(ctx context.Context) (Watch[E], error) -}