diff --git a/docs/examples/cluster-restore.yaml b/docs/examples/cluster-restore.yaml index 6f2ddb0..8b226ac 100644 --- a/docs/examples/cluster-restore.yaml +++ b/docs/examples/cluster-restore.yaml @@ -8,14 +8,15 @@ spec: bootstrap: recovery: - backup: - name: backup-example - usePlugin: true + source: source - plugins: - - name: barman-cloud.cloudnative-pg.io -# parameters: -# barmanObjectName: minio-store + externalClusters: + - name: source + plugin: + name: barman-cloud.cloudnative-pg.io + parameters: + barmanObjectName: minio-store + serverName: cluster-example storage: size: 1Gi diff --git a/go.mod b/go.mod index 3cd5e13..bdfc8b0 100644 --- a/go.mod +++ b/go.mod @@ -6,20 +6,20 @@ toolchain go1.23.1 require ( github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a - github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241017151552-20297270038b - github.com/cloudnative-pg/cnpg-i v0.0.0-20241021130537-c4a74d755f0a + github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241031170209-ad2b0d78a230 + github.com/cloudnative-pg/cnpg-i v0.0.0-20241030162745-80b6d07403c1 github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19 - github.com/cloudnative-pg/machinery v0.0.0-20241010122207-5ac7af31ef72 + github.com/cloudnative-pg/machinery v0.0.0-20241014090714-c27747f9974b github.com/onsi/ginkgo/v2 v2.20.2 github.com/onsi/gomega v1.34.2 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 google.golang.org/grpc v1.67.1 - k8s.io/api v0.31.1 - k8s.io/apimachinery v0.31.1 - k8s.io/client-go v0.31.1 + k8s.io/api v0.31.2 + k8s.io/apimachinery v0.31.2 + k8s.io/client-go v0.31.2 k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 - sigs.k8s.io/controller-runtime v0.19.0 + sigs.k8s.io/controller-runtime v0.19.1 ) require ( @@ -74,8 +74,8 @@ require ( github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.1 // indirect - github.com/prometheus/client_golang v1.20.4 // indirect + github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.2 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.59.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect @@ -102,13 +102,13 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect - golang.org/x/net v0.29.0 // indirect + golang.org/x/net v0.30.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/text v0.18.0 // indirect - golang.org/x/time v0.6.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.25.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect @@ -118,9 +118,9 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.31.1 // indirect - k8s.io/apiserver v0.31.1 // indirect - k8s.io/component-base v0.31.1 // indirect + k8s.io/apiextensions-apiserver v0.31.2 // indirect + k8s.io/apiserver v0.31.2 // indirect + k8s.io/component-base v0.31.2 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect diff --git a/go.sum b/go.sum index f837ca7..0d110f3 100644 --- a/go.sum +++ b/go.sum @@ -18,14 +18,14 @@ github.com/cloudnative-pg/api v0.0.0-20241004125129-98baa9f4957b h1:LZ9tIgKmWb8Z github.com/cloudnative-pg/api v0.0.0-20241004125129-98baa9f4957b/go.mod h1:mzd1EvoLYy16jJdne6/4nwhoj7t4IZ0MqJMEH4mla8Q= github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a h1:0v1ML9Eibfq3helbT9GtU0EstqFtG91k/MPO9azY5ME= github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a/go.mod h1:Jm0tOp5oB7utpt8wz6RfSv31h1mThOtffjfyxVupriE= -github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241017151552-20297270038b h1:47OKNQRgSs9XWvIt2bm8B1Yo7TA5oxBGjQPqF0j+Llw= -github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241017151552-20297270038b/go.mod h1:0grklCuA9WSA5lazBeTgDqLHjxP13fqAhqlveDx7hPg= -github.com/cloudnative-pg/cnpg-i v0.0.0-20241021130537-c4a74d755f0a h1:K4c+gX96NAt9C3AeffB8T4tvI3Qn9Fpi5x7Kzd+Iiyg= -github.com/cloudnative-pg/cnpg-i v0.0.0-20241021130537-c4a74d755f0a/go.mod h1:fAU7ySVzjpt/RZntxWZiWJCjaBJayzIxEnd0NuO7oQc= +github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241031170209-ad2b0d78a230 h1:zRqm1WUMOqkPWGyvtvCAdWlQ+WTtb0iQA/rvCar27/E= +github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241031170209-ad2b0d78a230/go.mod h1:La89zdElTqqZ5LXHFm/UjOwvS9iHSE8GuOW4fYUgHw8= +github.com/cloudnative-pg/cnpg-i v0.0.0-20241030162745-80b6d07403c1 h1:v3Vr+FH5BXmS7Eqx17u51oijZ4T7y62vUMCUAr7CffE= +github.com/cloudnative-pg/cnpg-i v0.0.0-20241030162745-80b6d07403c1/go.mod h1:fAU7ySVzjpt/RZntxWZiWJCjaBJayzIxEnd0NuO7oQc= github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19 h1:qy+LrScvQpIwt4qeg9FfCJuoC9CbX/kpFGLF8vSobXg= github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19/go.mod h1:X6r1fRuUEIAv4+5SSBY2RmQ201K6GcptOXgnmaX/8tY= -github.com/cloudnative-pg/machinery v0.0.0-20241010122207-5ac7af31ef72 h1:3pgtSYhv3RDd+51bnlqICNrcVpWQQvriCOvkxtbZpaE= -github.com/cloudnative-pg/machinery v0.0.0-20241010122207-5ac7af31ef72/go.mod h1:bWp1Es5zlxElg4Z/c5f0RKOkDcyNvDHdYIvNcPQU4WM= +github.com/cloudnative-pg/machinery v0.0.0-20241014090714-c27747f9974b h1:4Q2VQsPlLHliJdi87zodQ0FHLd1cJINMm4N70eu8rRg= +github.com/cloudnative-pg/machinery v0.0.0-20241014090714-c27747f9974b/go.mod h1:+mUFdys1IX+qwQUrV+/i56Tey/mYh8ZzWZYttwivRns= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -140,10 +140,10 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.1 h1:XGoEXT6WTTihO+MD8MAao+YaQIH905HbK0WK2lyo28k= -github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.1/go.mod h1:D0KY8md81DQKdaR/cXwnhoWB3MYYyc/UjvqE8GFkIvA= -github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= -github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.2 h1:F/MALZ518KfI1zEg+Kg8/uTzoXKDyqw+LNC/5irJlJE= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.2/go.mod h1:D0KY8md81DQKdaR/cXwnhoWB3MYYyc/UjvqE8GFkIvA= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= 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/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= @@ -228,8 +228,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn 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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -240,16 +240,16 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= 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.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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= @@ -286,18 +286,18 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= -k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= -k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= -k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= -k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= -k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.1 h1:Sars5ejQDCRBY5f7R3QFHdqN3s61nhkpaX8/k1iEw1c= -k8s.io/apiserver v0.31.1/go.mod h1:lzDhpeToamVZJmmFlaLwdYZwd7zB+WYRYIboqA1kGxM= -k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= -k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= -k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= -k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= +k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= +k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= +k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= 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-20240903163716-9e1beecbcb38 h1:1dWzkmJrrprYvjGwh9kEUxmcUV/CtNU8QM7h1FLWQOo= @@ -306,8 +306,8 @@ k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= +sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/internal/cmd/restore/main.go b/internal/cmd/restore/main.go index aa8f620..bc79b1e 100644 --- a/internal/cmd/restore/main.go +++ b/internal/cmd/restore/main.go @@ -36,8 +36,6 @@ func NewCmd() *cobra.Command { } _ = viper.BindEnv("namespace", "NAMESPACE") - _ = viper.BindEnv("backup-to-restore", "BACKUP_TO_RESTORE") - _ = viper.BindEnv("barman-archive-configuration", "BARMAN_OBJECT_NAME") _ = viper.BindEnv("cluster-name", "CLUSTER_NAME") _ = viper.BindEnv("pod-name", "POD_NAME") _ = viper.BindEnv("pgdata", "PGDATA") diff --git a/internal/cnpgi/common/backup.go b/internal/cnpgi/common/backup.go deleted file mode 100644 index 441ef2d..0000000 --- a/internal/cnpgi/common/backup.go +++ /dev/null @@ -1,21 +0,0 @@ -package common - -import ( - "encoding/json" - "fmt" - - barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api" - cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1" -) - -// GetCredentialsFromBackup extracts the Barman credentials from the backup -func GetCredentialsFromBackup(backup *cnpgv1.Backup) (barmanapi.BarmanCredentials, error) { - rawCred := backup.Status.PluginMetadata["credentials"] - - var creds barmanapi.BarmanCredentials - if err := json.Unmarshal([]byte(rawCred), &creds); err != nil { - return barmanapi.BarmanCredentials{}, fmt.Errorf("while unmarshaling credentials: %w", err) - } - - return creds, nil -} diff --git a/internal/cnpgi/common/common.go b/internal/cnpgi/common/common.go new file mode 100644 index 0000000..8d99482 --- /dev/null +++ b/internal/cnpgi/common/common.go @@ -0,0 +1,72 @@ +package common + +import ( + "fmt" + "strings" + + barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api" +) + +// TODO: refactor. +const ( + // ScratchDataDirectory is the directory to be used for scratch data. + ScratchDataDirectory = "/controller" + + // CertificatesDir location to store the certificates. + CertificatesDir = ScratchDataDirectory + "/certificates/" + + // BarmanBackupEndpointCACertificateLocation is the location where the barman endpoint + // CA certificate is stored. + BarmanBackupEndpointCACertificateLocation = CertificatesDir + BarmanBackupEndpointCACertificateFileName + + // BarmanBackupEndpointCACertificateFileName is the name of the file in which the barman endpoint + // CA certificate for backups is stored. + BarmanBackupEndpointCACertificateFileName = "backup-" + BarmanEndpointCACertificateFileName + + // BarmanRestoreEndpointCACertificateFileName is the name of the file in which the barman endpoint + // CA certificate for restores is stored. + BarmanRestoreEndpointCACertificateFileName = "restore-" + BarmanEndpointCACertificateFileName + + // BarmanEndpointCACertificateFileName is the name of the file in which the barman endpoint + // CA certificate is stored. + BarmanEndpointCACertificateFileName = "barman-ca.crt" +) + +// GetRestoreCABundleEnv gets the enveronment variables to be used when custom +// Object Store CA is present +func GetRestoreCABundleEnv(configuration *barmanapi.BarmanObjectStoreConfiguration) []string { + var env []string + + if configuration.EndpointCA != nil && configuration.BarmanCredentials.AWS != nil { + env = append(env, fmt.Sprintf("AWS_CA_BUNDLE=%s", BarmanBackupEndpointCACertificateLocation)) + } else if configuration.EndpointCA != nil && configuration.BarmanCredentials.Azure != nil { + env = append(env, fmt.Sprintf("REQUESTS_CA_BUNDLE=%s", BarmanBackupEndpointCACertificateLocation)) + } + return env +} + +// MergeEnv merges all the values inside incomingEnv into env. +func MergeEnv(env []string, incomingEnv []string) []string { + result := make([]string, len(env), len(env)+len(incomingEnv)) + copy(result, env) + + for _, incomingItem := range incomingEnv { + incomingKV := strings.SplitAfterN(incomingItem, "=", 2) + if len(incomingKV) != 2 { + continue + } + + found := false + for idx, item := range result { + if strings.HasPrefix(item, incomingKV[0]) { + result[idx] = incomingItem + found = true + } + } + if !found { + result = append(result, incomingItem) + } + } + + return result +} diff --git a/internal/cnpgi/instance/backup.go b/internal/cnpgi/instance/backup.go index 753238c..9ebe96a 100644 --- a/internal/cnpgi/instance/backup.go +++ b/internal/cnpgi/instance/backup.go @@ -2,7 +2,6 @@ package instance import ( "context" - "encoding/json" "fmt" "os" "strconv" @@ -11,6 +10,7 @@ import ( barmanBackup "github.com/cloudnative-pg/barman-cloud/pkg/backup" barmanCapabilities "github.com/cloudnative-pg/barman-cloud/pkg/capabilities" barmanCredentials "github.com/cloudnative-pg/barman-cloud/pkg/credentials" + cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1" "github.com/cloudnative-pg/cloudnative-pg/pkg/postgres" "github.com/cloudnative-pg/cnpg-i/pkg/backup" "github.com/cloudnative-pg/machinery/pkg/fileutils" @@ -20,6 +20,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" + "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/common" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata" ) @@ -69,6 +70,11 @@ func (b BackupServiceImplementation) Backup( contextLogger.Info("Starting backup") + var cluster cnpgv1.Cluster + if err := b.Client.Get(ctx, b.ClusterObjectKey, &cluster); err != nil { + return nil, err + } + var objectStore barmancloudv1.ObjectStore if err := b.Client.Get(ctx, b.BarmanObjectKey, &objectStore); err != nil { contextLogger.Error(err, "while getting object store", "key", b.BarmanObjectKey) @@ -93,24 +99,33 @@ func (b BackupServiceImplementation) Backup( // We need to connect to PostgreSQL and to do that we need // PGHOST (and the like) to be available osEnvironment := os.Environ() - caBundleEnvironment := getRestoreCABundleEnv(&objectStore.Spec.Configuration) + caBundleEnvironment := common.GetRestoreCABundleEnv(&objectStore.Spec.Configuration) env, err := barmanCredentials.EnvSetBackupCloudCredentials( ctx, b.Client, objectStore.Namespace, &objectStore.Spec.Configuration, - mergeEnv(osEnvironment, caBundleEnvironment)) + common.MergeEnv(osEnvironment, caBundleEnvironment)) if err != nil { contextLogger.Error(err, "while setting backup cloud credentials") return nil, err } + serverName := cluster.Name + for _, plugin := range cluster.Spec.Plugins { + if plugin.IsEnabled() && plugin.Name == metadata.PluginName { + if pluginServerName, ok := plugin.Parameters["serverName"]; ok { + serverName = pluginServerName + } + } + } + backupName := fmt.Sprintf("backup-%v", pgTime.ToCompactISO8601(time.Now())) if err = backupCmd.Take( ctx, backupName, - objectStore.Name, + serverName, env, barmanCloudExecutor{}, postgres.BackupTemporaryDirectory, @@ -122,7 +137,7 @@ func (b BackupServiceImplementation) Backup( executedBackupInfo, err := backupCmd.GetExecutedBackupInfo( ctx, backupName, - objectStore.Name, + serverName, barmanCloudExecutor{}, env) if err != nil { @@ -130,25 +145,6 @@ func (b BackupServiceImplementation) Backup( return nil, err } - cred, err := json.Marshal(objectStore.Spec.Configuration.BarmanCredentials) - if err != nil { - contextLogger.Error(err, "while marshalling credentials") - return nil, err - } - - var endpointCA *backup.KeyName - if objectStore.Spec.Configuration.EndpointCA != nil { - endpointCA = &backup.KeyName{ - Name: objectStore.Spec.Configuration.EndpointCA.Name, - Key: objectStore.Spec.Configuration.EndpointCA.Key, - } - } - - var encryption string - if objectStore.Spec.Configuration.Data != nil { - encryption = string(objectStore.Spec.Configuration.Data.Encryption) - } - contextLogger.Info("Backup completed", "backup", executedBackupInfo.ID) return &backup.BackupResult{ BackupId: executedBackupInfo.ID, @@ -166,13 +162,6 @@ func (b BackupServiceImplementation) Backup( "version": metadata.Data.Version, "name": metadata.Data.Name, "displayName": metadata.Data.DisplayName, - // TODO: is it safe? - "credentials": string(cred), }, - ServerName: objectStore.Name, - EndpointUrl: objectStore.Spec.Configuration.EndpointURL, - DestinationPath: objectStore.Spec.Configuration.DestinationPath, - EndpointCa: endpointCA, - Encryption: encryption, }, nil } diff --git a/internal/cnpgi/instance/wal.go b/internal/cnpgi/instance/wal.go index bc0905b..6d850d2 100644 --- a/internal/cnpgi/instance/wal.go +++ b/internal/cnpgi/instance/wal.go @@ -6,10 +6,8 @@ import ( "fmt" "os" "path" - "strings" "time" - barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api" "github.com/cloudnative-pg/barman-cloud/pkg/archiver" barmanCommand "github.com/cloudnative-pg/barman-cloud/pkg/command" barmanCredentials "github.com/cloudnative-pg/barman-cloud/pkg/credentials" @@ -21,6 +19,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" + "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/common" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata" ) @@ -66,6 +65,21 @@ func (w WALServiceImplementation) Archive( ctx context.Context, request *wal.WALArchiveRequest, ) (*wal.WALArchiveResult, error) { + var cluster cnpgv1.Cluster + if err := w.Client.Get(ctx, w.ClusterObjectKey, &cluster); err != nil { + return nil, err + } + + // TODO: refactor this code elsewhere + serverName := cluster.Name + for _, plugin := range cluster.Spec.Plugins { + if plugin.IsEnabled() && plugin.Name == metadata.PluginName { + if pluginServerName, ok := plugin.Parameters["serverName"]; ok { + serverName = pluginServerName + } + } + } + var objectStore barmancloudv1.ObjectStore if err := w.Client.Get(ctx, w.BarmanObjectKey, &objectStore); err != nil { return nil, err @@ -95,7 +109,7 @@ func (w WALServiceImplementation) Archive( return nil, err } - options, err := arch.BarmanCloudWalArchiveOptions(ctx, &objectStore.Spec.Configuration, objectStore.Name) + options, err := arch.BarmanCloudWalArchiveOptions(ctx, &objectStore.Spec.Configuration, serverName) if err != nil { return nil, err } @@ -111,6 +125,7 @@ func (w WALServiceImplementation) Archive( } // Restore implements the WALService interface +// nolint: gocognit func (w WALServiceImplementation) Restore( ctx context.Context, request *wal.WALRestoreRequest, @@ -134,7 +149,7 @@ func (w WALServiceImplementation) Restore( barmanConfiguration := &objectStore.Spec.Configuration - env := getRestoreCABundleEnv(barmanConfiguration) + env := common.GetRestoreCABundleEnv(barmanConfiguration) credentialsEnv, err := barmanCredentials.EnvSetBackupCloudCredentials( ctx, w.Client, @@ -145,9 +160,19 @@ func (w WALServiceImplementation) Restore( if err != nil { return nil, fmt.Errorf("while getting recover credentials: %w", err) } - env = mergeEnv(env, credentialsEnv) + env = common.MergeEnv(env, credentialsEnv) - options, err := barmanCommand.CloudWalRestoreOptions(ctx, barmanConfiguration, objectStore.Name) + // TODO: refactor this code elsewhere + serverName := cluster.Name + for _, plugin := range cluster.Spec.Plugins { + if plugin.IsEnabled() && plugin.Name == metadata.PluginName { + if pluginServerName, ok := plugin.Parameters["serverName"]; ok { + serverName = pluginServerName + } + } + } + + options, err := barmanCommand.CloudWalRestoreOptions(ctx, barmanConfiguration, serverName) if err != nil { return nil, fmt.Errorf("while getting barman-cloud-wal-restore options: %w", err) } @@ -254,68 +279,6 @@ func (w WALServiceImplementation) SetFirstRequired( panic("implement me") } -// mergeEnv merges all the values inside incomingEnv into env. -func mergeEnv(env []string, incomingEnv []string) []string { - result := make([]string, len(env), len(env)+len(incomingEnv)) - copy(result, env) - - for _, incomingItem := range incomingEnv { - incomingKV := strings.SplitAfterN(incomingItem, "=", 2) - if len(incomingKV) != 2 { - continue - } - - found := false - for idx, item := range result { - if strings.HasPrefix(item, incomingKV[0]) { - result[idx] = incomingItem - found = true - } - } - if !found { - result = append(result, incomingItem) - } - } - - return result -} - -// TODO: refactor. -const ( - // ScratchDataDirectory is the directory to be used for scratch data. - ScratchDataDirectory = "/controller" - - // CertificatesDir location to store the certificates. - CertificatesDir = ScratchDataDirectory + "/certificates/" - - // BarmanBackupEndpointCACertificateLocation is the location where the barman endpoint - // CA certificate is stored. - BarmanBackupEndpointCACertificateLocation = CertificatesDir + BarmanBackupEndpointCACertificateFileName - - // BarmanBackupEndpointCACertificateFileName is the name of the file in which the barman endpoint - // CA certificate for backups is stored. - BarmanBackupEndpointCACertificateFileName = "backup-" + BarmanEndpointCACertificateFileName - - // BarmanRestoreEndpointCACertificateFileName is the name of the file in which the barman endpoint - // CA certificate for restores is stored. - BarmanRestoreEndpointCACertificateFileName = "restore-" + BarmanEndpointCACertificateFileName - - // BarmanEndpointCACertificateFileName is the name of the file in which the barman endpoint - // CA certificate is stored. - BarmanEndpointCACertificateFileName = "barman-ca.crt" -) - -func getRestoreCABundleEnv(configuration *barmanapi.BarmanObjectStoreConfiguration) []string { - var env []string - - if configuration.EndpointCA != nil && configuration.BarmanCredentials.AWS != nil { - env = append(env, fmt.Sprintf("AWS_CA_BUNDLE=%s", BarmanBackupEndpointCACertificateLocation)) - } else if configuration.EndpointCA != nil && configuration.BarmanCredentials.Azure != nil { - env = append(env, fmt.Sprintf("REQUESTS_CA_BUNDLE=%s", BarmanBackupEndpointCACertificateLocation)) - } - return env -} - // isStreamingAvailable checks if this pod can replicate via streaming connection. func isStreamingAvailable(cluster *cnpgv1.Cluster, podName string) bool { if cluster == nil { diff --git a/internal/cnpgi/operator/lifecycle.go b/internal/cnpgi/operator/lifecycle.go index 3406df6..3e1d236 100644 --- a/internal/cnpgi/operator/lifecycle.go +++ b/internal/cnpgi/operator/lifecycle.go @@ -16,6 +16,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" + "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config" ) @@ -103,13 +104,11 @@ func reconcileJob( pluginConfiguration *config.PluginConfiguration, ) (*lifecycle.OperatorLifecycleResponse, error) { contextLogger := log.FromContext(ctx).WithName("lifecycle") - if !cluster.UsePluginForBootstrapRecoveryBackup() { - contextLogger.Debug("cluster does not use the plugin for recovery, skipping") + if pluginConfig := cluster.GetRecoverySourcePlugin(); pluginConfig == nil || pluginConfig.Name != metadata.PluginName { + contextLogger.Debug("cluster does not use the this plugin for recovery, skipping") return nil, nil } - backupSource := cluster.Spec.Bootstrap.Recovery.Backup - var job batchv1.Job if err := decoder.DecodeObject( request.GetObjectDefinition(), @@ -138,12 +137,6 @@ func reconcileJob( "full-recovery", corev1.Container{ Args: []string{"restore"}, - Env: []corev1.EnvVar{ - { - Name: "BACKUP_TO_RESTORE", - Value: backupSource.Name, - }, - }, }, ); err != nil { return nil, fmt.Errorf("while reconciling pod spec for job: %w", err) @@ -231,9 +224,6 @@ func reconcilePodSpec( sidecarConfig.Name = "plugin-barman-cloud" sidecarConfig.Image = viper.GetString("sidecar-image") sidecarConfig.ImagePullPolicy = cluster.Spec.ImagePullPolicy - sidecarConfig.Command = []string{ - "/manager", - } // merge the main container envs if they aren't already set for _, container := range spec.Containers { diff --git a/internal/cnpgi/operator/lifecycle_test.go b/internal/cnpgi/operator/lifecycle_test.go index d012271..2b59e40 100644 --- a/internal/cnpgi/operator/lifecycle_test.go +++ b/internal/cnpgi/operator/lifecycle_test.go @@ -9,7 +9,6 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/ptr" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config" @@ -34,17 +33,31 @@ var _ = Describe("LifecycleImplementation", func() { BeforeEach(func() { pluginConfiguration = &config.PluginConfiguration{ - BarmanObjectName: "barman-object", + BarmanObjectName: "minio-store-dest", } cluster = &cnpgv1.Cluster{ Spec: cnpgv1.ClusterSpec{ Bootstrap: &cnpgv1.BootstrapConfiguration{ Recovery: &cnpgv1.BootstrapRecovery{ - Backup: &cnpgv1.BackupSource{ - LocalObjectReference: cnpgv1.LocalObjectReference{ - Name: "backup-object", + Source: "origin-server", + }, + }, + ExternalClusters: []cnpgv1.ExternalCluster{ + { + Name: "origin-server", + PluginConfiguration: &cnpgv1.PluginConfiguration{ + Name: "barman-cloud.cloudnative-pg.io", + Parameters: map[string]string{ + "barmanObjectName": "minio-store-source", }, - UsePlugin: ptr.To(true), + }, + }, + }, + Plugins: cnpgv1.PluginConfigurationList{ + { + Name: "barman-cloud.cloudnative-pg.io", + Parameters: map[string]string{ + "barmanObjectName": "minio-store-dest", }, }, }, @@ -180,8 +193,9 @@ var _ = Describe("LifecycleImplementation", func() { err = json.Unmarshal(response.JsonPatch, &patch) Expect(err).NotTo(HaveOccurred()) Expect(patch).To(ContainElement(HaveKeyWithValue("op", "add"))) - Expect(patch).To(ContainElement(HaveKeyWithValue("path", "/spec/containers/1"))) - Expect(patch).To(ContainElement(HaveKeyWithValue("value", HaveKeyWithValue("name", "plugin-barman-cloud")))) + Expect(patch).To(ContainElement(HaveKeyWithValue("path", "/spec/initContainers"))) + Expect(patch).To(ContainElement( + HaveKey("value"))) }) It("returns an error for invalid pod definition", func(ctx SpecContext) { diff --git a/internal/cnpgi/operator/reconciler.go b/internal/cnpgi/operator/reconciler.go index c47fc29..ee66415 100644 --- a/internal/cnpgi/operator/reconciler.go +++ b/internal/cnpgi/operator/reconciler.go @@ -15,7 +15,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" - "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/common" + "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs" ) @@ -75,14 +75,16 @@ func (r ReconcilerImplementation) Pre( pluginConfiguration := config.NewFromCluster(&cluster) contextLogger.Debug("parsing barman object configuration") - var barmanObject *barmancloudv1.ObjectStore + + var barmanObjects []barmancloudv1.ObjectStore + // this could be empty during recoveries if pluginConfiguration.BarmanObjectName != "" { - barmanObject = &barmancloudv1.ObjectStore{} + var barmanObject barmancloudv1.ObjectStore if err := r.Client.Get(ctx, client.ObjectKey{ Namespace: cluster.Namespace, Name: pluginConfiguration.BarmanObjectName, - }, barmanObject); err != nil { + }, &barmanObject); err != nil { if apierrs.IsNotFound(err) { contextLogger.Info("barman object configuration not found, requeuing") return &reconciler.ReconcilerHooksResult{ @@ -92,28 +94,23 @@ func (r ReconcilerImplementation) Pre( return nil, err } + + barmanObjects = append(barmanObjects, barmanObject) + } + + if barmanObject, err := r.getRecoveryBarmanObject(ctx, &cluster); err != nil { + if apierrs.IsNotFound(err) { + contextLogger.Info("barman recovery object configuration not found, requeuing") + return &reconciler.ReconcilerHooksResult{ + Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_REQUEUE, + }, nil + } + } else if barmanObject != nil { + barmanObjects = append(barmanObjects, *barmanObject) } var additionalSecretNames []string - if cluster.UsePluginForBootstrapRecoveryBackup() { - var backup cnpgv1.Backup - if err := r.Client.Get(ctx, client.ObjectKey{ - Namespace: cluster.Namespace, - Name: cluster.Spec.Bootstrap.Recovery.Backup.Name, - }, &backup); err != nil { - return nil, err - } - credentials, err := common.GetCredentialsFromBackup(&backup) - if err != nil { - return nil, err - } - additionalSecretNames = append(additionalSecretNames, specs.CollectSecretNamesFromCredentials(&credentials)...) - - if backup.Status.EndpointCA != nil { - additionalSecretNames = append(additionalSecretNames, backup.Status.EndpointCA.Name) - } - } - if err := r.ensureRole(ctx, &cluster, barmanObject, additionalSecretNames); err != nil { + if err := r.ensureRole(ctx, &cluster, barmanObjects, additionalSecretNames); err != nil { return nil, err } @@ -127,6 +124,30 @@ func (r ReconcilerImplementation) Pre( }, nil } +func (r ReconcilerImplementation) getRecoveryBarmanObject( + ctx context.Context, + cluster *cnpgv1.Cluster, +) (*barmancloudv1.ObjectStore, error) { + recoveryConfig := cluster.GetRecoverySourcePlugin() + if recoveryConfig != nil && recoveryConfig.Name == metadata.PluginName { + // TODO: refactor -> cnpg-i-machinery should be able to help us on getting + // the configuration for a recovery plugin + if recoveryObjectStore, ok := recoveryConfig.Parameters["barmanObjectName"]; ok { + var barmanObject barmancloudv1.ObjectStore + if err := r.Client.Get(ctx, client.ObjectKey{ + Namespace: cluster.Namespace, + Name: recoveryObjectStore, + }, &barmanObject); err != nil { + return nil, err + } + + return &barmanObject, nil + } + } + + return nil, nil +} + // Post implements the reconciler interface func (r ReconcilerImplementation) Post( _ context.Context, @@ -140,11 +161,11 @@ func (r ReconcilerImplementation) Post( func (r ReconcilerImplementation) ensureRole( ctx context.Context, cluster *cnpgv1.Cluster, - barmanObject *barmancloudv1.ObjectStore, + barmanObjects []barmancloudv1.ObjectStore, additionalSecretNames []string, ) error { contextLogger := log.FromContext(ctx) - newRole := specs.BuildRole(cluster, barmanObject, additionalSecretNames) + newRole := specs.BuildRole(cluster, barmanObjects, additionalSecretNames) var role rbacv1.Role if err := r.Client.Get(ctx, client.ObjectKey{ diff --git a/internal/cnpgi/operator/specs/role.go b/internal/cnpgi/operator/specs/role.go index 12ef1ef..2fe521a 100644 --- a/internal/cnpgi/operator/specs/role.go +++ b/internal/cnpgi/operator/specs/role.go @@ -14,7 +14,7 @@ import ( // BuildRole builds the Role object for this cluster func BuildRole( cluster *cnpgv1.Cluster, - barmanObject *barmancloudv1.ObjectStore, + barmanObjects []barmancloudv1.ObjectStore, additionalSecretNames []string, ) *rbacv1.Role { role := &rbacv1.Role{ @@ -27,8 +27,7 @@ func BuildRole( } secretsSet := stringset.New() - // TODO: we should handle removals too? - if barmanObject != nil { + for _, barmanObject := range barmanObjects { role.Rules = append(role.Rules, rbacv1.PolicyRule{ APIGroups: []string{ "barmancloud.cnpg.io", diff --git a/internal/cnpgi/restore/manager.go b/internal/cnpgi/restore/manager.go index 0de7b1c..9bd79c4 100644 --- a/internal/cnpgi/restore/manager.go +++ b/internal/cnpgi/restore/manager.go @@ -32,9 +32,7 @@ func Start(ctx context.Context) error { setupLog := log.FromContext(ctx) setupLog.Info("Starting barman cloud instance plugin") namespace := viper.GetString("namespace") - archiveConfiguration := viper.GetString("barman-archive-configuration") clusterName := viper.GetString("cluster-name") - backupToRestoreName := viper.GetString("backup-to-restore") objs := map[client.Object]cache.ByObject{ &cnpgv1.Cluster{}: { @@ -43,20 +41,6 @@ func Start(ctx context.Context) error { namespace: {}, }, }, - &cnpgv1.Backup{}: { - Field: fields.OneTermEqualSelector("metadata.name", backupToRestoreName), - Namespaces: map[string]cache.Config{ - namespace: {}, - }, - }, - } - if archiveConfiguration != "" { - objs[&barmancloudv1.ObjectStore{}] = cache.ByObject{ - Field: fields.OneTermEqualSelector("metadata.name", archiveConfiguration), - Namespaces: map[string]cache.Config{ - namespace: {}, - }, - } } mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ @@ -68,6 +52,7 @@ func Start(ctx context.Context) error { Cache: &client.CacheOptions{ DisableFor: []client.Object{ &corev1.Secret{}, + &barmancloudv1.ObjectStore{}, }, }, }, @@ -80,18 +65,10 @@ func Start(ctx context.Context) error { if err := mgr.Add(&CNPGI{ PluginPath: viper.GetString("plugin-path"), SpoolDirectory: viper.GetString("spool-directory"), - ArchiveConfiguration: client.ObjectKey{ - Namespace: namespace, - Name: archiveConfiguration, - }, ClusterObjectKey: client.ObjectKey{ Namespace: namespace, Name: clusterName, }, - BackupToRestoreObjectKey: client.ObjectKey{ - Namespace: namespace, - Name: backupToRestoreName, - }, Client: mgr.GetClient(), PGDataPath: viper.GetString("pgdata"), }); err != nil { diff --git a/internal/cnpgi/restore/restore.go b/internal/cnpgi/restore/restore.go index 5cd6f99..9029156 100644 --- a/internal/cnpgi/restore/restore.go +++ b/internal/cnpgi/restore/restore.go @@ -12,6 +12,7 @@ import ( "github.com/cloudnative-pg/barman-cloud/pkg/api" barmanArchiver "github.com/cloudnative-pg/barman-cloud/pkg/archiver" barmanCapabilities "github.com/cloudnative-pg/barman-cloud/pkg/capabilities" + barmanCatalog "github.com/cloudnative-pg/barman-cloud/pkg/catalog" barmanCommand "github.com/cloudnative-pg/barman-cloud/pkg/command" barmanCredentials "github.com/cloudnative-pg/barman-cloud/pkg/credentials" barmanRestorer "github.com/cloudnative-pg/barman-cloud/pkg/restorer" @@ -22,10 +23,11 @@ import ( "github.com/cloudnative-pg/machinery/pkg/execlog" "github.com/cloudnative-pg/machinery/pkg/fileutils" "github.com/cloudnative-pg/machinery/pkg/log" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" - "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/common" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata" ) @@ -44,7 +46,6 @@ type JobHookImpl struct { Client client.Client ClusterObjectKey client.ObjectKey BackupToRestore client.ObjectKey - ArchiveConfiguration client.ObjectKey SpoolDirectory string PgDataPath string PgWalFolderToSymlink string @@ -78,32 +79,70 @@ func (impl JobHookImpl) Restore( ); err != nil { return nil, err } - // Before starting the restore we check if the archive destination is safe to use - // otherwise, we stop creating the cluster - if err := impl.checkBackupDestination(ctx, &cluster); err != nil { + + recoveryPluginConfiguration := cluster.GetRecoverySourcePlugin() + + var recoveryObjectStore barmancloudv1.ObjectStore + if err := impl.Client.Get(ctx, types.NamespacedName{ + Namespace: cluster.Namespace, + // TODO: refactor -> cnpg-i-machinery should be able to help us on getting + // the configuration for a recovery plugin + Name: recoveryPluginConfiguration.Parameters["barmanObjectName"], + }, &recoveryObjectStore); err != nil { return nil, err } - var backup cnpgv1.Backup - - if err := decoder.DecodeObject( - req.GetBackupDefinition(), - &backup, - cnpgv1.GroupVersion.WithKind("Backup"), - ); err != nil { - return nil, err + var targetObjectStoreName types.NamespacedName + for _, plugin := range cluster.Spec.Plugins { + if plugin.IsEnabled() && plugin.Name == metadata.PluginName { + targetObjectStoreName = types.NamespacedName{ + Namespace: cluster.Namespace, + Name: plugin.Parameters["barmanObjectName"], + } + } } - env, err := impl.getBarmanEnvFromBackup(ctx, &backup) + var targetObjectStore barmancloudv1.ObjectStore + if targetObjectStoreName.Name != "" { + if err := impl.Client.Get(ctx, targetObjectStoreName, &targetObjectStore); err != nil { + return nil, err + } + } + + // Before starting the restore we check if the archive destination is safe to use, + // otherwise we stop creating the cluster + if targetObjectStoreName.Name != "" { + if err := impl.checkBackupDestination(ctx, &cluster, &targetObjectStore.Spec.Configuration); err != nil { + return nil, err + } + } + + // Detect the backup to recover + backup, env, err := loadBackupObjectFromExternalCluster( + ctx, + impl.Client, + &cluster, + &recoveryObjectStore.Spec.Configuration, + ) if err != nil { return nil, err } - if err := impl.ensureArchiveContainsLastCheckpointRedoWAL(ctx, &cluster, env, &backup); err != nil { + if err := impl.ensureArchiveContainsLastCheckpointRedoWAL( + ctx, + env, + backup, + &recoveryObjectStore.Spec.Configuration, + ); err != nil { return nil, err } - if err := impl.restoreDataDir(ctx, &backup, env); err != nil { + if err := impl.restoreDataDir( + ctx, + backup, + env, + &recoveryObjectStore.Spec.Configuration, + ); err != nil { return nil, err } @@ -113,7 +152,7 @@ func (impl JobHookImpl) Restore( } } - config, err := getRestoreWalConfig(ctx, &backup) + config, err := getRestoreWalConfig(ctx, backup, &recoveryObjectStore.Spec.Configuration) if err != nil { return nil, err } @@ -126,7 +165,12 @@ func (impl JobHookImpl) Restore( } // restoreDataDir restores PGDATA from an existing backup -func (impl JobHookImpl) restoreDataDir(ctx context.Context, backup *cnpgv1.Backup, env []string) error { +func (impl JobHookImpl) restoreDataDir( + ctx context.Context, + backup *cnpgv1.Backup, + env []string, + barmanConfiguration *cnpgv1.BarmanObjectStoreConfiguration, +) error { var options []string if backup.Status.EndpointURL != "" { @@ -136,11 +180,7 @@ func (impl JobHookImpl) restoreDataDir(ctx context.Context, backup *cnpgv1.Backu options = append(options, backup.Status.ServerName) options = append(options, backup.Status.BackupID) - creds, err := common.GetCredentialsFromBackup(backup) - if err != nil { - return err - } - options, err = barmanCommand.AppendCloudProviderOptionsFromBackup(ctx, options, creds) + options, err := barmanCommand.AppendCloudProviderOptionsFromConfiguration(ctx, options, barmanConfiguration) if err != nil { return err } @@ -168,9 +208,9 @@ func (impl JobHookImpl) restoreDataDir(ctx context.Context, backup *cnpgv1.Backu func (impl JobHookImpl) ensureArchiveContainsLastCheckpointRedoWAL( ctx context.Context, - cluster *cnpgv1.Cluster, env []string, backup *cnpgv1.Backup, + barmanConfiguration *cnpgv1.BarmanObjectStoreConfiguration, ) error { // it's the full path of the file that will temporarily contain the LastCheckpointRedoWAL const testWALPath = RecoveryTemporaryDirectory + "/test.wal" @@ -191,17 +231,7 @@ func (impl JobHookImpl) ensureArchiveContainsLastCheckpointRedoWAL( return err } - creds, err := common.GetCredentialsFromBackup(backup) - if err != nil { - return err - } - opts, err := barmanCommand.CloudWalRestoreOptions(ctx, &api.BarmanObjectStoreConfiguration{ - BarmanCredentials: creds, - EndpointCA: backup.Status.EndpointCA, - EndpointURL: backup.Status.EndpointURL, - DestinationPath: backup.Status.DestinationPath, - ServerName: backup.Status.ServerName, - }, cluster.Name) + opts, err := barmanCommand.CloudWalRestoreOptions(ctx, barmanConfiguration, backup.Status.ServerName) if err != nil { return err } @@ -216,21 +246,13 @@ func (impl JobHookImpl) ensureArchiveContainsLastCheckpointRedoWAL( func (impl *JobHookImpl) checkBackupDestination( ctx context.Context, cluster *cnpgv1.Cluster, + barmanConfiguration *cnpgv1.BarmanObjectStoreConfiguration, ) error { - if impl.ArchiveConfiguration.Name == "" { - return nil - } - - var barmanObj barmancloudv1.ObjectStore - if err := impl.Client.Get(ctx, impl.ArchiveConfiguration, &barmanObj); err != nil { - return err - } - // Get environment from cache env, err := barmanCredentials.EnvSetRestoreCloudCredentials(ctx, impl.Client, - barmanObj.Namespace, - &barmanObj.Spec.Configuration, + cluster.Namespace, + barmanConfiguration, os.Environ()) if err != nil { return fmt.Errorf("can't get credentials for cluster %v: %w", cluster.Name, err) @@ -251,9 +273,19 @@ func (impl *JobHookImpl) checkBackupDestination( return fmt.Errorf("while creating the archiver: %w", err) } + // TODO: refactor this code elsewhere + serverName := cluster.Name + for _, plugin := range cluster.Spec.Plugins { + if plugin.IsEnabled() && plugin.Name == metadata.PluginName { + if pluginServerName, ok := plugin.Parameters["serverName"]; ok { + serverName = pluginServerName + } + } + } + // Get WAL archive options checkWalOptions, err := walArchiver.BarmanCloudCheckWalArchiveOptions( - ctx, &barmanObj.Spec.Configuration, barmanObj.Name) + ctx, barmanConfiguration, serverName) if err != nil { log.Error(err, "while getting barman-cloud-wal-archive options") return err @@ -267,34 +299,6 @@ func (impl *JobHookImpl) checkBackupDestination( return nil } -func (impl JobHookImpl) getBarmanEnvFromBackup( - ctx context.Context, - backup *cnpgv1.Backup, -) ([]string, error) { - creds, err := common.GetCredentialsFromBackup(backup) - if err != nil { - return nil, err - } - env, err := barmanCredentials.EnvSetRestoreCloudCredentials( - ctx, - impl.Client, - impl.BackupToRestore.Namespace, - &api.BarmanObjectStoreConfiguration{ - BarmanCredentials: creds, - EndpointURL: backup.Status.EndpointURL, - EndpointCA: backup.Status.EndpointCA, - DestinationPath: backup.Status.DestinationPath, - ServerName: backup.Status.ServerName, - }, - os.Environ()) - if err != nil { - return nil, err - } - - log.Info("Recovering existing backup", "backup", backup) - return env, nil -} - // restoreCustomWalDir moves the current pg_wal data to the specified custom wal dir and applies the symlink // returns indicating if any changes were made and any error encountered in the process func (impl JobHookImpl) restoreCustomWalDir(ctx context.Context) (bool, error) { @@ -332,7 +336,11 @@ func (impl JobHookImpl) restoreCustomWalDir(ctx context.Context) (bool, error) { // getRestoreWalConfig obtains the content to append to `custom.conf` allowing PostgreSQL // to complete the WAL recovery from the object storage and then start // as a new primary -func getRestoreWalConfig(ctx context.Context, backup *cnpgv1.Backup) (string, error) { +func getRestoreWalConfig( + ctx context.Context, + backup *cnpgv1.Backup, + barmanConfiguration *cnpgv1.BarmanObjectStoreConfiguration, +) (string, error) { var err error cmd := []string{barmanCapabilities.BarmanCloudWalRestore} @@ -342,12 +350,7 @@ func getRestoreWalConfig(ctx context.Context, backup *cnpgv1.Backup) (string, er cmd = append(cmd, backup.Status.DestinationPath) cmd = append(cmd, backup.Status.ServerName) - creds, err := common.GetCredentialsFromBackup(backup) - if err != nil { - return "", err - } - - cmd, err = barmanCommand.AppendCloudProviderOptionsFromBackup(ctx, cmd, creds) + cmd, err = barmanCommand.AppendCloudProviderOptionsFromConfiguration(ctx, cmd, barmanConfiguration) if err != nil { return "", err } @@ -361,3 +364,96 @@ func getRestoreWalConfig(ctx context.Context, backup *cnpgv1.Backup) (string, er return recoveryFileContents, nil } + +// loadBackupObjectFromExternalCluster generates an in-memory Backup structure given a reference to +// an external cluster, loading the required information from the object store +func loadBackupObjectFromExternalCluster( + ctx context.Context, + typedClient client.Client, + cluster *cnpgv1.Cluster, + recoveryObjectStore *api.BarmanObjectStoreConfiguration, +) (*cnpgv1.Backup, []string, error) { + contextLogger := log.FromContext(ctx) + sourceName := cluster.Spec.Bootstrap.Recovery.Source + + if sourceName == "" { + return nil, nil, fmt.Errorf("recovery source not specified") + } + + server, found := cluster.ExternalCluster(sourceName) + if !found { + return nil, nil, fmt.Errorf("missing external cluster: %v", sourceName) + } + + // TODO: document this, should this be in the helper? + var serverName string + if pluginServerName, ok := server.PluginConfiguration.Parameters["serverName"]; ok { + serverName = pluginServerName + } else { + serverName = server.Name + } + + contextLogger.Info("Recovering from external cluster", + "sourceName", sourceName, + "serverName", serverName) + + env, err := barmanCredentials.EnvSetRestoreCloudCredentials( + ctx, + typedClient, + cluster.Namespace, + recoveryObjectStore, + os.Environ()) + if err != nil { + return nil, nil, err + } + + backupCatalog, err := barmanCommand.GetBackupList(ctx, recoveryObjectStore, serverName, env) + if err != nil { + return nil, nil, err + } + + // We are now choosing the right backup to restore + var targetBackup *barmanCatalog.BarmanBackup + if cluster.Spec.Bootstrap.Recovery != nil && + cluster.Spec.Bootstrap.Recovery.RecoveryTarget != nil { + targetBackup, err = backupCatalog.FindBackupInfo( + cluster.Spec.Bootstrap.Recovery.RecoveryTarget, + ) + if err != nil { + return nil, nil, err + } + } else { + targetBackup = backupCatalog.LatestBackupInfo() + } + if targetBackup == nil { + return nil, nil, fmt.Errorf("no target backup found") + } + + contextLogger.Info("Target backup found", "backup", targetBackup) + + return &cnpgv1.Backup{ + Spec: cnpgv1.BackupSpec{ + Cluster: cnpgv1.LocalObjectReference{ + Name: serverName, + }, + }, + Status: cnpgv1.BackupStatus{ + BarmanCredentials: recoveryObjectStore.BarmanCredentials, + EndpointCA: recoveryObjectStore.EndpointCA, + EndpointURL: recoveryObjectStore.EndpointURL, + DestinationPath: recoveryObjectStore.DestinationPath, + ServerName: serverName, + BackupID: targetBackup.ID, + Phase: cnpgv1.BackupPhaseCompleted, + StartedAt: &metav1.Time{Time: targetBackup.BeginTime}, + StoppedAt: &metav1.Time{Time: targetBackup.EndTime}, + BeginWal: targetBackup.BeginWal, + EndWal: targetBackup.EndWal, + BeginLSN: targetBackup.BeginLSN, + EndLSN: targetBackup.EndLSN, + Error: targetBackup.Error, + CommandOutput: "", + CommandError: "", + }, + }, env, nil +} diff --git a/internal/cnpgi/restore/start.go b/internal/cnpgi/restore/start.go index d220d02..da06988 100644 --- a/internal/cnpgi/restore/start.go +++ b/internal/cnpgi/restore/start.go @@ -11,13 +11,11 @@ import ( // CNPGI is the implementation of the PostgreSQL sidecar type CNPGI struct { - PluginPath string - SpoolDirectory string - ArchiveConfiguration client.ObjectKey - ClusterObjectKey client.ObjectKey - BackupToRestoreObjectKey client.ObjectKey - Client client.Client - PGDataPath string + PluginPath string + SpoolDirectory string + ClusterObjectKey client.ObjectKey + Client client.Client + PGDataPath string } // Start starts the GRPC service @@ -29,11 +27,9 @@ func (c *CNPGI) Start(ctx context.Context) error { restore.RegisterRestoreJobHooksServer(server, &JobHookImpl{ Client: c.Client, ClusterObjectKey: c.ClusterObjectKey, - BackupToRestore: c.BackupToRestoreObjectKey, SpoolDirectory: c.SpoolDirectory, PgDataPath: c.PGDataPath, PgWalFolderToSymlink: PgWalVolumePgWalPath, - ArchiveConfiguration: c.ArchiveConfiguration, }) return nil }