diff --git a/cmd/instance/main.go b/cmd/instance/main.go new file mode 100644 index 0000000..d205cea --- /dev/null +++ b/cmd/instance/main.go @@ -0,0 +1,70 @@ +package main + +import ( + barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" + "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/instance" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "os" + controllerruntime "sigs.k8s.io/controller-runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(barmancloudv1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + setupLog.Info("Starting barman cloud instance plugin") + namespace := os.Getenv("NAMESPACE") + boName := os.Getenv("BARMAN_OBJECT_NAME") + + mgr, err := controllerruntime.NewManager(controllerruntime.GetConfigOrDie(), controllerruntime.Options{ + Scheme: scheme, + Cache: cache.Options{ + ByObject: map[client.Object]cache.ByObject{ + &barmancloudv1.ObjectStore{}: { + Field: fields.OneTermEqualSelector("metadata.name", boName), + Namespaces: map[string]cache.Config{ + namespace: {}, + }, + }, + }, + }, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err := mgr.Add(&instance.CNPGI{ + Client: mgr.GetClient(), + BarmanObjectKey: client.ObjectKey{ + Namespace: namespace, + Name: boName, + }, + PGDataPath: os.Getenv("PGDATA"), + PGWALPath: os.Getenv("PGWAL"), + SpoolDirectory: os.Getenv("SPOOL_DIRECTORY"), + }); err != nil { + setupLog.Error(err, "unable to create CNPGI runnable") + os.Exit(1) + } + + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/cmd/main.go b/cmd/operator/main.go similarity index 100% rename from cmd/main.go rename to cmd/operator/main.go diff --git a/go.mod b/go.mod index b09114a..329ecf2 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,9 @@ go 1.22.0 require ( github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a github.com/cloudnative-pg/cnpg-i v0.0.0-20240902182059-c9f193bf825b - github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240923090729-e3d2e7d21fb2 + github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240926095718-27da985944d4 github.com/onsi/ginkgo/v2 v2.20.2 github.com/onsi/gomega v1.34.2 - github.com/spf13/cobra v1.8.1 google.golang.org/grpc v1.66.0 k8s.io/apimachinery v0.31.0 k8s.io/client-go v0.31.0 @@ -19,6 +18,7 @@ require ( github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -53,6 +53,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -70,10 +71,12 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/thoas/go-funk v0.9.3 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect diff --git a/go.sum b/go.sum index ec09ebf..10a75db 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -14,8 +16,8 @@ github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a h1:0v1 github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a/go.mod h1:Jm0tOp5oB7utpt8wz6RfSv31h1mThOtffjfyxVupriE= github.com/cloudnative-pg/cnpg-i v0.0.0-20240902182059-c9f193bf825b h1:DKMuZrvZJkaZ/rNswcA4q2YST5TRhKPlxFxL5wQXRRs= github.com/cloudnative-pg/cnpg-i v0.0.0-20240902182059-c9f193bf825b/go.mod h1:LhDyBxtoGsWNf0+YXj+uIhFlzHeY8N0QEkO6Kqv8yKY= -github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240923090729-e3d2e7d21fb2 h1:0BhW71N+kkvqV/7I6Df7/wvV7JRojt5A+XnR98cKgVM= -github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240923090729-e3d2e7d21fb2/go.mod h1:dV1+nE7jWENm/fcnKBeKsaScMz685rQPbPCCDydJgsY= +github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240926095718-27da985944d4 h1:ZZkI87sz/Bn6O6jaMB4BDpZihGSAk8HkwXB6+ECKlgA= +github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20240926095718-27da985944d4/go.mod h1:dV1+nE7jWENm/fcnKBeKsaScMz685rQPbPCCDydJgsY= github.com/cloudnative-pg/machinery v0.0.0-20240919131343-9dd62b9257c7 h1:glRSFwMeX1tb1wlN6ZxihPH3nMXL9ZlwU1/xvNFB0iE= github.com/cloudnative-pg/machinery v0.0.0-20240919131343-9dd62b9257c7/go.mod h1:bWp1Es5zlxElg4Z/c5f0RKOkDcyNvDHdYIvNcPQU4WM= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -96,6 +98,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -154,6 +158,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -162,6 +167,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= +github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -250,6 +257,7 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/cnpgi/instance/cmd.go b/internal/cnpgi/instance/cmd.go deleted file mode 100644 index a0b2b1c..0000000 --- a/internal/cnpgi/instance/cmd.go +++ /dev/null @@ -1,22 +0,0 @@ -package instance - -import ( - "github.com/spf13/cobra" - - "github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/http" - "github.com/cloudnative-pg/cnpg-i/pkg/backup" - "github.com/cloudnative-pg/cnpg-i/pkg/wal" - "google.golang.org/grpc" -) - -func NewCMD() *cobra.Command { - cmd := http.CreateMainCmd(IdentityImplementation{}, func(server *grpc.Server) error { - // Register the declared implementations - wal.RegisterWALServer(server, WALServiceImplementation{}) - backup.RegisterBackupServer(server, BackupServiceImplementation{}) - return nil - }) - - cmd.Use = "plugin-instance" - return cmd -} diff --git a/internal/cnpgi/instance/start.go b/internal/cnpgi/instance/start.go new file mode 100644 index 0000000..92459a0 --- /dev/null +++ b/internal/cnpgi/instance/start.go @@ -0,0 +1,45 @@ +package instance + +import ( + "context" + "github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/http" + "github.com/cloudnative-pg/cnpg-i/pkg/backup" + "github.com/cloudnative-pg/cnpg-i/pkg/wal" + "google.golang.org/grpc" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type CNPGI struct { + Client client.Client + BarmanObjectKey client.ObjectKey + PGDataPath string + PGWALPath string + SpoolDirectory string +} + +func (c *CNPGI) Start(ctx context.Context) error { + enrich := func(server *grpc.Server) error { + wal.RegisterWALServer(server, WALServiceImplementation{ + BarmanObjectKey: c.BarmanObjectKey, + Client: c.Client, + SpoolDirectory: c.SpoolDirectory, + PGDataPath: c.PGDataPath, + PGWALPath: c.PGWALPath, + }) + backup.RegisterBackupServer(server, BackupServiceImplementation{}) + return nil + } + + srv := http.Server{ + IdentityImpl: IdentityImplementation{}, + Enrichers: []http.ServerEnricher{enrich}, + // TODO: fille + ServerCertPath: "", + ServerKeyPath: "", + ClientCertPath: "", + ServerAddress: "", + PluginPath: "", + } + + return srv.Start(ctx) +} diff --git a/internal/cnpgi/instance/wal.go b/internal/cnpgi/instance/wal.go index ecc2301..7aee72b 100644 --- a/internal/cnpgi/instance/wal.go +++ b/internal/cnpgi/instance/wal.go @@ -2,15 +2,28 @@ package instance import ( "context" + "errors" + barmanCredentials "github.com/cloudnative-pg/barman-cloud/pkg/credentials" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "os" + barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/cloudnative-pg/barman-cloud/pkg/archiver" "github.com/cloudnative-pg/cnpg-i/pkg/wal" ) type WALServiceImplementation struct { + BarmanObjectKey client.ObjectKey + Client client.Client + SpoolDirectory string + PGDataPath string + PGWALPath string wal.UnimplementedWALServer } -func (W WALServiceImplementation) GetCapabilities(ctx context.Context, request *wal.WALCapabilitiesRequest) (*wal.WALCapabilitiesResult, error) { +func (w WALServiceImplementation) GetCapabilities(ctx context.Context, request *wal.WALCapabilitiesRequest) (*wal.WALCapabilitiesResult, error) { return &wal.WALCapabilitiesResult{ Capabilities: []*wal.WALCapability{ { @@ -31,22 +44,53 @@ func (W WALServiceImplementation) GetCapabilities(ctx context.Context, request * }, nil } -func (W WALServiceImplementation) Archive(ctx context.Context, request *wal.WALArchiveRequest) (*wal.WALArchiveResult, error) { +func (w WALServiceImplementation) Archive(ctx context.Context, request *wal.WALArchiveRequest) (*wal.WALArchiveResult, error) { + var objectStore barmancloudv1.ObjectStore + if err := w.Client.Get(ctx, w.BarmanObjectKey, &objectStore); err != nil { + return nil, err + } + + envArchive, err := barmanCredentials.EnvSetBackupCloudCredentials( + ctx, + w.Client, + objectStore.Namespace, + &objectStore.Spec.Configuration, + os.Environ()) + if apierrors.IsForbidden(err) { + return nil, errors.New("backup credentials don't yet have access permissions. Will retry reconciliation loop") + } + + arch, err := archiver.New(ctx, envArchive, w.SpoolDirectory, w.PGDataPath, w.PGWALPath) + if err != nil { + return nil, err + } + + options, err := arch.BarmanCloudWalArchiveOptions(ctx, &objectStore.Spec.Configuration, objectStore.Name) + if err != nil { + return nil, err + } + walList := arch.GatherWALFilesToArchive(ctx, request.GetSourceFileName(), 1) + result := arch.ArchiveList(ctx, walList, options) + for _, archiverResult := range result { + if archiverResult.Err != nil { + return nil, archiverResult.Err + } + } + + return &wal.WALArchiveResult{}, nil +} + +func (w WALServiceImplementation) Restore(ctx context.Context, request *wal.WALRestoreRequest) (*wal.WALRestoreResult, error) { // TODO implement me panic("implement me") } -func (W WALServiceImplementation) Restore(ctx context.Context, request *wal.WALRestoreRequest) (*wal.WALRestoreResult, error) { +func (w WALServiceImplementation) Status(ctx context.Context, request *wal.WALStatusRequest) (*wal.WALStatusResult, error) { // TODO implement me panic("implement me") } -func (W WALServiceImplementation) Status(ctx context.Context, request *wal.WALStatusRequest) (*wal.WALStatusResult, error) { - // TODO implement me - panic("implement me") -} - -func (W WALServiceImplementation) SetFirstRequired(ctx context.Context, request *wal.SetFirstRequiredRequest) (*wal.SetFirstRequiredResult, error) { +func (w WALServiceImplementation) SetFirstRequired(ctx context.Context, request *wal.SetFirstRequiredRequest) (*wal.SetFirstRequiredResult, error) { // TODO implement me panic("implement me") }