diff --git a/go.mod b/go.mod
index 35fbcd201d42..7b1c6797950d 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,9 @@ require (
cloud.google.com/go/spanner v1.67.0
cloud.google.com/go/storage v1.43.0
github.com/VividCortex/gohistogram v1.0.0
+ github.com/argoproj/argo-workflows/v3 v3.5.13
github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6
+ github.com/golang-migrate/migrate/v4 v4.18.1
github.com/golangci/golangci-lint v1.62.2
github.com/google/flatbuffers v24.3.25+incompatible
github.com/google/generative-ai-go v0.18.0
@@ -36,8 +38,12 @@ require (
google.golang.org/api v0.198.0
google.golang.org/appengine/v2 v2.0.5
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1
+ google.golang.org/grpc v1.66.2
google.golang.org/protobuf v1.35.2
gopkg.in/yaml.v3 v3.0.1
+ k8s.io/apimachinery v0.31.4
+ k8s.io/client-go v0.31.4
+ sigs.k8s.io/yaml v1.4.0
)
require (
@@ -88,8 +94,9 @@ require (
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect
github.com/curioswitch/go-reassign v0.2.0 // indirect
github.com/daixiang0/gci v0.13.5 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
github.com/ettle/strcase v0.2.0 // indirect
@@ -97,12 +104,16 @@ require (
github.com/fatih/structtag v1.2.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/firefart/nonamedreturns v1.0.5 // indirect
- github.com/fsnotify/fsnotify v1.6.0 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghostiam/protogetter v0.3.8 // indirect
github.com/go-critic/go-critic v0.11.5 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
+ github.com/go-openapi/jsonreference v0.20.4 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
github.com/go-toolsmith/astequal v1.2.0 // indirect
@@ -112,9 +123,10 @@ require (
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
- github.com/gobwas/glob v0.2.3 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
+ github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe // indirect
+ github.com/goccy/go-json v0.10.3 // indirect
github.com/gofrs/flock v0.12.1 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
@@ -125,7 +137,9 @@ require (
github.com/golangci/plugin-module-register v0.1.1 // indirect
github.com/golangci/revgrep v0.5.3 // indirect
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
- github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect
+ github.com/google/gnostic-models v0.6.8 // indirect
+ github.com/google/gofuzz v1.2.0 // indirect
+ github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/safehtml v0.1.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
@@ -135,6 +149,9 @@ require (
github.com/gostaticanalysis/comment v1.4.2 // indirect
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
+ github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
@@ -145,12 +162,14 @@ require (
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/jjti/go-spancheck v0.6.2 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
github.com/julz/importas v0.1.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect
github.com/kisielk/errcheck v1.8.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.5 // indirect
github.com/klauspost/compress v1.17.9 // indirect
- github.com/klauspost/cpuid/v2 v2.2.5 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/kulti/thelper v0.6.3 // indirect
github.com/kunwardeep/paralleltest v1.0.10 // indirect
github.com/kyoh86/exportloopref v0.1.11 // indirect
@@ -160,6 +179,7 @@ require (
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/macabu/inamedparam v0.1.3 // indirect
github.com/magiconair/properties v1.8.7 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
github.com/maratori/testableexamples v1.0.0 // indirect
github.com/maratori/testpackage v1.1.1 // indirect
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect
@@ -169,6 +189,8 @@ require (
github.com/mgechev/revive v1.5.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
@@ -179,7 +201,7 @@ require (
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/polyfloyd/go-errorlint v1.7.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
@@ -195,6 +217,8 @@ require (
github.com/rs/zerolog v1.29.0 // indirect
github.com/ryancurrah/gomodguard v1.3.5 // indirect
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
+ github.com/sagikazarmark/locafero v0.4.0 // indirect
+ github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
@@ -205,17 +229,17 @@ require (
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sivchari/tenv v1.12.1 // indirect
github.com/sonatard/noctx v0.1.0 // indirect
+ github.com/sourcegraph/conc v0.3.0 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
- github.com/spf13/cast v1.5.0 // indirect
+ github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
- github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
- github.com/spf13/viper v1.15.0 // indirect
+ github.com/spf13/viper v1.18.2 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
- github.com/subosito/gotenv v1.4.2 // indirect
+ github.com/subosito/gotenv v1.6.0 // indirect
github.com/tdakkota/asciicheck v0.2.0 // indirect
github.com/tetafro/godot v1.4.18 // indirect
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect
@@ -226,6 +250,7 @@ require (
github.com/ultraware/whitespace v0.1.1 // indirect
github.com/uudashr/gocognit v1.1.3 // indirect
github.com/uudashr/iface v1.2.1 // indirect
+ github.com/x448/float16 v0.8.4 // indirect
github.com/xen0n/gosmopolitan v1.2.2 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.3.0 // indirect
@@ -242,7 +267,7 @@ require (
go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
- go.uber.org/multierr v1.9.0 // indirect
+ go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f // indirect
@@ -250,14 +275,27 @@ require (
golang.org/x/net v0.31.0 // indirect
golang.org/x/term v0.26.0 // indirect
golang.org/x/text v0.20.0 // indirect
- golang.org/x/time v0.6.0 // indirect
+ golang.org/x/time v0.7.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
- google.golang.org/grpc v1.66.2 // indirect
+ gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
honnef.co/go/tools v0.5.1 // indirect
+ k8s.io/api v0.31.4 // indirect
+ k8s.io/klog/v2 v2.130.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
+ k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
mvdan.cc/gofumpt v0.7.0 // indirect
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
+ sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
)
+
+// v4.4.2 causes "unknown field IgnoredFields in struct literal of type merge.Updater".
+replace sigs.k8s.io/structured-merge-diff/v4 v4.4.2 => sigs.k8s.io/structured-merge-diff/v4 v4.4.1
+
+// The newer versions require Go 1.23.
+// See https://github.com/kubernetes-sigs/json/issues/22#issuecomment-2411500423.
+replace sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 => sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd
diff --git a/go.sum b/go.sum
index 030872509519..4990b6dff256 100644
--- a/go.sum
+++ b/go.sum
@@ -693,6 +693,8 @@ github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4x
github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE=
github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
+github.com/argoproj/argo-workflows/v3 v3.5.13 h1:d+t+nTBgfHsTTuw+KL3CmBrjvo9/VlRcMNm+FRf8FBA=
+github.com/argoproj/argo-workflows/v3 v3.5.13/go.mod h1:DecB01a8UXDCjtIh0udY8XfIMIRrWrlbob7hk/uMmg0=
github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY=
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
@@ -765,14 +767,17 @@ github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT8
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6 h1:sE4tvxWw01v7K3MAHwKF2UF3xQbgy23PRURntuV1CkU=
github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
+github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
+github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -804,10 +809,12 @@ github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6
github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
-github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
-github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -830,6 +837,12 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+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/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
+github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
+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-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
@@ -860,14 +873,18 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
-github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe h1:zn8tqiUbec4wR94o7Qj3LZCAT6uGobhEgnDRg6isG5U=
+github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-migrate/migrate/v4 v4.18.1 h1:JML/k+t4tpHCpQTCAD62Nu43NUFzHY4CV3uAuvHGC+Y=
+github.com/golang-migrate/migrate/v4 v4.18.1/go.mod h1:HAX6m3sQgcdO81tdjn5exv20+3Kb13cmGli1hrD6hks=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
@@ -939,6 +956,8 @@ github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81A
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/generative-ai-go v0.18.0 h1:6ybg9vOCLcI/UpBBYXOTVgvKmcUKFRNj+2Cj3GnebSo=
github.com/google/generative-ai-go v0.18.0/go.mod h1:JYolL13VG7j79kM5BtHz4qwONHkeJQzOCkKXnpqtS/E=
+github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -956,6 +975,9 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+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/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -979,8 +1001,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA=
-github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
+github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
@@ -1030,9 +1052,15 @@ github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW
github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY=
github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
@@ -1061,6 +1089,10 @@ github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk=
github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA=
+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.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY=
@@ -1070,6 +1102,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos=
github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg=
github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -1080,8 +1113,8 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
-github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -1108,6 +1141,8 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio
github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4=
github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
@@ -1115,6 +1150,8 @@ github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
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=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI=
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
@@ -1144,6 +1181,11 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=
github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@@ -1158,6 +1200,7 @@ github.com/nunnatsa/ginkgolinter v0.18.3 h1:WgS7X3zzmni3vwHSBhvSgqrRgUecN6PQUcfB
github.com/nunnatsa/ginkgolinter v0.18.3/go.mod h1:BE1xyB/PNtXXG1azrvrqJW5eFH0hSRylNzFy8QHPwzs=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
@@ -1185,8 +1228,9 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
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/polyfloyd/go-errorlint v1.7.0 h1:Zp6lzCK4hpBDj8y8a237YK4EPrMXQWvOe3nGoH4pFrU=
github.com/polyfloyd/go-errorlint v1.7.0/go.mod h1:dGWKu85mGHnegQ2SWpEybFityCg3j7ZbwsVUxAOk9gY=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
@@ -1234,6 +1278,10 @@ github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
@@ -1258,6 +1306,8 @@ github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY=
github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw=
github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM=
github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -1268,16 +1318,14 @@ github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
-github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
-github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
-github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
-github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
-github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
+github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
+github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc=
@@ -1300,8 +1348,8 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
-github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM=
github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg=
github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
@@ -1330,6 +1378,8 @@ github.com/uudashr/iface v1.2.1 h1:vHHyzAUmWZ64Olq6NZT3vg/z1Ws56kyPdBOd5kTXDF8=
github.com/uudashr/iface v1.2.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
github.com/vektra/mockery/v2 v2.45.1 h1:6HpdnKiLCjVtzlRLQPUNIM0u7yrvAoZ7VWF1TltJvTM=
github.com/vektra/mockery/v2 v2.45.1/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8=
+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/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
@@ -1389,8 +1439,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/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
-go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -1659,7 +1709,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1704,8 +1753,8 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-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/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-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1750,6 +1799,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@@ -1762,6 +1812,7 @@ golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
@@ -2079,10 +2130,13 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+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.3/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=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -2098,6 +2152,18 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
+k8s.io/api v0.31.4 h1:I2QNzitPVsPeLQvexMEsj945QumYraqv9m74isPDKhM=
+k8s.io/api v0.31.4/go.mod h1:d+7vgXLvmcdT1BCo79VEgJxHHryww3V5np2OYTr6jdw=
+k8s.io/apimachinery v0.31.4 h1:8xjE2C4CzhYVm9DGf60yohpNUh5AEBnPxCryPBECmlM=
+k8s.io/apimachinery v0.31.4/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
+k8s.io/client-go v0.31.4 h1:t4QEXt4jgHIkKKlx06+W3+1JOwAFU/2OPiOo7H92eRQ=
+k8s.io/client-go v0.31.4/go.mod h1:kvuMro4sFYIa8sulL5Gi5GFqUPvfH2O/dXuKstbaaeg=
+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-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
+k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
+k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
+k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
@@ -2140,3 +2206,9 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+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=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
+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/syz-cluster/.dockerignore b/syz-cluster/.dockerignore
new file mode 100644
index 000000000000..aa75b1b3ba14
--- /dev/null
+++ b/syz-cluster/.dockerignore
@@ -0,0 +1,6 @@
+# Ignore temporary files.
+*~
+
+# Ignore Dockerfiles.
+Dockerfile.*
+Dockerfile
diff --git a/syz-cluster/Dockerfile.go-tests b/syz-cluster/Dockerfile.go-tests
new file mode 100644
index 000000000000..8dd59bdc3604
--- /dev/null
+++ b/syz-cluster/Dockerfile.go-tests
@@ -0,0 +1,26 @@
+FROM golang:1.23-bullseye
+
+RUN apt-get update && \
+ apt-get install -y git
+
+RUN useradd --create-home syzkaller
+
+WORKDIR /build
+
+# Prepare the dependencies.
+COPY go.mod ./
+COPY go.sum ./
+RUN go mod download
+
+# Copy the source files.
+COPY pkg/ pkg/
+COPY prog/ prog/
+COPY sys/ sys/
+COPY vm/ vm/
+COPY dashboard/dashapi/ dashboard/dashapi/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+COPY syz-cluster/controller/ syz-cluster/controller/
+COPY syz-cluster/workflow/ syz-cluster/workflow/
+
+ENTRYPOINT ["go", "test"]
+CMD [ "-v", "./syz-cluster/..."]
diff --git a/syz-cluster/Makefile b/syz-cluster/Makefile
new file mode 100644
index 000000000000..c58b168bbcc3
--- /dev/null
+++ b/syz-cluster/Makefile
@@ -0,0 +1,58 @@
+# Copyright 2024 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+build-controller-dev:
+ eval $$(minikube docker-env);\
+ docker build -t controller-image-local -f ./controller/Dockerfile ../
+
+build-series-tracker-dev:
+ eval $$(minikube docker-env);\
+ docker build -t series-tracker-local -f ./series-tracker/Dockerfile ../
+
+deploy-series-tracker-dev: build-series-tracker-dev
+ @kubectl rollout restart deployment series-tracker
+
+run-series-tracker-dev: build-series-tracker-dev
+ ./run-local.sh series-tracker
+
+build-web-dashboard-dev:
+ eval $$(minikube docker-env);\
+ docker build -t web-dashboard-local -f ./dashboard/Dockerfile ../
+
+deploy-web-dashboard-dev: build-web-dashboard-dev
+ @kubectl rollout restart deployment web-dashboard
+
+install-dev-config:
+ minikube kubectl -- apply -f ./overlays/dev/global-config.yaml
+
+build-db-mgmt-dev:
+ eval $$(minikube docker-env);\
+ docker build -t db-mgmt-local -f ./db-mgmt/Dockerfile ../
+
+build-triage-step-dev:
+ eval $$(minikube docker-env);\
+ docker build -t triage-step-local -f ./workflow/triage-step/Dockerfile ../
+
+build-build-step-dev:
+ eval $$(minikube docker-env);\
+ docker build -t build-step-local -f ./workflow/build-step/Dockerfile ../
+
+build-boot-step-dev:
+ eval $$(minikube docker-env);\
+ docker build -t boot-step-local -f ./workflow/boot-step/Dockerfile ../
+
+build-go-tests-dev:
+ eval $$(minikube docker-env);\
+ docker build -t go-tests-local -f Dockerfile.go-tests ../
+
+build-workflow-dev: build-triage-step-dev build-build-step-dev
+
+all-containers: build-controller-dev build-series-tracker-dev build-db-mgmt-dev build-web-dashboard-dev build-workflow-dev
+
+run-go-tests-dev: build-go-tests-dev
+ ./run-local.sh go-tests
+
+restart-spanner: build-db-mgmt-dev
+ minikube addons disable cloud-spanner;
+ minikube addons enable cloud-spanner;
+ ./run-local.sh db-mgmt migrate
diff --git a/syz-cluster/README.md b/syz-cluster/README.md
new file mode 100644
index 000000000000..9fc152f50df7
--- /dev/null
+++ b/syz-cluster/README.md
@@ -0,0 +1,37 @@
+## Local installation steps
+
+1. Install and start minikube: https://minikube.sigs.k8s.io/docs/start/
+```
+$ minikube start
+```
+2. Add a Spanner Add-on: https://minikube.sigs.k8s.io/docs/handbook/addons/cloud-spanner/
+```
+$ minikube addons enable cloud-spanner
+```
+3. Build all docker containers (might take a while):
+```
+$ make all-containers
+```
+4. Deploy the cluster:
+```
+$ kubectl create namespace argo
+$ minikube kubectl -- kubectl apply -k ./overlays/dev/
+$ argo template create workflow/*/workflow-template.yaml
+$ make restart-spanner
+```
+
+## Developmental tips
+
+1. Install Argo Workflows client: https://github.com/argoproj/argo-workflows/releases
+
+Then you can use the `argo` tool like this:
+
+```
+$ argo list
+```
+
+2. Forward the dashboard port:
+
+```
+$ kubectl port-forward service/web-dashboard-service --address 0.0.0.0 50123:80
+```
diff --git a/syz-cluster/controller/Dockerfile b/syz-cluster/controller/Dockerfile
new file mode 100644
index 000000000000..c6692e290bee
--- /dev/null
+++ b/syz-cluster/controller/Dockerfile
@@ -0,0 +1,23 @@
+FROM golang:1.23-alpine AS controller-builder
+
+WORKDIR /build
+
+# Prepare the dependencies.
+COPY go.mod ./
+COPY go.sum ./
+RUN go mod download
+
+# Build the tool.
+COPY syz-cluster/controller/ syz-cluster/controller/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+RUN go build -o /bin/controller /build/syz-cluster/controller
+
+# Build the container.
+FROM alpine:latest
+WORKDIR /app
+
+COPY --from=controller-builder /bin/controller /bin/controller
+
+EXPOSE 8080
+
+ENTRYPOINT ["/bin/controller"]
diff --git a/syz-cluster/controller/api.go b/syz-cluster/controller/api.go
new file mode 100644
index 000000000000..9db06c230dc3
--- /dev/null
+++ b/syz-cluster/controller/api.go
@@ -0,0 +1,152 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+// nolint: dupl // The methods look similar, but extracting the common parts will only make the code worse.
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+)
+
+type ControllerAPI struct {
+ seriesService *SeriesService
+ buildService *BuildService
+ testService *SessionTestService
+ findingService *FindingService
+}
+
+func NewControllerAPI(env *app.AppEnvironment) *ControllerAPI {
+ return &ControllerAPI{
+ seriesService: NewSeriesService(env),
+ buildService: NewBuildService(env),
+ testService: NewSessionTestService(env),
+ findingService: NewFindingService(env),
+ }
+}
+
+func (c ControllerAPI) Mux() *http.ServeMux {
+ mux := http.NewServeMux()
+ mux.HandleFunc("/sessions/{session_id}/series", c.getSessionSeries)
+ mux.HandleFunc("/series/{series_id}", c.getSeries)
+ mux.HandleFunc("/builds/last", c.getLastBuild)
+ mux.HandleFunc("/builds/upload", c.uploadBuild)
+ mux.HandleFunc("/tests/upload", c.uploadTest)
+ mux.HandleFunc("/findings/upload", c.uploadFinding)
+ return mux
+}
+
+func (c ControllerAPI) getSessionSeries(w http.ResponseWriter, r *http.Request) {
+ ctx := context.Background()
+ resp, err := c.seriesService.GetSessionSeries(ctx, r.PathValue("session_id"))
+ if err == ErrSeriesNotFound || err == ErrSessionNotFound {
+ http.Error(w, fmt.Sprint(err), http.StatusNotFound)
+ return
+ } else if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ reply(w, resp)
+}
+
+func (c ControllerAPI) getSeries(w http.ResponseWriter, r *http.Request) {
+ ctx := context.Background()
+ resp, err := c.seriesService.GetSeries(ctx, r.PathValue("series_id"))
+ if err == ErrSeriesNotFound {
+ http.Error(w, fmt.Sprint(err), http.StatusNotFound)
+ return
+ } else if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ reply(w, resp)
+}
+
+func (c ControllerAPI) uploadBuild(w http.ResponseWriter, r *http.Request) {
+ req := parseBody[api.UploadBuildReq](w, r)
+ if req == nil {
+ return
+ }
+ resp, err := c.buildService.Upload(context.Background(), req)
+ if err != nil {
+ // TODO: sometimes it's not StatusInternalServerError.
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ reply(w, resp)
+}
+
+func (c ControllerAPI) uploadTest(w http.ResponseWriter, r *http.Request) {
+ req := parseBody[api.TestResult](w, r)
+ if req == nil {
+ return
+ }
+ // TODO: add parameters validation.
+ err := c.testService.Save(context.Background(), req)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ reply[interface{}](w, nil)
+}
+
+func (c ControllerAPI) uploadFinding(w http.ResponseWriter, r *http.Request) {
+ req := parseBody[api.Finding](w, r)
+ if req == nil {
+ return
+ }
+ // TODO: add parameters validation.
+ err := c.findingService.Save(context.Background(), req)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ reply[interface{}](w, nil)
+}
+
+func (c ControllerAPI) getLastBuild(w http.ResponseWriter, r *http.Request) {
+ req := parseBody[api.LastBuildReq](w, r)
+ if req == nil {
+ return
+ }
+ resp, err := c.buildService.LastBuild(context.Background(), req)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ reply[*api.Build](w, resp)
+}
+
+func reply[T any](w http.ResponseWriter, resp T) {
+ w.Header().Set("Content-Type", "application/json")
+ err := json.NewEncoder(w).Encode(resp)
+ if err != nil {
+ http.Error(w, "failed to serialize the response", http.StatusInternalServerError)
+ return
+ }
+}
+
+func parseBody[T any](w http.ResponseWriter, r *http.Request) *T {
+ if r.Method != http.MethodPost {
+ http.Error(w, "must be called via POST", http.StatusMethodNotAllowed)
+ return nil
+ }
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ http.Error(w, "failed to read body", http.StatusBadRequest)
+ return nil
+ }
+ var data T
+ err = json.Unmarshal(body, &data)
+ if err != nil {
+ http.Error(w, "invalid body", http.StatusBadRequest)
+ return nil
+ }
+ return &data
+}
diff --git a/syz-cluster/controller/api_test.go b/syz-cluster/controller/api_test.go
new file mode 100644
index 000000000000..bc205392bf70
--- /dev/null
+++ b/syz-cluster/controller/api_test.go
@@ -0,0 +1,111 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAPIGetSeries(t *testing.T) {
+ env, ctx := app.TestEnvironment(t)
+ apiServer := NewControllerAPI(env)
+ server := httptest.NewServer(apiServer.Mux())
+ defer server.Close()
+
+ series := addTestSeries(t, db.NewSeriesRepository(env.Spanner), env.BlobStorage)
+ session := addTestSession(t, db.NewSessionRepository(env.Spanner), series)
+
+ client := api.NewClient(server.URL)
+ ret, err := client.GetSessionSeries(ctx, session.ID)
+ assert.NoError(t, err)
+ assert.Equal(t, testSeriesReply, ret)
+
+ ret, err = client.GetSeries(ctx, series.ID)
+ assert.NoError(t, err)
+ assert.Equal(t, testSeriesReply, ret)
+}
+
+func TestAPISuccessfulBuild(t *testing.T) {
+ env, ctx := app.TestEnvironment(t)
+ apiServer := NewControllerAPI(env)
+ server := httptest.NewServer(apiServer.Mux())
+ defer server.Close()
+
+ client := api.NewClient(server.URL)
+ buildInfo, _ := uploadTestBuild(t, client)
+ info, err := client.LastSuccessfulBuild(ctx, &api.LastBuildReq{
+ Arch: buildInfo.Arch,
+ TreeName: buildInfo.TreeName,
+ ConfigName: buildInfo.ConfigName,
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, buildInfo, info)
+}
+
+func TestAPISaveFinding(t *testing.T) {
+ env, ctx := app.TestEnvironment(t)
+ apiServer := NewControllerAPI(env)
+ server := httptest.NewServer(apiServer.Mux())
+ defer server.Close()
+
+ series := addTestSeries(t, db.NewSeriesRepository(env.Spanner), env.BlobStorage)
+ session := addTestSession(t, db.NewSessionRepository(env.Spanner), series)
+
+ client := api.NewClient(server.URL)
+ _, buildResp := uploadTestBuild(t, client)
+ err := client.UploadTestResult(ctx, &api.TestResult{
+ SessionID: session.ID,
+ BaseBuildID: buildResp.ID,
+ TestName: "test",
+ Result: api.TestRunning,
+ })
+ assert.NoError(t, err)
+
+ t.Run("not existing test", func(t *testing.T) {
+ err = client.UploadFinding(ctx, &api.Finding{
+ SessionID: session.ID,
+ TestName: "unknown test",
+ })
+ assert.Error(t, err)
+ })
+
+ t.Run("must succeed", func(t *testing.T) {
+ finding := &api.Finding{
+ SessionID: session.ID,
+ TestName: "test",
+ Report: []byte("report"),
+ Log: []byte("log"),
+ }
+ err = client.UploadFinding(ctx, finding)
+ assert.NoError(t, err)
+ // Even if the finding is reported the second time, it must still not fail.
+ err = client.UploadFinding(ctx, finding)
+ assert.NoError(t, err)
+ })
+}
+
+func uploadTestBuild(t *testing.T, client *api.Client) (*api.Build, *api.UploadBuildResp) {
+ buildInfo := &api.Build{
+ Arch: "amd64",
+ TreeName: "mainline",
+ ConfigName: "config",
+ CommitHash: "abcd",
+ CommitDate: time.Date(2020, time.January, 1, 3, 0, 0, 0, time.UTC),
+ BuildSuccess: true,
+ }
+ ret, err := client.UploadBuild(context.Background(), &api.UploadBuildReq{
+ Build: *buildInfo,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, ret.ID)
+ return buildInfo, ret
+}
diff --git a/syz-cluster/controller/deployment.yaml b/syz-cluster/controller/deployment.yaml
new file mode 100644
index 000000000000..9b52864c81e7
--- /dev/null
+++ b/syz-cluster/controller/deployment.yaml
@@ -0,0 +1,32 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: controller-deployment
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: controller
+ template:
+ metadata:
+ labels:
+ app: controller
+ spec:
+ containers:
+ - name: controller-image
+ image: controller-image # The actual image name is set in overalys.
+ envFrom:
+ - configMapRef:
+ name: global-config
+ ports:
+ - containerPort: 8080
+ volumeMounts:
+ - name: blobs-storage-disk
+ mountPath: /blob-storage
+ volumes:
+ - name: blobs-storage-disk
+ persistentVolumeClaim:
+ claimName: blob-storage-disk-claim
diff --git a/syz-cluster/controller/kustomization.yaml b/syz-cluster/controller/kustomization.yaml
new file mode 100644
index 000000000000..138983d7b815
--- /dev/null
+++ b/syz-cluster/controller/kustomization.yaml
@@ -0,0 +1,6 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+resources:
+- deployment.yaml
+- service.yaml
diff --git a/syz-cluster/controller/main.go b/syz-cluster/controller/main.go
new file mode 100644
index 000000000000..9667c223906d
--- /dev/null
+++ b/syz-cluster/controller/main.go
@@ -0,0 +1,30 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+// NOTE: This app assumes that only one copy of it is runnning at the same time.
+
+package main
+
+import (
+ "context"
+ "log"
+ "net/http"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+)
+
+func main() {
+ ctx := context.Background()
+ env, err := app.Environment(ctx)
+ if err != nil {
+ app.Fatalf("failed to set up environment: %v", err)
+ }
+ sp := NewSeriesProcessor(env)
+ go func() {
+ err := sp.Loop(ctx)
+ app.Fatalf("processor loop failed: %v", err)
+ }()
+ api := NewControllerAPI(env)
+ log.Printf("listening on port 8080")
+ app.Fatalf("listen failed: %v", http.ListenAndServe(":8080", api.Mux()))
+}
diff --git a/syz-cluster/controller/processor.go b/syz-cluster/controller/processor.go
new file mode 100644
index 000000000000..6a36a7551993
--- /dev/null
+++ b/syz-cluster/controller/processor.go
@@ -0,0 +1,210 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "log"
+ "os"
+ "strconv"
+ "sync"
+ "time"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/blob"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+ "github.com/google/syzkaller/syz-cluster/pkg/workflow"
+ "golang.org/x/sync/errgroup"
+)
+
+type SeriesProcessor struct {
+ blobStorage blob.Storage
+ seriesRepo *db.SeriesRepository
+ sessionRepo *db.SessionRepository
+ workflows workflow.Service
+ dbPollInterval time.Duration
+ parallelWorkers int
+}
+
+func NewSeriesProcessor(env *app.AppEnvironment) *SeriesProcessor {
+ workflows, err := workflow.NewArgoService()
+ if err != nil {
+ app.Fatalf("failed to initialize workflows: %v", err)
+ }
+ parallelWorkers := 1
+ if val := os.Getenv("PARALLEL_WORKERS"); val != "" {
+ var err error
+ parallelWorkers, err = strconv.Atoi(val)
+ if err != nil || parallelWorkers < 1 {
+ app.Fatalf("invalid PARALLEL_WORKERS value")
+ }
+ }
+ return &SeriesProcessor{
+ blobStorage: env.BlobStorage,
+ seriesRepo: db.NewSeriesRepository(env.Spanner),
+ sessionRepo: db.NewSessionRepository(env.Spanner),
+ dbPollInterval: time.Minute,
+ workflows: workflows,
+ parallelWorkers: parallelWorkers,
+ }
+}
+
+func (sp *SeriesProcessor) Loop(ctx context.Context) error {
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ ch := make(chan *db.Session, 1)
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ sp.seriesRunner(ctx, ch)
+ }()
+ // First pick up the previously running sessions.
+ activeSessions, err := sp.sessionRepo.ListRunning(ctx)
+ if err != nil {
+ return err
+ }
+ log.Printf("queried %d unfinished sessions", len(activeSessions))
+ for _, session := range activeSessions {
+ ch <- session
+ }
+ // Then, monitor the DB for the new series.
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ sp.streamSeries(ctx, ch)
+ close(ch)
+ }()
+ return nil
+}
+
+func (sp *SeriesProcessor) streamSeries(ctx context.Context, ch chan<- *db.Session) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(sp.dbPollInterval):
+ }
+ if len(ch) > 0 {
+ // There are still series to be picked, no need to query the DB.
+ continue
+ }
+ list, err := sp.seriesRepo.ListWithoutSession(ctx, cap(ch))
+ if err != nil {
+ app.Errorf("failed to query series: %v", err)
+ continue
+ }
+ // Note: it seems that we here actively rely on Spanner's external consistency.
+ // E.g. once we add new Session, we expect to no longer see the series in
+ // the returned list.
+ for _, series := range list {
+ session, err := sp.createSession(ctx, series)
+ if err != nil {
+ app.Errorf("failed to create session for %q: %v", series.ID, err)
+ continue
+ }
+ ch <- session
+ }
+ }
+}
+
+func (sp *SeriesProcessor) seriesRunner(ctx context.Context, ch <-chan *db.Session) {
+ var eg errgroup.Group
+ defer eg.Wait()
+
+ eg.SetLimit(sp.parallelWorkers)
+ for {
+ var session *db.Session
+ select {
+ case session = <-ch:
+ case <-ctx.Done():
+ return
+ }
+ log.Printf("scheduled session %q for series %q", session.ID, session.SeriesID)
+ eg.Go(func() error {
+ log.Printf("started processing session %q", session.ID)
+ sp.handleSession(ctx, session)
+ log.Printf("finished processing session %q", session.ID)
+ return nil
+ })
+ }
+}
+
+func (sp *SeriesProcessor) createSession(ctx context.Context, series *db.Series) (*db.Session, error) {
+ session := &db.Session{
+ CreatedAt: time.Now(),
+ }
+ err := sp.sessionRepo.Insert(ctx, series, session)
+ if err != nil {
+ return nil, err
+ }
+ return session, err
+}
+
+func (sp *SeriesProcessor) handleSession(ctx context.Context, session *db.Session) {
+ // TODO: set some sane deadline or just track indefinitely?
+ pollPeriod := sp.workflows.PollPeriod()
+ for {
+ select {
+ case <-time.After(pollPeriod):
+ case <-ctx.Done():
+ return
+ }
+ status, log, err := sp.workflows.Status(session.ID)
+ if err != nil {
+ app.Errorf("failed to query workflow %q status: %v", session.ID, err)
+ continue
+ }
+ if log != nil {
+ err := sp.updateSessionLog(ctx, session, log)
+ if err != nil {
+ app.Errorf("failed to update session log: %v", err)
+ }
+ }
+ switch status {
+ case workflow.StatusNotFound:
+ err := sp.workflows.Start(session.ID)
+ if err != nil {
+ app.Errorf("failed to start a workflow: %v", err)
+ }
+ case workflow.StatusFinished, workflow.StatusFailed:
+ // TODO: StatusFailed needs a different handling.
+ err := sp.sessionRepo.Update(ctx, session.ID, func(session *db.Session) error {
+ session.SetFinishedAt(time.Now())
+ return nil
+ })
+ if err == nil {
+ // Nothing to do here anymore.
+ return
+ }
+ // Let's hope the error was transient.
+ app.Errorf("failed to update session %q: %v", session.ID, err)
+ case workflow.StatusRunning:
+ // Let's keep on tracking.
+ continue
+ default:
+ panic("unexpected workflow status: " + status)
+ }
+ }
+}
+
+func (sp *SeriesProcessor) updateSessionLog(ctx context.Context, session *db.Session, log []byte) error {
+ return sp.sessionRepo.Update(ctx, session.ID, func(session *db.Session) error {
+ if session.LogURI == "" {
+ path, err := sp.blobStorage.Store(bytes.NewReader(log))
+ if err != nil {
+ return fmt.Errorf("failed to save the log: %w", err)
+ }
+ session.LogURI = path
+ } else {
+ err := sp.blobStorage.Update(session.LogURI, bytes.NewReader(log))
+ if err != nil {
+ return fmt.Errorf("failed to update the log %q: %w", session.LogURI, err)
+ }
+ }
+ return nil
+ })
+}
diff --git a/syz-cluster/controller/processor_test.go b/syz-cluster/controller/processor_test.go
new file mode 100644
index 000000000000..3b2d493b29d2
--- /dev/null
+++ b/syz-cluster/controller/processor_test.go
@@ -0,0 +1,151 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+ "github.com/google/syzkaller/syz-cluster/pkg/workflow"
+ "github.com/stretchr/testify/assert"
+)
+
+// It's a bit too long for a unit test, but it captures the whole main scenario of operation.
+func TestProcessor(t *testing.T) {
+ workflows := newMockedWorkflows()
+ processor, ctx := prepareProcessorTest(t, workflows)
+
+ // Start the loop.
+ var wg sync.WaitGroup
+ ctx2, cancel := context.WithCancel(ctx)
+ wg.Add(1)
+ go func() {
+ processor.Loop(ctx2)
+ wg.Done()
+ }()
+
+ // Add some series.
+ var allSeries []*db.Series
+ for i := 0; i < 10; i++ {
+ id := fmt.Sprintf("series-%d", i)
+ allSeries = append(allSeries, &db.Series{
+ ExtID: id,
+ Title: id,
+ })
+ }
+ for _, series := range allSeries[0:5] {
+ err := processor.seriesRepo.Insert(ctx, series, nil)
+ assert.NoError(t, err)
+ }
+
+ // Let some workflows finish.
+ for i := 0; i < 2; i++ {
+ workflows.finish <- struct{}{}
+ }
+
+ awaitFinishedSessions(t, processor.seriesRepo, 2)
+
+ // Restart the loop.
+ cancel()
+ wg.Wait()
+
+ ctx3, cancel := context.WithCancel(ctx)
+ wg.Add(1)
+ defer wg.Wait()
+ go func() {
+ processor.Loop(ctx3)
+ wg.Done()
+ }()
+
+ // Add some more series.
+ for _, series := range allSeries[5:10] {
+ err := processor.seriesRepo.Insert(ctx, series, nil)
+ assert.NoError(t, err)
+ }
+
+ // Finish all of them.
+ for i := 0; i < 8; i++ {
+ workflows.finish <- struct{}{}
+ }
+
+ awaitFinishedSessions(t, processor.seriesRepo, 10)
+ cancel()
+}
+
+func awaitFinishedSessions(t *testing.T, seriesRepo *db.SeriesRepository, wantFinished int) {
+ t.Logf("awaiting %d finished sessions", wantFinished)
+ deadline := time.Second * 2
+ interval := time.Second / 10
+ for i := 0; i < int(deadline/interval); i++ {
+ time.Sleep(interval)
+
+ list, err := seriesRepo.ListLatest(context.Background(), time.Time{}, 0)
+ assert.NoError(t, err)
+ withFinishedSeries := 0
+ for _, item := range list {
+ if item.Session == nil {
+ continue
+ }
+ if item.Session.FinishedAt.IsNull() {
+ continue
+ }
+ withFinishedSeries++
+ }
+ t.Logf("have %d finished", withFinishedSeries)
+ if withFinishedSeries == wantFinished {
+ return
+ }
+ }
+ t.Fatalf("never reached %d finished series", wantFinished)
+}
+
+type mockedWorkflows struct {
+ workflow.MockService
+ finish chan struct{}
+ created map[string]struct{}
+}
+
+func newMockedWorkflows() *mockedWorkflows {
+ obj := mockedWorkflows{
+ finish: make(chan struct{}),
+ created: make(map[string]struct{}),
+ }
+ obj.PollDelayValue = time.Millisecond
+ obj.OnStart = func(id string) error {
+ obj.created[id] = struct{}{}
+ return nil
+ }
+ obj.OnStatus = func(id string) (workflow.Status, []byte, error) {
+ _, ok := obj.created[id]
+ if !ok {
+ return workflow.StatusNotFound, nil, nil
+ }
+ finished := false
+ select {
+ case <-obj.finish:
+ finished = true
+ default:
+ }
+ if finished {
+ return workflow.StatusFinished, nil, nil
+ }
+ return workflow.StatusRunning, nil, nil
+ }
+ return &obj
+}
+
+func prepareProcessorTest(t *testing.T, workflows workflow.Service) (*SeriesProcessor, context.Context) {
+ client, ctx := db.NewTransientDB(t)
+ return &SeriesProcessor{
+ seriesRepo: db.NewSeriesRepository(client),
+ sessionRepo: db.NewSessionRepository(client),
+ workflows: workflows,
+ dbPollInterval: time.Second / 10,
+ parallelWorkers: 2,
+ }, ctx
+}
diff --git a/syz-cluster/controller/service.yaml b/syz-cluster/controller/service.yaml
new file mode 100644
index 000000000000..39aa1d9ff6b0
--- /dev/null
+++ b/syz-cluster/controller/service.yaml
@@ -0,0 +1,14 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: controller-service
+spec:
+ selector:
+ app: controller
+ ports:
+ - protocol: TCP
+ port: 8080
+ targetPort: 8080
diff --git a/syz-cluster/controller/services.go b/syz-cluster/controller/services.go
new file mode 100644
index 000000000000..6906f6ccdf05
--- /dev/null
+++ b/syz-cluster/controller/services.go
@@ -0,0 +1,198 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+
+ "cloud.google.com/go/spanner"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/blob"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+)
+
+type SeriesService struct {
+ sessionRepo *db.SessionRepository
+ seriesRepo *db.SeriesRepository
+ blobStorage blob.Storage
+}
+
+func NewSeriesService(env *app.AppEnvironment) *SeriesService {
+ return &SeriesService{
+ sessionRepo: db.NewSessionRepository(env.Spanner),
+ seriesRepo: db.NewSeriesRepository(env.Spanner),
+ blobStorage: env.BlobStorage,
+ }
+}
+
+var ErrSessionNotFound = errors.New("session not found")
+
+func (s *SeriesService) GetSessionSeries(ctx context.Context, sessionID string) (*api.Series, error) {
+ session, err := s.sessionRepo.GetByID(ctx, sessionID)
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch the session: %w", err)
+ } else if session == nil {
+ return nil, fmt.Errorf("%w: %q", ErrSessionNotFound, sessionID)
+ }
+ return s.GetSeries(ctx, session.SeriesID)
+}
+
+var ErrSeriesNotFound = errors.New("series not found")
+
+func (s *SeriesService) GetSeries(ctx context.Context, seriesID string) (*api.Series, error) {
+ series, err := s.seriesRepo.GetByID(ctx, seriesID)
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch the series: %w", err)
+ } else if series == nil {
+ return nil, ErrSeriesNotFound
+ }
+ patches, err := s.seriesRepo.ListPatches(ctx, series)
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch patches: %w", err)
+ }
+ ret := &api.Series{
+ ID: series.ID,
+ Cc: series.Cc,
+ PublishedAt: series.PublishedAt,
+ }
+ for _, patch := range patches {
+ reader, err := s.blobStorage.Read(patch.BodyURI)
+ var body []byte
+ if err == nil {
+ body, err = io.ReadAll(reader)
+ }
+ if err != nil {
+ return nil, fmt.Errorf("failed to read patch %q: %w", patch.ID, err)
+ }
+ ret.Patches = append(ret.Patches, body)
+ }
+ return ret, nil
+}
+
+type BuildService struct {
+ buildRepo *db.BuildRepository
+}
+
+func NewBuildService(env *app.AppEnvironment) *BuildService {
+ return &BuildService{
+ buildRepo: db.NewBuildRepository(env.Spanner),
+ }
+}
+
+func (s *BuildService) Upload(ctx context.Context, req *api.UploadBuildReq) (*api.UploadBuildResp, error) {
+ build := &db.Build{
+ Arch: req.Arch,
+ ConfigName: req.ConfigName,
+ TreeName: req.TreeName,
+ CommitHash: req.CommitHash,
+ CommitDate: req.CommitDate,
+ }
+ if req.SeriesID != "" {
+ build.SetSeriesID(req.SeriesID)
+ }
+ if req.BuildSuccess {
+ build.Status = db.BuildSuccess
+ } else {
+ build.Status = db.BuildFailed
+ }
+ // TODO: upload config and log.
+ err := s.buildRepo.Insert(ctx, build)
+ if err != nil {
+ return nil, err
+ }
+ return &api.UploadBuildResp{
+ ID: build.ID,
+ }, nil
+}
+
+func (s *BuildService) LastBuild(ctx context.Context, req *api.LastBuildReq) (*api.Build, error) {
+ build, err := s.buildRepo.LastBuiltTree(ctx, req.Arch, req.TreeName, req.ConfigName)
+ if build == nil || err != nil {
+ return nil, err
+ }
+ resp := &api.Build{
+ Arch: build.Arch,
+ TreeName: build.TreeName,
+ ConfigName: build.ConfigName,
+ CommitHash: build.CommitHash,
+ CommitDate: build.CommitDate,
+ BuildSuccess: true,
+ }
+ if !build.SeriesID.IsNull() {
+ resp.SeriesID = build.SeriesID.String()
+ }
+ return resp, nil
+}
+
+type SessionTestService struct {
+ testRepo *db.SessionTestRepository
+}
+
+func NewSessionTestService(env *app.AppEnvironment) *SessionTestService {
+ return &SessionTestService{
+ testRepo: db.NewSessionTestRepository(env.Spanner),
+ }
+}
+
+func (s *SessionTestService) Save(ctx context.Context, req *api.TestResult) error {
+ entity := &db.SessionTest{
+ SessionID: req.SessionID,
+ TestName: req.TestName,
+ Result: req.Result,
+ }
+ if req.BaseBuildID != "" {
+ entity.BaseBuildID = spanner.NullString{StringVal: req.BaseBuildID, Valid: true}
+ }
+ if req.PatchedBuildID != "" {
+ entity.PatchedBuildID = spanner.NullString{StringVal: req.PatchedBuildID, Valid: true}
+ }
+ return s.testRepo.InsertOrUpdate(context.Background(), entity)
+}
+
+type FindingService struct {
+ findingRepo *db.FindingRepository
+ blobStorage blob.Storage
+}
+
+func NewFindingService(env *app.AppEnvironment) *FindingService {
+ return &FindingService{
+ findingRepo: db.NewFindingRepository(env.Spanner),
+ blobStorage: env.BlobStorage,
+ }
+}
+
+func (s *FindingService) Save(ctx context.Context, req *api.Finding) error {
+ var reportURI, logURI string
+ var err error
+ if len(req.Log) > 0 {
+ logURI, err = s.blobStorage.Store(bytes.NewReader(req.Log))
+ if err != nil {
+ return fmt.Errorf("failed to save the log: %w", err)
+ }
+ }
+ if len(req.Report) > 0 {
+ reportURI, err = s.blobStorage.Store(bytes.NewReader(req.Report))
+ if err != nil {
+ return fmt.Errorf("failed to save the report: %w", err)
+ }
+ }
+ // TODO: if it's not actually addded, the blob records will be orphaned.
+ err = s.findingRepo.Save(ctx, &db.Finding{
+ SessionID: req.SessionID,
+ TestName: req.TestName,
+ Title: req.Title,
+ ReportURI: reportURI,
+ LogURI: logURI,
+ })
+ if err == db.ErrFindingExists {
+ // It's ok, just ignore.
+ return nil
+ }
+ return err
+}
diff --git a/syz-cluster/controller/services_test.go b/syz-cluster/controller/services_test.go
new file mode 100644
index 000000000000..578fa72fcbf9
--- /dev/null
+++ b/syz-cluster/controller/services_test.go
@@ -0,0 +1,85 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "testing"
+ "time"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/blob"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGetSeries(t *testing.T) {
+ env, ctx := app.TestEnvironment(t)
+ seriesRepo := db.NewSeriesRepository(env.Spanner)
+ series := addTestSeries(t, seriesRepo, env.BlobStorage)
+ sessionRepo := db.NewSessionRepository(env.Spanner)
+ session := addTestSession(t, sessionRepo, series)
+ service := &SeriesService{
+ seriesRepo: seriesRepo,
+ sessionRepo: sessionRepo,
+ blobStorage: env.BlobStorage,
+ }
+ ret, err := service.GetSessionSeries(ctx, session.ID)
+ assert.NoError(t, err)
+ assert.Equal(t, testSeriesReply, ret)
+ ret2, err := service.GetSeries(ctx, series.ID)
+ assert.NoError(t, err)
+ assert.Equal(t, testSeriesReply, ret2)
+}
+
+var testSeriesReply = &api.Series{
+ ID: "some-id",
+ PublishedAt: time.Date(2020, time.January, 1, 3, 0, 0, 0, time.UTC),
+ Cc: []string{"email"},
+ Patches: [][]byte{
+ []byte("first content"),
+ []byte("second content"),
+ },
+}
+
+func addTestSeries(t *testing.T, repo *db.SeriesRepository, storage blob.Storage) *db.Series {
+ series := &db.Series{
+ ID: "some-id",
+ ExtID: "ext-id",
+ AuthorName: "Name1 Name2",
+ AuthorEmail: "some@email.com",
+ Title: "test series name",
+ Version: 2,
+ PublishedAt: time.Date(2020, time.January, 1, 3, 0, 0, 0, time.UTC),
+ Cc: []string{"email"},
+ }
+
+ uri1, _ := storage.Store(bytes.NewReader([]byte("first content")))
+ uri2, _ := storage.Store(bytes.NewReader([]byte("second content")))
+
+ patches := []*db.Patch{
+ {Seq: 1, Link: "first link", BodyURI: uri1},
+ {Seq: 2, Link: "second link", BodyURI: uri2},
+ }
+ err := repo.Insert(context.Background(), series, func() ([]*db.Patch, error) {
+ return patches, nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ return series
+}
+
+func addTestSession(t *testing.T, repo *db.SessionRepository, series *db.Series) *db.Session {
+ session := &db.Session{
+ CreatedAt: time.Now(),
+ }
+ err := repo.Insert(context.Background(), series, session)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return session
+}
diff --git a/syz-cluster/dashboard/Dockerfile b/syz-cluster/dashboard/Dockerfile
new file mode 100644
index 000000000000..c813d856e461
--- /dev/null
+++ b/syz-cluster/dashboard/Dockerfile
@@ -0,0 +1,23 @@
+FROM golang:1.23-alpine AS dashboard-builder
+
+WORKDIR /build
+
+# Prepare the dependencies.
+COPY go.mod ./
+COPY go.sum ./
+RUN go mod download
+
+# Build the tool.
+COPY syz-cluster/dashboard/ syz-cluster/dashboard/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+RUN go build -o /bin/web-dashboard /build/syz-cluster/dashboard
+
+# Build the container.
+FROM alpine:latest
+WORKDIR /app
+
+COPY --from=dashboard-builder /bin/web-dashboard /bin/web-dashboard
+
+EXPOSE 8081
+
+ENTRYPOINT ["/bin/web-dashboard"]
diff --git a/syz-cluster/dashboard/README.md b/syz-cluster/dashboard/README.md
new file mode 100644
index 000000000000..4ed78f2541a6
--- /dev/null
+++ b/syz-cluster/dashboard/README.md
@@ -0,0 +1,7 @@
+To update and access the web dashboard during local development:
+
+```
+$ make install-dev-config
+$ make deploy-web-dashboard-dev
+$ kubectl port-forward service/web-dashboard-service --address 0.0.0.0 50123:80
+```
diff --git a/syz-cluster/dashboard/deployment.yaml b/syz-cluster/dashboard/deployment.yaml
new file mode 100644
index 000000000000..e6699f211bb0
--- /dev/null
+++ b/syz-cluster/dashboard/deployment.yaml
@@ -0,0 +1,32 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: web-dashboard
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: web-dashboard
+ template:
+ metadata:
+ labels:
+ app: web-dashboard
+ spec:
+ containers:
+ - name: web-dashboard-image
+ image: web-dashboard-image
+ envFrom:
+ - configMapRef:
+ name: global-config
+ ports:
+ - containerPort: 8081
+ volumeMounts:
+ - name: blobs-storage-disk
+ mountPath: /blob-storage
+ volumes:
+ - name: blobs-storage-disk
+ persistentVolumeClaim:
+ claimName: blob-storage-disk-claim
diff --git a/syz-cluster/dashboard/handler.go b/syz-cluster/dashboard/handler.go
new file mode 100644
index 000000000000..5e562ee11120
--- /dev/null
+++ b/syz-cluster/dashboard/handler.go
@@ -0,0 +1,188 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "embed"
+ "fmt"
+ "html/template"
+ "io"
+ "net/http"
+ "time"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/blob"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+)
+
+type dashboardHandler struct {
+ seriesRepo *db.SeriesRepository
+ sessionRepo *db.SessionRepository
+ sessionTestRepo *db.SessionTestRepository
+ findingRepo *db.FindingRepository
+ blobStorage blob.Storage
+ templates map[string]*template.Template
+}
+
+//go:embed templates/*
+var templates embed.FS
+
+func newHandler(env *app.AppEnvironment) (*dashboardHandler, error) {
+ perFile := map[string]*template.Template{}
+ var err error
+ for _, name := range []string{"index.html", "series.html"} {
+ perFile[name], err = template.ParseFS(templates, "templates/base.html", "templates/"+name)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return &dashboardHandler{
+ templates: perFile,
+ blobStorage: env.BlobStorage,
+ seriesRepo: db.NewSeriesRepository(env.Spanner),
+ sessionRepo: db.NewSessionRepository(env.Spanner),
+ sessionTestRepo: db.NewSessionTestRepository(env.Spanner),
+ findingRepo: db.NewFindingRepository(env.Spanner),
+ }, nil
+}
+
+func (h *dashboardHandler) seriesList(w http.ResponseWriter, r *http.Request) {
+ type MainPageData struct {
+ // It's probably not the best idea to expose db entities here,
+ // but so far redefining the entity would just duplicate the code.
+ List []*db.SeriesWithSession
+ }
+ var data MainPageData
+ var err error
+ data.List, err = h.seriesRepo.ListLatest(context.Background(), time.Time{}, 0)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("failed to query the list: %v", err), http.StatusInternalServerError)
+ return
+ }
+ err = h.templates["index.html"].ExecuteTemplate(w, "base.html", data)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+}
+
+func (h *dashboardHandler) seriesInfo(w http.ResponseWriter, r *http.Request) {
+ type SessionTest struct {
+ *db.FullSessionTest
+ Findings []*db.Finding
+ }
+ type SessionData struct {
+ *db.Session
+ Tests []SessionTest
+ }
+ type SeriesData struct {
+ *db.Series
+ Patches []*db.Patch
+ Sessions []SessionData
+ TotalPatches int
+ }
+ var data SeriesData
+ var err error
+ ctx := context.Background()
+ data.Series, err = h.seriesRepo.GetByID(ctx, r.PathValue("id"))
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ data.Patches, err = h.seriesRepo.ListPatches(ctx, data.Series)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ data.TotalPatches = len(data.Patches)
+ sessions, err := h.sessionRepo.ListForSeries(ctx, data.Series)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ for _, session := range sessions {
+ rawTests, err := h.sessionTestRepo.BySession(ctx, session.ID)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ findings, err := h.findingRepo.ListForSession(ctx, session)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ perName := groupFindings(findings)
+ sessionData := SessionData{
+ Session: session,
+ }
+ for _, test := range rawTests {
+ sessionData.Tests = append(sessionData.Tests, SessionTest{
+ FullSessionTest: test,
+ Findings: perName[test.TestName],
+ })
+ }
+ data.Sessions = append(data.Sessions, sessionData)
+ }
+
+ err = h.templates["series.html"].ExecuteTemplate(w, "base.html", data)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ }
+}
+
+func groupFindings(findings []*db.Finding) map[string][]*db.Finding {
+ ret := map[string][]*db.Finding{}
+ for _, finding := range findings {
+ ret[finding.TestName] = append(ret[finding.TestName], finding)
+ }
+ return ret
+}
+
+// nolint:dupl
+func (h *dashboardHandler) sessionLog(w http.ResponseWriter, r *http.Request) {
+ ctx := context.Background()
+ session, err := h.sessionRepo.GetByID(ctx, r.PathValue("id"))
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ if session == nil {
+ http.Error(w, "no such session exists in the DB", http.StatusNotFound)
+ return
+ }
+ h.streamBlob(w, session.LogURI)
+}
+
+// nolint:dupl
+func (h *dashboardHandler) patchContent(w http.ResponseWriter, r *http.Request) {
+ ctx := context.Background()
+ patch, err := h.seriesRepo.PatchByID(ctx, r.PathValue("id"))
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ if patch == nil {
+ http.Error(w, "no such patch exists in the DB", http.StatusNotFound)
+ return
+ }
+ h.streamBlob(w, patch.BodyURI)
+}
+
+func (h *dashboardHandler) streamBlob(w http.ResponseWriter, uri string) {
+ if uri == "" {
+ return
+ }
+ reader, err := h.blobStorage.Read(uri)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+ defer reader.Close()
+ _, err = io.Copy(w, reader)
+ if err != nil {
+ http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
+ return
+ }
+}
diff --git a/syz-cluster/dashboard/kustomization.yaml b/syz-cluster/dashboard/kustomization.yaml
new file mode 100644
index 000000000000..138983d7b815
--- /dev/null
+++ b/syz-cluster/dashboard/kustomization.yaml
@@ -0,0 +1,6 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+resources:
+- deployment.yaml
+- service.yaml
diff --git a/syz-cluster/dashboard/main.go b/syz-cluster/dashboard/main.go
new file mode 100644
index 000000000000..2f551048c1f2
--- /dev/null
+++ b/syz-cluster/dashboard/main.go
@@ -0,0 +1,42 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "embed"
+ "io/fs"
+ "log"
+ "net/http"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+)
+
+//go:embed static
+var staticFs embed.FS
+
+func main() {
+ ctx := context.Background()
+ env, err := app.Environment(ctx)
+ if err != nil {
+ app.Fatalf("failed to set up environment: %v", err)
+ }
+ handler, err := newHandler(env)
+ if err != nil {
+ app.Fatalf("failed to set up handler: %v", err)
+ }
+ http.HandleFunc("/sessions/{id}/log", handler.sessionLog)
+ http.HandleFunc("/series/{id}", handler.seriesInfo)
+ http.HandleFunc("/patches/{id}", handler.patchContent)
+ http.HandleFunc("/", handler.seriesList)
+
+ staticFiles, err := fs.Sub(staticFs, "static")
+ if err != nil {
+ app.Fatalf("failed to parse templates: %v", err)
+ }
+ http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFiles))))
+
+ log.Printf("listening at port 8081")
+ log.Fatal(http.ListenAndServe(":8081", nil))
+}
diff --git a/syz-cluster/dashboard/service.yaml b/syz-cluster/dashboard/service.yaml
new file mode 100644
index 000000000000..a5b2521e473e
--- /dev/null
+++ b/syz-cluster/dashboard/service.yaml
@@ -0,0 +1,15 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: web-dashboard-service
+spec:
+ selector:
+ app: web-dashboard
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 8081
+ type: LoadBalancer
diff --git a/syz-cluster/dashboard/static/bootstrap.min.css b/syz-cluster/dashboard/static/bootstrap.min.css
new file mode 100644
index 000000000000..39934146ffdc
--- /dev/null
+++ b/syz-cluster/dashboard/static/bootstrap.min.css
@@ -0,0 +1,6 @@
+@charset "UTF-8";/*!
+ * Bootstrap v5.3.3 (https://getbootstrap.com/)
+ * Copyright 2011-2024 The Bootstrap Authors
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--bs-offcanvas-padding-y)) calc(-.5 * var(--bs-offcanvas-padding-x)) calc(-.5 * var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}}
+/*# sourceMappingURL=bootstrap.min.css.map */
\ No newline at end of file
diff --git a/syz-cluster/dashboard/static/index.html b/syz-cluster/dashboard/static/index.html
new file mode 100644
index 000000000000..0e502a588e0d
--- /dev/null
+++ b/syz-cluster/dashboard/static/index.html
@@ -0,0 +1 @@
+
diff --git a/syz-cluster/dashboard/templates/base.html b/syz-cluster/dashboard/templates/base.html
new file mode 100644
index 000000000000..a2b286abcf5d
--- /dev/null
+++ b/syz-cluster/dashboard/templates/base.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ syz-cluster
+
+
+
+ {{block "content" .}}{{end}}
+
+
diff --git a/syz-cluster/dashboard/templates/index.html b/syz-cluster/dashboard/templates/index.html
new file mode 100644
index 000000000000..6d8caa9fbd0b
--- /dev/null
+++ b/syz-cluster/dashboard/templates/index.html
@@ -0,0 +1,25 @@
+{{define "content"}}
+
+
+
+ | Published |
+ Title |
+ Version |
+ Author |
+ Status |
+
+
+
+ {{range .List}}
+
+ | {{.Series.PublishedAt.Format "2006-01-02 15:04 MST"}} |
+ {{.Series.Title}} |
+ {{.Series.Version}} |
+ {{.Series.AuthorEmail}} |
+ {{if .Session}}{{if .Session.FinishedAt.IsNull}}in progress{{else}}finished{{end}}{{else}}waiting{{end}} |
+
+ {{end}}
+
+
+{{end}}
+
diff --git a/syz-cluster/dashboard/templates/series.html b/syz-cluster/dashboard/templates/series.html
new file mode 100644
index 000000000000..2b39f8a697d3
--- /dev/null
+++ b/syz-cluster/dashboard/templates/series.html
@@ -0,0 +1,100 @@
+{{define "content"}}
+
+
Patch Series
+
+
+
+ | Subject |
+ {{.Title}} |
+
+
+ | Author |
+ {{.AuthorEmail}} |
+
+
+ | Date |
+ {{.PublishedAt}} |
+
+
+ | Version |
+ {{.Version}} |
+
+
+
+
+
Patches ({{.TotalPatches}})
+
+
+
+ | Name |
+ Content |
+
+
+
+ {{$data := .}}
+ {{range .Patches}}
+
+ | {{.Title}} |
+ [Body] |
+
+ {{end}}
+
+
+ {{range .Sessions}}
+
Session {{.CreatedAt.Format "2006-01-02"}}
+
+
+
+ | ID (for dev) |
+ {{.ID}} |
+
+
+ | Status |
+ {{if .FinishedAt.IsNull}}in progress{{else}}finshed{{end}} |
+
+ {{if .LogURI}}
+
+ | Execution Log |
+ [Link] |
+
+ {{end}}
+
+
+
+
+
+ | Test |
+ Base |
+ Patched |
+ Verdict |
+
+
+
+ {{range .Tests}}
+
+ | {{.TestName}} |
+ {{if .BaseBuild}}{{.BaseBuild.CommitHash}}{{end}} |
+ {{if .PatchedBuild}}{{.PatchedBuild.CommitHash}}[patched]{{end}} |
+ {{.Result}} |
+
+ {{if .Findings}}
+
+
+
+
+ {{range .Findings}}
+
+ | {{.Title}} |
+
+ {{end}}
+
+
+ |
+
+ {{end}}
+ {{end}}
+
+
+ {{end}}
+
+{{end}}
diff --git a/syz-cluster/db-mgmt/Dockerfile b/syz-cluster/db-mgmt/Dockerfile
new file mode 100644
index 000000000000..a999a31d36ca
--- /dev/null
+++ b/syz-cluster/db-mgmt/Dockerfile
@@ -0,0 +1,21 @@
+FROM golang:1.23-alpine AS builder
+
+WORKDIR /build
+
+# Prepare the dependencies.
+COPY go.mod ./
+COPY go.sum ./
+RUN go mod download
+
+# Build the tool.
+COPY syz-cluster/db-mgmt/*.go syz-cluster/db-mgmt/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+RUN go build -o /bin/db-mgmt /build/syz-cluster/db-mgmt
+
+# Create the actual container.
+FROM alpine:latest
+WORKDIR /app
+
+COPY --from=builder /bin/db-mgmt /bin/db-mgmt
+
+ENTRYPOINT ["/bin/db-mgmt"]
diff --git a/syz-cluster/db-mgmt/README.md b/syz-cluster/db-mgmt/README.md
new file mode 100644
index 000000000000..5ad156287658
--- /dev/null
+++ b/syz-cluster/db-mgmt/README.md
@@ -0,0 +1,7 @@
+How to run DB migrations locally:
+
+```
+cd $SYZKALLER/syz-cluster
+make build-db-mgmt-dev restart-spanner
+./run-local.sh db-mgmt migrate
+```
diff --git a/syz-cluster/db-mgmt/deployment.yaml b/syz-cluster/db-mgmt/deployment.yaml
new file mode 100644
index 000000000000..d81d7eced420
--- /dev/null
+++ b/syz-cluster/db-mgmt/deployment.yaml
@@ -0,0 +1,23 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: db-mgmt
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: db-mgmt
+ template:
+ metadata:
+ labels:
+ app: db-mgmt
+ spec:
+ containers:
+ - name: db-mgmt-local
+ image: db-mgmt-local:latest
+ imagePullPolicy: Never
+ command: ["db-mgmt", "migrate", "/migrations"]
+ restartPolicy: Never
diff --git a/syz-cluster/db-mgmt/main.go b/syz-cluster/db-mgmt/main.go
new file mode 100644
index 000000000000..17ad70f1d1a3
--- /dev/null
+++ b/syz-cluster/db-mgmt/main.go
@@ -0,0 +1,83 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "os"
+
+ "cloud.google.com/go/spanner"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+ "google.golang.org/api/iterator"
+)
+
+func runSQL(ctx context.Context, uri db.ParsedURI, command string) error {
+ client, err := spanner.NewClient(ctx, uri.Full)
+ if err != nil {
+ return err
+ }
+ defer client.Close()
+ stmt := spanner.Statement{SQL: command}
+ iter := client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+
+ for {
+ row, err := iter.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ cols := row.ColumnNames()
+ fmt.Println(cols)
+ for i := 0; i < len(cols); i++ {
+ fmt.Printf("\t%s", row.ColumnValue(i))
+ }
+ fmt.Printf("\n")
+ }
+ return nil
+}
+
+func main() {
+ ctx := context.Background()
+ uri, err := app.DefaultSpannerURI()
+ if err != nil {
+ app.Fatalf("failed to get Spanner URI: %v", err)
+ }
+ if os.Getenv("SPANNER_EMULATOR_HOST") != "" {
+ // Should only be done in the test/dev environment.
+ log.Printf("check if a Spanner instance is present")
+ err = db.CreateSpannerInstance(ctx, uri)
+ if err != nil {
+ app.Fatalf("failed to create Spanner instance: %v", err)
+ }
+ }
+ log.Printf("check if DB is present")
+ err = db.CreateSpannerDB(ctx, uri)
+ if err != nil {
+ app.Fatalf("failed to create Spanner DB: %v", err)
+ }
+ if len(os.Args) > 1 {
+ switch os.Args[1] {
+ case "migrate":
+ log.Printf("running schema migrations")
+ err = db.RunMigrations(ctx, uri.Full)
+ case "run":
+ if len(os.Args) < 3 {
+ app.Fatalf("second argument is the SQL query to run")
+ }
+ err = runSQL(ctx, uri, os.Args[2])
+ default:
+ app.Fatalf("unknown command: %s", os.Args[1])
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ log.Printf("finished!")
+}
diff --git a/syz-cluster/kernel-disk/cron.yaml b/syz-cluster/kernel-disk/cron.yaml
new file mode 100644
index 000000000000..8249e9c774e5
--- /dev/null
+++ b/syz-cluster/kernel-disk/cron.yaml
@@ -0,0 +1,45 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: kernel-repo-update
+spec:
+ schedule: "0 */6 * * *" # Update every 6 hours
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ restartPolicy: Never
+ volumes:
+ - name: git-repo
+ persistentVolumeClaim:
+ claimName: base-kernel-repo-pv-claim
+ containers:
+ - name: git-updater-debug-job
+ image: alpine/git:latest
+ imagePullPolicy: IfNotPresent
+ volumeMounts:
+ - name: git-repo
+ mountPath: /repo.git
+ resources:
+ requests:
+ cpu: 4
+ memory: 8G
+ limits:
+ cpu: 8
+ memory: 16G
+ command: # TODO: request the trees via the controller's API.
+ - "/bin/sh"
+ - "-c"
+ - |
+ cd /repo.git
+ if [ ! -d "refs" ]; then
+ git init --bare
+ fi
+ if ! git config --get remote.torvalds.url > /dev/null; then
+ git remote add torvalds git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
+ fi
+ git fetch torvalds --tags
+ git tag -f torvalds-head torvalds/master
diff --git a/syz-cluster/kernel-disk/kustomization.yaml b/syz-cluster/kernel-disk/kustomization.yaml
new file mode 100644
index 000000000000..aeff33f63d09
--- /dev/null
+++ b/syz-cluster/kernel-disk/kustomization.yaml
@@ -0,0 +1,6 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+resources:
+ - pvc.yaml
+ - cron.yaml
diff --git a/syz-cluster/kernel-disk/pvc.yaml b/syz-cluster/kernel-disk/pvc.yaml
new file mode 100644
index 000000000000..1977e969bca6
--- /dev/null
+++ b/syz-cluster/kernel-disk/pvc.yaml
@@ -0,0 +1,14 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: base-kernel-repo-pv-claim
+spec:
+ storageClassName: standard
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 32Gi
diff --git a/syz-cluster/overlays/dev/blobs-pvc-dev.yaml b/syz-cluster/overlays/dev/blobs-pvc-dev.yaml
new file mode 100644
index 000000000000..d001315a9eb4
--- /dev/null
+++ b/syz-cluster/overlays/dev/blobs-pvc-dev.yaml
@@ -0,0 +1,14 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: blob-storage-disk-claim
+spec:
+ accessModes:
+ - ReadWriteMany
+ resources:
+ requests:
+ storage: 1Gi
+ storageClassName: standard
diff --git a/syz-cluster/overlays/dev/fake-gcs.yaml b/syz-cluster/overlays/dev/fake-gcs.yaml
new file mode 100644
index 000000000000..362da197c342
--- /dev/null
+++ b/syz-cluster/overlays/dev/fake-gcs.yaml
@@ -0,0 +1,54 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: fake-gcs-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: fake-gcs-server
+ template:
+ metadata:
+ labels:
+ app: fake-gcs-server
+ spec:
+ initContainers:
+ - name: create-test-bucket
+ image: busybox
+ command: ["sh", "-c", "mkdir -p /data/test-bucket"]
+ volumeMounts:
+ - name: data-volume
+ mountPath: /data
+ containers:
+ - name: fake-gcs-server
+ imagePullPolicy: IfNotPresent
+ image: fsouza/fake-gcs-server
+ args: [
+ "-scheme", "http",
+ "-public-host", "fake-gcs-server.default.svc.cluster.local",
+ "-external-url", "http://fake-gcs-server.default.svc.cluster.local:4443"
+ ]
+ ports:
+ - containerPort: 4443
+ volumeMounts:
+ - name: data-volume
+ mountPath: /data
+ volumes:
+ - name: data-volume
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: fake-gcs-server
+spec:
+ selector:
+ app: fake-gcs-server
+ ports:
+ - protocol: TCP
+ port: 4443
+ targetPort: 4443
+ type: LoadBalancer
diff --git a/syz-cluster/overlays/dev/global-config.yaml b/syz-cluster/overlays/dev/global-config.yaml
new file mode 100644
index 000000000000..0ee6bb8b502f
--- /dev/null
+++ b/syz-cluster/overlays/dev/global-config.yaml
@@ -0,0 +1,12 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: global-config
+data:
+ SPANNER_EMULATOR_HOST: "cloud-spanner-emulator:9010"
+ SPANNER_DATABASE_URI: "projects/my-project/instances/my-instance/databases/db"
+ LOCAL_BLOB_STORAGE_PATH: "/blob-storage"
+ PARALLEL_WORKERS: "1" # Process only one series at a time.
diff --git a/syz-cluster/overlays/dev/kustomization.yaml b/syz-cluster/overlays/dev/kustomization.yaml
new file mode 100644
index 000000000000..815048f4e51a
--- /dev/null
+++ b/syz-cluster/overlays/dev/kustomization.yaml
@@ -0,0 +1,42 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+resources:
+ - ../../controller
+ - ../../dashboard
+ - ../../series-tracker
+ - ../../kernel-disk
+ - global-config.yaml
+ - https://github.com/argoproj/argo-workflows/releases/download/v3.6.2/install.yaml
+ - workflow-roles.yaml
+ - fake-gcs.yaml
+ - workflow-artifacts.yaml
+ - blobs-pvc-dev.yaml
+
+patches:
+ - target:
+ kind: Deployment
+ patch: |-
+ - op: replace
+ path: /spec/template/spec/containers/0/imagePullPolicy
+ value: IfNotPresent
+ - target:
+ kind: ConfigMap
+ name: workflow-controller-configmap
+ patch: |-
+ - op: replace
+ path: /data
+ value:
+ config: |
+ executor:
+ env:
+ - name: STORAGE_EMULATOR_HOST
+ value: http://fake-gcs-server.default.svc.cluster.local:4443
+
+images:
+ - name: controller-image
+ newName: controller-image-local:latest
+ - name: web-dashboard-image
+ newName: web-dashboard-local:latest
+ - name: series-tracker-image
+ newName: series-tracker-local:latest
diff --git a/syz-cluster/overlays/dev/workflow-artifacts.yaml b/syz-cluster/overlays/dev/workflow-artifacts.yaml
new file mode 100644
index 000000000000..fe34bf84d4f9
--- /dev/null
+++ b/syz-cluster/overlays/dev/workflow-artifacts.yaml
@@ -0,0 +1,13 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: artifact-repositories
+ annotations:
+ workflows.argoproj.io/default-artifact-repository: gcs-repo
+data:
+ gcs-repo: |
+ gcs:
+ bucket: test-bucket
diff --git a/syz-cluster/overlays/dev/workflow-roles.yaml b/syz-cluster/overlays/dev/workflow-roles.yaml
new file mode 100644
index 000000000000..e4722a2bec5d
--- /dev/null
+++ b/syz-cluster/overlays/dev/workflow-roles.yaml
@@ -0,0 +1,69 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ namespace: default
+ name: argo-workflow-role
+rules:
+- apiGroups:
+ - argoproj.io
+ resources:
+ - workflowartifactgctasks
+ - workflows
+ verbs:
+ - get
+ - list
+ - watch
+ - create
+ - update
+ - patch
+ - delete
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: argo-workflow-list-binding
+ namespace: default
+subjects:
+- kind: ServiceAccount
+ name: default
+ namespace: default
+roleRef:
+ kind: Role
+ name: argo-workflow-role
+ apiGroup: rbac.authorization.k8s.io
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ namespace: default
+ name: executor
+rules:
+- apiGroups: ["argoproj.io"]
+ resources:
+ - workflowtaskresults
+ verbs:
+ - create
+ - patch
+
+---
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: executor-default
+ namespace: default
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: executor
+subjects:
+- kind: ServiceAccount
+ name: default
+ namespace: default
diff --git a/syz-cluster/pkg/api/api.go b/syz-cluster/pkg/api/api.go
new file mode 100644
index 000000000000..510dd1c474c1
--- /dev/null
+++ b/syz-cluster/pkg/api/api.go
@@ -0,0 +1,102 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package api
+
+import "time"
+
+type Series struct {
+ ID string
+ PublishedAt time.Time
+ Cc []string
+ Patches [][]byte
+}
+
+type TriageResult struct {
+ // If true, ignore the patch series completely.
+ Skip bool `json:"skip"`
+ // Fuzzing configurations to try.
+ Fuzz []*FuzzConfig `json:"fuzz"`
+}
+
+// The data layout faclitates the simplicity of the workflow definition.
+type FuzzConfig struct {
+ Base BuildRequest `json:"base"`
+ Patched BuildRequest `json:"patched"`
+ Config string `json:"config"` // Refers to workflow/configs/{}.
+}
+
+// The triage step of the workflow will request these from controller.
+type Tree struct {
+ Name string `json:"name"` // Primary key.
+ URL string `json:"URL"`
+ Branch string `json:"branch"`
+ EmailLists []string `json:"email_lists"`
+ Priority int64 `json:"priority"` // Higher numbers mean higher priority.
+ ConfigName string `json:"config_name"`
+}
+
+type BuildRequest struct {
+ Arch string `json:"arch"`
+ TreeName string `json:"tree_name"`
+ CommitHash string `json:"commit_hash"`
+ ConfigName string `json:"config_name"` // These are known to both the triage and build steps.
+ SeriesID string `json:"series_id"`
+}
+
+// BuildResult is returned from the build workflow step.
+type BuildResult struct {
+ BuildID string `json:"build_id"`
+ Success bool `json:"success"`
+}
+
+type Build struct {
+ Arch string `json:"arch"`
+ TreeName string `json:"tree_name"`
+ CommitHash string `json:"commit_hash"`
+ CommitDate time.Time `json:"commit_date"`
+ ConfigName string `json:"config_name"`
+ SeriesID string `json:"series_id"`
+ BuildSuccess bool `json:"build_success"`
+}
+
+const (
+ TestRunning string = "running"
+ TestPassed string = "passed"
+ TestFailed string = "failed" // TODO: drop it? only mark completion?
+ TestError string = "error"
+)
+
+type TestResult struct {
+ SessionID string `json:"session_id"`
+ BaseBuildID string `json:"base_build_id"`
+ PatchedBuildID string `json:"patched_build_id"`
+ TestName string `json:"test_name"`
+ Result string `json:"result"`
+ Log []byte `json:"log"`
+}
+
+type BootResult struct {
+ Success bool `json:"success"`
+}
+
+// Finding is a kernel crash, boot error, etc. found during a test.
+type Finding struct {
+ SessionID string `json:"session_id"`
+ TestName string `json:"test_name"`
+ Title string `json:"title"`
+ Report []byte `json:"report"`
+ Log []byte `json:"log"`
+}
+
+// For now, there's no reason to obtain these really via a real API call.
+var defaultTrees = []*Tree{
+ {
+ Name: `torvalds`,
+ URL: `git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git`,
+ Branch: `master`,
+ Priority: 0,
+ EmailLists: []string{},
+ ConfigName: `upstream-apparmor-kasan.config`,
+ },
+}
diff --git a/syz-cluster/pkg/api/client.go b/syz-cluster/pkg/api/client.go
new file mode 100644
index 000000000000..5f4121c9e250
--- /dev/null
+++ b/syz-cluster/pkg/api/client.go
@@ -0,0 +1,124 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package api
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+)
+
+type Client struct {
+ baseURL string
+}
+
+func NewClient(url string) *Client {
+ return &Client{baseURL: strings.TrimRight(url, "/")}
+}
+
+func (client Client) GetSessionSeries(_ context.Context, sessionID string) (*Series, error) {
+ // TODO: add support for the context.
+ return getJSON[Series](client.baseURL + "/sessions/" + sessionID + "/series")
+}
+
+func (client Client) GetSeries(_ context.Context, seriesID string) (*Series, error) {
+ // TODO: add support for the context.
+ return getJSON[Series](client.baseURL + "/series/" + seriesID)
+}
+
+func (client Client) GetTrees() []*Tree {
+ return defaultTrees
+}
+
+type LastBuildReq struct {
+ Arch string
+ ConfigName string
+ TreeName string
+}
+
+func (client Client) LastSuccessfulBuild(ctx context.Context, req *LastBuildReq) (*Build, error) {
+ return postJSON[LastBuildReq, Build](ctx, client.baseURL+"/builds/last", req)
+}
+
+type UploadBuildReq struct {
+ Build
+ Config []byte `json:"config"`
+ Log []byte `json:"log"`
+}
+
+type UploadBuildResp struct {
+ ID string
+}
+
+func (client Client) UploadBuild(ctx context.Context, req *UploadBuildReq) (*UploadBuildResp, error) {
+ return postJSON[UploadBuildReq, UploadBuildResp](ctx, client.baseURL+"/builds/upload", req)
+}
+
+func (client Client) UploadTestResult(ctx context.Context, req *TestResult) error {
+ _, err := postJSON[TestResult, any](ctx, client.baseURL+"/tests/upload", req)
+ return err
+}
+
+func (client Client) UploadFinding(ctx context.Context, req *Finding) error {
+ _, err := postJSON[Finding, any](ctx, client.baseURL+"/findings/upload", req)
+ return err
+}
+
+func getJSON[Resp any](url string) (*Resp, error) {
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ if err := ensure200(resp); err != nil {
+ return nil, err
+ }
+ var data Resp
+ err = json.NewDecoder(resp.Body).Decode(&data)
+ if err != nil {
+ return nil, err
+ }
+ return &data, nil
+}
+
+func postJSON[Req any, Resp any](ctx context.Context, url string, req *Req) (*Resp, error) {
+ jsonBody, err := json.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+ httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(jsonBody))
+ if err != nil {
+ return nil, err
+ }
+ httpReq.Header.Set("Content-Type", "application/json")
+ resp, err := http.DefaultClient.Do(httpReq)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ if err := ensure200(resp); err != nil {
+ return nil, err
+ }
+ var data Resp
+ err = json.NewDecoder(resp.Body).Decode(&data)
+ if err != nil {
+ return nil, err
+ }
+ return &data, nil
+}
+
+func ensure200(resp *http.Response) error {
+ if resp.StatusCode != http.StatusOK {
+ bodyBytes, _ := io.ReadAll(resp.Body)
+ if len(bodyBytes) > 128 {
+ bodyBytes = bodyBytes[:128]
+ }
+ return fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, bodyBytes)
+ }
+ return nil
+}
diff --git a/syz-cluster/pkg/app/env.go b/syz-cluster/pkg/app/env.go
new file mode 100644
index 000000000000..53ba9a77fba1
--- /dev/null
+++ b/syz-cluster/pkg/app/env.go
@@ -0,0 +1,80 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package app
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+
+ "cloud.google.com/go/spanner"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/blob"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+)
+
+type AppEnvironment struct {
+ Spanner *spanner.Client
+ BlobStorage blob.Storage
+}
+
+func Environment(ctx context.Context) (*AppEnvironment, error) {
+ spanner, err := DefaultSpanner(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("failed to set up a Spanner client: %w", err)
+ }
+ storage, err := DefaultStorage()
+ if err != nil {
+ return nil, fmt.Errorf("failed to set up the blob storage: %w", err)
+ }
+ return &AppEnvironment{
+ Spanner: spanner,
+ BlobStorage: storage,
+ }, nil
+}
+
+func TestEnvironment(t *testing.T) (*AppEnvironment, context.Context) {
+ client, ctx := db.NewTransientDB(t)
+ return &AppEnvironment{
+ Spanner: client,
+ BlobStorage: blob.NewLocalStorage(t.TempDir()),
+ }, ctx
+}
+
+func DefaultSpannerURI() (db.ParsedURI, error) {
+ rawURI := os.Getenv("SPANNER_DATABASE_URI")
+ if rawURI == "" {
+ return db.ParsedURI{}, fmt.Errorf("no SPANNER_DATABASE_URI is set")
+ }
+ return db.ParseURI(rawURI)
+}
+
+func DefaultSpanner(ctx context.Context) (*spanner.Client, error) {
+ uri, err := DefaultSpannerURI()
+ if err != nil {
+ // Validate the URI early on.
+ return nil, err
+ }
+ return spanner.NewClient(ctx, uri.Full)
+}
+
+func DefaultStorage() (blob.Storage, error) {
+ // LOCAL_BLOB_STORAGE_PATH is set in the dev environment.
+ path := os.Getenv("LOCAL_BLOB_STORAGE_PATH")
+ if path == "" {
+ // TODO: implement GCS support.
+ return nil, fmt.Errorf("empty LOCAL_BLOB_STORAGE_PATH")
+ }
+ err := os.MkdirAll(path, 0666)
+ if err != nil {
+ return nil, err
+ }
+ return blob.NewLocalStorage(path), nil
+}
+
+func DefaultClient() *api.Client {
+ // TODO: take it from some env variable.
+ return api.NewClient(`http://controller-service:8080`)
+}
diff --git a/syz-cluster/pkg/app/logging.go b/syz-cluster/pkg/app/logging.go
new file mode 100644
index 000000000000..a4202dd842e6
--- /dev/null
+++ b/syz-cluster/pkg/app/logging.go
@@ -0,0 +1,16 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package app
+
+import "log"
+
+// TODO: catch these with monitoring.
+
+func Errorf(fmt string, args ...interface{}) {
+ log.Printf(fmt, args...)
+}
+
+func Fatalf(fmt string, args ...interface{}) {
+ log.Fatalf(fmt, args...)
+}
diff --git a/syz-cluster/pkg/blob/storage.go b/syz-cluster/pkg/blob/storage.go
new file mode 100644
index 000000000000..a38899c33eff
--- /dev/null
+++ b/syz-cluster/pkg/blob/storage.go
@@ -0,0 +1,72 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package blob
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+// Storage is not assumed to be used for partciularly large objects (e.g. GB of size),
+// but rather for blobs that risk overwhelming Spanner column size limits.
+type Storage interface {
+ // Store returns a URI to use later.
+ Store(source io.Reader) (string, error)
+ Update(key string, source io.Reader) error
+ Read(uri string) (io.ReadCloser, error)
+}
+
+var _ Storage = (*LocalStorage)(nil)
+
+type LocalStorage struct {
+ baseFolder string
+}
+
+func NewLocalStorage(baseFolder string) *LocalStorage {
+ return &LocalStorage{baseFolder: baseFolder}
+}
+
+const localStoragePrefix = "local://"
+
+func (ls *LocalStorage) Store(source io.Reader) (string, error) {
+ name := fmt.Sprint(time.Now().UnixNano())
+ err := ls.writeFile(name, source)
+ if err != nil {
+ return "", err
+ }
+ return localStoragePrefix + name, nil
+}
+
+func (ls *LocalStorage) Update(uri string, source io.Reader) error {
+ if !strings.HasPrefix(uri, localStoragePrefix) {
+ return fmt.Errorf("unsupported URI type")
+ }
+ return ls.writeFile(strings.TrimPrefix(uri, localStoragePrefix), source)
+}
+
+func (ls *LocalStorage) Read(uri string) (io.ReadCloser, error) {
+ if !strings.HasPrefix(uri, localStoragePrefix) {
+ return nil, fmt.Errorf("unsupported URI type")
+ }
+ // TODO: add some other URI validation checks?
+ path := filepath.Join(ls.baseFolder, strings.TrimPrefix(uri, localStoragePrefix))
+ return os.Open(path)
+}
+
+func (ls *LocalStorage) writeFile(name string, source io.Reader) error {
+ file, err := os.Create(filepath.Join(ls.baseFolder, name))
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ _, err = io.Copy(file, source)
+ if err != nil {
+ return fmt.Errorf("failed to save data: %w", err)
+ }
+ return nil
+}
diff --git a/syz-cluster/pkg/blob/storage_test.go b/syz-cluster/pkg/blob/storage_test.go
new file mode 100644
index 000000000000..54bc255c79c0
--- /dev/null
+++ b/syz-cluster/pkg/blob/storage_test.go
@@ -0,0 +1,36 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package blob
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLocalStorage(t *testing.T) {
+ storage := NewLocalStorage(t.TempDir())
+ var uris []string
+ for i := 0; i < 2; i++ {
+ content := fmt.Sprintf("object #%d", i)
+ uri, err := storage.Store(bytes.NewReader([]byte(content)))
+ assert.NoError(t, err)
+ uris = append(uris, uri)
+ }
+ for i, uri := range uris {
+ reader, err := storage.Read(uri)
+ assert.NoError(t, err)
+ readBytes, err := io.ReadAll(reader)
+ reader.Close()
+ assert.NoError(t, err)
+ assert.EqualValues(t, fmt.Sprintf("object #%d", i), readBytes)
+ }
+ _, err := storage.Read(localStoragePrefix + "abcdef")
+ assert.Error(t, err)
+ _, err = storage.Read("abcdef")
+ assert.Error(t, err)
+}
diff --git a/syz-cluster/pkg/db/build_repo.go b/syz-cluster/pkg/db/build_repo.go
new file mode 100644
index 000000000000..e87a18f6350c
--- /dev/null
+++ b/syz-cluster/pkg/db/build_repo.go
@@ -0,0 +1,59 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "context"
+
+ "cloud.google.com/go/spanner"
+ "github.com/google/uuid"
+)
+
+type BuildRepository struct {
+ client *spanner.Client
+ *genericEntityOps[Build, string]
+}
+
+func NewBuildRepository(client *spanner.Client) *BuildRepository {
+ return &BuildRepository{
+ client: client,
+ genericEntityOps: &genericEntityOps[Build, string]{
+ client: client,
+ keyField: "ID",
+ table: "Builds",
+ },
+ }
+}
+
+func (repo *BuildRepository) Insert(ctx context.Context, build *Build) error {
+ if build.ID == "" {
+ build.ID = uuid.New().String()
+ }
+ _, err := repo.client.ReadWriteTransaction(ctx,
+ func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
+ m, err := spanner.InsertStruct("Builds", build)
+ if err != nil {
+ return err
+ }
+ return txn.BufferWrite([]*spanner.Mutation{m})
+ })
+ return err
+}
+
+func (repo *BuildRepository) LastBuiltTree(ctx context.Context, arch, tree, config string) (*Build, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM `Builds` WHERE `TreeName` = @tree" +
+ " AND `Arch` = @arch AND `ConfigName` = @config" +
+ " AND `SeriesID` IS NULL AND `Status` = 'success'" +
+ " ORDER BY `CommitDate` DESC LIMIT 1",
+ Params: map[string]interface{}{
+ "tree": tree,
+ "arch": arch,
+ "config": config,
+ },
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readOne[Build](iter)
+}
diff --git a/syz-cluster/pkg/db/build_repo_test.go b/syz-cluster/pkg/db/build_repo_test.go
new file mode 100644
index 000000000000..3b070a12aff9
--- /dev/null
+++ b/syz-cluster/pkg/db/build_repo_test.go
@@ -0,0 +1,60 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLastSuccessfulBuild(t *testing.T) {
+ client, ctx := NewTransientDB(t)
+ repo := NewBuildRepository(client)
+
+ build, err := repo.LastBuiltTree(ctx, "amd64", "mainline", "kasan")
+ assert.NoError(t, err)
+ assert.Nil(t, build)
+
+ // Insert a non-successful.
+ err = repo.Insert(ctx, &Build{
+ Arch: "amd64",
+ TreeName: "mainline",
+ CommitHash: "bad",
+ CommitDate: time.Now(),
+ ConfigName: "kasan",
+ Status: BuildFailed,
+ })
+ assert.NoError(t, err)
+
+ // It should not be queried.
+ build, err = repo.LastBuiltTree(ctx, "amd64", "mainline", "kasan")
+ assert.NoError(t, err)
+ assert.Nil(t, build)
+
+ // Insert the correct one.
+ err = repo.Insert(ctx, &Build{
+ Arch: "amd64",
+ TreeName: "mainline",
+ CommitHash: "good",
+ CommitDate: time.Now(),
+ ConfigName: "kasan",
+ Status: BuildSuccess,
+ })
+ assert.NoError(t, err)
+
+ // It should be in the output.
+ build, err = repo.LastBuiltTree(ctx, "amd64", "mainline", "kasan")
+ assert.NoError(t, err)
+ assert.Equal(t, "good", build.CommitHash)
+
+ // But not for different arguments.
+ build, err = repo.LastBuiltTree(ctx, "arm64", "mainline", "kasan")
+ assert.NoError(t, err)
+ assert.Nil(t, build)
+ build, err = repo.LastBuiltTree(ctx, "amd64", "mainline", "kmsan")
+ assert.NoError(t, err)
+ assert.Nil(t, build)
+}
diff --git a/syz-cluster/pkg/db/entities.go b/syz-cluster/pkg/db/entities.go
new file mode 100644
index 000000000000..dcaa2cb44bfa
--- /dev/null
+++ b/syz-cluster/pkg/db/entities.go
@@ -0,0 +1,87 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "time"
+
+ "cloud.google.com/go/spanner"
+)
+
+type Series struct {
+ ID string `spanner:"ID"`
+ ExtID string `spanner:"ExtID"`
+ AuthorName string `spanner:"AuthorName"`
+ AuthorEmail string `spanner:"AuthorEmail"`
+ Title string `spanner:"Title"`
+ Link string `spanner:"Link"`
+ Version int64 `spanner:"Version"`
+ PublishedAt time.Time `spanner:"PublishedAt"`
+ LatestSessionID spanner.NullString `spanner:"LatestSessionID"`
+ Cc []string `spanner:"Cc"`
+}
+
+func (s *Series) SetLatestSession(session *Session) {
+ s.LatestSessionID = spanner.NullString{StringVal: session.ID, Valid: true}
+}
+
+type Patch struct {
+ ID string `spanner:"ID"`
+ Seq int64 `spanner:"Seq"`
+ SeriesID string `spanner:"SeriesID"`
+ Title string `spanner:"Title"`
+ Link string `spanner:"Link"`
+ BodyURI string `spanner:"BodyURI"`
+}
+
+type Build struct {
+ ID string `spanner:"ID"`
+ TreeName string `spanner:"TreeName"`
+ CommitHash string `spanner:"CommitHash"`
+ CommitDate time.Time `spanner:"CommitDate"`
+ SeriesID spanner.NullString `spanner:"SeriesID"`
+ Arch string `spanner:"Arch"`
+ ConfigName string `spanner:"ConfigName"`
+ ConfigURI string `spanner:"ConfigURI"`
+ Status string `spanner:"Status"`
+}
+
+func (b *Build) SetSeriesID(val string) {
+ b.SeriesID = spanner.NullString{StringVal: val, Valid: true}
+}
+
+const (
+ BuildFailed string = "build_failed"
+ // BuiltNotTested string = "built"
+ // BuildTestFailed string = "tests_failed"
+ BuildSuccess string = "success"
+)
+
+type Session struct {
+ ID string `spanner:"ID"`
+ SeriesID string `spanner:"SeriesID"`
+ CreatedAt time.Time `spanner:"CreatedAt"`
+ FinishedAt spanner.NullTime `spanner:"FinishedAt"`
+ LogURI string `spanner:"LogURI"`
+}
+
+func (s *Session) SetFinishedAt(t time.Time) {
+ s.FinishedAt = spanner.NullTime{Time: t, Valid: true}
+}
+
+type SessionTest struct {
+ SessionID string `spanner:"SessionID"`
+ BaseBuildID spanner.NullString `spanner:"BaseBuildID"`
+ PatchedBuildID spanner.NullString `spanner:"PatchedBuildID"`
+ TestName string `spanner:"TestName"`
+ Result string `spanner:"Result"`
+}
+
+type Finding struct {
+ SessionID string `spanner:"SessionID"`
+ TestName string `spanner:"TestName"`
+ Title string `spanner:"Title"`
+ ReportURI string `spanner:"ReportURI"`
+ LogURI string `spanner:"LogURI"`
+}
diff --git a/syz-cluster/pkg/db/finding_repo.go b/syz-cluster/pkg/db/finding_repo.go
new file mode 100644
index 000000000000..93577d32cdfb
--- /dev/null
+++ b/syz-cluster/pkg/db/finding_repo.go
@@ -0,0 +1,65 @@
+// Copyright 2025 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "context"
+ "errors"
+
+ "cloud.google.com/go/spanner"
+ "google.golang.org/api/iterator"
+)
+
+type FindingRepository struct {
+ client *spanner.Client
+}
+
+func NewFindingRepository(client *spanner.Client) *FindingRepository {
+ return &FindingRepository{
+ client: client,
+ }
+}
+
+var ErrFindingExists = errors.New("the finding already exists")
+
+// Save either adds the finding to the database or returns ErrFindingExists.
+func (repo *FindingRepository) Save(ctx context.Context, finding *Finding) error {
+ _, err := repo.client.ReadWriteTransaction(ctx,
+ func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
+ stmt := spanner.Statement{
+ SQL: "SELECT * from `Findings` WHERE `SessionID`=@sessionID " +
+ "AND `TestName` = @testName AND `Title`=@title",
+ Params: map[string]interface{}{
+ "sessionID": finding.SessionID,
+ "testName": finding.TestName,
+ "title": finding.Title,
+ },
+ }
+ iter := txn.Query(ctx, stmt)
+ defer iter.Stop()
+ _, iterErr := iter.Next()
+ if iterErr == nil {
+ return ErrFindingExists
+ } else if iterErr != iterator.Done {
+ return iterErr
+ }
+ m, err := spanner.InsertStruct("Findings", finding)
+ if err != nil {
+ return err
+ }
+ return txn.BufferWrite([]*spanner.Mutation{m})
+ })
+ return err
+}
+
+// nolint: dupl
+func (repo *FindingRepository) ListForSession(ctx context.Context, session *Session) ([]*Finding, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM `Findings` WHERE `SessionID` = @session ORDER BY `TestName`, `Title`",
+ Params: map[string]interface{}{"session": session.ID},
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readEntities[Finding](iter)
+}
diff --git a/syz-cluster/pkg/db/finding_repo_test.go b/syz-cluster/pkg/db/finding_repo_test.go
new file mode 100644
index 000000000000..9afa22edeafb
--- /dev/null
+++ b/syz-cluster/pkg/db/finding_repo_test.go
@@ -0,0 +1,71 @@
+// Copyright 2025 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "testing"
+ "time"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestFindingRepo(t *testing.T) {
+ client, ctx := NewTransientDB(t)
+ sessionRepo := NewSessionRepository(client)
+ seriesRepo := NewSeriesRepository(client)
+ findingRepo := NewFindingRepository(client)
+ testsRepo := NewSessionTestRepository(client)
+
+ series := &Series{ExtID: "some-series"}
+ err := seriesRepo.Insert(ctx, series, nil)
+ assert.NoError(t, err)
+
+ session := &Session{CreatedAt: time.Now()}
+ err = sessionRepo.Insert(ctx, series, session)
+ assert.NoError(t, err)
+
+ // Add test steps.
+ for _, name := range []string{"first", "second"} {
+ err = testsRepo.InsertOrUpdate(ctx, &SessionTest{
+ SessionID: session.ID,
+ TestName: name,
+ Result: api.TestPassed,
+ })
+ assert.NoError(t, err)
+ }
+
+ // Add findings.
+ toInsert := []*Finding{
+ {
+ TestName: "first",
+ Title: "A",
+ SessionID: session.ID,
+ },
+ {
+ TestName: "first",
+ Title: "B",
+ SessionID: session.ID,
+ },
+ {
+ TestName: "second",
+ Title: "A",
+ SessionID: session.ID,
+ },
+ }
+ // Insert them all.
+ for _, finding := range toInsert {
+ err := findingRepo.Save(ctx, finding)
+ assert.NoError(t, err, "finding=%q", finding)
+ }
+ // Now it should report a duplicate each time.
+ for _, finding := range toInsert {
+ err := findingRepo.Save(ctx, finding)
+ assert.ErrorIs(t, err, ErrFindingExists)
+ }
+
+ list, err := findingRepo.ListForSession(ctx, session)
+ assert.NoError(t, err)
+ assert.Equal(t, toInsert, list)
+}
diff --git a/syz-cluster/pkg/db/migrations/1_initialize.down.sql b/syz-cluster/pkg/db/migrations/1_initialize.down.sql
new file mode 100644
index 000000000000..050a78ac4b99
--- /dev/null
+++ b/syz-cluster/pkg/db/migrations/1_initialize.down.sql
@@ -0,0 +1,10 @@
+BEGIN TRANSACTION;
+
+DROP TABLE Series;
+DROP TABLE Patches;
+DROP TABLE Sessions;
+DROP TABLE SessionTests;
+DROP TABLE Builds;
+DROP TABLE Findings;
+
+COMMIT;
diff --git a/syz-cluster/pkg/db/migrations/1_initialize.up.sql b/syz-cluster/pkg/db/migrations/1_initialize.up.sql
new file mode 100644
index 000000000000..b7dcfea260d1
--- /dev/null
+++ b/syz-cluster/pkg/db/migrations/1_initialize.up.sql
@@ -0,0 +1,85 @@
+CREATE TABLE Series (
+ ID STRING(36) NOT NULL, -- UUID
+ ExtID STRING(128) NOT NULL, -- For LKML, it's a message ID of the series.
+ AuthorName STRING(512) NOT NULL,
+ AuthorEmail STRING(512) NOT NULL,
+ Title STRING(512) NOT NULL,
+ Version INT64 NOT NULL,
+ Link STRING(512) NOT NULL,
+ PublishedAt TIMESTAMP NOT NULL,
+ LatestSessionID STRING(36),
+ Cc ARRAY,
+) PRIMARY KEY (ID);
+
+CREATE INDEX SeriesByPublishedAt ON Series (PublishedAt);
+CREATE UNIQUE INDEX SeriesByExtID ON Series (ExtID);
+
+CREATE TABLE Patches (
+ ID STRING(36) NOT NULL, -- UUID
+ SeriesID STRING(36) NOT NULL,
+ Seq INT64 NOT NULL,
+ Title STRING(512) NOT NULL,
+ Link STRING(512) NOT NULL,
+ BodyURI STRING(512) NOT NULL, -- These might be too big to store directly in Spanner.
+ CONSTRAINT FK_SeriesPatches FOREIGN KEY (SeriesID) REFERENCES Series (ID),
+) PRIMARY KEY(ID);
+
+CREATE INDEX PatchesBySeriesAndSeq ON Patches (SeriesID, Seq);
+
+CREATE TABLE Builds (
+ ID STRING(36) NOT NULL, -- UUID
+ TreeName STRING(128) NOT NULL,
+ CommitHash STRING(256) NOT NULL,
+ CommitDate TIMESTAMP NOT NULL,
+ SeriesID STRING(36), -- NULL if no series were applied to the tree.
+ Arch STRING(128) NOT NULL,
+ ConfigName STRING(256) NOT NULL, -- E.g. subsystem-specific build configuration names. Known to the builders.
+ ConfigURI STRING(512) NOT NULL, -- The config actually used during the build.
+ Status STRING(128) NOT NULL,
+ CONSTRAINT FK_Series FOREIGN KEY (SeriesID) REFERENCES Series (ID),
+ CONSTRAINT StatusEnum CHECK (Status IN ('build_failed', 'built', 'tests_failed', 'success')),
+) PRIMARY KEY(ID);
+
+-- It does not cover all fields that will be requested, but it should be discriminative enough.
+CREATE INDEX LastSuccessfulBuild ON Builds (TreeName, SeriesID, CommitDate DESC);
+
+/*
+ There may be multiple sessions per a single series, e.g. if
+ 1) We happened to re-deploy the new version when the previous was being fuzzed.
+ 2) We want to run bechmarks: some sessions will correspond solely to them.
+*/
+CREATE TABLE Sessions (
+ ID STRING(36) NOT NULL, -- UUID
+ SeriesID STRING(36) NOT NULL,
+ CreatedAt TIMESTAMP NOT NULL,
+ FinishedAt TIMESTAMP,
+ LogURI STRING(512) NOT NULL,
+ -- TODO: moderation/reporting.
+ CONSTRAINT FK_SeriesSessions FOREIGN KEY (SeriesID) REFERENCES Series (ID),
+) PRIMARY KEY(ID);
+
+ALTER TABLE Series ADD CONSTRAINT FK_SeriesLatestSession FOREIGN KEY (LatestSessionID) REFERENCES Sessions (ID);
+
+-- Tests are filled after they are finished.
+CREATE TABLE SessionTests (
+ SessionID STRING(36) NOT NULL, -- UUID
+ TestName STRING(256) NOT NULL,
+-- Parameters JSON, -- Test-dependent set of parameters.
+ Result STRING(36) NOT NULL,
+ BaseBuildID STRING(36),
+ PatchedBuildID STRING(36),
+ CONSTRAINT FK_SessionResults FOREIGN KEY (SessionID) REFERENCES Sessions (ID),
+ CONSTRAINT ResultEnum CHECK (Result IN ('passed', 'failed', 'error', 'running')),
+ CONSTRAINT FK_BaseBuild FOREIGN KEY (BaseBuildID) REFERENCES Builds (ID),
+ CONSTRAINT FK_PatchedBuild FOREIGN KEY (PatchedBuildID) REFERENCES Builds (ID),
+) PRIMARY KEY(SessionID, TestName);
+
+CREATE TABLE Findings (
+ SessionID STRING(36) NOT NULL,
+ TestName STRING(256) NOT NULL,
+ Title STRING(256) NOT NULL,
+ ReportURI STRING(256) NOT NULL,
+ LogURI STRING(256) NOT NULL,
+ CONSTRAINT FK_SessionCrashes FOREIGN KEY (SessionID) REFERENCES Sessions (ID),
+ CONSTRAINT FK_TestCrashes FOREIGN KEY (SessionID, TestName) REFERENCES SessionTests (SessionID, TestName),
+) PRIMARY KEY(SessionID, TestName, Title);
diff --git a/syz-cluster/pkg/db/series_repo.go b/syz-cluster/pkg/db/series_repo.go
new file mode 100644
index 000000000000..2c449f5318be
--- /dev/null
+++ b/syz-cluster/pkg/db/series_repo.go
@@ -0,0 +1,208 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+// TODO: split off some SeriesPatchesRepository.
+
+import (
+ "context"
+ "errors"
+ "sync"
+ "time"
+
+ "cloud.google.com/go/spanner"
+ "github.com/google/uuid"
+ "google.golang.org/api/iterator"
+)
+
+type SeriesRepository struct {
+ client *spanner.Client
+ *genericEntityOps[Series, string]
+}
+
+func NewSeriesRepository(client *spanner.Client) *SeriesRepository {
+ return &SeriesRepository{
+ client: client,
+ genericEntityOps: &genericEntityOps[Series, string]{
+ client: client,
+ keyField: "ID",
+ table: "Series",
+ },
+ }
+}
+
+// TODO: move to SeriesPatchesRepository?
+func (repo *SeriesRepository) PatchByID(ctx context.Context, id string) (*Patch, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM Patches WHERE ID=@id",
+ Params: map[string]interface{}{"id": id},
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readOne[Patch](iter)
+}
+
+var ErrSeriesExists = errors.New("the series already exists")
+
+// Insert() checks whether there already exists a series with the same ExtID.
+// Since Patch content is stored elsewhere, we do not demand it be filled out before calling Insert().
+// Instead, Insert() obtains this data via a callback.
+func (repo *SeriesRepository) Insert(ctx context.Context, series *Series,
+ queryPatches func() ([]*Patch, error)) error {
+ var patches []*Patch
+ var patchesErr error
+ var patchesOnce sync.Once
+ doQueryPatches := func() {
+ if queryPatches == nil {
+ return
+ }
+ patches, patchesErr = queryPatches()
+ }
+ if series.ID == "" {
+ series.ID = uuid.New().String()
+ }
+ _, err := repo.client.ReadWriteTransaction(ctx,
+ func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
+ // Check if the series already exists.
+ stmt := spanner.Statement{
+ SQL: "SELECT 1 from `Series` WHERE `ExtID`=@extID",
+ Params: map[string]interface{}{"ExtID": series.ExtID},
+ }
+ iter := txn.Query(ctx, stmt)
+ defer iter.Stop()
+
+ _, iterErr := iter.Next()
+ if iterErr == nil {
+ return ErrSeriesExists
+ } else if iterErr != iterator.Done {
+ return iterErr
+ }
+ // Query patches (once).
+ patchesOnce.Do(doQueryPatches)
+ if patchesErr != nil {
+ return patchesErr
+ }
+ // Save the objects.
+ var stmts []*spanner.Mutation
+ seriesStmt, err := spanner.InsertStruct("Series", series)
+ if err != nil {
+ return err
+ }
+ stmts = append(stmts, seriesStmt)
+ for _, patch := range patches {
+ patch.ID = uuid.New().String()
+ patch.SeriesID = series.ID
+ stmt, err := spanner.InsertStruct("Patches", patch)
+ if err != nil {
+ return err
+ }
+ stmts = append(stmts, stmt)
+ }
+ return txn.BufferWrite(stmts)
+ })
+ return err
+}
+
+func (repo *SeriesRepository) Count(ctx context.Context) (int, error) {
+ stmt := spanner.Statement{SQL: "SELECT COUNT(*) FROM `Series`"}
+ var count int64
+ err := repo.client.Single().Query(ctx, stmt).Do(func(row *spanner.Row) error {
+ return row.Column(0, &count)
+ })
+ return int(count), err
+}
+
+type SeriesWithSession struct {
+ Series *Series
+ Session *Session
+}
+
+// ListLatest() returns the list of series ordered by the decreasing PublishedAt value.
+func (repo *SeriesRepository) ListLatest(ctx context.Context,
+ maxPublishedAt time.Time, limit int) ([]*SeriesWithSession, error) {
+ ro := repo.client.ReadOnlyTransaction()
+ defer ro.Close()
+
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM Series",
+ Params: map[string]interface{}{},
+ }
+ if !maxPublishedAt.IsZero() {
+ stmt.SQL += " WHERE PublishedAt < @toTime"
+ stmt.Params["toTime"] = maxPublishedAt
+ }
+ stmt.SQL += " ORDER BY PublishedAt DESC"
+ if limit > 0 {
+ stmt.SQL += " LIMIT @limit"
+ stmt.Params["limit"] = limit
+ }
+ iter := ro.Query(ctx, stmt)
+ defer iter.Stop()
+
+ seriesList, err := readEntities[Series](iter)
+ if err != nil {
+ return nil, err
+ }
+
+ // Now query Sessions.
+ var keys []string
+ var ret []*SeriesWithSession
+ idToSeries := map[string]*SeriesWithSession{}
+ for _, series := range seriesList {
+ if !series.LatestSessionID.IsNull() {
+ keys = append(keys, series.LatestSessionID.String())
+ }
+ obj := &SeriesWithSession{Series: series}
+ ret = append(ret, obj)
+ idToSeries[series.ID] = obj
+ }
+ if len(keys) > 0 {
+ iter := ro.Query(ctx, spanner.Statement{
+ SQL: "SELECT * FROM Sessions WHERE ID IN UNNEST(@ids)",
+ Params: map[string]interface{}{
+ "ids": keys,
+ },
+ })
+ defer iter.Stop()
+ sessions, err := readEntities[Session](iter)
+ if err != nil {
+ return nil, err
+ }
+ for _, session := range sessions {
+ obj := idToSeries[session.SeriesID]
+ if obj != nil {
+ obj.Session = session
+ }
+ }
+ }
+ return ret, nil
+}
+
+func (repo *SeriesRepository) ListWithoutSession(ctx context.Context, limit int) ([]*Series, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM Series WHERE `LatestSessionID` IS NULL ORDER BY `PublishedAt`",
+ Params: map[string]interface{}{},
+ }
+ if limit > 0 {
+ stmt.SQL += " LIMIT @limit"
+ stmt.Params["limit"] = limit
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readEntities[Series](iter)
+}
+
+// golint sees too much similarity with SessionRepository's ListForSeries, but in reality there's not.
+// nolint:dupl
+func (repo *SeriesRepository) ListPatches(ctx context.Context, series *Series) ([]*Patch, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM `Patches` WHERE `SeriesID` = @seriesID ORDER BY `Seq`",
+ Params: map[string]interface{}{
+ "seriesID": series.ID,
+ },
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readEntities[Patch](iter)
+}
diff --git a/syz-cluster/pkg/db/series_repo_test.go b/syz-cluster/pkg/db/series_repo_test.go
new file mode 100644
index 000000000000..c01049e5c845
--- /dev/null
+++ b/syz-cluster/pkg/db/series_repo_test.go
@@ -0,0 +1,133 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSeriesRepositoryGet(t *testing.T) {
+ client, ctx := NewTransientDB(t)
+ repo := NewSeriesRepository(client)
+ series := &Series{
+ ExtID: "ext-id",
+ AuthorName: "Name1 Name2",
+ AuthorEmail: "some@email.com",
+ Title: "something",
+ Version: 2,
+ PublishedAt: time.Date(2020, time.January, 1, 3, 0, 0, 0, time.UTC),
+ Cc: []string{"email"},
+ }
+ patches := []*Patch{
+ {
+ Title: "first patch",
+ Seq: 1,
+ Link: "first link",
+ BodyURI: "gcs://patch1",
+ },
+ {
+ Title: "second patch",
+ Seq: 2,
+ Link: "second link",
+ BodyURI: "gcs://patch2",
+ },
+ }
+ err := repo.Insert(ctx, series, func() ([]*Patch, error) {
+ return patches, nil
+ })
+ assert.NoError(t, err)
+ // Check that we obtain the exact object from the DB.
+ series2, err := repo.GetByID(ctx, series.ID)
+ assert.NoError(t, err)
+ assert.EqualValues(t, series, series2)
+ // Compare the patches.
+ patches2, err := repo.ListPatches(ctx, series)
+ assert.NoError(t, err)
+ assert.EqualValues(t, patches, patches2)
+}
+
+func TestSeriesRepositoryList(t *testing.T) {
+ client, ctx := NewTransientDB(t)
+ repo := NewSeriesRepository(client)
+ for _, series := range []*Series{
+ {
+ ExtID: "series-3",
+ Title: "Series 3",
+ PublishedAt: time.Date(2020, time.January, 1, 3, 0, 0, 0, time.UTC),
+ },
+ {
+ ExtID: "series-1",
+ Title: "Series 1",
+ PublishedAt: time.Date(2020, time.January, 1, 1, 0, 0, 0, time.UTC),
+ },
+ {
+ ExtID: "series-2",
+ Title: "Series 2",
+ PublishedAt: time.Date(2020, time.January, 1, 2, 0, 0, 0, time.UTC),
+ },
+ } {
+ err := repo.Insert(ctx, series, func() ([]*Patch, error) { return nil, nil })
+ assert.NoError(t, err)
+ }
+
+ t.Run("count", func(t *testing.T) {
+ count, err := repo.Count(ctx)
+ assert.NoError(t, err)
+ assert.Equal(t, 3, count)
+ })
+
+ t.Run("all", func(t *testing.T) {
+ list, err := repo.ListLatest(ctx, time.Time{}, 0)
+ assert.NoError(t, err)
+ assert.Len(t, list, 3)
+ })
+
+ t.Run("with_limit", func(t *testing.T) {
+ list, err := repo.ListLatest(ctx, time.Time{}, 2)
+ assert.NoError(t, err)
+ assert.Len(t, list, 2)
+ assert.Equal(t, "Series 3", list[0].Series.Title)
+ assert.Equal(t, "Series 2", list[1].Series.Title)
+ })
+
+ t.Run("with_from", func(t *testing.T) {
+ // Skips the latest series.
+ list, err := repo.ListLatest(ctx, time.Date(2020, time.January, 1, 3, 0, 0, 0, time.UTC), 0)
+ assert.NoError(t, err)
+ assert.Len(t, list, 2)
+ assert.Equal(t, "Series 2", list[0].Series.Title)
+ assert.Equal(t, "Series 1", list[1].Series.Title)
+ })
+}
+
+func TestSeriesRepositoryUpdate(t *testing.T) {
+ client, ctx := NewTransientDB(t)
+ repo := NewSeriesRepository(client)
+ series := &Series{
+ ExtID: "ext-id",
+ AuthorName: "Name1 Name2",
+ AuthorEmail: "some@email.com",
+ Title: "something",
+ Version: 2,
+ PublishedAt: time.Date(2020, time.January, 1, 3, 0, 0, 0, time.UTC),
+ Cc: []string{"email"},
+ }
+ err := repo.Insert(ctx, series, func() ([]*Patch, error) {
+ return nil, nil
+ })
+ assert.NoError(t, err)
+ // Update the object.
+ err = repo.Update(ctx, series.ID, func(series *Series) error {
+ series.Title = "updated title"
+ return nil
+ })
+ assert.NoError(t, err)
+ // Check that the entity has been updated.
+ series2, err := repo.GetByID(ctx, series.ID)
+ assert.NoError(t, err)
+ assert.Equal(t, "updated title", series2.Title)
+}
diff --git a/syz-cluster/pkg/db/session_repo.go b/syz-cluster/pkg/db/session_repo.go
new file mode 100644
index 000000000000..551f7e488101
--- /dev/null
+++ b/syz-cluster/pkg/db/session_repo.go
@@ -0,0 +1,79 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "context"
+
+ "cloud.google.com/go/spanner"
+ "github.com/google/uuid"
+)
+
+type SessionRepository struct {
+ client *spanner.Client
+ *genericEntityOps[Session, string]
+}
+
+func NewSessionRepository(client *spanner.Client) *SessionRepository {
+ return &SessionRepository{
+ client: client,
+ genericEntityOps: &genericEntityOps[Session, string]{
+ client: client,
+ keyField: "ID",
+ table: "Sessions",
+ },
+ }
+}
+
+func (repo *SessionRepository) Insert(ctx context.Context, series *Series, session *Session) error {
+ if session.ID == "" {
+ session.ID = uuid.New().String()
+ }
+ _, err := repo.client.ReadWriteTransaction(ctx,
+ func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
+ // TODO: we need to update LastSessionID only for sessions whose results might
+ // be reported to the author.
+ stmt := spanner.Statement{
+ SQL: "SELECT * from `Series` WHERE `ID`=@id",
+ Params: map[string]interface{}{"id": series.ID},
+ }
+ iter := txn.Query(ctx, stmt)
+ series, err := readOne[Series](iter)
+ iter.Stop()
+ if err != nil {
+ return err
+ }
+ series.SetLatestSession(session)
+ updateSeries, err := spanner.UpdateStruct("Series", series)
+ if err != nil {
+ return err
+ }
+ session.SeriesID = series.ID
+ insertSession, err := spanner.InsertStruct("Sessions", session)
+ if err != nil {
+ return err
+ }
+ return txn.BufferWrite([]*spanner.Mutation{updateSeries, insertSession})
+ })
+ return err
+}
+
+func (repo *SessionRepository) ListRunning(ctx context.Context) ([]*Session, error) {
+ stmt := spanner.Statement{SQL: "SELECT * FROM `Sessions` WHERE `FinishedAt` IS NULL"}
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readEntities[Session](iter)
+}
+
+// golint sees too much similarity with SeriesRepository's ListPatches, but in reality there's not.
+// nolint:dupl
+func (repo *SessionRepository) ListForSeries(ctx context.Context, series *Series) ([]*Session, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM `Sessions` WHERE `SeriesID` = @series ORDER BY CreatedAt DESC",
+ Params: map[string]interface{}{"series": series.ID},
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readEntities[Session](iter)
+}
diff --git a/syz-cluster/pkg/db/session_repo_test.go b/syz-cluster/pkg/db/session_repo_test.go
new file mode 100644
index 000000000000..55cee2f3162c
--- /dev/null
+++ b/syz-cluster/pkg/db/session_repo_test.go
@@ -0,0 +1,43 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSeriesInsertSession(t *testing.T) {
+ client, ctx := NewTransientDB(t)
+ sessionRepo := NewSessionRepository(client)
+ seriesRepo := NewSeriesRepository(client)
+
+ series := &Series{ExtID: "some-series"}
+ err := seriesRepo.Insert(ctx, series, nil)
+ assert.NoError(t, err)
+
+ // This series is indeed without a session.
+ list, err := seriesRepo.ListWithoutSession(ctx, 10)
+ assert.NoError(t, err)
+ assert.Len(t, list, 1)
+
+ // Add a new session.
+ session := &Session{CreatedAt: time.Now()}
+ err = sessionRepo.Insert(ctx, series, session)
+ assert.NoError(t, err)
+
+ // All sessions are with sessions now.
+ list, err = seriesRepo.ListWithoutSession(ctx, 10)
+ assert.NoError(t, err)
+ assert.Len(t, list, 0)
+
+ // We can also query the information together.
+
+ list2, err := seriesRepo.ListLatest(ctx, time.Time{}, 0)
+ assert.NoError(t, err)
+ assert.Len(t, list2, 1)
+ assert.NotNil(t, list2[0].Session)
+}
diff --git a/syz-cluster/pkg/db/session_test_repo.go b/syz-cluster/pkg/db/session_test_repo.go
new file mode 100644
index 000000000000..f3eb62268c69
--- /dev/null
+++ b/syz-cluster/pkg/db/session_test_repo.go
@@ -0,0 +1,112 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "context"
+
+ "cloud.google.com/go/spanner"
+ "google.golang.org/api/iterator"
+)
+
+type SessionTestRepository struct {
+ client *spanner.Client
+}
+
+func NewSessionTestRepository(client *spanner.Client) *SessionTestRepository {
+ return &SessionTestRepository{
+ client: client,
+ }
+}
+
+func (repo *SessionTestRepository) InsertOrUpdate(ctx context.Context, test *SessionTest) error {
+ _, err := repo.client.ReadWriteTransaction(ctx,
+ func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
+ // Check if the test already exists.
+ stmt := spanner.Statement{
+ SQL: "SELECT * from `SessionTests` WHERE `SessionID`=@sessionID AND `TestName` = @testName",
+ Params: map[string]interface{}{
+ "sessionID": test.SessionID,
+ "testName": test.TestName,
+ },
+ }
+ iter := txn.Query(ctx, stmt)
+ defer iter.Stop()
+
+ var stmts []*spanner.Mutation
+
+ _, iterErr := iter.Next()
+ if iterErr == nil {
+ m, err := spanner.UpdateStruct("SessionTests", test)
+ if err != nil {
+ return err
+ }
+ stmts = append(stmts, m)
+ } else if iterErr != iterator.Done {
+ return iterErr
+ } else {
+ m, err := spanner.InsertStruct("SessionTests", test)
+ if err != nil {
+ return err
+ }
+ stmts = append(stmts, m)
+ }
+ return txn.BufferWrite(stmts)
+ })
+ return err
+}
+
+type FullSessionTest struct {
+ *SessionTest
+ BaseBuild *Build
+ PatchedBuild *Build
+}
+
+func (repo *SessionTestRepository) BySession(ctx context.Context, sessionID string) ([]*FullSessionTest, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM `SessionTests` WHERE `SessionID` = @session" +
+ " ORDER BY `TestName`",
+ Params: map[string]interface{}{"session": sessionID},
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ list, err := readEntities[SessionTest](iter)
+ if err != nil {
+ return nil, err
+ }
+ var ret []*FullSessionTest
+ needBuilds := map[string][]**Build{}
+ for _, obj := range list {
+ full := &FullSessionTest{SessionTest: obj}
+ ret = append(ret, full)
+ if id := obj.BaseBuildID.String(); !obj.BaseBuildID.IsNull() {
+ needBuilds[id] = append(needBuilds[id], &full.BaseBuild)
+ }
+ if id := obj.PatchedBuildID.String(); !obj.PatchedBuildID.IsNull() {
+ needBuilds[id] = append(needBuilds[id], &full.PatchedBuild)
+ }
+ }
+ if len(needBuilds) > 0 {
+ var keys []string
+ for key := range needBuilds {
+ keys = append(keys, key)
+ }
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM `Builds` WHERE `ID` IN UNNEST(@ids)",
+ Params: map[string]interface{}{"ids": keys},
+ }
+ iter := repo.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ builds, err := readEntities[Build](iter)
+ if err != nil {
+ return nil, err
+ }
+ for _, build := range builds {
+ for _, patch := range needBuilds[build.ID] {
+ *patch = build
+ }
+ }
+ }
+ return ret, nil
+}
diff --git a/syz-cluster/pkg/db/session_test_repo_test.go b/syz-cluster/pkg/db/session_test_repo_test.go
new file mode 100644
index 000000000000..2ecd696d30e6
--- /dev/null
+++ b/syz-cluster/pkg/db/session_test_repo_test.go
@@ -0,0 +1,58 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "cloud.google.com/go/spanner"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSessionTestRepository(t *testing.T) {
+ client, ctx := NewTransientDB(t)
+ sessionRepo := NewSessionRepository(client)
+ seriesRepo := NewSeriesRepository(client)
+ testsRepo := NewSessionTestRepository(client)
+ buildRepo := NewBuildRepository(client)
+
+ series := &Series{ExtID: "some-series"}
+ err := seriesRepo.Insert(ctx, series, nil)
+ assert.NoError(t, err)
+
+ session := &Session{CreatedAt: time.Now()}
+ err = sessionRepo.Insert(ctx, series, session)
+ assert.NoError(t, err)
+
+ build1 := &Build{TreeName: "mainline", Arch: "amd64", CommitHash: "abcd", Status: "success"}
+ err = buildRepo.Insert(ctx, build1)
+ assert.NoError(t, err)
+ build2 := &Build{TreeName: "mainline", Arch: "amd64", CommitHash: "efgh", Status: "success"}
+ err = buildRepo.Insert(ctx, build2)
+ assert.NoError(t, err)
+
+ // Add several tests.
+ for i := 0; i < 2; i++ {
+ test := &SessionTest{
+ SessionID: session.ID,
+ TestName: fmt.Sprintf("test %d", i),
+ BaseBuildID: spanner.NullString{StringVal: build1.ID, Valid: true},
+ PatchedBuildID: spanner.NullString{StringVal: build2.ID, Valid: true},
+ Result: api.TestPassed,
+ }
+ err = testsRepo.InsertOrUpdate(ctx, test)
+ assert.NoError(t, err)
+ }
+
+ list, err := testsRepo.BySession(ctx, session.ID)
+ assert.NoError(t, err)
+ assert.Len(t, list, 2)
+ for _, test := range list {
+ assert.NotNil(t, test.BaseBuild)
+ assert.NotNil(t, test.PatchedBuild)
+ }
+}
diff --git a/syz-cluster/pkg/db/spanner.go b/syz-cluster/pkg/db/spanner.go
new file mode 100644
index 000000000000..b2def03988cb
--- /dev/null
+++ b/syz-cluster/pkg/db/spanner.go
@@ -0,0 +1,300 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package db
+
+import (
+ "bufio"
+ "context"
+ "embed"
+ "fmt"
+ "io"
+ "os"
+ "os/exec"
+ "regexp"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "cloud.google.com/go/spanner"
+ database "cloud.google.com/go/spanner/admin/database/apiv1"
+ "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
+ instance "cloud.google.com/go/spanner/admin/instance/apiv1"
+ "cloud.google.com/go/spanner/admin/instance/apiv1/instancepb"
+ "github.com/golang-migrate/migrate/v4"
+ migrate_spanner "github.com/golang-migrate/migrate/v4/database/spanner"
+ "github.com/golang-migrate/migrate/v4/source/iofs"
+ "google.golang.org/api/iterator"
+ "google.golang.org/grpc/codes"
+)
+
+type ParsedURI struct {
+ ProjectPrefix string // projects/
+ InstancePrefix string // projects//instances/
+ Instance string
+ Database string
+ Full string
+}
+
+func ParseURI(uri string) (ParsedURI, error) {
+ ret := ParsedURI{Full: uri}
+ matches := regexp.MustCompile(`projects/(.*)/instances/(.*)/databases/(.*)`).FindStringSubmatch(uri)
+ if matches == nil || len(matches) != 4 {
+ return ret, fmt.Errorf("failed to parse %q", uri)
+ }
+ ret.ProjectPrefix = "projects/" + matches[1]
+ ret.InstancePrefix = ret.ProjectPrefix + "/instances/" + matches[2]
+ ret.Instance = matches[2]
+ ret.Database = matches[3]
+ return ret, nil
+}
+
+func CreateSpannerInstance(ctx context.Context, uri ParsedURI) error {
+ client, err := instance.NewInstanceAdminClient(ctx)
+ if err != nil {
+ return err
+ }
+ defer client.Close()
+ _, err = client.GetInstance(ctx, &instancepb.GetInstanceRequest{
+ Name: uri.InstancePrefix,
+ })
+ if err != nil && spanner.ErrCode(err) == codes.NotFound {
+ _, err = client.CreateInstance(ctx, &instancepb.CreateInstanceRequest{
+ Parent: uri.ProjectPrefix,
+ InstanceId: uri.Instance,
+ })
+ return err
+ }
+ return err
+}
+
+func CreateSpannerDB(ctx context.Context, uri ParsedURI) error {
+ client, err := database.NewDatabaseAdminClient(ctx)
+ if err != nil {
+ return err
+ }
+ defer client.Close()
+ _, err = client.GetDatabase(ctx, &databasepb.GetDatabaseRequest{Name: uri.Full})
+ if err != nil && spanner.ErrCode(err) == codes.NotFound {
+ op, err := client.CreateDatabase(ctx, &databasepb.CreateDatabaseRequest{
+ Parent: uri.InstancePrefix,
+ CreateStatement: `CREATE DATABASE ` + uri.Database,
+ ExtraStatements: []string{},
+ })
+ if err != nil {
+ return err
+ }
+ _, err = op.Wait(ctx)
+ return err
+ }
+ return err
+}
+
+func dropSpannerDB(ctx context.Context, uri ParsedURI) error {
+ client, err := database.NewDatabaseAdminClient(ctx)
+ if err != nil {
+ return err
+ }
+ defer client.Close()
+ return client.DropDatabase(ctx, &databasepb.DropDatabaseRequest{Database: uri.Full})
+}
+
+//go:embed migrations/*.sql
+var migrationsFs embed.FS
+
+func RunMigrations(ctx context.Context, uri string) error {
+ sourceDriver, err := iofs.New(migrationsFs, "migrations")
+ if err != nil {
+ return err
+ }
+ s := &migrate_spanner.Spanner{}
+ dbDriver, err := s.Open("spanner://" + uri + "?x-clean-statements=true")
+ if err != nil {
+ return err
+ }
+ m, err := migrate.NewWithInstance("iofs", sourceDriver, "spanner", dbDriver)
+ if err != nil {
+ return err
+ }
+ return m.Up()
+}
+
+func NewTransientDB(t *testing.T) (*spanner.Client, context.Context) {
+ // If the environment contains the emulator binary, start it.
+ if bin := os.Getenv("SPANNER_EMULATOR_BIN"); bin != "" {
+ host := spannerTestWrapper(t, bin)
+ os.Setenv("SPANNER_EMULATOR_HOST", host)
+ } else if os.Getenv("CI") != "" {
+ // We do want to always run these tests on CI.
+ t.Fatalf("CI is set, but SPANNER_EMULATOR_BIN is empty")
+ }
+ if os.Getenv("SPANNER_EMULATOR_HOST") == "" {
+ t.Skip("SPANNER_EMULATOR_HOST must be set")
+ return nil, nil
+ }
+ uri, err := ParseURI("projects/my-project/instances/test-instance/databases/" +
+ fmt.Sprintf("db%v", time.Now().UnixNano()))
+ if err != nil {
+ t.Fatal(err)
+ }
+ ctx := context.Background()
+ err = CreateSpannerInstance(ctx, uri)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = CreateSpannerDB(ctx, uri)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(func() {
+ err := dropSpannerDB(ctx, uri)
+ if err != nil {
+ t.Logf("failed to drop the test DB: %v", err)
+ }
+ })
+ client, err := spanner.NewClient(ctx, uri.Full)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(client.Close)
+ err = RunMigrations(ctx, uri.Full)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return client, ctx
+}
+
+var setupSpannerOnce sync.Once
+var spannerHost string
+
+func spannerTestWrapper(t *testing.T, bin string) string {
+ setupSpannerOnce.Do(func() {
+ t.Logf("this could be the first test requiring a Spanner emulator, starting %s", bin)
+ cmd, host, err := runSpanner(bin)
+ if err != nil {
+ t.Fatal(err)
+ }
+ spannerHost = host
+ t.Cleanup(func() {
+ cmd.Process.Kill()
+ cmd.Wait()
+ })
+ })
+ return spannerHost
+}
+
+var portRe = regexp.MustCompile(`Server address: ([\w:]+)`)
+
+func runSpanner(bin string) (*exec.Cmd, string, error) {
+ cmd := exec.Command(bin, "--override_max_databases_per_instance=1000",
+ "--grpc_port=0", "--http_port=0")
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, "", err
+ }
+ cmd.Stderr = cmd.Stdout
+ if err := cmd.Start(); err != nil {
+ return nil, "", err
+ }
+ scanner := bufio.NewScanner(stdout)
+ started, host := false, ""
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.Contains(line, "Cloud Spanner Emulator running") {
+ started = true
+ } else if parts := portRe.FindStringSubmatch(line); parts != nil {
+ host = parts[1]
+ }
+ if started && host != "" {
+ break
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return cmd, "", err
+ }
+ // The program may block if we don't read out all the remaining output.
+ go io.Copy(io.Discard, stdout)
+
+ if !started {
+ return cmd, "", fmt.Errorf("the emulator did not print that it started")
+ }
+ if host == "" {
+ return cmd, "", fmt.Errorf("did not detect the host")
+ }
+ return cmd, host, nil
+}
+
+func readOne[T any](iter *spanner.RowIterator) (*T, error) {
+ row, err := iter.Next()
+ if err == iterator.Done {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ var obj T
+ err = row.ToStruct(&obj)
+ if err != nil {
+ return nil, err
+ }
+ return &obj, nil
+}
+
+func readEntities[T any](iter *spanner.RowIterator) ([]*T, error) {
+ var ret []*T
+ for {
+ obj, err := readOne[T](iter)
+ if err != nil {
+ return nil, err
+ }
+ if obj == nil {
+ break
+ }
+ ret = append(ret, obj)
+ }
+ return ret, nil
+}
+
+type genericEntityOps[EntityType, KeyType any] struct {
+ client *spanner.Client
+ keyField string
+ table string
+}
+
+func (g *genericEntityOps[EntityType, KeyType]) GetByID(ctx context.Context, key KeyType) (*EntityType, error) {
+ stmt := spanner.Statement{
+ SQL: "SELECT * FROM " + g.table + " WHERE " + g.keyField + "=@key",
+ Params: map[string]interface{}{"key": key},
+ }
+ iter := g.client.Single().Query(ctx, stmt)
+ defer iter.Stop()
+ return readOne[EntityType](iter)
+}
+
+func (g *genericEntityOps[EntityType, KeyType]) Update(ctx context.Context, key KeyType,
+ cb func(*EntityType) error) error {
+ _, err := g.client.ReadWriteTransaction(ctx,
+ func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
+ stmt := spanner.Statement{
+ SQL: "SELECT * from `" + g.table + "` WHERE `" + g.keyField + "`=@key",
+ Params: map[string]interface{}{"key": key},
+ }
+ iter := txn.Query(ctx, stmt)
+ entity, err := readOne[EntityType](iter)
+ iter.Stop()
+ if err != nil {
+ return err
+ }
+ err = cb(entity)
+ if err != nil {
+ return err
+ }
+ m, err := spanner.UpdateStruct(g.table, entity)
+ if err != nil {
+ return err
+ }
+ return txn.BufferWrite([]*spanner.Mutation{m})
+ })
+ return err
+}
diff --git a/syz-cluster/pkg/triage/commit.go b/syz-cluster/pkg/triage/commit.go
new file mode 100644
index 000000000000..53d20702c14c
--- /dev/null
+++ b/syz-cluster/pkg/triage/commit.go
@@ -0,0 +1,67 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package triage
+
+import (
+ "log"
+ "time"
+
+ "github.com/google/syzkaller/pkg/vcs"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+)
+
+// TODO: Some further improvements:
+// 1. Consider the blob hashes incorporated into the git diff. These may restrict the set of base commits.
+// 2. Add support for experimental sessions: these may be way behind the current HEAD.
+
+type TreeOps interface {
+ HeadCommit(tree *api.Tree) (*vcs.Commit, error)
+ ApplySeries(commit string, patches [][]byte) error
+}
+
+type CommitSelector struct {
+ ops TreeOps
+}
+
+func NewCommitSelector(ops TreeOps) *CommitSelector {
+ return &CommitSelector{ops: ops}
+}
+
+// Returns the commit hashes to try.
+func (cs *CommitSelector) Select(series *api.Series, tree *api.Tree, lastBuild *api.Build) ([]string, error) {
+ head, err := cs.ops.HeadCommit(tree)
+ if err != nil || head == nil {
+ return nil, err
+ }
+ log.Printf("current HEAD: %q (%v)", head.Hash, head.Date)
+ // If the series is already too old, it may be incompatible even if it applies cleanly.
+ const seriesLagsBehind = time.Hour * 24 * 10
+ if diff := head.CommitDate.Sub(series.PublishedAt); series.PublishedAt.Before(head.CommitDate) &&
+ diff > seriesLagsBehind {
+ log.Printf("the series is too old: %v", diff)
+ return nil, nil
+ }
+ hashes := []string{head.Hash}
+ if lastBuild != nil {
+ // Let's use the same criteria for the last built commit.
+ // If it's too old already, it's better not to use it.
+ if diff := head.CommitDate.Sub(lastBuild.CommitDate); diff > seriesLagsBehind {
+ log.Printf("the last successful build is already too old: %v, skipping", diff)
+ } else {
+ hashes = append(hashes, lastBuild.CommitHash)
+ }
+ }
+ var ret []string
+ for _, hash := range hashes {
+ log.Printf("considering %q", hash)
+ err := cs.ops.ApplySeries(hash, series.Patches)
+ if err == nil {
+ log.Printf("series can be applied to %q", hash)
+ ret = append(ret, hash)
+ } else {
+ log.Printf("failed to apply to %q: %v", hash, err)
+ }
+ }
+ return ret, nil
+}
diff --git a/syz-cluster/pkg/triage/commit_test.go b/syz-cluster/pkg/triage/commit_test.go
new file mode 100644
index 000000000000..514afd6ce05b
--- /dev/null
+++ b/syz-cluster/pkg/triage/commit_test.go
@@ -0,0 +1,123 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package triage
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/google/syzkaller/pkg/vcs"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCommitSelector(t *testing.T) {
+ allApply := map[string]bool{"head": true, "build": true}
+ tests := []struct {
+ name string
+ ops TreeOps
+ series *api.Series
+ last *api.Build
+ commits []string
+ }{
+ {
+ name: "fresh series, no last build",
+ series: &api.Series{PublishedAt: date("2020-Jan-15")},
+ ops: newTestGitOps(&vcs.Commit{Hash: "head", CommitDate: date("2020-Jan-10")}, allApply),
+ commits: []string{"head"},
+ },
+ {
+ name: "fresh series with a fresh last build",
+ series: &api.Series{PublishedAt: date("2020-Jan-15")},
+ ops: newTestGitOps(&vcs.Commit{Hash: "head", CommitDate: date("2020-Jan-10")}, allApply),
+ last: &api.Build{CommitHash: "build", CommitDate: date("2020-Jan-06")},
+ commits: []string{"head", "build"},
+ },
+ {
+ name: "fresh series with a too old last build",
+ series: &api.Series{PublishedAt: date("2020-Jan-15")},
+ ops: newTestGitOps(&vcs.Commit{Hash: "head", CommitDate: date("2020-Jan-10")}, allApply),
+ last: &api.Build{CommitHash: "build", CommitDate: date("2019-Dec-20")},
+ commits: []string{"head"},
+ },
+ {
+ name: "slightly old series",
+ series: &api.Series{PublishedAt: date("2020-Jan-15")},
+ ops: newTestGitOps(&vcs.Commit{Hash: "head", CommitDate: date("2020-Jan-20")}, allApply),
+ commits: []string{"head"},
+ },
+ {
+ name: "a too old series",
+ series: &api.Series{PublishedAt: date("2020-Jan-15")},
+ ops: newTestGitOps(&vcs.Commit{Hash: "head", CommitDate: date("2020-Feb-15")}, allApply),
+ commits: nil,
+ },
+ {
+ name: "doesn't apply to the older build",
+ series: &api.Series{PublishedAt: date("2020-Jan-15")},
+ ops: newTestGitOps(
+ &vcs.Commit{Hash: "head", CommitDate: date("2020-Jan-13")},
+ map[string]bool{"head": true, "build": false},
+ ),
+ last: &api.Build{CommitHash: "build", CommitDate: date("2020-Jan-10")},
+ commits: []string{"head"},
+ },
+ {
+ name: "doesn't apply anywhere",
+ series: &api.Series{PublishedAt: date("2020-Jan-15")},
+ ops: newTestGitOps(
+ &vcs.Commit{Hash: "head", CommitDate: date("2020-Jan-13")},
+ nil,
+ ),
+ last: &api.Build{CommitHash: "build", CommitDate: date("2020-Jan-10")},
+ commits: nil,
+ },
+ }
+
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ selector := NewCommitSelector(test.ops)
+ commits, err := selector.Select(test.series, testTree, test.last)
+ assert.NoError(t, err)
+ assert.Equal(t, test.commits, commits)
+ })
+ }
+}
+
+func date(date string) time.Time {
+ t, err := time.Parse("2006-Jan-02", date)
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+var testTree = &api.Tree{} // all tests will use the same tree
+
+type testGitOps struct {
+ applies map[string]bool
+ head map[*api.Tree]*vcs.Commit
+}
+
+func newTestGitOps(head *vcs.Commit, applies map[string]bool) *testGitOps {
+ return &testGitOps{
+ applies: applies,
+ head: map[*api.Tree]*vcs.Commit{
+ testTree: head,
+ },
+ }
+}
+
+func (ops *testGitOps) HeadCommit(tree *api.Tree) (*vcs.Commit, error) {
+ return ops.head[tree], nil
+}
+
+func (ops *testGitOps) ApplySeries(commit string, _ [][]byte) error {
+ if ops.applies[commit] {
+ return nil
+ }
+ return fmt.Errorf("didn't apply")
+}
diff --git a/syz-cluster/pkg/triage/git.go b/syz-cluster/pkg/triage/git.go
new file mode 100644
index 000000000000..db8f6b629390
--- /dev/null
+++ b/syz-cluster/pkg/triage/git.go
@@ -0,0 +1,49 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package triage
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/google/syzkaller/pkg/vcs"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+)
+
+type GitTreeOps struct {
+ *vcs.Git
+}
+
+func NewGitTreeOps(dir string, sandbox bool) (*GitTreeOps, error) {
+ ops := &GitTreeOps{
+ Git: &vcs.Git{
+ Dir: dir,
+ // TODO: why doesn't sandbox=true work normally under go tests?
+ Sandbox: sandbox,
+ Env: os.Environ(),
+ },
+ }
+ err := ops.Reset()
+ return ops, err
+}
+
+func (ops *GitTreeOps) HeadCommit(tree *api.Tree) (*vcs.Commit, error) {
+ // See kernel-disk/cron.yaml.
+ return ops.Commit(tree.Name + "-head")
+}
+
+func (ops *GitTreeOps) ApplySeries(commit string, patches [][]byte) error {
+ ops.Reset()
+ _, err := ops.Run("reset", "--hard", commit)
+ if err != nil {
+ return err
+ }
+ for i, patch := range patches {
+ err := ops.Apply(patch)
+ if err != nil {
+ return fmt.Errorf("failed to apply patch %d: %w", i, err)
+ }
+ }
+ return nil
+}
diff --git a/syz-cluster/pkg/triage/git_test.go b/syz-cluster/pkg/triage/git_test.go
new file mode 100644
index 000000000000..c9e6c54726a1
--- /dev/null
+++ b/syz-cluster/pkg/triage/git_test.go
@@ -0,0 +1,97 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package triage
+
+import (
+ "path/filepath"
+ "testing"
+
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/pkg/vcs"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGitTreeOpsHead(t *testing.T) {
+ baseDir := t.TempDir()
+ repo := vcs.MakeTestRepo(t, baseDir)
+ // Emulate the behavior of the kernel-disk machinery.
+ osutil.WriteFile(filepath.Join(baseDir, "file.txt"), []byte("Some content"))
+ repo.Git("add", "file.txt")
+ head1 := repo.CommitChange("first head")
+ repo.SetTag("mainline-head")
+ osutil.WriteFile(filepath.Join(baseDir, "file.txt"), []byte("Another content"))
+ repo.Git("add", "file.txt")
+ head2 := repo.CommitChange("second head")
+ repo.SetTag("second-head")
+ // Verify that the right commits are queried.
+ ops, err := NewGitTreeOps(baseDir, false)
+ assert.NoError(t, err)
+ commit, err := ops.HeadCommit(&api.Tree{Name: "mainline"})
+ assert.NoError(t, err)
+ assert.Equal(t, head1.Hash, commit.Hash)
+ commit, err = ops.HeadCommit(&api.Tree{Name: "second"})
+ assert.NoError(t, err)
+ assert.Equal(t, head2.Hash, commit.Hash)
+}
+
+func TestGitTreeOpsApply(t *testing.T) {
+ baseDir := t.TempDir()
+ repo := vcs.MakeTestRepo(t, baseDir)
+ osutil.WriteFile(filepath.Join(baseDir, "file.txt"), []byte("First\nSecond\nThird\n"))
+ repo.Git("add", "file.txt")
+ base := repo.CommitChange("base")
+
+ ops, err := NewGitTreeOps(baseDir, false)
+ assert.NoError(t, err)
+ assert.Error(t, ops.ApplySeries(base.Hash, [][]byte{goodPatch, wontApply}))
+ assert.NoError(t, ops.ApplySeries(base.Hash, [][]byte{goodPatch}))
+}
+
+var wontApply = []byte(`From dc2cf7bc4a9dbe170d47338d0fe6d2351c88c9d1 Mon Sep 17 00:00:00 2001
+From: Test Syzkaller
+Date: Tue, 10 Dec 2024 17:58:20 +0100
+Subject: [PATCH] change1
+
+---
+ file.txt | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/file.txt b/file.txt
+index 0d39765..97c39a4 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,3 +1,3 @@
+-1First
+-1Second
+-1Third
++First1
++Second
++Third1
+--
+2.47.1.545.g3c1d2e2a6a-goog
+`)
+
+var goodPatch = []byte(`From 708670e05c0462d3783f774cef82f9a3b3099f9a Mon Sep 17 00:00:00 2001
+From: Test Syzkaller
+Date: Tue, 10 Dec 2024 17:57:37 +0100
+Subject: [PATCH] change1
+
+---
+ file.txt | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/file.txt b/file.txt
+index ab7c514..97c39a4 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,3 +1,3 @@
+-First
++First1
+ Second
+-Third
++Third1
+--
+2.47.1.545.g3c1d2e2a6a-goog
+`)
diff --git a/syz-cluster/pkg/triage/tree.go b/syz-cluster/pkg/triage/tree.go
new file mode 100644
index 000000000000..592bbce78bdc
--- /dev/null
+++ b/syz-cluster/pkg/triage/tree.go
@@ -0,0 +1,35 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package triage
+
+import (
+ "strings"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+)
+
+// TODO: add tests.
+func SelectTree(series *api.Series, trees []*api.Tree) *api.Tree {
+ seriesCc := map[string]bool{}
+ for _, cc := range series.Cc {
+ seriesCc[strings.ToLower(cc)] = true
+ }
+ var best *api.Tree
+ for _, tree := range trees {
+ intersects := false
+ for _, cc := range tree.EmailLists {
+ if seriesCc[strings.ToLower(cc)] {
+ intersects = true
+ break
+ }
+ }
+ if len(tree.EmailLists) > 0 && !intersects {
+ continue
+ }
+ if best == nil || tree.Priority > best.Priority {
+ best = tree
+ }
+ }
+ return best
+}
diff --git a/syz-cluster/pkg/triage/tree_test.go b/syz-cluster/pkg/triage/tree_test.go
new file mode 100644
index 000000000000..f55793909aeb
--- /dev/null
+++ b/syz-cluster/pkg/triage/tree_test.go
@@ -0,0 +1,61 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package triage
+
+import (
+ "testing"
+
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSelectTree(t *testing.T) {
+ trees := []*api.Tree{
+ {
+ Name: "mainline",
+ EmailLists: nil,
+ Priority: 0,
+ },
+ {
+ Name: "net",
+ EmailLists: []string{"net@list"},
+ Priority: 1,
+ },
+ {
+ Name: "wireless",
+ EmailLists: []string{"wireless@list"},
+ Priority: 2,
+ },
+ }
+ tests := []struct {
+ testName string
+ result string
+ series *api.Series
+ }{
+ {
+ testName: "only-net",
+ result: "net",
+ series: &api.Series{Cc: []string{"net@list"}},
+ },
+ {
+ testName: "prefer-wireless",
+ result: "wireless",
+ series: &api.Series{Cc: []string{"net@list", "wireless@list"}},
+ },
+ {
+ testName: "fallback",
+ result: "mainline",
+ series: &api.Series{Cc: []string{"unknown@list"}},
+ },
+ }
+
+ for _, test := range tests {
+ test := test
+ t.Run(test.testName, func(t *testing.T) {
+ ret := SelectTree(test.series, trees)
+ assert.NotNil(t, ret)
+ assert.Equal(t, test.result, ret.Name)
+ })
+ }
+}
diff --git a/syz-cluster/pkg/workflow/argo.go b/syz-cluster/pkg/workflow/argo.go
new file mode 100644
index 000000000000..502b0cf7fe80
--- /dev/null
+++ b/syz-cluster/pkg/workflow/argo.go
@@ -0,0 +1,115 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package workflow
+
+import (
+ "bytes"
+ "context"
+ "embed"
+ "fmt"
+ "sort"
+ "time"
+
+ "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
+ wfclientset "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned"
+ wftypes "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned/typed/workflow/v1alpha1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ restclient "k8s.io/client-go/rest"
+ "sigs.k8s.io/yaml"
+)
+
+//go:embed *.yaml
+var workflowsFS embed.FS
+
+type ArgoService struct {
+ wfClient wftypes.WorkflowInterface
+ template *v1alpha1.Workflow
+}
+
+func NewArgoService() (*ArgoService, error) {
+ kubeConfig, err := restclient.InClusterConfig()
+ if err != nil {
+ return nil, err
+ }
+ namespace := "default"
+ wfClient := wfclientset.NewForConfigOrDie(kubeConfig).ArgoprojV1alpha1().Workflows(namespace)
+ templateData, err := workflowsFS.ReadFile("template.yaml")
+ if err != nil {
+ return nil, err
+ }
+ var wf v1alpha1.Workflow
+ err = yaml.Unmarshal(templateData, &wf)
+ if err != nil {
+ return nil, err
+ }
+ return &ArgoService{
+ wfClient: wfClient,
+ template: &wf,
+ }, nil
+}
+
+// TODO: substitute the proper (non-dev) Docker image names.
+func (w *ArgoService) Start(sessionID string) error {
+ workflow := w.template.DeepCopy()
+ workflow.ObjectMeta.Labels = map[string]string{
+ "workflow-id": sessionID,
+ }
+ for i, param := range workflow.Spec.Arguments.Parameters {
+ if param.Name == "session-id" {
+ workflow.Spec.Arguments.Parameters[i].Value = v1alpha1.AnyStringPtr(sessionID)
+ }
+ }
+ _, err := w.wfClient.Create(context.Background(), workflow, metav1.CreateOptions{})
+ return err
+}
+
+func (w *ArgoService) Status(sessionID string) (Status, []byte, error) {
+ listOptions := metav1.ListOptions{
+ LabelSelector: fmt.Sprintf("workflow-id=%s", sessionID),
+ }
+ workflows, err := w.wfClient.List(context.Background(), listOptions)
+ if err != nil || len(workflows.Items) == 0 {
+ return StatusNotFound, nil, err
+ }
+ wf := workflows.Items[0]
+ log := w.generateLog(wf.Status.Nodes)
+ switch wf.Status.Phase {
+ case v1alpha1.WorkflowRunning, v1alpha1.WorkflowPending:
+ return StatusRunning, log, nil
+ case v1alpha1.WorkflowSucceeded:
+ return StatusFinished, log, nil
+ }
+ return StatusFailed, log, nil
+}
+
+func (w *ArgoService) generateLog(nodes v1alpha1.Nodes) []byte {
+ var list []v1alpha1.NodeStatus
+ for _, node := range nodes {
+ list = append(list, node)
+ }
+ sort.Slice(list, func(i, j int) bool {
+ a, b := list[i], list[j]
+ if !a.StartedAt.Equal(&b.StartedAt) {
+ return a.StartedAt.Before(&b.StartedAt)
+ }
+ return a.Name < b.Name
+ })
+ var buf bytes.Buffer
+ for i, val := range list {
+ if i > 0 {
+ buf.WriteString("---------\n")
+ }
+ fmt.Fprintf(&buf, "Name: %s\n", val.Name)
+ fmt.Fprintf(&buf, "Phase: %s\n", val.Phase)
+ fmt.Fprintf(&buf, "StartedAt: %s\n", val.StartedAt)
+ fmt.Fprintf(&buf, "FinishedAt: %s\n", val.FinishedAt)
+ fmt.Fprintf(&buf, "Input: %s\n", val.Inputs)
+ fmt.Fprintf(&buf, "Output: %s\n", val.Outputs)
+ }
+ return buf.Bytes()
+}
+
+func (w *ArgoService) PollPeriod() time.Duration {
+ return time.Minute
+}
diff --git a/syz-cluster/pkg/workflow/service.go b/syz-cluster/pkg/workflow/service.go
new file mode 100644
index 000000000000..4ec7eb5cf1aa
--- /dev/null
+++ b/syz-cluster/pkg/workflow/service.go
@@ -0,0 +1,59 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package workflow
+
+import (
+ "sync"
+ "time"
+)
+
+// Service is the interface for starting and managing the workflows that process individual patch series.
+// The workflow includes steps like building base/patched kernel, dong boot tests, running fuzzing, etc.
+// It's assumed that the workflow will query the necessary data and report its detailed progress itself,
+// so we only need to be able to start it and to check its current overall state.
+type Service interface {
+ Start(sessionID string) error
+ Status(id string) (Status, []byte, error)
+ // The recommended value. May depend on the implementation (test/prod).
+ PollPeriod() time.Duration
+}
+
+type Status string
+
+const (
+ StatusNotFound Status = "not_found"
+ StatusRunning Status = "running"
+ StatusFinished Status = "finished"
+ StatusFailed Status = "failed"
+)
+
+// MockService serializes callback invocations to simplify test implementations.
+type MockService struct {
+ mu sync.Mutex
+ PollDelayValue time.Duration
+ OnStart func(string) error
+ OnStatus func(string) (Status, []byte, error)
+}
+
+func (ms *MockService) Start(id string) error {
+ ms.mu.Lock()
+ defer ms.mu.Unlock()
+ if ms.OnStart != nil {
+ return ms.OnStart(id)
+ }
+ return nil
+}
+
+func (ms *MockService) Status(id string) (Status, []byte, error) {
+ ms.mu.Lock()
+ defer ms.mu.Unlock()
+ if ms.OnStatus != nil {
+ return ms.OnStatus(id)
+ }
+ return StatusNotFound, nil, nil
+}
+
+func (ms *MockService) PollPeriod() time.Duration {
+ return ms.PollDelayValue
+}
diff --git a/syz-cluster/pkg/workflow/template.yaml b/syz-cluster/pkg/workflow/template.yaml
new file mode 100644
index 000000000000..a75b1761bc45
--- /dev/null
+++ b/syz-cluster/pkg/workflow/template.yaml
@@ -0,0 +1,174 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: argoproj.io/v1alpha1
+kind: Workflow
+metadata:
+ generateName: series-workflow
+spec:
+ entrypoint: main
+ arguments:
+ parameters:
+ - name: session-id
+ value: "some-session-id"
+# TODO: there seems to be no way to pass env variables into the GC workflow.
+# Set ARGO_ARTIFACT_GC_ENABLED=0 for the local setup?
+# artifactGC:
+# strategy: OnWorkflowCompletion
+ templates:
+ - name: main
+ # Don't schedule new steps if any of the previous steps failed.
+ failFast: true
+ # Note that failFast and parallelism only affect this template's steps.
+ parallelism: 1
+ steps:
+ - - name: run-triage
+ templateRef:
+ name: triage-step-template
+ template: triage-step
+ - - name: abort-on-skip
+ template: exit-workflow
+ when: "{{=jsonpath(steps['run-triage'].outputs.parameters.result, '$.skip') == true}}"
+ - - name: iterate-fuzz
+ template: process-fuzz-wrapper
+ arguments:
+ parameters:
+ - name: element
+ value: "{{item}}"
+ # Because of parallelism=1, the steps will be scheduled one after another.
+ # Because of failFast=True, the Failed status acts as the "break" operation.
+ withParam: "{{=jsonpath(steps['run-triage'].outputs.parameters.result, '$.fuzz')}}"
+ # Ignoge the (fake) Failed status to still keep the overall workflow status a Success.
+ continueOn:
+ failed: true
+ # The wrapper inverts the process-fuzz status in order to let iterate-fuzz iterate until a success.
+ - name: process-fuzz-wrapper
+ inputs:
+ parameters:
+ - name: element
+ steps:
+ - - name: run-process-fuzz
+ template: process-fuzz
+ arguments:
+ parameters:
+ - name: element
+ value: "{{inputs.parameters.element}}"
+ continueOn:
+ failed: true
+ - - name: break-if-succeeded
+ template: exit-workflow
+ when: "{{=steps['run-process-fuzz'].status == Succeeded}}"
+ - name: process-fuzz
+ inputs:
+ parameters:
+ - name: element
+ steps:
+ - - name: save-base-req
+ template: extract-request
+ arguments:
+ parameters:
+ - name: data
+ value: "{{=jsonpath(inputs.parameters.element, '$.base')}}"
+ - - name: base-build
+ templateRef:
+ name: build-step-template
+ template: build-step
+ arguments:
+ parameters:
+ - name: test-name
+ value: "Build Base"
+ artifacts:
+ - name: request
+ from: "{{steps.save-base-req.outputs.artifacts.request}}"
+ - - name: continue-if-base-build-failed
+ template: exit-workflow
+ when: "{{=jsonpath(steps['base-build'].outputs.parameters.result, '$.success') == false}}"
+ - - name: save-patched-req
+ template: extract-request
+ arguments:
+ parameters:
+ - name: data
+ value: "{{=jsonpath(inputs.parameters.element, '$.patched')}}"
+ - - name: patched-build
+ templateRef:
+ name: build-step-template
+ template: build-step
+ arguments:
+ parameters:
+ - name: test-name
+ value: "Build Patched"
+ - name: findings
+ value: "true"
+ artifacts:
+ - name: request
+ from: "{{steps.save-patched-req.outputs.artifacts.request}}"
+ - - name: continue-if-patched-build-failed
+ template: exit-workflow
+ when: "{{=jsonpath(steps['patched-build'].outputs.parameters.result, '$.success') == false}}"
+ - - name: boot-test-base
+ templateRef:
+ name: boot-step-template
+ template: boot-step
+ arguments:
+ artifacts:
+ - name: kernel
+ from: "{{steps.base-build.outputs.artifacts.kernel}}"
+ parameters:
+ - name: config
+ value: "{{=jsonpath(inputs.parameters.element, '$.config')}}"
+ - name: base-build-id
+ value: "{{=jsonpath(steps['base-build'].outputs.parameters.result, '$.build_id')}}"
+ - name: test-name
+ value: "Boot test: Base"
+ - name: boot-test-patched
+ templateRef:
+ name: boot-step-template
+ template: boot-step
+ arguments:
+ artifacts:
+ - name: kernel
+ from: "{{steps.patched-build.outputs.artifacts.kernel}}"
+ parameters:
+ - name: config
+ value: "{{=jsonpath(inputs.parameters.element, '$.config')}}"
+ - name: patched-build-id
+ value: "{{=jsonpath(steps['patched-build'].outputs.parameters.result, '$.build_id')}}"
+ - name: report-findings
+ value: "true"
+ - name: test-name
+ value: "Boot test: Patched"
+ - - name: break-if-base-boot-failed
+ template: exit-workflow
+ arguments:
+ parameters:
+ - name: code
+ value: 0
+ when: "{{=jsonpath(steps['boot-test-base'].outputs.parameters.result, '$.success') == false}}"
+ - - name: break-if-patched-boot-failed
+ template: exit-workflow
+ arguments:
+ parameters:
+ - name: code
+ value: 0
+ when: "{{=jsonpath(steps['boot-test-patched'].outputs.parameters.result, '$.success') == false}}"
+ - name: extract-request
+ inputs:
+ parameters:
+ - name: data
+ outputs:
+ artifacts:
+ - name: request
+ path: /tmp/request.json
+ container:
+ image: alpine:latest
+ command: [sh, -c]
+ args: ["echo '{{inputs.parameters.data}}' > /tmp/request.json"]
+ - name: exit-workflow
+ inputs:
+ parameters:
+ - name: code
+ value: 1
+ container:
+ image: alpine:latest
+ command: ['/bin/sh', '-c']
+ args: ["exit {{inputs.parameters.code}}"]
diff --git a/syz-cluster/run-local.sh b/syz-cluster/run-local.sh
new file mode 100755
index 000000000000..6d5d8f6291e0
--- /dev/null
+++ b/syz-cluster/run-local.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# Copyright 2024 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+if [ -z "$1" ]; then
+ echo "Error: No command/service name provided."
+ exit 1
+fi
+
+name="$1"
+shift
+
+alias kubectl="minikube kubectl --"
+# Clean up in case the run comand was prematurely aborted.
+# TODO: find out how to rely on envs from overlays/dev/global-config.yaml.
+kubectl delete pod run-local >/dev/null 2>&1 || true
+kubectl run run-local --image="$name-local" \
+ --image-pull-policy=Never \
+ --restart=Never \
+ --env="SPANNER_EMULATOR_HOST=cloud-spanner-emulator:9010" \
+ --env="SPANNER_DATABASE_URI=projects/my-project/instances/my-instance/databases/db" \
+ --env="LOCAL_BLOB_STORAGE_PATH=/tmp/blobs/" \
+ --rm \
+ --attach -- "$@"
diff --git a/syz-cluster/series-tracker/Dockerfile b/syz-cluster/series-tracker/Dockerfile
new file mode 100644
index 000000000000..4b7c49cd93c3
--- /dev/null
+++ b/syz-cluster/series-tracker/Dockerfile
@@ -0,0 +1,30 @@
+# Copyright 2024 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+FROM golang:1.23-alpine AS series-tracker-builder
+
+WORKDIR /build
+
+# Prepare the dependencies.
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Build the tool.
+COPY pkg/ pkg/
+# TODO: get rid of this dependency.
+COPY prog/ prog/
+COPY dashboard/dashapi/ dashboard/dashapi/
+COPY sys/targets/ sys/targets/
+COPY syz-cluster/series-tracker/*.go syz-cluster/series-tracker/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+
+RUN go build -o /build/series-tracker-bin /build/syz-cluster/series-tracker
+
+FROM ubuntu:latest
+
+RUN apt-get update && \
+ apt-get install -y git
+
+COPY --from=series-tracker-builder /build/series-tracker-bin /bin/series-tracker
+
+ENTRYPOINT ["/bin/series-tracker"]
diff --git a/syz-cluster/series-tracker/Dockerfile.test b/syz-cluster/series-tracker/Dockerfile.test
new file mode 100644
index 000000000000..1f9ca22de355
--- /dev/null
+++ b/syz-cluster/series-tracker/Dockerfile.test
@@ -0,0 +1,39 @@
+# I. Checkout the git repository.
+FROM ubuntu:latest AS git-source
+
+RUN apt-get update && \
+ apt-get install -y git
+
+WORKDIR /git-repo
+
+RUN git init
+RUN git remote add docs-0 http://lore.kernel.org/linux-doc/0
+RUN git fetch docs-0
+RUN git checkout docs-0/master
+
+# II. Build the tool.
+FROM golang:1.23-alpine AS series-tracker-builder
+
+WORKDIR /build
+
+# Prepare the dependencies.
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Build the tool.
+COPY pkg/ pkg/
+# TODO: get rid of this dependency.
+COPY prog/ prog/
+COPY dashboard/dashapi/ dashboard/dashapi/
+COPY sys/targets/ sys/targets/
+COPY syz-cluster/series-tracker/*.go syz-cluster/series-tracker/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+
+RUN go build -o /build/series-tracker-bin /build/syz-cluster/series-tracker
+
+# III. Create the actual container.
+FROM git-source
+
+COPY --from=series-tracker-builder /build/series-tracker-bin /bin/series-tracker
+
+ENTRYPOINT ["/bin/series-tracker"]
diff --git a/syz-cluster/series-tracker/deployment.yaml b/syz-cluster/series-tracker/deployment.yaml
new file mode 100644
index 000000000000..2a84f0722640
--- /dev/null
+++ b/syz-cluster/series-tracker/deployment.yaml
@@ -0,0 +1,35 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: series-tracker
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: series-tracker
+ template:
+ metadata:
+ labels:
+ app: series-tracker
+ spec:
+ containers:
+ - name: series-tracker-image
+ image: series-tracker-image
+ envFrom:
+ - configMapRef:
+ name: global-config
+ volumeMounts:
+ - name: series-tracker-repo-disk
+ mountPath: /git-repo
+ - name: blobs-storage-disk
+ mountPath: /blob-storage
+ volumes:
+ - name: series-tracker-repo-disk
+ persistentVolumeClaim:
+ claimName: series-tracker-repo-disk-claim
+ - name: blobs-storage-disk
+ persistentVolumeClaim:
+ claimName: blob-storage-disk-claim
diff --git a/syz-cluster/series-tracker/git-pvc.yaml b/syz-cluster/series-tracker/git-pvc.yaml
new file mode 100644
index 000000000000..b9f61f39ad65
--- /dev/null
+++ b/syz-cluster/series-tracker/git-pvc.yaml
@@ -0,0 +1,14 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: series-tracker-repo-disk-claim
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 25Gi
+ storageClassName: standard
diff --git a/syz-cluster/series-tracker/kustomization.yaml b/syz-cluster/series-tracker/kustomization.yaml
new file mode 100644
index 000000000000..e949daf9cbc5
--- /dev/null
+++ b/syz-cluster/series-tracker/kustomization.yaml
@@ -0,0 +1,6 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+resources:
+- deployment.yaml
+- git-pvc.yaml
diff --git a/syz-cluster/series-tracker/main.go b/syz-cluster/series-tracker/main.go
new file mode 100644
index 000000000000..a8121bf92ec0
--- /dev/null
+++ b/syz-cluster/series-tracker/main.go
@@ -0,0 +1,198 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "context"
+ "flag"
+ "fmt"
+ "log"
+ "path/filepath"
+ "regexp"
+ "time"
+
+ "github.com/google/syzkaller/pkg/email"
+ "github.com/google/syzkaller/pkg/email/lore"
+ "github.com/google/syzkaller/pkg/vcs"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/blob"
+ "github.com/google/syzkaller/syz-cluster/pkg/db"
+)
+
+var flagVerbose = flag.Bool("verbose", false, "enable verbose output")
+
+// TODO: add more.
+var archivesToQuery = []string{"linux-wireless", "netfilter-devel"}
+
+func main() {
+ flag.Parse()
+ ctx := context.Background()
+ env, err := app.Environment(ctx)
+ if err != nil {
+ app.Fatalf("failed to set up environment: %v", err)
+ }
+ manifest := NewManifestSource(`https://lore.kernel.org`)
+ fetcher := &SeriesFetcher{
+ gitRepoFolder: `/git-repo`, // Set in deployment.yaml.
+ seriesRepo: db.NewSeriesRepository(env.Spanner),
+ blobStorage: env.BlobStorage,
+ manifest: manifest,
+ }
+ go manifest.Loop(ctx)
+
+ // On start, look at the last week of messages.
+ nextFrom := time.Now().Add(-time.Hour * 24 * 7)
+ for {
+ oldFrom := nextFrom
+ // Then, parse last 30 minutes every 15 minutes.
+ nextFrom = time.Now().Add(-time.Minute * 15)
+ err := fetcher.Update(ctx, oldFrom)
+ if err != nil {
+ // TODO: make sure these are alerted.
+ log.Print(err)
+ }
+ time.Sleep(15 * time.Minute)
+ }
+}
+
+type SeriesFetcher struct {
+ gitRepoFolder string
+ seriesRepo *db.SeriesRepository
+ blobStorage blob.Storage
+ manifest *ManifestSource
+}
+
+func (sf *SeriesFetcher) Update(ctx context.Context, from time.Time) error {
+ log.Printf("querying email threads since %v", from)
+
+ manifest := sf.manifest.Get(ctx)
+ if manifest == nil {
+ return fmt.Errorf("failed to query the manifest data")
+ }
+ var list []lore.EmailReader
+ for _, name := range archivesToQuery {
+ info, ok := manifest[name]
+ if !ok {
+ return fmt.Errorf("manifest has no info for %q", name)
+ }
+ url := info.LastEpochURL()
+ log.Printf("polling %s", url)
+
+ folderName := sanitizeName(name)
+ if folderName == "" {
+ return fmt.Errorf("invalid archive name: %q", name)
+ }
+ gitRepo := vcs.NewLKMLRepo(filepath.Join(sf.gitRepoFolder, folderName))
+ // TODO: by querying only the last archive, we risk losing the series that are split between both.
+ // But for now let's ignore this possibility.
+ _, err := gitRepo.Poll(url, "master")
+ if err != nil {
+ return fmt.Errorf("failed to poll %q: %w", url, err)
+ }
+ repoList, err := lore.ReadArchive(gitRepo, from)
+ if err != nil {
+ return err
+ }
+ log.Printf("queried %d emails", len(repoList))
+ list = append(list, repoList...)
+ }
+
+ var emails []*email.Email
+ idToReader := map[string]lore.EmailReader{}
+ for _, item := range list {
+ // TODO: this could be done in several threads.
+ email, err := item.Parse(nil, nil)
+ if err != nil {
+ log.Printf("failed to parse email: %v", err)
+ continue
+ }
+ idToReader[email.MessageID] = item
+ emails = append(emails, email)
+ }
+ log.Printf("extracted: %d", len(list))
+
+ allSeries := lore.PatchSeries(emails)
+ log.Printf("collected %d series", len(allSeries))
+
+ for _, series := range allSeries {
+ if *flagVerbose {
+ logSeries(series)
+ }
+ err := sf.handleSeries(ctx, series, idToReader)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (sf *SeriesFetcher) handleSeries(ctx context.Context, series *lore.Series,
+ idToReader map[string]lore.EmailReader) error {
+ if series.Corrupted != "" {
+ log.Printf("skipping %s because of %q", series.MessageID, series.Corrupted)
+ return nil
+ }
+ first := series.Patches[0]
+ date := first.Date
+ if date.IsZero() || date.After(time.Now()) {
+ // We cannot fully trust dates from the mailing list as some of them are very weird, e.g.
+ // https://lore.kernel.org/all/20770915-nolibc-run-user-v1-1-3caec61726dc@weissschuh.net/raw.
+ date = time.Now()
+ }
+ err := sf.seriesRepo.Insert(ctx, &db.Series{
+ ExtID: series.MessageID,
+ // TODO: set AuthorName?
+ AuthorEmail: first.Author,
+ Title: series.Subject,
+ Version: int64(series.Version),
+ Link: "https://lore.kernel.org/all/" + series.MessageID,
+ PublishedAt: date,
+ // TODO: set Cc.
+ }, func() ([]*db.Patch, error) {
+ var ret []*db.Patch
+ for _, patch := range series.Patches {
+ body, err := idToReader[patch.MessageID].Read()
+ if err != nil {
+ return nil, fmt.Errorf("failed to extract %q: %w", patch.MessageID, err)
+ }
+ // In case of errors, we will waste some space, but let's ignore it for simplicity.
+ // Patches are not super big.
+ uri, err := sf.blobStorage.Store(bytes.NewReader(body))
+ if err != nil {
+ return nil, fmt.Errorf("failed to upload patch body: %w", err)
+ }
+ ret = append(ret, &db.Patch{
+ Seq: int64(patch.Seq),
+ Title: patch.Subject,
+ Link: "https://lore.kernel.org/all/" + patch.MessageID,
+ BodyURI: uri,
+ })
+ }
+ return ret, nil
+ })
+ if err == db.ErrSeriesExists {
+ log.Printf("series %s already exists in the DB", series.MessageID)
+ return nil
+ }
+ log.Printf("series %s saved to the DB", series.MessageID)
+ return nil
+}
+
+func logSeries(series *lore.Series) {
+ log.Printf("series ID=%s Subject=%s Patches=%d Version=%d Corrupted=%q",
+ series.MessageID, series.Subject, len(series.Patches), series.Version,
+ series.Corrupted)
+ for _, m := range series.Patches {
+ log.Printf(" #%d ID=%s Subject=%s", m.Seq, m.MessageID, m.Subject)
+ }
+}
+
+func sanitizeName(str string) string {
+ reg, err := regexp.Compile("[^a-zA-Z0-9]+")
+ if err != nil {
+ return ""
+ }
+ return reg.ReplaceAllString(str, "")
+}
diff --git a/syz-cluster/series-tracker/manifest.go b/syz-cluster/series-tracker/manifest.go
new file mode 100644
index 000000000000..7bb256ebb8e4
--- /dev/null
+++ b/syz-cluster/series-tracker/manifest.go
@@ -0,0 +1,139 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "compress/gzip"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "regexp"
+ "strconv"
+ "sync"
+ "time"
+)
+
+type InboxInfo struct {
+ Prefix string
+ Epochs int
+}
+
+func (ii InboxInfo) EpochURL(id int) string {
+ return fmt.Sprintf("%s/git/%d.git", ii.Prefix, id)
+}
+
+func (ii InboxInfo) LastEpochURL() string {
+ return ii.EpochURL(ii.Epochs - 1)
+}
+
+var archiveRe = regexp.MustCompile(`/([\w-]+)/git/(\d+)\.git`)
+
+func ParseManifest(baseURL string, jsonData []byte) (map[string]*InboxInfo, error) {
+ var rawMap map[string]json.RawMessage
+ err := json.Unmarshal(jsonData, &rawMap)
+ if err != nil {
+ return nil, err
+ }
+ ret := map[string]*InboxInfo{}
+ for url := range rawMap {
+ groups := archiveRe.FindStringSubmatch(url)
+ if len(groups) == 0 {
+ // TODO: monitor these.
+ log.Printf("unexpected manifest.js key: %q", url)
+ continue
+ }
+ epoch, err := strconv.Atoi(groups[2])
+ if err != nil {
+ log.Printf("invalid manifest.js key: %q", url)
+ continue
+ }
+ inbox := ret[groups[1]]
+ if inbox == nil {
+ inbox = &InboxInfo{Prefix: fmt.Sprintf("%s/%s", baseURL, groups[1])}
+ ret[groups[1]] = inbox
+ }
+ inbox.Epochs = max(inbox.Epochs, epoch+1)
+ }
+ return ret, nil
+}
+
+func QueryManifest(baseURL string) (map[string]*InboxInfo, error) {
+ resp, err := http.Get(baseURL + "/manifest.js.gz")
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ gzReader, err := gzip.NewReader(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ defer gzReader.Close()
+
+ var buf bytes.Buffer
+ _, err = io.Copy(&buf, gzReader)
+ if err != nil {
+ return nil, err
+ }
+ return ParseManifest(baseURL, buf.Bytes())
+}
+
+// ManifestSource keeps an up to date version of the manifest.
+type ManifestSource struct {
+ mu sync.Mutex
+ url string
+ latestOk map[string]*InboxInfo
+ firstLoaded chan struct{} // The channel will be closed on the first successful load.
+}
+
+func NewManifestSource(baseURL string) *ManifestSource {
+ return &ManifestSource{
+ url: baseURL,
+ firstLoaded: make(chan struct{}),
+ }
+}
+
+func (ms *ManifestSource) Loop(ctx context.Context) {
+ // When we try to load for the first time, retry more frequently.
+ const backOffPeriod = time.Minute * 15
+ // Then, update rarely. New epochs are very infrequent.
+ const refreshPeriod = time.Hour * 12
+
+ alreadyLoaded := false
+ nextAttemptIn := backOffPeriod
+ for {
+ info, err := QueryManifest(ms.url)
+ log.Printf("loaded manifest: %v", err)
+ if err == nil {
+ ms.mu.Lock()
+ ms.latestOk = info
+ ms.mu.Unlock()
+ if !alreadyLoaded {
+ alreadyLoaded = true
+ nextAttemptIn = refreshPeriod
+ close(ms.firstLoaded)
+ }
+ }
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(nextAttemptIn):
+ }
+ }
+}
+
+func (ms *ManifestSource) Get(ctx context.Context) map[string]*InboxInfo {
+ select {
+ case <-ms.firstLoaded:
+ ms.mu.Lock()
+ defer ms.mu.Unlock()
+ return ms.latestOk
+ case <-ctx.Done():
+ return nil
+ }
+}
diff --git a/syz-cluster/series-tracker/manifest_test.go b/syz-cluster/series-tracker/manifest_test.go
new file mode 100644
index 000000000000..2e3bbde5a6e5
--- /dev/null
+++ b/syz-cluster/series-tracker/manifest_test.go
@@ -0,0 +1,44 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestParseManifest(t *testing.T) {
+ info, err := ParseManifest("http://localhost", []byte(testManifest))
+ assert.NoError(t, err)
+ assert.Len(t, info, 2)
+ assert.Equal(t, 1, info["name"].Epochs)
+ second := info["name2"]
+ assert.Equal(t, 2, second.Epochs)
+ assert.Equal(t, "http://localhost/name2/git/1.git", second.EpochURL(1))
+}
+
+const testManifest = `{
+ "/name2/git/1.git": {
+ "modified": 1638806983,
+ "owner": null,
+ "reference": null,
+ "description": "Another repo",
+ "fingerprint": "788f666601f9641375e11e167b5e6b1eeb549cbb"
+ },
+ "/name/git/0.git": {
+ "modified": 1638806983,
+ "owner": null,
+ "reference": null,
+ "description": "Some repo",
+ "fingerprint": "788f666601f9641375e11e167b5e6b1eeb549cbb"
+ },
+ "/name2/git/0.git": {
+ "modified": 1638806983,
+ "owner": null,
+ "reference": null,
+ "description": "Another repo",
+ "fingerprint": "788f666601f9641375e11e167b5e6b1eeb549cbb"
+ }
+}`
diff --git a/syz-cluster/workflow/boot-step/Dockerfile b/syz-cluster/workflow/boot-step/Dockerfile
new file mode 100644
index 000000000000..7fa89e04a488
--- /dev/null
+++ b/syz-cluster/workflow/boot-step/Dockerfile
@@ -0,0 +1,45 @@
+# syntax=docker.io/docker/dockerfile:1.7-labs
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+# Build syzkaller.
+FROM gcr.io/syzkaller/env as syzkaller-builder
+WORKDIR /build
+# First query the modules to facilitate caching.
+COPY go.mod go.sum ./
+RUN go mod download
+COPY --exclude=vendor --exclude=syz-cluster . .
+RUN make TARGETARCH=amd64
+
+FROM golang:1.23-alpine AS boot-step-builder
+WORKDIR /build
+
+# Copy the code and the dependencies.
+COPY go.mod go.sum ./
+RUN go mod download
+COPY pkg/ pkg/
+# TODO: get rid of the prog/ dependency?
+COPY prog/ prog/
+COPY vm/ vm/
+COPY executor/ executor/
+COPY dashboard/dashapi/ dashboard/dashapi/
+# Copying from the builder to take the `make descriptions` result.
+COPY --from=syzkaller-builder /build/sys/ sys/
+COPY syz-cluster/workflow/boot-step/*.go syz-cluster/workflow/boot-step/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+
+RUN go build -o /build/boot-step-bin /build/syz-cluster/workflow/boot-step
+
+FROM debian:bookworm
+
+RUN apt-get update && \
+ apt-get install -y qemu-system openssh-client
+
+# pkg/osutil uses syzkaller user for sandboxing.
+RUN useradd --create-home syzkaller
+
+COPY --from=syzkaller-builder /build/bin/ /syzkaller/bin/
+COPY --from=boot-step-builder /build/boot-step-bin /bin/boot-step
+COPY syz-cluster/workflow/configs/ /configs/
+
+ENTRYPOINT ["/bin/boot-tracker"]
diff --git a/syz-cluster/workflow/boot-step/main.go b/syz-cluster/workflow/boot-step/main.go
new file mode 100644
index 000000000000..8adf15fac451
--- /dev/null
+++ b/syz-cluster/workflow/boot-step/main.go
@@ -0,0 +1,102 @@
+// Copyright 2025 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "log"
+ "path/filepath"
+
+ "github.com/google/syzkaller/pkg/instance"
+ "github.com/google/syzkaller/pkg/mgrconfig"
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+)
+
+var (
+ flagConfig = flag.String("config", "", "syzkaller config")
+ flagSession = flag.String("session", "", "session ID")
+ flagTestName = flag.String("test_name", "", "test name")
+ flagBaseBuild = flag.String("base_build", "", "base build ID")
+ flagPatchedBuild = flag.String("patched_build", "", "patched build ID")
+ flagOutput = flag.String("output", "", "where to store the result")
+ flagFindings = flag.Bool("findings", false, "report failur as findings")
+)
+
+func main() {
+ flag.Parse()
+ if *flagConfig == "" || *flagSession == "" || *flagTestName == "" {
+ app.Fatalf("--config, --session and --test_name must be set")
+ }
+
+ ctx := context.Background()
+ client := app.DefaultClient()
+
+ testResult := &api.TestResult{
+ SessionID: *flagSession,
+ TestName: *flagTestName,
+ BaseBuildID: *flagBaseBuild,
+ PatchedBuildID: *flagPatchedBuild,
+ Result: api.TestRunning,
+ }
+ // Report that we've begun the test -- it will let us report the findings.
+ err := client.UploadTestResult(ctx, testResult)
+ if err != nil {
+ app.Fatalf("failed to upload test result: %v", err)
+ }
+
+ bootedFine, err := runTest(ctx, client)
+ if err != nil {
+ app.Fatalf("failed to run the boot test: %v", err)
+ }
+ if bootedFine {
+ testResult.Result = api.TestPassed
+ } else {
+ testResult.Result = api.TestFailed
+ }
+
+ // Report the test results.
+ err = client.UploadTestResult(ctx, testResult)
+ if err != nil {
+ app.Fatalf("failed to upload test result: %v", err)
+ }
+ if *flagOutput != "" {
+ osutil.WriteJSON(*flagOutput, &api.BootResult{
+ Success: bootedFine,
+ })
+ }
+}
+
+func runTest(ctx context.Context, client *api.Client) (bool, error) {
+ cfg, err := mgrconfig.LoadFile(filepath.Join("/configs", *flagConfig, "base.cfg"))
+ if err != nil {
+ return false, err
+ }
+ cfg.Workdir = "/tmp/test-workdir"
+ rep, err := instance.RunSmokeTest(cfg)
+ if err != nil {
+ return false, err
+ } else if rep == nil {
+ return true, nil
+ }
+
+ log.Printf("found: %q", rep.Title)
+ if *flagFindings {
+ log.Printf("reporting the finding")
+ findingErr := client.UploadFinding(ctx, &api.Finding{
+ SessionID: *flagSession,
+ TestName: *flagTestName,
+ Title: rep.Title,
+ Report: rep.Report,
+ Log: rep.Output,
+ })
+ if findingErr != nil {
+ return false, fmt.Errorf("failed to report the finding: %w", findingErr)
+ }
+ }
+ return false, nil
+}
diff --git a/syz-cluster/workflow/boot-step/workflow-template.yaml b/syz-cluster/workflow/boot-step/workflow-template.yaml
new file mode 100644
index 000000000000..1f7e1f70f572
--- /dev/null
+++ b/syz-cluster/workflow/boot-step/workflow-template.yaml
@@ -0,0 +1,70 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+ name: boot-step-template
+spec:
+ templates:
+ - name: boot-step
+ inputs:
+ parameters:
+ - name: config
+ value: ""
+ - name: base-build-id
+ value: ""
+ - name: patched-build-id
+ value: ""
+ - name: test-name
+ value: ""
+ - name: report-findings
+ value: "false"
+ artifacts:
+ - name: kernel
+ path: /kernel
+ container:
+ image: boot-step-local
+ imagePullPolicy: IfNotPresent
+ command: ["/bin/boot-step"]
+ args: [
+ "--config", "{{inputs.parameters.config}}",
+ "--output", "/output/result.json",
+ "--session", "{{workflow.parameters.session-id}}",
+ "--test_name", "{{inputs.parameters.test-name}}",
+ "--base_build", "{{inputs.parameters.base-build-id}}",
+ "--patched_build", "{{inputs.parameters.patched-build-id}}",
+ "-findings={{inputs.parameters.report-findings}}"
+ ]
+ resources:
+ requests:
+ cpu: 6
+ memory: 12G
+ limits:
+ cpu: 8
+ memory: 24G
+ volumeMounts:
+ - name: workdir
+ mountPath: /workdir
+ - name: output
+ mountPath: /output
+ - name: dev-kvm
+ mountPath: /dev/kvm
+ # Needed for /dev/kvm.
+ # TODO: there's a "device plugin" mechanism in k8s that can share it more safely.
+ securityContext:
+ privileged: true
+ volumes:
+ - name: workdir
+ emptyDir: {}
+ - name: output
+ emptyDir: {}
+ - name: dev-kvm
+ hostPath:
+ path: /dev/kvm
+ type: CharDevice
+ outputs:
+ parameters:
+ - name: result
+ valueFrom:
+ path: /output/result.json
diff --git a/syz-cluster/workflow/build-step/Dockerfile b/syz-cluster/workflow/build-step/Dockerfile
new file mode 100644
index 000000000000..1dc7665abd45
--- /dev/null
+++ b/syz-cluster/workflow/build-step/Dockerfile
@@ -0,0 +1,70 @@
+# Copyright 2024 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+FROM golang:1.23-alpine AS build-step-builder
+
+WORKDIR /build
+
+# Copy the code and the dependencies.
+COPY go.mod go.sum ./
+RUN go mod download
+COPY pkg/ pkg/
+# TODO: get rid of the prog/ dependency?
+COPY prog/ prog/
+COPY vm/ vm/
+COPY dashboard/dashapi/ dashboard/dashapi/
+COPY sys/ sys/
+COPY syz-cluster/workflow/build-step/*.go syz-cluster/workflow/build-step/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+
+RUN go build -o /build/build-step-bin /build/syz-cluster/workflow/build-step
+
+FROM debian:bookworm
+
+# pkg/osutil uses syzkaller user for sandboxing.
+RUN useradd --create-home syzkaller
+
+# The prerequisites for building the kernel.
+RUN apt-get update && \
+ apt-get install -y git make binutils gcc g++ binutils make \
+ flex bison bc gawk dwarves cpio texinfo texi2html lzop lbzip2 \
+ zlib1g-dev libelf-dev libncurses-dev libmpc-dev libssl-dev \
+ apt-transport-https curl gnupg python-is-python3
+
+# TODO: it's duplicated from the syzbot's Docker container.
+
+# The default clang-14 is too old, install the latest one.
+RUN apt-get install -y -q gnupg software-properties-common apt-transport-https
+RUN curl https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+RUN add-apt-repository "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-15 main"
+RUN apt-get update --allow-releaseinfo-change
+RUN apt-get install -y -q --no-install-recommends llvm-15 clang-15 clang-format-15 clang-tidy-15 lld-15
+RUN apt autoremove -y -q
+RUN apt-get update && apt-get install -y sudo
+RUN sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-15 100
+RUN sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-15 100
+RUN sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 100
+RUN sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100
+RUN sudo update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/lld-15 100
+RUN sudo update-alternatives --install /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-15 100
+RUN sudo update-alternatives --install /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-15 100
+RUN sudo update-alternatives --install /usr/bin/llvm-objcopy llvm-objcopy /usr/bin/llvm-objcopy-15 100
+RUN sudo update-alternatives --install /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-15 100
+RUN sudo update-alternatives --install /usr/bin/llvm-addr2line llvm-addr2line /usr/bin/llvm-addr2line-15 100
+RUN sudo update-alternatives --install /usr/bin/llvm-readelf llvm-readelf /usr/bin/llvm-readelf-15 100
+RUN sudo update-alternatives --install /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-15 100
+
+# Download the base buildroot image.
+RUN apt-get update && apt-get install -y wget
+RUN mkdir -p /disk-images
+RUN wget https://storage.googleapis.com/syzkaller/images/buildroot_amd64_2024.09.gz -O /disk-images/buildroot_amd64_2024.09.gz
+RUN gzip -d /disk-images/buildroot_amd64_2024.09.gz
+
+# Download some base kernel configs.
+
+RUN mkdir -p /kernel-configs
+RUN wget https://raw.githubusercontent.com/google/syzkaller/refs/heads/master/dashboard/config/linux/upstream-apparmor-kasan.config -O /kernel-configs/upstream-apparmor-kasan.config
+
+COPY --from=build-step-builder /build/build-step-bin /bin/build-step
+
+ENTRYPOINT ["/bin/series-tracker"]
diff --git a/syz-cluster/workflow/build-step/main.go b/syz-cluster/workflow/build-step/main.go
new file mode 100644
index 000000000000..bd226401e8fb
--- /dev/null
+++ b/syz-cluster/workflow/build-step/main.go
@@ -0,0 +1,217 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+
+ "github.com/google/syzkaller/pkg/build"
+ "github.com/google/syzkaller/pkg/debugtracer"
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/pkg/vcs"
+ "github.com/google/syzkaller/sys/targets"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/triage"
+)
+
+var (
+ flagRequest = flag.String("request", "", "path to a build request description")
+ flagRepository = flag.String("repository", "", "path to a kernel checkout")
+ flagOutput = flag.String("output", "", "path to save kernel build artifacts")
+ flagTestName = flag.String("test_name", "", "test name")
+ flagSession = flag.String("session", "", "session ID")
+ flagFindings = flag.Bool("findings", false, "report build failures as findings")
+)
+
+func main() {
+ flag.Parse()
+ ensureFlags(*flagRequest, "--request",
+ *flagRepository, "--repository",
+ *flagOutput, "--output",
+ *flagSession, "--session",
+ *flagTestName, "--test_name")
+
+ req := readRequest()
+ ctx := context.Background()
+ client := app.DefaultClient()
+ // TODO: (optimization) query whether the same BuildRequest has already been completed.
+ var series *api.Series
+ if req.SeriesID != "" {
+ var err error
+ series, err = client.GetSeries(ctx, req.SeriesID)
+ if err != nil {
+ app.Fatalf("failed to query the series info: %v", err)
+ }
+ }
+ uploadReq := &api.UploadBuildReq{
+ Build: api.Build{
+ TreeName: req.TreeName,
+ CommitHash: req.CommitHash,
+ SeriesID: req.SeriesID,
+ },
+ }
+ commit, err := checkoutKernel(req, series)
+ if commit != nil {
+ uploadReq.CommitDate = commit.CommitDate
+ }
+ var finding *api.Finding
+ if err != nil {
+ log.Printf("failed to checkout: %v", err)
+ uploadReq.Log = []byte(err.Error())
+ } else {
+ err := buildKernel(req)
+ if err == nil {
+ uploadReq.BuildSuccess = true
+ } else {
+ log.Printf("failed to build: %v", err)
+ uploadReq.Log = []byte(err.Error())
+ finding = &api.Finding{
+ SessionID: *flagSession,
+ TestName: *flagTestName,
+ Title: "failed to build the kernel",
+ Log: uploadReq.Log,
+ }
+ }
+ }
+ reportResults(ctx, client, req.SeriesID != "", uploadReq, finding)
+}
+
+func reportResults(ctx context.Context, client *api.Client, patched bool,
+ uploadReq *api.UploadBuildReq, finding *api.Finding) {
+ buildInfo, err := client.UploadBuild(ctx, uploadReq)
+ if err != nil {
+ app.Fatalf("failed to upload build: %v", err)
+ }
+ log.Printf("uploaded build, reply: %q", buildInfo)
+ osutil.WriteJSON(filepath.Join(*flagOutput, "result.json"), &api.BuildResult{
+ BuildID: buildInfo.ID,
+ Success: uploadReq.BuildSuccess,
+ })
+ testResult := &api.TestResult{
+ SessionID: *flagSession,
+ TestName: *flagTestName,
+ Result: api.TestFailed,
+ }
+ if uploadReq.BuildSuccess {
+ testResult.Result = api.TestPassed
+ }
+ if patched {
+ testResult.PatchedBuildID = buildInfo.ID
+ } else {
+ testResult.BaseBuildID = buildInfo.ID
+ }
+ err = client.UploadTestResult(ctx, testResult)
+ if err != nil {
+ app.Fatalf("failed to report the test result: %v", err)
+ }
+ if *flagFindings && finding != nil {
+ err = client.UploadFinding(ctx, finding)
+ if err != nil {
+ app.Fatalf("failed to report the finding: %v", err)
+ }
+ }
+}
+
+func readRequest() *api.BuildRequest {
+ raw, err := os.ReadFile(*flagRequest)
+ if err != nil {
+ app.Fatalf("failed to read request: %v", err)
+ return nil
+ }
+ var req api.BuildRequest
+ err = json.Unmarshal(raw, &req)
+ if err != nil {
+ app.Fatalf("failed to unmarshal request: %v, %s", err, raw)
+ return nil
+ }
+ return &req
+}
+
+func checkoutKernel(req *api.BuildRequest, series *api.Series) (*vcs.Commit, error) {
+ log.Printf("checking out %q", req.CommitHash)
+ ops, err := triage.NewGitTreeOps(*flagRepository, true)
+ if err != nil {
+ return nil, err
+ }
+ commit, err := ops.Commit(req.CommitHash)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get commit info: %w", err)
+ }
+ var patches [][]byte
+ if series != nil {
+ patches = series.Patches
+ }
+ if len(patches) > 0 {
+ log.Printf("applying %d patches", len(patches))
+ }
+ err = ops.ApplySeries(req.CommitHash, patches)
+ return commit, err
+}
+
+func buildKernel(req *api.BuildRequest) error {
+ kernelConfig, err := os.ReadFile(filepath.Join("/kernel-configs", req.ConfigName))
+ if err != nil {
+ return fmt.Errorf("failed to read the kernel config: %w", err)
+ }
+ if req.Arch != "amd64" {
+ // TODO: lift this restriction.
+ return fmt.Errorf("only amd64 builds are supported now")
+ }
+ params := build.Params{
+ TargetOS: targets.Linux,
+ TargetArch: req.Arch,
+ VMType: "qemu", // TODO: support others.
+ KernelDir: *flagRepository,
+ OutputDir: *flagOutput,
+ Compiler: "clang",
+ Linker: "ld.lld",
+ UserspaceDir: "/disk-images/buildroot_amd64_2024.09", // See the Dockerfile.
+ Config: kernelConfig,
+ Tracer: &debugtracer.GenericTracer{
+ TraceWriter: os.Stdout,
+ OutDir: "",
+ },
+ }
+ log.Printf("started build: %q", req)
+ info, err := build.Image(params)
+ log.Printf("compiler: %q", info.CompilerID)
+ if err != nil {
+ var kernelError *build.KernelError
+ var verboseError *osutil.VerboseError
+ switch {
+ case errors.As(err, &kernelError):
+ log.Printf("kernel error: %q / %s", kernelError.Report, kernelError.Output)
+ case errors.As(err, &verboseError):
+ log.Printf("verbose error: %q / %s", verboseError.Title, verboseError.Output)
+ default:
+ log.Printf("other error: %v", err)
+ }
+ return err
+ }
+ log.Printf("build finished successfully")
+ // TODO: capture build logs and the compiler identity.
+ // Note: Output directory has the following structure:
+ // |-- image
+ // |-- kernel
+ // |-- kernel.config
+ // `-- obj
+ // `-- vmlinux
+ return nil
+}
+
+func ensureFlags(args ...string) {
+ for i := 0; i+1 < len(args); i += 2 {
+ if args[i] == "" {
+ app.Fatalf("%s must be set", args[i+1])
+ }
+ }
+}
diff --git a/syz-cluster/workflow/build-step/workflow-template.yaml b/syz-cluster/workflow/build-step/workflow-template.yaml
new file mode 100644
index 000000000000..fa6c9c0ca172
--- /dev/null
+++ b/syz-cluster/workflow/build-step/workflow-template.yaml
@@ -0,0 +1,101 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+ name: build-step-template
+spec:
+ templates:
+ - name: build-step
+ inputs:
+ parameters:
+ - name: findings
+ value: "false"
+ - name: test-name
+ artifacts:
+ - name: request
+ path: /tmp/request.json
+ initContainers:
+ - name: setup-overlays
+ image: bitnami/git:latest
+ imagePullPolicy: IfNotPresent
+ command:
+ - sh
+ - -c
+ - |
+ mkdir /data/overlayfs /data/.git
+ mount -t tmpfs -o size=128M tmpfs /data/overlayfs
+ mkdir /data/overlayfs/upper /data/overlayfs/work
+ mount -t overlay overlay -o lowerdir=/kernel-repo,upperdir=/data/overlayfs/upper,workdir=/data/overlayfs/work /data/.git
+ chmod 0777 /data/.git
+ git --git-dir=/data/.git --work-tree=/workdir checkout v3.0
+ chmod -R 0777 /data/.git/logs
+ chmod -R 0777 /workdir
+ volumeMounts:
+ - name: shared-git-repo
+ mountPath: /data
+ mountPropagation: Bidirectional
+ - name: base-kernel-repo
+ mountPath: /kernel-repo
+ readOnly: true
+ - name: workdir
+ mountPath: /workdir
+ securityContext:
+ privileged: true
+ capabilities:
+ add: ["SYS_ADMIN"]
+ container:
+ image: build-step-local
+ imagePullPolicy: IfNotPresent
+ command: ["/bin/build-step"]
+ args: [
+ "--request", "/tmp/request.json",
+ "--repository", "/workdir",
+ "--output", "/output",
+ "--session", "{{workflow.parameters.session-id}}",
+ "--test_name", "{{inputs.parameters.test-name}}",
+ "-findings={{inputs.parameters.findings}}"
+ ]
+ env:
+ - name: GIT_DIR
+ value: "/data/.git"
+ - name: GIT_DISCOVERY_ACROSS_FILESYSTEM
+ value: "1"
+ - name: GIT_WORK_TREE
+ value: "/workdir"
+ - name: HOME # Otherwise it's failing with "warning: unable to access '/root/.config/git/attributes': Permission denied.".
+ value: "/home/syzkaller"
+ volumeMounts:
+ - name: shared-git-repo
+ mountPath: /data
+ - name: base-kernel-repo
+ mountPath: /kernel-repo
+ readOnly: true
+ - name: workdir
+ mountPath: /workdir
+ - name: output
+ mountPath: /output
+ securityContext:
+ privileged: true
+ capabilities:
+ add: ["SYS_ADMIN"] # We need to mount a loop device during the kernel build.
+ volumes:
+ - name: base-kernel-repo
+ persistentVolumeClaim:
+ claimName: base-kernel-repo-pv-claim
+ - name: shared-git-repo
+ emptyDir:
+ medium: Memory
+ - name: workdir
+ emptyDir: {}
+ - name: output
+ emptyDir: {}
+ outputs:
+ parameters:
+ - name: result
+ valueFrom:
+ path: /output/result.json
+ artifacts:
+ - name: kernel
+ path: /output
diff --git a/syz-cluster/workflow/permissions.yaml b/syz-cluster/workflow/permissions.yaml
new file mode 100644
index 000000000000..806589e5e851
--- /dev/null
+++ b/syz-cluster/workflow/permissions.yaml
@@ -0,0 +1,15 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: executor
+rules:
+ - apiGroups:
+ - argoproj.io
+ resources:
+ - workflowtaskresults
+ verbs:
+ - create
+ - patch
diff --git a/syz-cluster/workflow/triage-step/Dockerfile b/syz-cluster/workflow/triage-step/Dockerfile
new file mode 100644
index 000000000000..65d68f2dcfff
--- /dev/null
+++ b/syz-cluster/workflow/triage-step/Dockerfile
@@ -0,0 +1,33 @@
+# Copyright 2024 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+FROM golang:1.23-alpine AS triage-step-builder
+
+WORKDIR /build
+
+# Prepare the dependencies.
+COPY go.mod go.sum ./
+RUN go mod download
+
+# Build the tool.
+COPY pkg/ pkg/
+# TODO: get rid of this dependency.
+COPY prog/ prog/
+COPY dashboard/dashapi/ dashboard/dashapi/
+COPY sys/targets/ sys/targets/
+COPY syz-cluster/workflow/triage-step/*.go syz-cluster/workflow/triage-step/
+COPY syz-cluster/pkg/ syz-cluster/pkg/
+
+RUN go build -o /build/triage-step-bin /build/syz-cluster/workflow/triage-step
+
+FROM ubuntu:latest
+
+RUN apt-get update && \
+ apt-get install -y git
+
+# pkg/osutil uses syzkaller user for sandboxing.
+RUN useradd --create-home syzkaller
+
+COPY --from=triage-step-builder /build/triage-step-bin /bin/triage-step
+
+ENTRYPOINT ["/bin/series-tracker"]
diff --git a/syz-cluster/workflow/triage-step/README.md b/syz-cluster/workflow/triage-step/README.md
new file mode 100644
index 000000000000..9d4b517255a1
--- /dev/null
+++ b/syz-cluster/workflow/triage-step/README.md
@@ -0,0 +1,34 @@
+## Ephemeral disk size usage estimations for Linux
+
+```
+$ git fetch origin +refs/tags/torvalds-head:refs/tags/torvalds-head --depth=1
+$ du -h .
+260M .
+$ git checkout torvalds-head
+$ du -h .
+2G .
+$ git fetch origin 2dde18cd1d8fac735875f2e4987f11817cc0bc2c --depth=1
+$ du -h .
+2.1G .
+$ git checkout 2dde18cd1d8fac735875f2e4987f11817cc0bc2c
+$ du -h .
+2G .
+```
+
+## Without cloning the repository
+
+```
+mkdir ~/shallow-repo ~/shallow-repo/.git ~/shallow-repo/workdir ~/overlayfs
+mount -t tmpfs -o size=128M tmpfs /root/overlayfs
+mkdir ~/overlayfs/upper ~/overlayfs/work
+mount -t overlay overlay -o lowerdir=/kernel-repo,upperdir=/root/overlayfs/upper,workdir=/root/overlayfs/work /root/shallow-repo/.git
+git --git-dir=/root/shallow-repo/.git --work-tree=/root/shallow-repo/workdir checkout master
+```
+
+Needs:
+
+```
+ securityContext:
+ capabilities:
+ add: ["SYS_ADMIN"]
+```
diff --git a/syz-cluster/workflow/triage-step/main.go b/syz-cluster/workflow/triage-step/main.go
new file mode 100644
index 000000000000..6a45972eaf27
--- /dev/null
+++ b/syz-cluster/workflow/triage-step/main.go
@@ -0,0 +1,98 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/syz-cluster/pkg/api"
+ "github.com/google/syzkaller/syz-cluster/pkg/app"
+ "github.com/google/syzkaller/syz-cluster/pkg/triage"
+)
+
+var (
+ flagSession = flag.String("session", "", "session ID")
+ flagRepo = flag.String("repository", "", "path to a kernel checkout")
+ flagVerdict = flag.String("verdict", "", "where to save the verdict")
+)
+
+func main() {
+ flag.Parse()
+ if *flagSession == "" || *flagRepo == "" {
+ // TODO: abort the whole workflow, no sense to retry. Alert the error.
+ app.Fatalf("--session and --repo must be set")
+ }
+ client := app.DefaultClient()
+ repo, err := triage.NewGitTreeOps(*flagRepo, true)
+ if err != nil {
+ app.Fatalf("failed to initialize the repository: %v", err)
+ }
+ verdict, err := getVerdict(*flagSession, client, repo)
+ if err != nil {
+ app.Fatalf("failed to get the verdict: %v", err)
+ }
+ if *flagVerdict != "" {
+ osutil.WriteJSON(*flagVerdict, verdict)
+ }
+
+ // TODO:
+ // 1. It might be that the kernel builds/boots for one arch and does not build for another.
+ // 2. What if controller does not reply? Let Argo just restart the step.
+}
+
+func getVerdict(sessionID string, client *api.Client, ops triage.TreeOps) (*api.TriageResult, error) {
+ ctx := context.Background()
+ series, err := client.GetSessionSeries(ctx, sessionID)
+ if err != nil {
+ // TODO: the workflow step must be retried.
+ return nil, fmt.Errorf("failed to query series: %w", err)
+ }
+ tree := triage.SelectTree(series, client.GetTrees())
+ if tree == nil {
+ return &api.TriageResult{
+ Skip: true,
+ }, nil
+ }
+ arch := "amd64"
+ lastBuild, err := client.LastSuccessfulBuild(ctx, &api.LastBuildReq{
+ Arch: arch,
+ ConfigName: tree.ConfigName,
+ TreeName: tree.Name,
+ })
+ if err != nil {
+ // TODO: the workflow step must be retried.
+ return nil, fmt.Errorf("failed to query the last build: %w", err)
+ }
+ selector := triage.NewCommitSelector(ops)
+ commits, err := selector.Select(series, tree, lastBuild)
+ if err != nil {
+ // TODO: the workflow step must be retried.
+ return nil, fmt.Errorf("failed to run the commit selector: %w", err)
+ }
+ if len(commits) == 0 {
+ return &api.TriageResult{
+ Skip: true,
+ }, nil
+ }
+ ret := &api.TriageResult{}
+ for _, commit := range commits {
+ base := api.BuildRequest{
+ TreeName: tree.Name,
+ ConfigName: tree.ConfigName,
+ CommitHash: commit,
+ Arch: arch,
+ }
+ patched := base
+ patched.SeriesID = series.ID
+ ret.Fuzz = append(ret.Fuzz, &api.FuzzConfig{
+ Base: base,
+ Patched: patched,
+ Config: "all",
+ })
+ }
+ return ret, nil
+}
diff --git a/syz-cluster/workflow/triage-step/workflow-template.yaml b/syz-cluster/workflow/triage-step/workflow-template.yaml
new file mode 100644
index 000000000000..8228f35375d0
--- /dev/null
+++ b/syz-cluster/workflow/triage-step/workflow-template.yaml
@@ -0,0 +1,78 @@
+# Copyright 2025 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+apiVersion: argoproj.io/v1alpha1
+kind: WorkflowTemplate
+metadata:
+ name: triage-step-template
+spec:
+ templates:
+ - name: triage-step
+ initContainers:
+ - name: setup-overlays
+ image: bitnami/git:latest
+ imagePullPolicy: IfNotPresent
+ command:
+ - sh
+ - -c
+ - |
+ mkdir /data/overlayfs /data/.git
+ mount -t tmpfs -o size=128M tmpfs /data/overlayfs
+ mkdir /data/overlayfs/upper /data/overlayfs/work
+ mount -t overlay overlay -o lowerdir=/kernel-repo,upperdir=/data/overlayfs/upper,workdir=/data/overlayfs/work /data/.git
+ chmod 0777 /data/.git
+ git --git-dir=/data/.git --work-tree=/workdir checkout v3.0
+ chmod -R 0777 /data/.git/logs
+ chmod -R 0777 /workdir
+ volumeMounts:
+ - name: shared-git-repo
+ mountPath: /data
+ mountPropagation: Bidirectional
+ - name: base-kernel-repo
+ mountPath: /kernel-repo
+ readOnly: true
+ - name: workdir
+ mountPath: /workdir
+ securityContext:
+ privileged: true
+ capabilities:
+ add: ["SYS_ADMIN"]
+ container:
+ image: triage-step-local
+ imagePullPolicy: IfNotPresent
+ command: ["/bin/triage-step", "--session", "{{workflow.parameters.session-id}}", "--repository", "/workdir", "--verdict", "/output/result.json"]
+ env:
+ - name: GIT_DIR
+ value: "/data/.git"
+ - name: GIT_DISCOVERY_ACROSS_FILESYSTEM
+ value: "1"
+ - name: GIT_WORK_TREE
+ value: "/workdir"
+ - name: HOME # Otherwise it's failing with "warning: unable to access '/root/.config/git/attributes': Permission denied.".
+ value: "/home/syzkaller"
+ volumeMounts:
+ - name: shared-git-repo
+ mountPath: /data
+ - name: base-kernel-repo
+ mountPath: /kernel-repo
+ readOnly: true
+ - name: workdir
+ mountPath: /workdir
+ - name: output
+ mountPath: /output
+ volumes:
+ - name: base-kernel-repo
+ persistentVolumeClaim:
+ claimName: base-kernel-repo-pv-claim
+ - name: shared-git-repo
+ emptyDir:
+ medium: Memory
+ - name: workdir
+ emptyDir: {}
+ - name: output
+ emptyDir: {}
+ outputs:
+ parameters:
+ - name: result
+ valueFrom:
+ path: /output/result.json
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/auxiliary.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/auxiliary.go
new file mode 100644
index 000000000000..1c8385f86ee1
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/auxiliary.go
@@ -0,0 +1,636 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
+
+package database
+
+import (
+ "context"
+ "time"
+
+ "cloud.google.com/go/longrunning"
+ longrunningpb "cloud.google.com/go/longrunning/autogen/longrunningpb"
+ databasepb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
+ gax "github.com/googleapis/gax-go/v2"
+ "google.golang.org/api/iterator"
+)
+
+// CopyBackupOperation manages a long-running operation from CopyBackup.
+type CopyBackupOperation struct {
+ lro *longrunning.Operation
+ pollPath string
+}
+
+// Wait blocks until the long-running operation is completed, returning the response and any errors encountered.
+//
+// See documentation of Poll for error-handling information.
+func (op *CopyBackupOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Backup
+ if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+// Poll fetches the latest state of the long-running operation.
+//
+// Poll also fetches the latest metadata, which can be retrieved by Metadata.
+//
+// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and
+// the operation has completed with failure, the error is returned and op.Done will return true.
+// If Poll succeeds and the operation has completed successfully,
+// op.Done will return true, and the response of the operation is returned.
+// If Poll succeeds and the operation has not completed, the returned response and error are both nil.
+func (op *CopyBackupOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Backup
+ if err := op.lro.Poll(ctx, &resp, opts...); err != nil {
+ return nil, err
+ }
+ if !op.Done() {
+ return nil, nil
+ }
+ return &resp, nil
+}
+
+// Metadata returns metadata associated with the long-running operation.
+// Metadata itself does not contact the server, but Poll does.
+// To get the latest metadata, call this method after a successful call to Poll.
+// If the metadata is not available, the returned metadata and error are both nil.
+func (op *CopyBackupOperation) Metadata() (*databasepb.CopyBackupMetadata, error) {
+ var meta databasepb.CopyBackupMetadata
+ if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+ return &meta, nil
+}
+
+// Done reports whether the long-running operation has completed.
+func (op *CopyBackupOperation) Done() bool {
+ return op.lro.Done()
+}
+
+// Name returns the name of the long-running operation.
+// The name is assigned by the server and is unique within the service from which the operation is created.
+func (op *CopyBackupOperation) Name() string {
+ return op.lro.Name()
+}
+
+// CreateBackupOperation manages a long-running operation from CreateBackup.
+type CreateBackupOperation struct {
+ lro *longrunning.Operation
+ pollPath string
+}
+
+// Wait blocks until the long-running operation is completed, returning the response and any errors encountered.
+//
+// See documentation of Poll for error-handling information.
+func (op *CreateBackupOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Backup
+ if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+// Poll fetches the latest state of the long-running operation.
+//
+// Poll also fetches the latest metadata, which can be retrieved by Metadata.
+//
+// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and
+// the operation has completed with failure, the error is returned and op.Done will return true.
+// If Poll succeeds and the operation has completed successfully,
+// op.Done will return true, and the response of the operation is returned.
+// If Poll succeeds and the operation has not completed, the returned response and error are both nil.
+func (op *CreateBackupOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Backup
+ if err := op.lro.Poll(ctx, &resp, opts...); err != nil {
+ return nil, err
+ }
+ if !op.Done() {
+ return nil, nil
+ }
+ return &resp, nil
+}
+
+// Metadata returns metadata associated with the long-running operation.
+// Metadata itself does not contact the server, but Poll does.
+// To get the latest metadata, call this method after a successful call to Poll.
+// If the metadata is not available, the returned metadata and error are both nil.
+func (op *CreateBackupOperation) Metadata() (*databasepb.CreateBackupMetadata, error) {
+ var meta databasepb.CreateBackupMetadata
+ if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+ return &meta, nil
+}
+
+// Done reports whether the long-running operation has completed.
+func (op *CreateBackupOperation) Done() bool {
+ return op.lro.Done()
+}
+
+// Name returns the name of the long-running operation.
+// The name is assigned by the server and is unique within the service from which the operation is created.
+func (op *CreateBackupOperation) Name() string {
+ return op.lro.Name()
+}
+
+// CreateDatabaseOperation manages a long-running operation from CreateDatabase.
+type CreateDatabaseOperation struct {
+ lro *longrunning.Operation
+ pollPath string
+}
+
+// Wait blocks until the long-running operation is completed, returning the response and any errors encountered.
+//
+// See documentation of Poll for error-handling information.
+func (op *CreateDatabaseOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Database
+ if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+// Poll fetches the latest state of the long-running operation.
+//
+// Poll also fetches the latest metadata, which can be retrieved by Metadata.
+//
+// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and
+// the operation has completed with failure, the error is returned and op.Done will return true.
+// If Poll succeeds and the operation has completed successfully,
+// op.Done will return true, and the response of the operation is returned.
+// If Poll succeeds and the operation has not completed, the returned response and error are both nil.
+func (op *CreateDatabaseOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Database
+ if err := op.lro.Poll(ctx, &resp, opts...); err != nil {
+ return nil, err
+ }
+ if !op.Done() {
+ return nil, nil
+ }
+ return &resp, nil
+}
+
+// Metadata returns metadata associated with the long-running operation.
+// Metadata itself does not contact the server, but Poll does.
+// To get the latest metadata, call this method after a successful call to Poll.
+// If the metadata is not available, the returned metadata and error are both nil.
+func (op *CreateDatabaseOperation) Metadata() (*databasepb.CreateDatabaseMetadata, error) {
+ var meta databasepb.CreateDatabaseMetadata
+ if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+ return &meta, nil
+}
+
+// Done reports whether the long-running operation has completed.
+func (op *CreateDatabaseOperation) Done() bool {
+ return op.lro.Done()
+}
+
+// Name returns the name of the long-running operation.
+// The name is assigned by the server and is unique within the service from which the operation is created.
+func (op *CreateDatabaseOperation) Name() string {
+ return op.lro.Name()
+}
+
+// RestoreDatabaseOperation manages a long-running operation from RestoreDatabase.
+type RestoreDatabaseOperation struct {
+ lro *longrunning.Operation
+ pollPath string
+}
+
+// Wait blocks until the long-running operation is completed, returning the response and any errors encountered.
+//
+// See documentation of Poll for error-handling information.
+func (op *RestoreDatabaseOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Database
+ if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+// Poll fetches the latest state of the long-running operation.
+//
+// Poll also fetches the latest metadata, which can be retrieved by Metadata.
+//
+// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and
+// the operation has completed with failure, the error is returned and op.Done will return true.
+// If Poll succeeds and the operation has completed successfully,
+// op.Done will return true, and the response of the operation is returned.
+// If Poll succeeds and the operation has not completed, the returned response and error are both nil.
+func (op *RestoreDatabaseOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Database
+ if err := op.lro.Poll(ctx, &resp, opts...); err != nil {
+ return nil, err
+ }
+ if !op.Done() {
+ return nil, nil
+ }
+ return &resp, nil
+}
+
+// Metadata returns metadata associated with the long-running operation.
+// Metadata itself does not contact the server, but Poll does.
+// To get the latest metadata, call this method after a successful call to Poll.
+// If the metadata is not available, the returned metadata and error are both nil.
+func (op *RestoreDatabaseOperation) Metadata() (*databasepb.RestoreDatabaseMetadata, error) {
+ var meta databasepb.RestoreDatabaseMetadata
+ if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+ return &meta, nil
+}
+
+// Done reports whether the long-running operation has completed.
+func (op *RestoreDatabaseOperation) Done() bool {
+ return op.lro.Done()
+}
+
+// Name returns the name of the long-running operation.
+// The name is assigned by the server and is unique within the service from which the operation is created.
+func (op *RestoreDatabaseOperation) Name() string {
+ return op.lro.Name()
+}
+
+// UpdateDatabaseDdlOperation manages a long-running operation from UpdateDatabaseDdl.
+type UpdateDatabaseDdlOperation struct {
+ lro *longrunning.Operation
+ pollPath string
+}
+
+// Wait blocks until the long-running operation is completed, returning the response and any errors encountered.
+//
+// See documentation of Poll for error-handling information.
+func (op *UpdateDatabaseDdlOperation) Wait(ctx context.Context, opts ...gax.CallOption) error {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ return op.lro.WaitWithInterval(ctx, nil, time.Minute, opts...)
+}
+
+// Poll fetches the latest state of the long-running operation.
+//
+// Poll also fetches the latest metadata, which can be retrieved by Metadata.
+//
+// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and
+// the operation has completed with failure, the error is returned and op.Done will return true.
+// If Poll succeeds and the operation has completed successfully,
+// op.Done will return true, and the response of the operation is returned.
+// If Poll succeeds and the operation has not completed, the returned response and error are both nil.
+func (op *UpdateDatabaseDdlOperation) Poll(ctx context.Context, opts ...gax.CallOption) error {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ return op.lro.Poll(ctx, nil, opts...)
+}
+
+// Metadata returns metadata associated with the long-running operation.
+// Metadata itself does not contact the server, but Poll does.
+// To get the latest metadata, call this method after a successful call to Poll.
+// If the metadata is not available, the returned metadata and error are both nil.
+func (op *UpdateDatabaseDdlOperation) Metadata() (*databasepb.UpdateDatabaseDdlMetadata, error) {
+ var meta databasepb.UpdateDatabaseDdlMetadata
+ if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+ return &meta, nil
+}
+
+// Done reports whether the long-running operation has completed.
+func (op *UpdateDatabaseDdlOperation) Done() bool {
+ return op.lro.Done()
+}
+
+// Name returns the name of the long-running operation.
+// The name is assigned by the server and is unique within the service from which the operation is created.
+func (op *UpdateDatabaseDdlOperation) Name() string {
+ return op.lro.Name()
+}
+
+// UpdateDatabaseOperation manages a long-running operation from UpdateDatabase.
+type UpdateDatabaseOperation struct {
+ lro *longrunning.Operation
+ pollPath string
+}
+
+// Wait blocks until the long-running operation is completed, returning the response and any errors encountered.
+//
+// See documentation of Poll for error-handling information.
+func (op *UpdateDatabaseOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Database
+ if err := op.lro.WaitWithInterval(ctx, &resp, time.Minute, opts...); err != nil {
+ return nil, err
+ }
+ return &resp, nil
+}
+
+// Poll fetches the latest state of the long-running operation.
+//
+// Poll also fetches the latest metadata, which can be retrieved by Metadata.
+//
+// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and
+// the operation has completed with failure, the error is returned and op.Done will return true.
+// If Poll succeeds and the operation has completed successfully,
+// op.Done will return true, and the response of the operation is returned.
+// If Poll succeeds and the operation has not completed, the returned response and error are both nil.
+func (op *UpdateDatabaseOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) {
+ opts = append([]gax.CallOption{gax.WithPath(op.pollPath)}, opts...)
+ var resp databasepb.Database
+ if err := op.lro.Poll(ctx, &resp, opts...); err != nil {
+ return nil, err
+ }
+ if !op.Done() {
+ return nil, nil
+ }
+ return &resp, nil
+}
+
+// Metadata returns metadata associated with the long-running operation.
+// Metadata itself does not contact the server, but Poll does.
+// To get the latest metadata, call this method after a successful call to Poll.
+// If the metadata is not available, the returned metadata and error are both nil.
+func (op *UpdateDatabaseOperation) Metadata() (*databasepb.UpdateDatabaseMetadata, error) {
+ var meta databasepb.UpdateDatabaseMetadata
+ if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+ return &meta, nil
+}
+
+// Done reports whether the long-running operation has completed.
+func (op *UpdateDatabaseOperation) Done() bool {
+ return op.lro.Done()
+}
+
+// Name returns the name of the long-running operation.
+// The name is assigned by the server and is unique within the service from which the operation is created.
+func (op *UpdateDatabaseOperation) Name() string {
+ return op.lro.Name()
+}
+
+// BackupIterator manages a stream of *databasepb.Backup.
+type BackupIterator struct {
+ items []*databasepb.Backup
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // Response is the raw response for the current page.
+ // It must be cast to the RPC response type.
+ // Calling Next() or InternalFetch() updates this value.
+ Response interface{}
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*databasepb.Backup, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *BackupIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *BackupIterator) Next() (*databasepb.Backup, error) {
+ var item *databasepb.Backup
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *BackupIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *BackupIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
+
+// BackupScheduleIterator manages a stream of *databasepb.BackupSchedule.
+type BackupScheduleIterator struct {
+ items []*databasepb.BackupSchedule
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // Response is the raw response for the current page.
+ // It must be cast to the RPC response type.
+ // Calling Next() or InternalFetch() updates this value.
+ Response interface{}
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*databasepb.BackupSchedule, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *BackupScheduleIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *BackupScheduleIterator) Next() (*databasepb.BackupSchedule, error) {
+ var item *databasepb.BackupSchedule
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *BackupScheduleIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *BackupScheduleIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
+
+// DatabaseIterator manages a stream of *databasepb.Database.
+type DatabaseIterator struct {
+ items []*databasepb.Database
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // Response is the raw response for the current page.
+ // It must be cast to the RPC response type.
+ // Calling Next() or InternalFetch() updates this value.
+ Response interface{}
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*databasepb.Database, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *DatabaseIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *DatabaseIterator) Next() (*databasepb.Database, error) {
+ var item *databasepb.Database
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *DatabaseIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *DatabaseIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
+
+// DatabaseRoleIterator manages a stream of *databasepb.DatabaseRole.
+type DatabaseRoleIterator struct {
+ items []*databasepb.DatabaseRole
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // Response is the raw response for the current page.
+ // It must be cast to the RPC response type.
+ // Calling Next() or InternalFetch() updates this value.
+ Response interface{}
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*databasepb.DatabaseRole, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *DatabaseRoleIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *DatabaseRoleIterator) Next() (*databasepb.DatabaseRole, error) {
+ var item *databasepb.DatabaseRole
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *DatabaseRoleIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *DatabaseRoleIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
+
+// OperationIterator manages a stream of *longrunningpb.Operation.
+type OperationIterator struct {
+ items []*longrunningpb.Operation
+ pageInfo *iterator.PageInfo
+ nextFunc func() error
+
+ // Response is the raw response for the current page.
+ // It must be cast to the RPC response type.
+ // Calling Next() or InternalFetch() updates this value.
+ Response interface{}
+
+ // InternalFetch is for use by the Google Cloud Libraries only.
+ // It is not part of the stable interface of this package.
+ //
+ // InternalFetch returns results from a single call to the underlying RPC.
+ // The number of results is no greater than pageSize.
+ // If there are no more results, nextPageToken is empty and err is nil.
+ InternalFetch func(pageSize int, pageToken string) (results []*longrunningpb.Operation, nextPageToken string, err error)
+}
+
+// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
+func (it *OperationIterator) PageInfo() *iterator.PageInfo {
+ return it.pageInfo
+}
+
+// Next returns the next result. Its second return value is iterator.Done if there are no more
+// results. Once Next returns Done, all subsequent calls will return Done.
+func (it *OperationIterator) Next() (*longrunningpb.Operation, error) {
+ var item *longrunningpb.Operation
+ if err := it.nextFunc(); err != nil {
+ return item, err
+ }
+ item = it.items[0]
+ it.items = it.items[1:]
+ return item, nil
+}
+
+func (it *OperationIterator) bufLen() int {
+ return len(it.items)
+}
+
+func (it *OperationIterator) takeBuf() interface{} {
+ b := it.items
+ it.items = nil
+ return b
+}
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/backup.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/backup.go
new file mode 100644
index 000000000000..648c7f88e2d0
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/backup.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2020 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package database
+
+import (
+ "context"
+ "fmt"
+ "regexp"
+ "time"
+
+ "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
+ "github.com/googleapis/gax-go/v2"
+ pbt "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+var (
+ validDBPattern = regexp.MustCompile("^projects/(?P[^/]+)/instances/(?P[^/]+)/databases/(?P[^/]+)$")
+)
+
+// StartBackupOperation creates a backup of the given database. It will be stored
+// as projects//instances//backups/. The
+// backup will be automatically deleted by Cloud Spanner after its expiration.
+//
+// backupID must be unique across an instance.
+//
+// expireTime is the time the backup will expire. It is respected to
+// microsecond granularity.
+//
+// databasePath must have the form
+// projects//instances//databases/.
+func (c *DatabaseAdminClient) StartBackupOperation(ctx context.Context, backupID string, databasePath string, expireTime time.Time, opts ...gax.CallOption) (*CreateBackupOperation, error) {
+ m := validDBPattern.FindStringSubmatch(databasePath)
+ if m == nil {
+ return nil, fmt.Errorf("database name %q should conform to pattern %q",
+ databasePath, validDBPattern)
+ }
+ ts := &pbt.Timestamp{Seconds: expireTime.Unix(), Nanos: int32(expireTime.Nanosecond())}
+ // Create request from parameters.
+ req := &databasepb.CreateBackupRequest{
+ Parent: fmt.Sprintf("projects/%s/instances/%s", m[1], m[2]),
+ BackupId: backupID,
+ Backup: &databasepb.Backup{
+ Database: databasePath,
+ ExpireTime: ts,
+ },
+ }
+ return c.CreateBackup(ctx, req, opts...)
+}
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database.go
new file mode 100644
index 000000000000..f68a4cb65b51
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database.go
@@ -0,0 +1,120 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package database
+
+import (
+ "context"
+ "fmt"
+ "regexp"
+ "strings"
+ "time"
+ "unicode"
+
+ "cloud.google.com/go/longrunning/autogen/longrunningpb"
+ "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
+ "github.com/googleapis/gax-go/v2"
+ "google.golang.org/api/iterator"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+var retryer = gax.OnCodes(
+ []codes.Code{codes.DeadlineExceeded, codes.Unavailable},
+ gax.Backoff{Initial: time.Millisecond, Max: time.Millisecond, Multiplier: 1.0},
+)
+
+// CreateDatabaseWithRetry creates a new database and retries the call if the
+// backend returns a retryable error. The actual CreateDatabase RPC is only
+// retried if the initial call did not reach the server. In other cases, the
+// client will query the backend for the long-running operation that was
+// created by the initial RPC and return that operation.
+func (c *DatabaseAdminClient) CreateDatabaseWithRetry(ctx context.Context, req *databasepb.CreateDatabaseRequest, opts ...gax.CallOption) (*CreateDatabaseOperation, error) {
+ for {
+ db, createErr := c.CreateDatabase(ctx, req, opts...)
+ if createErr == nil {
+ return db, nil
+ }
+ // Failed, check whether we should retry.
+ delay, shouldRetry := retryer.Retry(createErr)
+ if !shouldRetry {
+ return nil, createErr
+ }
+ if err := gax.Sleep(ctx, delay); err != nil {
+ return nil, err
+ }
+ // Extract the name of the database.
+ dbName := extractDBName(req.CreateStatement)
+ // Query the backend for any corresponding long-running operation to
+ // determine whether we should retry the RPC or not.
+ iter := c.ListDatabaseOperations(ctx, &databasepb.ListDatabaseOperationsRequest{
+ Parent: req.Parent,
+ Filter: fmt.Sprintf("(metadata.@type:type.googleapis.com/google.spanner.admin.database.v1.CreateDatabaseMetadata) AND (name:%s/databases/%s/operations/)", req.Parent, dbName),
+ }, opts...)
+ var mostRecentOp *longrunningpb.Operation
+ for {
+ op, err := iter.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+ // A running operation is the most recent and should be returned.
+ if !op.Done {
+ return c.CreateDatabaseOperation(op.Name), nil
+ }
+ if op.GetError() == nil {
+ mostRecentOp = op
+ }
+ }
+ if mostRecentOp == nil {
+ continue
+ }
+ // Only finished operations found. Check whether the database exists.
+ _, getErr := c.GetDatabase(ctx, &databasepb.GetDatabaseRequest{
+ Name: fmt.Sprintf("%s/databases/%s", req.Parent, dbName),
+ })
+ if getErr == nil {
+ // Database found, return one of the long-running operations that
+ // has finished, which again should return the database.
+ return c.CreateDatabaseOperation(mostRecentOp.Name), nil
+ }
+ if status.Code(getErr) == codes.NotFound {
+ continue
+ }
+ // Error getting the database that was not NotFound.
+ return nil, getErr
+ }
+}
+
+var dbNameRegEx = regexp.MustCompile("\\s*CREATE\\s+DATABASE\\s+(.+)\\s*")
+
+// extractDBName extracts the database name from a valid CREATE DATABASE
+// statement. We don't have to worry about invalid create statements, as those
+// should already have been handled by the backend and should return a non-
+// retryable error.
+func extractDBName(createStatement string) string {
+ if dbNameRegEx.MatchString(createStatement) {
+ namePossiblyWithQuotes := strings.TrimRightFunc(dbNameRegEx.FindStringSubmatch(createStatement)[1], unicode.IsSpace)
+ if len(namePossiblyWithQuotes) > 0 && namePossiblyWithQuotes[0] == '`' {
+ if len(namePossiblyWithQuotes) > 5 && namePossiblyWithQuotes[1] == '`' && namePossiblyWithQuotes[2] == '`' {
+ return string(namePossiblyWithQuotes[3 : len(namePossiblyWithQuotes)-3])
+ }
+ return string(namePossiblyWithQuotes[1 : len(namePossiblyWithQuotes)-1])
+ }
+ return string(namePossiblyWithQuotes)
+ }
+ return ""
+}
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client.go
new file mode 100644
index 000000000000..1af1d1ed56ec
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client.go
@@ -0,0 +1,4194 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
+
+package database
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "math"
+ "net/http"
+ "net/url"
+ "time"
+
+ iampb "cloud.google.com/go/iam/apiv1/iampb"
+ "cloud.google.com/go/longrunning"
+ lroauto "cloud.google.com/go/longrunning/autogen"
+ longrunningpb "cloud.google.com/go/longrunning/autogen/longrunningpb"
+ databasepb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
+ gax "github.com/googleapis/gax-go/v2"
+ "google.golang.org/api/googleapi"
+ "google.golang.org/api/iterator"
+ "google.golang.org/api/option"
+ "google.golang.org/api/option/internaloption"
+ gtransport "google.golang.org/api/transport/grpc"
+ httptransport "google.golang.org/api/transport/http"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/protobuf/encoding/protojson"
+ "google.golang.org/protobuf/proto"
+)
+
+var newDatabaseAdminClientHook clientHook
+
+// DatabaseAdminCallOptions contains the retry settings for each method of DatabaseAdminClient.
+type DatabaseAdminCallOptions struct {
+ ListDatabases []gax.CallOption
+ CreateDatabase []gax.CallOption
+ GetDatabase []gax.CallOption
+ UpdateDatabase []gax.CallOption
+ UpdateDatabaseDdl []gax.CallOption
+ DropDatabase []gax.CallOption
+ GetDatabaseDdl []gax.CallOption
+ SetIamPolicy []gax.CallOption
+ GetIamPolicy []gax.CallOption
+ TestIamPermissions []gax.CallOption
+ CreateBackup []gax.CallOption
+ CopyBackup []gax.CallOption
+ GetBackup []gax.CallOption
+ UpdateBackup []gax.CallOption
+ DeleteBackup []gax.CallOption
+ ListBackups []gax.CallOption
+ RestoreDatabase []gax.CallOption
+ ListDatabaseOperations []gax.CallOption
+ ListBackupOperations []gax.CallOption
+ ListDatabaseRoles []gax.CallOption
+ CreateBackupSchedule []gax.CallOption
+ GetBackupSchedule []gax.CallOption
+ UpdateBackupSchedule []gax.CallOption
+ DeleteBackupSchedule []gax.CallOption
+ ListBackupSchedules []gax.CallOption
+ CancelOperation []gax.CallOption
+ DeleteOperation []gax.CallOption
+ GetOperation []gax.CallOption
+ ListOperations []gax.CallOption
+}
+
+func defaultDatabaseAdminGRPCClientOptions() []option.ClientOption {
+ return []option.ClientOption{
+ internaloption.WithDefaultEndpoint("spanner.googleapis.com:443"),
+ internaloption.WithDefaultEndpointTemplate("spanner.UNIVERSE_DOMAIN:443"),
+ internaloption.WithDefaultMTLSEndpoint("spanner.mtls.googleapis.com:443"),
+ internaloption.WithDefaultUniverseDomain("googleapis.com"),
+ internaloption.WithDefaultAudience("https://spanner.googleapis.com/"),
+ internaloption.WithDefaultScopes(DefaultAuthScopes()...),
+ internaloption.EnableJwtWithScope(),
+ option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
+ grpc.MaxCallRecvMsgSize(math.MaxInt32))),
+ }
+}
+
+func defaultDatabaseAdminCallOptions() *DatabaseAdminCallOptions {
+ return &DatabaseAdminCallOptions{
+ ListDatabases: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ CreateDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ GetDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ UpdateDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ UpdateDatabaseDdl: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ DropDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ GetDatabaseDdl: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ SetIamPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ GetIamPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ TestIamPermissions: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ CreateBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ CopyBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ GetBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ UpdateBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ DeleteBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ ListBackups: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ RestoreDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ ListDatabaseOperations: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ ListBackupOperations: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ ListDatabaseRoles: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ CreateBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ GetBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ UpdateBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ DeleteBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ ListBackupSchedules: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnCodes([]codes.Code{
+ codes.Unavailable,
+ codes.DeadlineExceeded,
+ }, gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ })
+ }),
+ },
+ CancelOperation: []gax.CallOption{},
+ DeleteOperation: []gax.CallOption{},
+ GetOperation: []gax.CallOption{},
+ ListOperations: []gax.CallOption{},
+ }
+}
+
+func defaultDatabaseAdminRESTCallOptions() *DatabaseAdminCallOptions {
+ return &DatabaseAdminCallOptions{
+ ListDatabases: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ CreateDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ GetDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ UpdateDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ UpdateDatabaseDdl: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ DropDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ GetDatabaseDdl: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ SetIamPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ GetIamPolicy: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ TestIamPermissions: []gax.CallOption{
+ gax.WithTimeout(30000 * time.Millisecond),
+ },
+ CreateBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ CopyBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ GetBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ UpdateBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ DeleteBackup: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ ListBackups: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ RestoreDatabase: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ },
+ ListDatabaseOperations: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ ListBackupOperations: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ ListDatabaseRoles: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ CreateBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ GetBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ UpdateBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ DeleteBackupSchedule: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ ListBackupSchedules: []gax.CallOption{
+ gax.WithTimeout(3600000 * time.Millisecond),
+ gax.WithRetry(func() gax.Retryer {
+ return gax.OnHTTPCodes(gax.Backoff{
+ Initial: 1000 * time.Millisecond,
+ Max: 32000 * time.Millisecond,
+ Multiplier: 1.30,
+ },
+ http.StatusServiceUnavailable,
+ http.StatusGatewayTimeout)
+ }),
+ },
+ CancelOperation: []gax.CallOption{},
+ DeleteOperation: []gax.CallOption{},
+ GetOperation: []gax.CallOption{},
+ ListOperations: []gax.CallOption{},
+ }
+}
+
+// internalDatabaseAdminClient is an interface that defines the methods available from Cloud Spanner API.
+type internalDatabaseAdminClient interface {
+ Close() error
+ setGoogleClientInfo(...string)
+ Connection() *grpc.ClientConn
+ ListDatabases(context.Context, *databasepb.ListDatabasesRequest, ...gax.CallOption) *DatabaseIterator
+ CreateDatabase(context.Context, *databasepb.CreateDatabaseRequest, ...gax.CallOption) (*CreateDatabaseOperation, error)
+ CreateDatabaseOperation(name string) *CreateDatabaseOperation
+ GetDatabase(context.Context, *databasepb.GetDatabaseRequest, ...gax.CallOption) (*databasepb.Database, error)
+ UpdateDatabase(context.Context, *databasepb.UpdateDatabaseRequest, ...gax.CallOption) (*UpdateDatabaseOperation, error)
+ UpdateDatabaseOperation(name string) *UpdateDatabaseOperation
+ UpdateDatabaseDdl(context.Context, *databasepb.UpdateDatabaseDdlRequest, ...gax.CallOption) (*UpdateDatabaseDdlOperation, error)
+ UpdateDatabaseDdlOperation(name string) *UpdateDatabaseDdlOperation
+ DropDatabase(context.Context, *databasepb.DropDatabaseRequest, ...gax.CallOption) error
+ GetDatabaseDdl(context.Context, *databasepb.GetDatabaseDdlRequest, ...gax.CallOption) (*databasepb.GetDatabaseDdlResponse, error)
+ SetIamPolicy(context.Context, *iampb.SetIamPolicyRequest, ...gax.CallOption) (*iampb.Policy, error)
+ GetIamPolicy(context.Context, *iampb.GetIamPolicyRequest, ...gax.CallOption) (*iampb.Policy, error)
+ TestIamPermissions(context.Context, *iampb.TestIamPermissionsRequest, ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error)
+ CreateBackup(context.Context, *databasepb.CreateBackupRequest, ...gax.CallOption) (*CreateBackupOperation, error)
+ CreateBackupOperation(name string) *CreateBackupOperation
+ CopyBackup(context.Context, *databasepb.CopyBackupRequest, ...gax.CallOption) (*CopyBackupOperation, error)
+ CopyBackupOperation(name string) *CopyBackupOperation
+ GetBackup(context.Context, *databasepb.GetBackupRequest, ...gax.CallOption) (*databasepb.Backup, error)
+ UpdateBackup(context.Context, *databasepb.UpdateBackupRequest, ...gax.CallOption) (*databasepb.Backup, error)
+ DeleteBackup(context.Context, *databasepb.DeleteBackupRequest, ...gax.CallOption) error
+ ListBackups(context.Context, *databasepb.ListBackupsRequest, ...gax.CallOption) *BackupIterator
+ RestoreDatabase(context.Context, *databasepb.RestoreDatabaseRequest, ...gax.CallOption) (*RestoreDatabaseOperation, error)
+ RestoreDatabaseOperation(name string) *RestoreDatabaseOperation
+ ListDatabaseOperations(context.Context, *databasepb.ListDatabaseOperationsRequest, ...gax.CallOption) *OperationIterator
+ ListBackupOperations(context.Context, *databasepb.ListBackupOperationsRequest, ...gax.CallOption) *OperationIterator
+ ListDatabaseRoles(context.Context, *databasepb.ListDatabaseRolesRequest, ...gax.CallOption) *DatabaseRoleIterator
+ CreateBackupSchedule(context.Context, *databasepb.CreateBackupScheduleRequest, ...gax.CallOption) (*databasepb.BackupSchedule, error)
+ GetBackupSchedule(context.Context, *databasepb.GetBackupScheduleRequest, ...gax.CallOption) (*databasepb.BackupSchedule, error)
+ UpdateBackupSchedule(context.Context, *databasepb.UpdateBackupScheduleRequest, ...gax.CallOption) (*databasepb.BackupSchedule, error)
+ DeleteBackupSchedule(context.Context, *databasepb.DeleteBackupScheduleRequest, ...gax.CallOption) error
+ ListBackupSchedules(context.Context, *databasepb.ListBackupSchedulesRequest, ...gax.CallOption) *BackupScheduleIterator
+ CancelOperation(context.Context, *longrunningpb.CancelOperationRequest, ...gax.CallOption) error
+ DeleteOperation(context.Context, *longrunningpb.DeleteOperationRequest, ...gax.CallOption) error
+ GetOperation(context.Context, *longrunningpb.GetOperationRequest, ...gax.CallOption) (*longrunningpb.Operation, error)
+ ListOperations(context.Context, *longrunningpb.ListOperationsRequest, ...gax.CallOption) *OperationIterator
+}
+
+// DatabaseAdminClient is a client for interacting with Cloud Spanner API.
+// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
+//
+// # Cloud Spanner Database Admin API
+//
+// The Cloud Spanner Database Admin API can be used to:
+//
+// create, drop, and list databases
+//
+// update the schema of pre-existing databases
+//
+// create, delete, copy and list backups for a database
+//
+// restore a database from an existing backup
+type DatabaseAdminClient struct {
+ // The internal transport-dependent client.
+ internalClient internalDatabaseAdminClient
+
+ // The call options for this service.
+ CallOptions *DatabaseAdminCallOptions
+
+ // LROClient is used internally to handle long-running operations.
+ // It is exposed so that its CallOptions can be modified if required.
+ // Users should not Close this client.
+ LROClient *lroauto.OperationsClient
+}
+
+// Wrapper methods routed to the internal client.
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *DatabaseAdminClient) Close() error {
+ return c.internalClient.Close()
+}
+
+// setGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *DatabaseAdminClient) setGoogleClientInfo(keyval ...string) {
+ c.internalClient.setGoogleClientInfo(keyval...)
+}
+
+// Connection returns a connection to the API service.
+//
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
+func (c *DatabaseAdminClient) Connection() *grpc.ClientConn {
+ return c.internalClient.Connection()
+}
+
+// ListDatabases lists Cloud Spanner databases.
+func (c *DatabaseAdminClient) ListDatabases(ctx context.Context, req *databasepb.ListDatabasesRequest, opts ...gax.CallOption) *DatabaseIterator {
+ return c.internalClient.ListDatabases(ctx, req, opts...)
+}
+
+// CreateDatabase creates a new Cloud Spanner database and starts to prepare it for serving.
+// The returned [long-running operation][google.longrunning.Operation] will
+// have a name of the format /operations/ and
+// can be used to track preparation of the database. The
+// metadata field type is
+// CreateDatabaseMetadata.
+// The response field type is
+// Database, if successful.
+func (c *DatabaseAdminClient) CreateDatabase(ctx context.Context, req *databasepb.CreateDatabaseRequest, opts ...gax.CallOption) (*CreateDatabaseOperation, error) {
+ return c.internalClient.CreateDatabase(ctx, req, opts...)
+}
+
+// CreateDatabaseOperation returns a new CreateDatabaseOperation from a given name.
+// The name must be that of a previously created CreateDatabaseOperation, possibly from a different process.
+func (c *DatabaseAdminClient) CreateDatabaseOperation(name string) *CreateDatabaseOperation {
+ return c.internalClient.CreateDatabaseOperation(name)
+}
+
+// GetDatabase gets the state of a Cloud Spanner database.
+func (c *DatabaseAdminClient) GetDatabase(ctx context.Context, req *databasepb.GetDatabaseRequest, opts ...gax.CallOption) (*databasepb.Database, error) {
+ return c.internalClient.GetDatabase(ctx, req, opts...)
+}
+
+// UpdateDatabase updates a Cloud Spanner database. The returned
+// [long-running operation][google.longrunning.Operation] can be used to track
+// the progress of updating the database. If the named database does not
+// exist, returns NOT_FOUND.
+//
+// While the operation is pending:
+//
+// The database’s
+// reconciling
+// field is set to true.
+//
+// Cancelling the operation is best-effort. If the cancellation succeeds,
+// the operation metadata’s
+// cancel_time
+// is set, the updates are reverted, and the operation terminates with a
+// CANCELLED status.
+//
+// New UpdateDatabase requests will return a FAILED_PRECONDITION error
+// until the pending operation is done (returns successfully or with
+// error).
+//
+// Reading the database via the API continues to give the pre-request
+// values.
+//
+// Upon completion of the returned operation:
+//
+// The new values are in effect and readable via the API.
+//
+// The database’s
+// reconciling
+// field becomes false.
+//
+// The returned [long-running operation][google.longrunning.Operation] will
+// have a name of the format
+// projects//instances//databases//operations/
+// and can be used to track the database modification. The
+// metadata field type is
+// UpdateDatabaseMetadata.
+// The response field type is
+// Database, if successful.
+func (c *DatabaseAdminClient) UpdateDatabase(ctx context.Context, req *databasepb.UpdateDatabaseRequest, opts ...gax.CallOption) (*UpdateDatabaseOperation, error) {
+ return c.internalClient.UpdateDatabase(ctx, req, opts...)
+}
+
+// UpdateDatabaseOperation returns a new UpdateDatabaseOperation from a given name.
+// The name must be that of a previously created UpdateDatabaseOperation, possibly from a different process.
+func (c *DatabaseAdminClient) UpdateDatabaseOperation(name string) *UpdateDatabaseOperation {
+ return c.internalClient.UpdateDatabaseOperation(name)
+}
+
+// UpdateDatabaseDdl updates the schema of a Cloud Spanner database by
+// creating/altering/dropping tables, columns, indexes, etc. The returned
+// [long-running operation][google.longrunning.Operation] will have a name of
+// the format /operations/ and can be used to
+// track execution of the schema change(s). The
+// metadata field type is
+// UpdateDatabaseDdlMetadata.
+// The operation has no response.
+func (c *DatabaseAdminClient) UpdateDatabaseDdl(ctx context.Context, req *databasepb.UpdateDatabaseDdlRequest, opts ...gax.CallOption) (*UpdateDatabaseDdlOperation, error) {
+ return c.internalClient.UpdateDatabaseDdl(ctx, req, opts...)
+}
+
+// UpdateDatabaseDdlOperation returns a new UpdateDatabaseDdlOperation from a given name.
+// The name must be that of a previously created UpdateDatabaseDdlOperation, possibly from a different process.
+func (c *DatabaseAdminClient) UpdateDatabaseDdlOperation(name string) *UpdateDatabaseDdlOperation {
+ return c.internalClient.UpdateDatabaseDdlOperation(name)
+}
+
+// DropDatabase drops (aka deletes) a Cloud Spanner database.
+// Completed backups for the database will be retained according to their
+// expire_time.
+// Note: Cloud Spanner might continue to accept requests for a few seconds
+// after the database has been deleted.
+func (c *DatabaseAdminClient) DropDatabase(ctx context.Context, req *databasepb.DropDatabaseRequest, opts ...gax.CallOption) error {
+ return c.internalClient.DropDatabase(ctx, req, opts...)
+}
+
+// GetDatabaseDdl returns the schema of a Cloud Spanner database as a list of formatted
+// DDL statements. This method does not show pending schema updates, those may
+// be queried using the Operations API.
+func (c *DatabaseAdminClient) GetDatabaseDdl(ctx context.Context, req *databasepb.GetDatabaseDdlRequest, opts ...gax.CallOption) (*databasepb.GetDatabaseDdlResponse, error) {
+ return c.internalClient.GetDatabaseDdl(ctx, req, opts...)
+}
+
+// SetIamPolicy sets the access control policy on a database or backup resource.
+// Replaces any existing policy.
+//
+// Authorization requires spanner.databases.setIamPolicy
+// permission on resource.
+// For backups, authorization requires spanner.backups.setIamPolicy
+// permission on resource.
+func (c *DatabaseAdminClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) {
+ return c.internalClient.SetIamPolicy(ctx, req, opts...)
+}
+
+// GetIamPolicy gets the access control policy for a database or backup resource.
+// Returns an empty policy if a database or backup exists but does not have a
+// policy set.
+//
+// Authorization requires spanner.databases.getIamPolicy permission on
+// resource.
+// For backups, authorization requires spanner.backups.getIamPolicy
+// permission on resource.
+func (c *DatabaseAdminClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) {
+ return c.internalClient.GetIamPolicy(ctx, req, opts...)
+}
+
+// TestIamPermissions returns permissions that the caller has on the specified database or backup
+// resource.
+//
+// Attempting this RPC on a non-existent Cloud Spanner database will
+// result in a NOT_FOUND error if the user has
+// spanner.databases.list permission on the containing Cloud
+// Spanner instance. Otherwise returns an empty set of permissions.
+// Calling this method on a backup that does not exist will
+// result in a NOT_FOUND error if the user has
+// spanner.backups.list permission on the containing instance.
+func (c *DatabaseAdminClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) {
+ return c.internalClient.TestIamPermissions(ctx, req, opts...)
+}
+
+// CreateBackup starts creating a new Cloud Spanner Backup.
+// The returned backup [long-running operation][google.longrunning.Operation]
+// will have a name of the format
+// projects//instances//backups//operations/
+// and can be used to track creation of the backup. The
+// metadata field type is
+// CreateBackupMetadata.
+// The response field type is
+// Backup, if successful.
+// Cancelling the returned operation will stop the creation and delete the
+// backup. There can be only one pending backup creation per database. Backup
+// creation of different databases can run concurrently.
+func (c *DatabaseAdminClient) CreateBackup(ctx context.Context, req *databasepb.CreateBackupRequest, opts ...gax.CallOption) (*CreateBackupOperation, error) {
+ return c.internalClient.CreateBackup(ctx, req, opts...)
+}
+
+// CreateBackupOperation returns a new CreateBackupOperation from a given name.
+// The name must be that of a previously created CreateBackupOperation, possibly from a different process.
+func (c *DatabaseAdminClient) CreateBackupOperation(name string) *CreateBackupOperation {
+ return c.internalClient.CreateBackupOperation(name)
+}
+
+// CopyBackup starts copying a Cloud Spanner Backup.
+// The returned backup [long-running operation][google.longrunning.Operation]
+// will have a name of the format
+// projects//instances//backups//operations/
+// and can be used to track copying of the backup. The operation is associated
+// with the destination backup.
+// The metadata field type is
+// CopyBackupMetadata.
+// The response field type is
+// Backup, if successful.
+// Cancelling the returned operation will stop the copying and delete the
+// destination backup. Concurrent CopyBackup requests can run on the same
+// source backup.
+func (c *DatabaseAdminClient) CopyBackup(ctx context.Context, req *databasepb.CopyBackupRequest, opts ...gax.CallOption) (*CopyBackupOperation, error) {
+ return c.internalClient.CopyBackup(ctx, req, opts...)
+}
+
+// CopyBackupOperation returns a new CopyBackupOperation from a given name.
+// The name must be that of a previously created CopyBackupOperation, possibly from a different process.
+func (c *DatabaseAdminClient) CopyBackupOperation(name string) *CopyBackupOperation {
+ return c.internalClient.CopyBackupOperation(name)
+}
+
+// GetBackup gets metadata on a pending or completed
+// Backup.
+func (c *DatabaseAdminClient) GetBackup(ctx context.Context, req *databasepb.GetBackupRequest, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ return c.internalClient.GetBackup(ctx, req, opts...)
+}
+
+// UpdateBackup updates a pending or completed
+// Backup.
+func (c *DatabaseAdminClient) UpdateBackup(ctx context.Context, req *databasepb.UpdateBackupRequest, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ return c.internalClient.UpdateBackup(ctx, req, opts...)
+}
+
+// DeleteBackup deletes a pending or completed
+// Backup.
+func (c *DatabaseAdminClient) DeleteBackup(ctx context.Context, req *databasepb.DeleteBackupRequest, opts ...gax.CallOption) error {
+ return c.internalClient.DeleteBackup(ctx, req, opts...)
+}
+
+// ListBackups lists completed and pending backups.
+// Backups returned are ordered by create_time in descending order,
+// starting from the most recent create_time.
+func (c *DatabaseAdminClient) ListBackups(ctx context.Context, req *databasepb.ListBackupsRequest, opts ...gax.CallOption) *BackupIterator {
+ return c.internalClient.ListBackups(ctx, req, opts...)
+}
+
+// RestoreDatabase create a new database by restoring from a completed backup. The new
+// database must be in the same project and in an instance with the same
+// instance configuration as the instance containing
+// the backup. The returned database [long-running
+// operation][google.longrunning.Operation] has a name of the format
+// projects//instances//databases//operations/,
+// and can be used to track the progress of the operation, and to cancel it.
+// The metadata field type is
+// RestoreDatabaseMetadata.
+// The response type
+// is Database, if
+// successful. Cancelling the returned operation will stop the restore and
+// delete the database.
+// There can be only one database being restored into an instance at a time.
+// Once the restore operation completes, a new restore operation can be
+// initiated, without waiting for the optimize operation associated with the
+// first restore to complete.
+func (c *DatabaseAdminClient) RestoreDatabase(ctx context.Context, req *databasepb.RestoreDatabaseRequest, opts ...gax.CallOption) (*RestoreDatabaseOperation, error) {
+ return c.internalClient.RestoreDatabase(ctx, req, opts...)
+}
+
+// RestoreDatabaseOperation returns a new RestoreDatabaseOperation from a given name.
+// The name must be that of a previously created RestoreDatabaseOperation, possibly from a different process.
+func (c *DatabaseAdminClient) RestoreDatabaseOperation(name string) *RestoreDatabaseOperation {
+ return c.internalClient.RestoreDatabaseOperation(name)
+}
+
+// ListDatabaseOperations lists database [longrunning-operations][google.longrunning.Operation].
+// A database operation has a name of the form
+// projects//instances//databases//operations/.
+// The long-running operation
+// metadata field type
+// metadata.type_url describes the type of the metadata. Operations returned
+// include those that have completed/failed/canceled within the last 7 days,
+// and pending operations.
+func (c *DatabaseAdminClient) ListDatabaseOperations(ctx context.Context, req *databasepb.ListDatabaseOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ return c.internalClient.ListDatabaseOperations(ctx, req, opts...)
+}
+
+// ListBackupOperations lists the backup [long-running operations][google.longrunning.Operation] in
+// the given instance. A backup operation has a name of the form
+// projects//instances//backups//operations/.
+// The long-running operation
+// metadata field type
+// metadata.type_url describes the type of the metadata. Operations returned
+// include those that have completed/failed/canceled within the last 7 days,
+// and pending operations. Operations returned are ordered by
+// operation.metadata.value.progress.start_time in descending order starting
+// from the most recently started operation.
+func (c *DatabaseAdminClient) ListBackupOperations(ctx context.Context, req *databasepb.ListBackupOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ return c.internalClient.ListBackupOperations(ctx, req, opts...)
+}
+
+// ListDatabaseRoles lists Cloud Spanner database roles.
+func (c *DatabaseAdminClient) ListDatabaseRoles(ctx context.Context, req *databasepb.ListDatabaseRolesRequest, opts ...gax.CallOption) *DatabaseRoleIterator {
+ return c.internalClient.ListDatabaseRoles(ctx, req, opts...)
+}
+
+// CreateBackupSchedule creates a new backup schedule.
+func (c *DatabaseAdminClient) CreateBackupSchedule(ctx context.Context, req *databasepb.CreateBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ return c.internalClient.CreateBackupSchedule(ctx, req, opts...)
+}
+
+// GetBackupSchedule gets backup schedule for the input schedule name.
+func (c *DatabaseAdminClient) GetBackupSchedule(ctx context.Context, req *databasepb.GetBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ return c.internalClient.GetBackupSchedule(ctx, req, opts...)
+}
+
+// UpdateBackupSchedule updates a backup schedule.
+func (c *DatabaseAdminClient) UpdateBackupSchedule(ctx context.Context, req *databasepb.UpdateBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ return c.internalClient.UpdateBackupSchedule(ctx, req, opts...)
+}
+
+// DeleteBackupSchedule deletes a backup schedule.
+func (c *DatabaseAdminClient) DeleteBackupSchedule(ctx context.Context, req *databasepb.DeleteBackupScheduleRequest, opts ...gax.CallOption) error {
+ return c.internalClient.DeleteBackupSchedule(ctx, req, opts...)
+}
+
+// ListBackupSchedules lists all the backup schedules for the database.
+func (c *DatabaseAdminClient) ListBackupSchedules(ctx context.Context, req *databasepb.ListBackupSchedulesRequest, opts ...gax.CallOption) *BackupScheduleIterator {
+ return c.internalClient.ListBackupSchedules(ctx, req, opts...)
+}
+
+// CancelOperation is a utility method from google.longrunning.Operations.
+func (c *DatabaseAdminClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error {
+ return c.internalClient.CancelOperation(ctx, req, opts...)
+}
+
+// DeleteOperation is a utility method from google.longrunning.Operations.
+func (c *DatabaseAdminClient) DeleteOperation(ctx context.Context, req *longrunningpb.DeleteOperationRequest, opts ...gax.CallOption) error {
+ return c.internalClient.DeleteOperation(ctx, req, opts...)
+}
+
+// GetOperation is a utility method from google.longrunning.Operations.
+func (c *DatabaseAdminClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) {
+ return c.internalClient.GetOperation(ctx, req, opts...)
+}
+
+// ListOperations is a utility method from google.longrunning.Operations.
+func (c *DatabaseAdminClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ return c.internalClient.ListOperations(ctx, req, opts...)
+}
+
+// databaseAdminGRPCClient is a client for interacting with Cloud Spanner API over gRPC transport.
+//
+// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
+type databaseAdminGRPCClient struct {
+ // Connection pool of gRPC connections to the service.
+ connPool gtransport.ConnPool
+
+ // Points back to the CallOptions field of the containing DatabaseAdminClient
+ CallOptions **DatabaseAdminCallOptions
+
+ // The gRPC API client.
+ databaseAdminClient databasepb.DatabaseAdminClient
+
+ // LROClient is used internally to handle long-running operations.
+ // It is exposed so that its CallOptions can be modified if required.
+ // Users should not Close this client.
+ LROClient **lroauto.OperationsClient
+
+ operationsClient longrunningpb.OperationsClient
+
+ // The x-goog-* metadata to be sent with each request.
+ xGoogHeaders []string
+}
+
+// NewDatabaseAdminClient creates a new database admin client based on gRPC.
+// The returned client must be Closed when it is done being used to clean up its underlying connections.
+//
+// # Cloud Spanner Database Admin API
+//
+// The Cloud Spanner Database Admin API can be used to:
+//
+// create, drop, and list databases
+//
+// update the schema of pre-existing databases
+//
+// create, delete, copy and list backups for a database
+//
+// restore a database from an existing backup
+func NewDatabaseAdminClient(ctx context.Context, opts ...option.ClientOption) (*DatabaseAdminClient, error) {
+ clientOpts := defaultDatabaseAdminGRPCClientOptions()
+ if newDatabaseAdminClientHook != nil {
+ hookOpts, err := newDatabaseAdminClientHook(ctx, clientHookParams{})
+ if err != nil {
+ return nil, err
+ }
+ clientOpts = append(clientOpts, hookOpts...)
+ }
+
+ connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
+ if err != nil {
+ return nil, err
+ }
+ client := DatabaseAdminClient{CallOptions: defaultDatabaseAdminCallOptions()}
+
+ c := &databaseAdminGRPCClient{
+ connPool: connPool,
+ databaseAdminClient: databasepb.NewDatabaseAdminClient(connPool),
+ CallOptions: &client.CallOptions,
+ operationsClient: longrunningpb.NewOperationsClient(connPool),
+ }
+ c.setGoogleClientInfo()
+
+ client.internalClient = c
+
+ client.LROClient, err = lroauto.NewOperationsClient(ctx, gtransport.WithConnPool(connPool))
+ if err != nil {
+ // This error "should not happen", since we are just reusing old connection pool
+ // and never actually need to dial.
+ // If this does happen, we could leak connp. However, we cannot close conn:
+ // If the user invoked the constructor with option.WithGRPCConn,
+ // we would close a connection that's still in use.
+ // TODO: investigate error conditions.
+ return nil, err
+ }
+ c.LROClient = &client.LROClient
+ return &client, nil
+}
+
+// Connection returns a connection to the API service.
+//
+// Deprecated: Connections are now pooled so this method does not always
+// return the same resource.
+func (c *databaseAdminGRPCClient) Connection() *grpc.ClientConn {
+ return c.connPool.Conn()
+}
+
+// setGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *databaseAdminGRPCClient) setGoogleClientInfo(keyval ...string) {
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
+ kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version)
+ c.xGoogHeaders = []string{
+ "x-goog-api-client", gax.XGoogHeader(kv...),
+ }
+}
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *databaseAdminGRPCClient) Close() error {
+ return c.connPool.Close()
+}
+
+// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
+type databaseAdminRESTClient struct {
+ // The http endpoint to connect to.
+ endpoint string
+
+ // The http client.
+ httpClient *http.Client
+
+ // LROClient is used internally to handle long-running operations.
+ // It is exposed so that its CallOptions can be modified if required.
+ // Users should not Close this client.
+ LROClient **lroauto.OperationsClient
+
+ // The x-goog-* headers to be sent with each request.
+ xGoogHeaders []string
+
+ // Points back to the CallOptions field of the containing DatabaseAdminClient
+ CallOptions **DatabaseAdminCallOptions
+}
+
+// NewDatabaseAdminRESTClient creates a new database admin rest client.
+//
+// # Cloud Spanner Database Admin API
+//
+// The Cloud Spanner Database Admin API can be used to:
+//
+// create, drop, and list databases
+//
+// update the schema of pre-existing databases
+//
+// create, delete, copy and list backups for a database
+//
+// restore a database from an existing backup
+func NewDatabaseAdminRESTClient(ctx context.Context, opts ...option.ClientOption) (*DatabaseAdminClient, error) {
+ clientOpts := append(defaultDatabaseAdminRESTClientOptions(), opts...)
+ httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...)
+ if err != nil {
+ return nil, err
+ }
+
+ callOpts := defaultDatabaseAdminRESTCallOptions()
+ c := &databaseAdminRESTClient{
+ endpoint: endpoint,
+ httpClient: httpClient,
+ CallOptions: &callOpts,
+ }
+ c.setGoogleClientInfo()
+
+ lroOpts := []option.ClientOption{
+ option.WithHTTPClient(httpClient),
+ option.WithEndpoint(endpoint),
+ }
+ opClient, err := lroauto.NewOperationsRESTClient(ctx, lroOpts...)
+ if err != nil {
+ return nil, err
+ }
+ c.LROClient = &opClient
+
+ return &DatabaseAdminClient{internalClient: c, CallOptions: callOpts}, nil
+}
+
+func defaultDatabaseAdminRESTClientOptions() []option.ClientOption {
+ return []option.ClientOption{
+ internaloption.WithDefaultEndpoint("https://spanner.googleapis.com"),
+ internaloption.WithDefaultEndpointTemplate("https://spanner.UNIVERSE_DOMAIN"),
+ internaloption.WithDefaultMTLSEndpoint("https://spanner.mtls.googleapis.com"),
+ internaloption.WithDefaultUniverseDomain("googleapis.com"),
+ internaloption.WithDefaultAudience("https://spanner.googleapis.com/"),
+ internaloption.WithDefaultScopes(DefaultAuthScopes()...),
+ }
+}
+
+// setGoogleClientInfo sets the name and version of the application in
+// the `x-goog-api-client` header passed on each request. Intended for
+// use by Google-written clients.
+func (c *databaseAdminRESTClient) setGoogleClientInfo(keyval ...string) {
+ kv := append([]string{"gl-go", gax.GoVersion}, keyval...)
+ kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "rest", "UNKNOWN")
+ c.xGoogHeaders = []string{
+ "x-goog-api-client", gax.XGoogHeader(kv...),
+ }
+}
+
+// Close closes the connection to the API service. The user should invoke this when
+// the client is no longer required.
+func (c *databaseAdminRESTClient) Close() error {
+ // Replace httpClient with nil to force cleanup.
+ c.httpClient = nil
+ return nil
+}
+
+// Connection returns a connection to the API service.
+//
+// Deprecated: This method always returns nil.
+func (c *databaseAdminRESTClient) Connection() *grpc.ClientConn {
+ return nil
+}
+func (c *databaseAdminGRPCClient) ListDatabases(ctx context.Context, req *databasepb.ListDatabasesRequest, opts ...gax.CallOption) *DatabaseIterator {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).ListDatabases[0:len((*c.CallOptions).ListDatabases):len((*c.CallOptions).ListDatabases)], opts...)
+ it := &DatabaseIterator{}
+ req = proto.Clone(req).(*databasepb.ListDatabasesRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.Database, string, error) {
+ resp := &databasepb.ListDatabasesResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.ListDatabases(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetDatabases(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+func (c *databaseAdminGRPCClient) CreateDatabase(ctx context.Context, req *databasepb.CreateDatabaseRequest, opts ...gax.CallOption) (*CreateDatabaseOperation, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).CreateDatabase[0:len((*c.CallOptions).CreateDatabase):len((*c.CallOptions).CreateDatabase)], opts...)
+ var resp *longrunningpb.Operation
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.CreateDatabase(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &CreateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ }, nil
+}
+
+func (c *databaseAdminGRPCClient) GetDatabase(ctx context.Context, req *databasepb.GetDatabaseRequest, opts ...gax.CallOption) (*databasepb.Database, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).GetDatabase[0:len((*c.CallOptions).GetDatabase):len((*c.CallOptions).GetDatabase)], opts...)
+ var resp *databasepb.Database
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.GetDatabase(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) UpdateDatabase(ctx context.Context, req *databasepb.UpdateDatabaseRequest, opts ...gax.CallOption) (*UpdateDatabaseOperation, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database.name", url.QueryEscape(req.GetDatabase().GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).UpdateDatabase[0:len((*c.CallOptions).UpdateDatabase):len((*c.CallOptions).UpdateDatabase)], opts...)
+ var resp *longrunningpb.Operation
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.UpdateDatabase(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &UpdateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ }, nil
+}
+
+func (c *databaseAdminGRPCClient) UpdateDatabaseDdl(ctx context.Context, req *databasepb.UpdateDatabaseDdlRequest, opts ...gax.CallOption) (*UpdateDatabaseDdlOperation, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database", url.QueryEscape(req.GetDatabase()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).UpdateDatabaseDdl[0:len((*c.CallOptions).UpdateDatabaseDdl):len((*c.CallOptions).UpdateDatabaseDdl)], opts...)
+ var resp *longrunningpb.Operation
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.UpdateDatabaseDdl(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &UpdateDatabaseDdlOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ }, nil
+}
+
+func (c *databaseAdminGRPCClient) DropDatabase(ctx context.Context, req *databasepb.DropDatabaseRequest, opts ...gax.CallOption) error {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database", url.QueryEscape(req.GetDatabase()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).DropDatabase[0:len((*c.CallOptions).DropDatabase):len((*c.CallOptions).DropDatabase)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.databaseAdminClient.DropDatabase(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+func (c *databaseAdminGRPCClient) GetDatabaseDdl(ctx context.Context, req *databasepb.GetDatabaseDdlRequest, opts ...gax.CallOption) (*databasepb.GetDatabaseDdlResponse, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database", url.QueryEscape(req.GetDatabase()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).GetDatabaseDdl[0:len((*c.CallOptions).GetDatabaseDdl):len((*c.CallOptions).GetDatabaseDdl)], opts...)
+ var resp *databasepb.GetDatabaseDdlResponse
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.GetDatabaseDdl(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...)
+ var resp *iampb.Policy
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.SetIamPolicy(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...)
+ var resp *iampb.Policy
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.GetIamPolicy(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...)
+ var resp *iampb.TestIamPermissionsResponse
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.TestIamPermissions(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) CreateBackup(ctx context.Context, req *databasepb.CreateBackupRequest, opts ...gax.CallOption) (*CreateBackupOperation, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).CreateBackup[0:len((*c.CallOptions).CreateBackup):len((*c.CallOptions).CreateBackup)], opts...)
+ var resp *longrunningpb.Operation
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.CreateBackup(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &CreateBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ }, nil
+}
+
+func (c *databaseAdminGRPCClient) CopyBackup(ctx context.Context, req *databasepb.CopyBackupRequest, opts ...gax.CallOption) (*CopyBackupOperation, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).CopyBackup[0:len((*c.CallOptions).CopyBackup):len((*c.CallOptions).CopyBackup)], opts...)
+ var resp *longrunningpb.Operation
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.CopyBackup(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &CopyBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ }, nil
+}
+
+func (c *databaseAdminGRPCClient) GetBackup(ctx context.Context, req *databasepb.GetBackupRequest, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).GetBackup[0:len((*c.CallOptions).GetBackup):len((*c.CallOptions).GetBackup)], opts...)
+ var resp *databasepb.Backup
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.GetBackup(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) UpdateBackup(ctx context.Context, req *databasepb.UpdateBackupRequest, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "backup.name", url.QueryEscape(req.GetBackup().GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).UpdateBackup[0:len((*c.CallOptions).UpdateBackup):len((*c.CallOptions).UpdateBackup)], opts...)
+ var resp *databasepb.Backup
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.UpdateBackup(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) DeleteBackup(ctx context.Context, req *databasepb.DeleteBackupRequest, opts ...gax.CallOption) error {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).DeleteBackup[0:len((*c.CallOptions).DeleteBackup):len((*c.CallOptions).DeleteBackup)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.databaseAdminClient.DeleteBackup(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+func (c *databaseAdminGRPCClient) ListBackups(ctx context.Context, req *databasepb.ListBackupsRequest, opts ...gax.CallOption) *BackupIterator {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).ListBackups[0:len((*c.CallOptions).ListBackups):len((*c.CallOptions).ListBackups)], opts...)
+ it := &BackupIterator{}
+ req = proto.Clone(req).(*databasepb.ListBackupsRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.Backup, string, error) {
+ resp := &databasepb.ListBackupsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.ListBackups(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetBackups(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+func (c *databaseAdminGRPCClient) RestoreDatabase(ctx context.Context, req *databasepb.RestoreDatabaseRequest, opts ...gax.CallOption) (*RestoreDatabaseOperation, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).RestoreDatabase[0:len((*c.CallOptions).RestoreDatabase):len((*c.CallOptions).RestoreDatabase)], opts...)
+ var resp *longrunningpb.Operation
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.RestoreDatabase(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &RestoreDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ }, nil
+}
+
+func (c *databaseAdminGRPCClient) ListDatabaseOperations(ctx context.Context, req *databasepb.ListDatabaseOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).ListDatabaseOperations[0:len((*c.CallOptions).ListDatabaseOperations):len((*c.CallOptions).ListDatabaseOperations)], opts...)
+ it := &OperationIterator{}
+ req = proto.Clone(req).(*databasepb.ListDatabaseOperationsRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) {
+ resp := &databasepb.ListDatabaseOperationsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.ListDatabaseOperations(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetOperations(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+func (c *databaseAdminGRPCClient) ListBackupOperations(ctx context.Context, req *databasepb.ListBackupOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).ListBackupOperations[0:len((*c.CallOptions).ListBackupOperations):len((*c.CallOptions).ListBackupOperations)], opts...)
+ it := &OperationIterator{}
+ req = proto.Clone(req).(*databasepb.ListBackupOperationsRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) {
+ resp := &databasepb.ListBackupOperationsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.ListBackupOperations(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetOperations(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+func (c *databaseAdminGRPCClient) ListDatabaseRoles(ctx context.Context, req *databasepb.ListDatabaseRolesRequest, opts ...gax.CallOption) *DatabaseRoleIterator {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).ListDatabaseRoles[0:len((*c.CallOptions).ListDatabaseRoles):len((*c.CallOptions).ListDatabaseRoles)], opts...)
+ it := &DatabaseRoleIterator{}
+ req = proto.Clone(req).(*databasepb.ListDatabaseRolesRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.DatabaseRole, string, error) {
+ resp := &databasepb.ListDatabaseRolesResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.ListDatabaseRoles(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetDatabaseRoles(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+func (c *databaseAdminGRPCClient) CreateBackupSchedule(ctx context.Context, req *databasepb.CreateBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).CreateBackupSchedule[0:len((*c.CallOptions).CreateBackupSchedule):len((*c.CallOptions).CreateBackupSchedule)], opts...)
+ var resp *databasepb.BackupSchedule
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.CreateBackupSchedule(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) GetBackupSchedule(ctx context.Context, req *databasepb.GetBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).GetBackupSchedule[0:len((*c.CallOptions).GetBackupSchedule):len((*c.CallOptions).GetBackupSchedule)], opts...)
+ var resp *databasepb.BackupSchedule
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.GetBackupSchedule(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) UpdateBackupSchedule(ctx context.Context, req *databasepb.UpdateBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "backup_schedule.name", url.QueryEscape(req.GetBackupSchedule().GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).UpdateBackupSchedule[0:len((*c.CallOptions).UpdateBackupSchedule):len((*c.CallOptions).UpdateBackupSchedule)], opts...)
+ var resp *databasepb.BackupSchedule
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.UpdateBackupSchedule(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) DeleteBackupSchedule(ctx context.Context, req *databasepb.DeleteBackupScheduleRequest, opts ...gax.CallOption) error {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).DeleteBackupSchedule[0:len((*c.CallOptions).DeleteBackupSchedule):len((*c.CallOptions).DeleteBackupSchedule)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.databaseAdminClient.DeleteBackupSchedule(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+func (c *databaseAdminGRPCClient) ListBackupSchedules(ctx context.Context, req *databasepb.ListBackupSchedulesRequest, opts ...gax.CallOption) *BackupScheduleIterator {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).ListBackupSchedules[0:len((*c.CallOptions).ListBackupSchedules):len((*c.CallOptions).ListBackupSchedules)], opts...)
+ it := &BackupScheduleIterator{}
+ req = proto.Clone(req).(*databasepb.ListBackupSchedulesRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.BackupSchedule, string, error) {
+ resp := &databasepb.ListBackupSchedulesResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.databaseAdminClient.ListBackupSchedules(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetBackupSchedules(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+func (c *databaseAdminGRPCClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).CancelOperation[0:len((*c.CallOptions).CancelOperation):len((*c.CallOptions).CancelOperation)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.operationsClient.CancelOperation(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+func (c *databaseAdminGRPCClient) DeleteOperation(ctx context.Context, req *longrunningpb.DeleteOperationRequest, opts ...gax.CallOption) error {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).DeleteOperation[0:len((*c.CallOptions).DeleteOperation):len((*c.CallOptions).DeleteOperation)], opts...)
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ _, err = c.operationsClient.DeleteOperation(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ return err
+}
+
+func (c *databaseAdminGRPCClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...)
+ var resp *longrunningpb.Operation
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.operationsClient.GetOperation(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+func (c *databaseAdminGRPCClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
+ opts = append((*c.CallOptions).ListOperations[0:len((*c.CallOptions).ListOperations):len((*c.CallOptions).ListOperations)], opts...)
+ it := &OperationIterator{}
+ req = proto.Clone(req).(*longrunningpb.ListOperationsRequest)
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) {
+ resp := &longrunningpb.ListOperationsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ var err error
+ resp, err = c.operationsClient.ListOperations(ctx, req, settings.GRPC...)
+ return err
+ }, opts...)
+ if err != nil {
+ return nil, "", err
+ }
+
+ it.Response = resp
+ return resp.GetOperations(), resp.GetNextPageToken(), nil
+ }
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// ListDatabases lists Cloud Spanner databases.
+func (c *databaseAdminRESTClient) ListDatabases(ctx context.Context, req *databasepb.ListDatabasesRequest, opts ...gax.CallOption) *DatabaseIterator {
+ it := &DatabaseIterator{}
+ req = proto.Clone(req).(*databasepb.ListDatabasesRequest)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.Database, string, error) {
+ resp := &databasepb.ListDatabasesResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, "", err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/databases", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetPageSize() != 0 {
+ params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize()))
+ }
+ if req.GetPageToken() != "" {
+ params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken()))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := append(c.xGoogHeaders, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, "", e
+ }
+ it.Response = resp
+ return resp.GetDatabases(), resp.GetNextPageToken(), nil
+ }
+
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// CreateDatabase creates a new Cloud Spanner database and starts to prepare it for serving.
+// The returned [long-running operation][google.longrunning.Operation] will
+// have a name of the format /operations/ and
+// can be used to track preparation of the database. The
+// metadata field type is
+// CreateDatabaseMetadata.
+// The response field type is
+// Database, if successful.
+func (c *databaseAdminRESTClient) CreateDatabase(ctx context.Context, req *databasepb.CreateDatabaseRequest, opts ...gax.CallOption) (*CreateDatabaseOperation, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/databases", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &longrunningpb.Operation{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+
+ override := fmt.Sprintf("/v1/%s", resp.GetName())
+ return &CreateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ pollPath: override,
+ }, nil
+}
+
+// GetDatabase gets the state of a Cloud Spanner database.
+func (c *databaseAdminRESTClient) GetDatabase(ctx context.Context, req *databasepb.GetDatabaseRequest, opts ...gax.CallOption) (*databasepb.Database, error) {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).GetDatabase[0:len((*c.CallOptions).GetDatabase):len((*c.CallOptions).GetDatabase)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &databasepb.Database{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// UpdateDatabase updates a Cloud Spanner database. The returned
+// [long-running operation][google.longrunning.Operation] can be used to track
+// the progress of updating the database. If the named database does not
+// exist, returns NOT_FOUND.
+//
+// While the operation is pending:
+//
+// The database’s
+// reconciling
+// field is set to true.
+//
+// Cancelling the operation is best-effort. If the cancellation succeeds,
+// the operation metadata’s
+// cancel_time
+// is set, the updates are reverted, and the operation terminates with a
+// CANCELLED status.
+//
+// New UpdateDatabase requests will return a FAILED_PRECONDITION error
+// until the pending operation is done (returns successfully or with
+// error).
+//
+// Reading the database via the API continues to give the pre-request
+// values.
+//
+// Upon completion of the returned operation:
+//
+// The new values are in effect and readable via the API.
+//
+// The database’s
+// reconciling
+// field becomes false.
+//
+// The returned [long-running operation][google.longrunning.Operation] will
+// have a name of the format
+// projects//instances//databases//operations/
+// and can be used to track the database modification. The
+// metadata field type is
+// UpdateDatabaseMetadata.
+// The response field type is
+// Database, if successful.
+func (c *databaseAdminRESTClient) UpdateDatabase(ctx context.Context, req *databasepb.UpdateDatabaseRequest, opts ...gax.CallOption) (*UpdateDatabaseOperation, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ body := req.GetDatabase()
+ jsonReq, err := m.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetDatabase().GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetUpdateMask() != nil {
+ updateMask, err := protojson.Marshal(req.GetUpdateMask())
+ if err != nil {
+ return nil, err
+ }
+ params.Add("updateMask", string(updateMask[1:len(updateMask)-1]))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database.name", url.QueryEscape(req.GetDatabase().GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &longrunningpb.Operation{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+
+ override := fmt.Sprintf("/v1/%s", resp.GetName())
+ return &UpdateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ pollPath: override,
+ }, nil
+}
+
+// UpdateDatabaseDdl updates the schema of a Cloud Spanner database by
+// creating/altering/dropping tables, columns, indexes, etc. The returned
+// [long-running operation][google.longrunning.Operation] will have a name of
+// the format /operations/ and can be used to
+// track execution of the schema change(s). The
+// metadata field type is
+// UpdateDatabaseDdlMetadata.
+// The operation has no response.
+func (c *databaseAdminRESTClient) UpdateDatabaseDdl(ctx context.Context, req *databasepb.UpdateDatabaseDdlRequest, opts ...gax.CallOption) (*UpdateDatabaseDdlOperation, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/ddl", req.GetDatabase())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database", url.QueryEscape(req.GetDatabase()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &longrunningpb.Operation{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+
+ override := fmt.Sprintf("/v1/%s", resp.GetName())
+ return &UpdateDatabaseDdlOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ pollPath: override,
+ }, nil
+}
+
+// DropDatabase drops (aka deletes) a Cloud Spanner database.
+// Completed backups for the database will be retained according to their
+// expire_time.
+// Note: Cloud Spanner might continue to accept requests for a few seconds
+// after the database has been deleted.
+func (c *databaseAdminRESTClient) DropDatabase(ctx context.Context, req *databasepb.DropDatabaseRequest, opts ...gax.CallOption) error {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetDatabase())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database", url.QueryEscape(req.GetDatabase()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ // Returns nil if there is no error, otherwise wraps
+ // the response code and body into a non-nil error
+ return googleapi.CheckResponse(httpRsp)
+ }, opts...)
+}
+
+// GetDatabaseDdl returns the schema of a Cloud Spanner database as a list of formatted
+// DDL statements. This method does not show pending schema updates, those may
+// be queried using the Operations API.
+func (c *databaseAdminRESTClient) GetDatabaseDdl(ctx context.Context, req *databasepb.GetDatabaseDdlRequest, opts ...gax.CallOption) (*databasepb.GetDatabaseDdlResponse, error) {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/ddl", req.GetDatabase())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "database", url.QueryEscape(req.GetDatabase()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).GetDatabaseDdl[0:len((*c.CallOptions).GetDatabaseDdl):len((*c.CallOptions).GetDatabaseDdl)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &databasepb.GetDatabaseDdlResponse{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// SetIamPolicy sets the access control policy on a database or backup resource.
+// Replaces any existing policy.
+//
+// Authorization requires spanner.databases.setIamPolicy
+// permission on resource.
+// For backups, authorization requires spanner.backups.setIamPolicy
+// permission on resource.
+func (c *databaseAdminRESTClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v:setIamPolicy", req.GetResource())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &iampb.Policy{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// GetIamPolicy gets the access control policy for a database or backup resource.
+// Returns an empty policy if a database or backup exists but does not have a
+// policy set.
+//
+// Authorization requires spanner.databases.getIamPolicy permission on
+// resource.
+// For backups, authorization requires spanner.backups.getIamPolicy
+// permission on resource.
+func (c *databaseAdminRESTClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v:getIamPolicy", req.GetResource())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &iampb.Policy{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// TestIamPermissions returns permissions that the caller has on the specified database or backup
+// resource.
+//
+// Attempting this RPC on a non-existent Cloud Spanner database will
+// result in a NOT_FOUND error if the user has
+// spanner.databases.list permission on the containing Cloud
+// Spanner instance. Otherwise returns an empty set of permissions.
+// Calling this method on a backup that does not exist will
+// result in a NOT_FOUND error if the user has
+// spanner.backups.list permission on the containing instance.
+func (c *databaseAdminRESTClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v:testIamPermissions", req.GetResource())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "resource", url.QueryEscape(req.GetResource()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &iampb.TestIamPermissionsResponse{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// CreateBackup starts creating a new Cloud Spanner Backup.
+// The returned backup [long-running operation][google.longrunning.Operation]
+// will have a name of the format
+// projects//instances//backups//operations/
+// and can be used to track creation of the backup. The
+// metadata field type is
+// CreateBackupMetadata.
+// The response field type is
+// Backup, if successful.
+// Cancelling the returned operation will stop the creation and delete the
+// backup. There can be only one pending backup creation per database. Backup
+// creation of different databases can run concurrently.
+func (c *databaseAdminRESTClient) CreateBackup(ctx context.Context, req *databasepb.CreateBackupRequest, opts ...gax.CallOption) (*CreateBackupOperation, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ body := req.GetBackup()
+ jsonReq, err := m.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/backups", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ params.Add("backupId", fmt.Sprintf("%v", req.GetBackupId()))
+ params.Add("encryptionConfig.encryptionType", fmt.Sprintf("%v", req.GetEncryptionConfig().GetEncryptionType()))
+ if req.GetEncryptionConfig().GetKmsKeyName() != "" {
+ params.Add("encryptionConfig.kmsKeyName", fmt.Sprintf("%v", req.GetEncryptionConfig().GetKmsKeyName()))
+ }
+ if items := req.GetEncryptionConfig().GetKmsKeyNames(); len(items) > 0 {
+ for _, item := range items {
+ params.Add("encryptionConfig.kmsKeyNames", fmt.Sprintf("%v", item))
+ }
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &longrunningpb.Operation{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+
+ override := fmt.Sprintf("/v1/%s", resp.GetName())
+ return &CreateBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ pollPath: override,
+ }, nil
+}
+
+// CopyBackup starts copying a Cloud Spanner Backup.
+// The returned backup [long-running operation][google.longrunning.Operation]
+// will have a name of the format
+// projects//instances//backups//operations/
+// and can be used to track copying of the backup. The operation is associated
+// with the destination backup.
+// The metadata field type is
+// CopyBackupMetadata.
+// The response field type is
+// Backup, if successful.
+// Cancelling the returned operation will stop the copying and delete the
+// destination backup. Concurrent CopyBackup requests can run on the same
+// source backup.
+func (c *databaseAdminRESTClient) CopyBackup(ctx context.Context, req *databasepb.CopyBackupRequest, opts ...gax.CallOption) (*CopyBackupOperation, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/backups:copy", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &longrunningpb.Operation{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+
+ override := fmt.Sprintf("/v1/%s", resp.GetName())
+ return &CopyBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ pollPath: override,
+ }, nil
+}
+
+// GetBackup gets metadata on a pending or completed
+// Backup.
+func (c *databaseAdminRESTClient) GetBackup(ctx context.Context, req *databasepb.GetBackupRequest, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).GetBackup[0:len((*c.CallOptions).GetBackup):len((*c.CallOptions).GetBackup)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &databasepb.Backup{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// UpdateBackup updates a pending or completed
+// Backup.
+func (c *databaseAdminRESTClient) UpdateBackup(ctx context.Context, req *databasepb.UpdateBackupRequest, opts ...gax.CallOption) (*databasepb.Backup, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ body := req.GetBackup()
+ jsonReq, err := m.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetBackup().GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetUpdateMask() != nil {
+ updateMask, err := protojson.Marshal(req.GetUpdateMask())
+ if err != nil {
+ return nil, err
+ }
+ params.Add("updateMask", string(updateMask[1:len(updateMask)-1]))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "backup.name", url.QueryEscape(req.GetBackup().GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).UpdateBackup[0:len((*c.CallOptions).UpdateBackup):len((*c.CallOptions).UpdateBackup)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &databasepb.Backup{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// DeleteBackup deletes a pending or completed
+// Backup.
+func (c *databaseAdminRESTClient) DeleteBackup(ctx context.Context, req *databasepb.DeleteBackupRequest, opts ...gax.CallOption) error {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ // Returns nil if there is no error, otherwise wraps
+ // the response code and body into a non-nil error
+ return googleapi.CheckResponse(httpRsp)
+ }, opts...)
+}
+
+// ListBackups lists completed and pending backups.
+// Backups returned are ordered by create_time in descending order,
+// starting from the most recent create_time.
+func (c *databaseAdminRESTClient) ListBackups(ctx context.Context, req *databasepb.ListBackupsRequest, opts ...gax.CallOption) *BackupIterator {
+ it := &BackupIterator{}
+ req = proto.Clone(req).(*databasepb.ListBackupsRequest)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.Backup, string, error) {
+ resp := &databasepb.ListBackupsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, "", err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/backups", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetFilter() != "" {
+ params.Add("filter", fmt.Sprintf("%v", req.GetFilter()))
+ }
+ if req.GetPageSize() != 0 {
+ params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize()))
+ }
+ if req.GetPageToken() != "" {
+ params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken()))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := append(c.xGoogHeaders, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, "", e
+ }
+ it.Response = resp
+ return resp.GetBackups(), resp.GetNextPageToken(), nil
+ }
+
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// RestoreDatabase create a new database by restoring from a completed backup. The new
+// database must be in the same project and in an instance with the same
+// instance configuration as the instance containing
+// the backup. The returned database [long-running
+// operation][google.longrunning.Operation] has a name of the format
+// projects//instances//databases//operations/,
+// and can be used to track the progress of the operation, and to cancel it.
+// The metadata field type is
+// RestoreDatabaseMetadata.
+// The response type
+// is Database, if
+// successful. Cancelling the returned operation will stop the restore and
+// delete the database.
+// There can be only one database being restored into an instance at a time.
+// Once the restore operation completes, a new restore operation can be
+// initiated, without waiting for the optimize operation associated with the
+// first restore to complete.
+func (c *databaseAdminRESTClient) RestoreDatabase(ctx context.Context, req *databasepb.RestoreDatabaseRequest, opts ...gax.CallOption) (*RestoreDatabaseOperation, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ jsonReq, err := m.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/databases:restore", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &longrunningpb.Operation{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+
+ override := fmt.Sprintf("/v1/%s", resp.GetName())
+ return &RestoreDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, resp),
+ pollPath: override,
+ }, nil
+}
+
+// ListDatabaseOperations lists database [longrunning-operations][google.longrunning.Operation].
+// A database operation has a name of the form
+// projects//instances//databases//operations/.
+// The long-running operation
+// metadata field type
+// metadata.type_url describes the type of the metadata. Operations returned
+// include those that have completed/failed/canceled within the last 7 days,
+// and pending operations.
+func (c *databaseAdminRESTClient) ListDatabaseOperations(ctx context.Context, req *databasepb.ListDatabaseOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ it := &OperationIterator{}
+ req = proto.Clone(req).(*databasepb.ListDatabaseOperationsRequest)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) {
+ resp := &databasepb.ListDatabaseOperationsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, "", err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/databaseOperations", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetFilter() != "" {
+ params.Add("filter", fmt.Sprintf("%v", req.GetFilter()))
+ }
+ if req.GetPageSize() != 0 {
+ params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize()))
+ }
+ if req.GetPageToken() != "" {
+ params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken()))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := append(c.xGoogHeaders, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, "", e
+ }
+ it.Response = resp
+ return resp.GetOperations(), resp.GetNextPageToken(), nil
+ }
+
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// ListBackupOperations lists the backup [long-running operations][google.longrunning.Operation] in
+// the given instance. A backup operation has a name of the form
+// projects//instances//backups//operations/.
+// The long-running operation
+// metadata field type
+// metadata.type_url describes the type of the metadata. Operations returned
+// include those that have completed/failed/canceled within the last 7 days,
+// and pending operations. Operations returned are ordered by
+// operation.metadata.value.progress.start_time in descending order starting
+// from the most recently started operation.
+func (c *databaseAdminRESTClient) ListBackupOperations(ctx context.Context, req *databasepb.ListBackupOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ it := &OperationIterator{}
+ req = proto.Clone(req).(*databasepb.ListBackupOperationsRequest)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) {
+ resp := &databasepb.ListBackupOperationsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, "", err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/backupOperations", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetFilter() != "" {
+ params.Add("filter", fmt.Sprintf("%v", req.GetFilter()))
+ }
+ if req.GetPageSize() != 0 {
+ params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize()))
+ }
+ if req.GetPageToken() != "" {
+ params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken()))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := append(c.xGoogHeaders, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, "", e
+ }
+ it.Response = resp
+ return resp.GetOperations(), resp.GetNextPageToken(), nil
+ }
+
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// ListDatabaseRoles lists Cloud Spanner database roles.
+func (c *databaseAdminRESTClient) ListDatabaseRoles(ctx context.Context, req *databasepb.ListDatabaseRolesRequest, opts ...gax.CallOption) *DatabaseRoleIterator {
+ it := &DatabaseRoleIterator{}
+ req = proto.Clone(req).(*databasepb.ListDatabaseRolesRequest)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.DatabaseRole, string, error) {
+ resp := &databasepb.ListDatabaseRolesResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, "", err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/databaseRoles", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetPageSize() != 0 {
+ params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize()))
+ }
+ if req.GetPageToken() != "" {
+ params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken()))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := append(c.xGoogHeaders, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, "", e
+ }
+ it.Response = resp
+ return resp.GetDatabaseRoles(), resp.GetNextPageToken(), nil
+ }
+
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// CreateBackupSchedule creates a new backup schedule.
+func (c *databaseAdminRESTClient) CreateBackupSchedule(ctx context.Context, req *databasepb.CreateBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ body := req.GetBackupSchedule()
+ jsonReq, err := m.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/backupSchedules", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ params.Add("backupScheduleId", fmt.Sprintf("%v", req.GetBackupScheduleId()))
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).CreateBackupSchedule[0:len((*c.CallOptions).CreateBackupSchedule):len((*c.CallOptions).CreateBackupSchedule)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &databasepb.BackupSchedule{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// GetBackupSchedule gets backup schedule for the input schedule name.
+func (c *databaseAdminRESTClient) GetBackupSchedule(ctx context.Context, req *databasepb.GetBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).GetBackupSchedule[0:len((*c.CallOptions).GetBackupSchedule):len((*c.CallOptions).GetBackupSchedule)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &databasepb.BackupSchedule{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// UpdateBackupSchedule updates a backup schedule.
+func (c *databaseAdminRESTClient) UpdateBackupSchedule(ctx context.Context, req *databasepb.UpdateBackupScheduleRequest, opts ...gax.CallOption) (*databasepb.BackupSchedule, error) {
+ m := protojson.MarshalOptions{AllowPartial: true, UseEnumNumbers: true}
+ body := req.GetBackupSchedule()
+ jsonReq, err := m.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetBackupSchedule().GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetUpdateMask() != nil {
+ updateMask, err := protojson.Marshal(req.GetUpdateMask())
+ if err != nil {
+ return nil, err
+ }
+ params.Add("updateMask", string(updateMask[1:len(updateMask)-1]))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "backup_schedule.name", url.QueryEscape(req.GetBackupSchedule().GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).UpdateBackupSchedule[0:len((*c.CallOptions).UpdateBackupSchedule):len((*c.CallOptions).UpdateBackupSchedule)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &databasepb.BackupSchedule{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("PATCH", baseUrl.String(), bytes.NewReader(jsonReq))
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// DeleteBackupSchedule deletes a backup schedule.
+func (c *databaseAdminRESTClient) DeleteBackupSchedule(ctx context.Context, req *databasepb.DeleteBackupScheduleRequest, opts ...gax.CallOption) error {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ // Returns nil if there is no error, otherwise wraps
+ // the response code and body into a non-nil error
+ return googleapi.CheckResponse(httpRsp)
+ }, opts...)
+}
+
+// ListBackupSchedules lists all the backup schedules for the database.
+func (c *databaseAdminRESTClient) ListBackupSchedules(ctx context.Context, req *databasepb.ListBackupSchedulesRequest, opts ...gax.CallOption) *BackupScheduleIterator {
+ it := &BackupScheduleIterator{}
+ req = proto.Clone(req).(*databasepb.ListBackupSchedulesRequest)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.BackupSchedule, string, error) {
+ resp := &databasepb.ListBackupSchedulesResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, "", err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v/backupSchedules", req.GetParent())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetPageSize() != 0 {
+ params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize()))
+ }
+ if req.GetPageToken() != "" {
+ params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken()))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := append(c.xGoogHeaders, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, "", e
+ }
+ it.Response = resp
+ return resp.GetBackupSchedules(), resp.GetNextPageToken(), nil
+ }
+
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// CancelOperation is a utility method from google.longrunning.Operations.
+func (c *databaseAdminRESTClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v:cancel", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("POST", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ // Returns nil if there is no error, otherwise wraps
+ // the response code and body into a non-nil error
+ return googleapi.CheckResponse(httpRsp)
+ }, opts...)
+}
+
+// DeleteOperation is a utility method from google.longrunning.Operations.
+func (c *databaseAdminRESTClient) DeleteOperation(ctx context.Context, req *longrunningpb.DeleteOperationRequest, opts ...gax.CallOption) error {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ return gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("DELETE", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ // Returns nil if there is no error, otherwise wraps
+ // the response code and body into a non-nil error
+ return googleapi.CheckResponse(httpRsp)
+ }, opts...)
+}
+
+// GetOperation is a utility method from google.longrunning.Operations.
+func (c *databaseAdminRESTClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) {
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := []string{"x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))}
+
+ hds = append(c.xGoogHeaders, hds...)
+ hds = append(hds, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ opts = append((*c.CallOptions).GetOperation[0:len((*c.CallOptions).GetOperation):len((*c.CallOptions).GetOperation)], opts...)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ resp := &longrunningpb.Operation{}
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq = httpReq.WithContext(ctx)
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, e
+ }
+ return resp, nil
+}
+
+// ListOperations is a utility method from google.longrunning.Operations.
+func (c *databaseAdminRESTClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator {
+ it := &OperationIterator{}
+ req = proto.Clone(req).(*longrunningpb.ListOperationsRequest)
+ unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
+ it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) {
+ resp := &longrunningpb.ListOperationsResponse{}
+ if pageToken != "" {
+ req.PageToken = pageToken
+ }
+ if pageSize > math.MaxInt32 {
+ req.PageSize = math.MaxInt32
+ } else if pageSize != 0 {
+ req.PageSize = int32(pageSize)
+ }
+ baseUrl, err := url.Parse(c.endpoint)
+ if err != nil {
+ return nil, "", err
+ }
+ baseUrl.Path += fmt.Sprintf("/v1/%v", req.GetName())
+
+ params := url.Values{}
+ params.Add("$alt", "json;enum-encoding=int")
+ if req.GetFilter() != "" {
+ params.Add("filter", fmt.Sprintf("%v", req.GetFilter()))
+ }
+ if req.GetPageSize() != 0 {
+ params.Add("pageSize", fmt.Sprintf("%v", req.GetPageSize()))
+ }
+ if req.GetPageToken() != "" {
+ params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken()))
+ }
+
+ baseUrl.RawQuery = params.Encode()
+
+ // Build HTTP headers from client and context metadata.
+ hds := append(c.xGoogHeaders, "Content-Type", "application/json")
+ headers := gax.BuildHeaders(ctx, hds...)
+ e := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
+ if settings.Path != "" {
+ baseUrl.Path = settings.Path
+ }
+ httpReq, err := http.NewRequest("GET", baseUrl.String(), nil)
+ if err != nil {
+ return err
+ }
+ httpReq.Header = headers
+
+ httpRsp, err := c.httpClient.Do(httpReq)
+ if err != nil {
+ return err
+ }
+ defer httpRsp.Body.Close()
+
+ if err = googleapi.CheckResponse(httpRsp); err != nil {
+ return err
+ }
+
+ buf, err := io.ReadAll(httpRsp.Body)
+ if err != nil {
+ return err
+ }
+
+ if err := unm.Unmarshal(buf, resp); err != nil {
+ return err
+ }
+
+ return nil
+ }, opts...)
+ if e != nil {
+ return nil, "", e
+ }
+ it.Response = resp
+ return resp.GetOperations(), resp.GetNextPageToken(), nil
+ }
+
+ fetch := func(pageSize int, pageToken string) (string, error) {
+ items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
+ if err != nil {
+ return "", err
+ }
+ it.items = append(it.items, items...)
+ return nextPageToken, nil
+ }
+
+ it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
+ it.pageInfo.MaxSize = int(req.GetPageSize())
+ it.pageInfo.Token = req.GetPageToken()
+
+ return it
+}
+
+// CopyBackupOperation returns a new CopyBackupOperation from a given name.
+// The name must be that of a previously created CopyBackupOperation, possibly from a different process.
+func (c *databaseAdminGRPCClient) CopyBackupOperation(name string) *CopyBackupOperation {
+ return &CopyBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ }
+}
+
+// CopyBackupOperation returns a new CopyBackupOperation from a given name.
+// The name must be that of a previously created CopyBackupOperation, possibly from a different process.
+func (c *databaseAdminRESTClient) CopyBackupOperation(name string) *CopyBackupOperation {
+ override := fmt.Sprintf("/v1/%s", name)
+ return &CopyBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ pollPath: override,
+ }
+}
+
+// CreateBackupOperation returns a new CreateBackupOperation from a given name.
+// The name must be that of a previously created CreateBackupOperation, possibly from a different process.
+func (c *databaseAdminGRPCClient) CreateBackupOperation(name string) *CreateBackupOperation {
+ return &CreateBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ }
+}
+
+// CreateBackupOperation returns a new CreateBackupOperation from a given name.
+// The name must be that of a previously created CreateBackupOperation, possibly from a different process.
+func (c *databaseAdminRESTClient) CreateBackupOperation(name string) *CreateBackupOperation {
+ override := fmt.Sprintf("/v1/%s", name)
+ return &CreateBackupOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ pollPath: override,
+ }
+}
+
+// CreateDatabaseOperation returns a new CreateDatabaseOperation from a given name.
+// The name must be that of a previously created CreateDatabaseOperation, possibly from a different process.
+func (c *databaseAdminGRPCClient) CreateDatabaseOperation(name string) *CreateDatabaseOperation {
+ return &CreateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ }
+}
+
+// CreateDatabaseOperation returns a new CreateDatabaseOperation from a given name.
+// The name must be that of a previously created CreateDatabaseOperation, possibly from a different process.
+func (c *databaseAdminRESTClient) CreateDatabaseOperation(name string) *CreateDatabaseOperation {
+ override := fmt.Sprintf("/v1/%s", name)
+ return &CreateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ pollPath: override,
+ }
+}
+
+// RestoreDatabaseOperation returns a new RestoreDatabaseOperation from a given name.
+// The name must be that of a previously created RestoreDatabaseOperation, possibly from a different process.
+func (c *databaseAdminGRPCClient) RestoreDatabaseOperation(name string) *RestoreDatabaseOperation {
+ return &RestoreDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ }
+}
+
+// RestoreDatabaseOperation returns a new RestoreDatabaseOperation from a given name.
+// The name must be that of a previously created RestoreDatabaseOperation, possibly from a different process.
+func (c *databaseAdminRESTClient) RestoreDatabaseOperation(name string) *RestoreDatabaseOperation {
+ override := fmt.Sprintf("/v1/%s", name)
+ return &RestoreDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ pollPath: override,
+ }
+}
+
+// UpdateDatabaseOperation returns a new UpdateDatabaseOperation from a given name.
+// The name must be that of a previously created UpdateDatabaseOperation, possibly from a different process.
+func (c *databaseAdminGRPCClient) UpdateDatabaseOperation(name string) *UpdateDatabaseOperation {
+ return &UpdateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ }
+}
+
+// UpdateDatabaseOperation returns a new UpdateDatabaseOperation from a given name.
+// The name must be that of a previously created UpdateDatabaseOperation, possibly from a different process.
+func (c *databaseAdminRESTClient) UpdateDatabaseOperation(name string) *UpdateDatabaseOperation {
+ override := fmt.Sprintf("/v1/%s", name)
+ return &UpdateDatabaseOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ pollPath: override,
+ }
+}
+
+// UpdateDatabaseDdlOperation returns a new UpdateDatabaseDdlOperation from a given name.
+// The name must be that of a previously created UpdateDatabaseDdlOperation, possibly from a different process.
+func (c *databaseAdminGRPCClient) UpdateDatabaseDdlOperation(name string) *UpdateDatabaseDdlOperation {
+ return &UpdateDatabaseDdlOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ }
+}
+
+// UpdateDatabaseDdlOperation returns a new UpdateDatabaseDdlOperation from a given name.
+// The name must be that of a previously created UpdateDatabaseDdlOperation, possibly from a different process.
+func (c *databaseAdminRESTClient) UpdateDatabaseDdlOperation(name string) *UpdateDatabaseDdlOperation {
+ override := fmt.Sprintf("/v1/%s", name)
+ return &UpdateDatabaseDdlOperation{
+ lro: longrunning.InternalNewOperation(*c.LROClient, &longrunningpb.Operation{Name: name}),
+ pollPath: override,
+ }
+}
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/backup.pb.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/backup.pb.go
new file mode 100644
index 000000000000..7a5db895c507
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/backup.pb.go
@@ -0,0 +1,2446 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.34.2
+// protoc v4.25.3
+// source: google/spanner/admin/database/v1/backup.proto
+
+package databasepb
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ longrunningpb "cloud.google.com/go/longrunning/autogen/longrunningpb"
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Indicates the current state of the backup.
+type Backup_State int32
+
+const (
+ // Not specified.
+ Backup_STATE_UNSPECIFIED Backup_State = 0
+ // The pending backup is still being created. Operations on the
+ // backup may fail with `FAILED_PRECONDITION` in this state.
+ Backup_CREATING Backup_State = 1
+ // The backup is complete and ready for use.
+ Backup_READY Backup_State = 2
+)
+
+// Enum value maps for Backup_State.
+var (
+ Backup_State_name = map[int32]string{
+ 0: "STATE_UNSPECIFIED",
+ 1: "CREATING",
+ 2: "READY",
+ }
+ Backup_State_value = map[string]int32{
+ "STATE_UNSPECIFIED": 0,
+ "CREATING": 1,
+ "READY": 2,
+ }
+)
+
+func (x Backup_State) Enum() *Backup_State {
+ p := new(Backup_State)
+ *p = x
+ return p
+}
+
+func (x Backup_State) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Backup_State) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_backup_proto_enumTypes[0].Descriptor()
+}
+
+func (Backup_State) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_backup_proto_enumTypes[0]
+}
+
+func (x Backup_State) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Backup_State.Descriptor instead.
+func (Backup_State) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{0, 0}
+}
+
+// Encryption types for the backup.
+type CreateBackupEncryptionConfig_EncryptionType int32
+
+const (
+ // Unspecified. Do not use.
+ CreateBackupEncryptionConfig_ENCRYPTION_TYPE_UNSPECIFIED CreateBackupEncryptionConfig_EncryptionType = 0
+ // Use the same encryption configuration as the database. This is the
+ // default option when
+ // [encryption_config][google.spanner.admin.database.v1.CreateBackupEncryptionConfig]
+ // is empty. For example, if the database is using
+ // `Customer_Managed_Encryption`, the backup will be using the same Cloud
+ // KMS key as the database.
+ CreateBackupEncryptionConfig_USE_DATABASE_ENCRYPTION CreateBackupEncryptionConfig_EncryptionType = 1
+ // Use Google default encryption.
+ CreateBackupEncryptionConfig_GOOGLE_DEFAULT_ENCRYPTION CreateBackupEncryptionConfig_EncryptionType = 2
+ // Use customer managed encryption. If specified, `kms_key_name`
+ // must contain a valid Cloud KMS key.
+ CreateBackupEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION CreateBackupEncryptionConfig_EncryptionType = 3
+)
+
+// Enum value maps for CreateBackupEncryptionConfig_EncryptionType.
+var (
+ CreateBackupEncryptionConfig_EncryptionType_name = map[int32]string{
+ 0: "ENCRYPTION_TYPE_UNSPECIFIED",
+ 1: "USE_DATABASE_ENCRYPTION",
+ 2: "GOOGLE_DEFAULT_ENCRYPTION",
+ 3: "CUSTOMER_MANAGED_ENCRYPTION",
+ }
+ CreateBackupEncryptionConfig_EncryptionType_value = map[string]int32{
+ "ENCRYPTION_TYPE_UNSPECIFIED": 0,
+ "USE_DATABASE_ENCRYPTION": 1,
+ "GOOGLE_DEFAULT_ENCRYPTION": 2,
+ "CUSTOMER_MANAGED_ENCRYPTION": 3,
+ }
+)
+
+func (x CreateBackupEncryptionConfig_EncryptionType) Enum() *CreateBackupEncryptionConfig_EncryptionType {
+ p := new(CreateBackupEncryptionConfig_EncryptionType)
+ *p = x
+ return p
+}
+
+func (x CreateBackupEncryptionConfig_EncryptionType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CreateBackupEncryptionConfig_EncryptionType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_backup_proto_enumTypes[1].Descriptor()
+}
+
+func (CreateBackupEncryptionConfig_EncryptionType) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_backup_proto_enumTypes[1]
+}
+
+func (x CreateBackupEncryptionConfig_EncryptionType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CreateBackupEncryptionConfig_EncryptionType.Descriptor instead.
+func (CreateBackupEncryptionConfig_EncryptionType) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{13, 0}
+}
+
+// Encryption types for the backup.
+type CopyBackupEncryptionConfig_EncryptionType int32
+
+const (
+ // Unspecified. Do not use.
+ CopyBackupEncryptionConfig_ENCRYPTION_TYPE_UNSPECIFIED CopyBackupEncryptionConfig_EncryptionType = 0
+ // This is the default option for
+ // [CopyBackup][google.spanner.admin.database.v1.DatabaseAdmin.CopyBackup]
+ // when
+ // [encryption_config][google.spanner.admin.database.v1.CopyBackupEncryptionConfig]
+ // is not specified. For example, if the source backup is using
+ // `Customer_Managed_Encryption`, the backup will be using the same Cloud
+ // KMS key as the source backup.
+ CopyBackupEncryptionConfig_USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION CopyBackupEncryptionConfig_EncryptionType = 1
+ // Use Google default encryption.
+ CopyBackupEncryptionConfig_GOOGLE_DEFAULT_ENCRYPTION CopyBackupEncryptionConfig_EncryptionType = 2
+ // Use customer managed encryption. If specified, either `kms_key_name` or
+ // `kms_key_names` must contain valid Cloud KMS key(s).
+ CopyBackupEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION CopyBackupEncryptionConfig_EncryptionType = 3
+)
+
+// Enum value maps for CopyBackupEncryptionConfig_EncryptionType.
+var (
+ CopyBackupEncryptionConfig_EncryptionType_name = map[int32]string{
+ 0: "ENCRYPTION_TYPE_UNSPECIFIED",
+ 1: "USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION",
+ 2: "GOOGLE_DEFAULT_ENCRYPTION",
+ 3: "CUSTOMER_MANAGED_ENCRYPTION",
+ }
+ CopyBackupEncryptionConfig_EncryptionType_value = map[string]int32{
+ "ENCRYPTION_TYPE_UNSPECIFIED": 0,
+ "USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION": 1,
+ "GOOGLE_DEFAULT_ENCRYPTION": 2,
+ "CUSTOMER_MANAGED_ENCRYPTION": 3,
+ }
+)
+
+func (x CopyBackupEncryptionConfig_EncryptionType) Enum() *CopyBackupEncryptionConfig_EncryptionType {
+ p := new(CopyBackupEncryptionConfig_EncryptionType)
+ *p = x
+ return p
+}
+
+func (x CopyBackupEncryptionConfig_EncryptionType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CopyBackupEncryptionConfig_EncryptionType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_backup_proto_enumTypes[2].Descriptor()
+}
+
+func (CopyBackupEncryptionConfig_EncryptionType) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_backup_proto_enumTypes[2]
+}
+
+func (x CopyBackupEncryptionConfig_EncryptionType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CopyBackupEncryptionConfig_EncryptionType.Descriptor instead.
+func (CopyBackupEncryptionConfig_EncryptionType) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{14, 0}
+}
+
+// A backup of a Cloud Spanner database.
+type Backup struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required for the
+ // [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup]
+ // operation. Name of the database from which this backup was created. This
+ // needs to be in the same instance as the backup. Values are of the form
+ // `projects//instances//databases/`.
+ Database string `protobuf:"bytes,2,opt,name=database,proto3" json:"database,omitempty"`
+ // The backup will contain an externally consistent copy of the database at
+ // the timestamp specified by `version_time`. If `version_time` is not
+ // specified, the system will set `version_time` to the `create_time` of the
+ // backup.
+ VersionTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=version_time,json=versionTime,proto3" json:"version_time,omitempty"`
+ // Required for the
+ // [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup]
+ // operation. The expiration time of the backup, with microseconds
+ // granularity that must be at least 6 hours and at most 366 days
+ // from the time the CreateBackup request is processed. Once the `expire_time`
+ // has passed, the backup is eligible to be automatically deleted by Cloud
+ // Spanner to free the resources used by the backup.
+ ExpireTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expire_time,json=expireTime,proto3" json:"expire_time,omitempty"`
+ // Output only for the
+ // [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup]
+ // operation. Required for the
+ // [UpdateBackup][google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackup]
+ // operation.
+ //
+ // A globally unique identifier for the backup which cannot be
+ // changed. Values are of the form
+ // `projects//instances//backups/[a-z][a-z0-9_\-]*[a-z0-9]`
+ // The final segment of the name must be between 2 and 60 characters
+ // in length.
+ //
+ // The backup is stored in the location(s) specified in the instance
+ // configuration of the instance containing the backup, identified
+ // by the prefix of the backup name of the form
+ // `projects//instances/`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Output only. The time the
+ // [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup]
+ // request is received. If the request does not specify `version_time`, the
+ // `version_time` of the backup will be equivalent to the `create_time`.
+ CreateTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"`
+ // Output only. Size of the backup in bytes.
+ SizeBytes int64 `protobuf:"varint,5,opt,name=size_bytes,json=sizeBytes,proto3" json:"size_bytes,omitempty"`
+ // Output only. The number of bytes that will be freed by deleting this
+ // backup. This value will be zero if, for example, this backup is part of an
+ // incremental backup chain and younger backups in the chain require that we
+ // keep its data. For backups not in an incremental backup chain, this is
+ // always the size of the backup. This value may change if backups on the same
+ // chain get created, deleted or expired.
+ FreeableSizeBytes int64 `protobuf:"varint,15,opt,name=freeable_size_bytes,json=freeableSizeBytes,proto3" json:"freeable_size_bytes,omitempty"`
+ // Output only. For a backup in an incremental backup chain, this is the
+ // storage space needed to keep the data that has changed since the previous
+ // backup. For all other backups, this is always the size of the backup. This
+ // value may change if backups on the same chain get deleted or expired.
+ //
+ // This field can be used to calculate the total storage space used by a set
+ // of backups. For example, the total space used by all backups of a database
+ // can be computed by summing up this field.
+ ExclusiveSizeBytes int64 `protobuf:"varint,16,opt,name=exclusive_size_bytes,json=exclusiveSizeBytes,proto3" json:"exclusive_size_bytes,omitempty"`
+ // Output only. The current state of the backup.
+ State Backup_State `protobuf:"varint,6,opt,name=state,proto3,enum=google.spanner.admin.database.v1.Backup_State" json:"state,omitempty"`
+ // Output only. The names of the restored databases that reference the backup.
+ // The database names are of
+ // the form `projects//instances//databases/`.
+ // Referencing databases may exist in different instances. The existence of
+ // any referencing database prevents the backup from being deleted. When a
+ // restored database from the backup enters the `READY` state, the reference
+ // to the backup is removed.
+ ReferencingDatabases []string `protobuf:"bytes,7,rep,name=referencing_databases,json=referencingDatabases,proto3" json:"referencing_databases,omitempty"`
+ // Output only. The encryption information for the backup.
+ EncryptionInfo *EncryptionInfo `protobuf:"bytes,8,opt,name=encryption_info,json=encryptionInfo,proto3" json:"encryption_info,omitempty"`
+ // Output only. The encryption information for the backup, whether it is
+ // protected by one or more KMS keys. The information includes all Cloud
+ // KMS key versions used to encrypt the backup. The `encryption_status' field
+ // inside of each `EncryptionInfo` is not populated. At least one of the key
+ // versions must be available for the backup to be restored. If a key version
+ // is revoked in the middle of a restore, the restore behavior is undefined.
+ EncryptionInformation []*EncryptionInfo `protobuf:"bytes,13,rep,name=encryption_information,json=encryptionInformation,proto3" json:"encryption_information,omitempty"`
+ // Output only. The database dialect information for the backup.
+ DatabaseDialect DatabaseDialect `protobuf:"varint,10,opt,name=database_dialect,json=databaseDialect,proto3,enum=google.spanner.admin.database.v1.DatabaseDialect" json:"database_dialect,omitempty"`
+ // Output only. The names of the destination backups being created by copying
+ // this source backup. The backup names are of the form
+ // `projects//instances//backups/`.
+ // Referencing backups may exist in different instances. The existence of
+ // any referencing backup prevents the backup from being deleted. When the
+ // copy operation is done (either successfully completed or cancelled or the
+ // destination backup is deleted), the reference to the backup is removed.
+ ReferencingBackups []string `protobuf:"bytes,11,rep,name=referencing_backups,json=referencingBackups,proto3" json:"referencing_backups,omitempty"`
+ // Output only. The max allowed expiration time of the backup, with
+ // microseconds granularity. A backup's expiration time can be configured in
+ // multiple APIs: CreateBackup, UpdateBackup, CopyBackup. When updating or
+ // copying an existing backup, the expiration time specified must be
+ // less than `Backup.max_expire_time`.
+ MaxExpireTime *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=max_expire_time,json=maxExpireTime,proto3" json:"max_expire_time,omitempty"`
+ // Output only. List of backup schedule URIs that are associated with
+ // creating this backup. This is only applicable for scheduled backups, and
+ // is empty for on-demand backups.
+ //
+ // To optimize for storage, whenever possible, multiple schedules are
+ // collapsed together to create one backup. In such cases, this field captures
+ // the list of all backup schedule URIs that are associated with creating
+ // this backup. If collapsing is not done, then this field captures the
+ // single backup schedule URI associated with creating this backup.
+ BackupSchedules []string `protobuf:"bytes,14,rep,name=backup_schedules,json=backupSchedules,proto3" json:"backup_schedules,omitempty"`
+ // Output only. Populated only for backups in an incremental backup chain.
+ // Backups share the same chain id if and only if they belong to the same
+ // incremental backup chain. Use this field to determine which backups are
+ // part of the same incremental backup chain. The ordering of backups in the
+ // chain can be determined by ordering the backup `version_time`.
+ IncrementalBackupChainId string `protobuf:"bytes,17,opt,name=incremental_backup_chain_id,json=incrementalBackupChainId,proto3" json:"incremental_backup_chain_id,omitempty"`
+ // Output only. Data deleted at a time older than this is guaranteed not to be
+ // retained in order to support this backup. For a backup in an incremental
+ // backup chain, this is the version time of the oldest backup that exists or
+ // ever existed in the chain. For all other backups, this is the version time
+ // of the backup. This field can be used to understand what data is being
+ // retained by the backup system.
+ OldestVersionTime *timestamppb.Timestamp `protobuf:"bytes,18,opt,name=oldest_version_time,json=oldestVersionTime,proto3" json:"oldest_version_time,omitempty"`
+}
+
+func (x *Backup) Reset() {
+ *x = Backup{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Backup) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Backup) ProtoMessage() {}
+
+func (x *Backup) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Backup.ProtoReflect.Descriptor instead.
+func (*Backup) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Backup) GetDatabase() string {
+ if x != nil {
+ return x.Database
+ }
+ return ""
+}
+
+func (x *Backup) GetVersionTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.VersionTime
+ }
+ return nil
+}
+
+func (x *Backup) GetExpireTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.ExpireTime
+ }
+ return nil
+}
+
+func (x *Backup) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *Backup) GetCreateTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreateTime
+ }
+ return nil
+}
+
+func (x *Backup) GetSizeBytes() int64 {
+ if x != nil {
+ return x.SizeBytes
+ }
+ return 0
+}
+
+func (x *Backup) GetFreeableSizeBytes() int64 {
+ if x != nil {
+ return x.FreeableSizeBytes
+ }
+ return 0
+}
+
+func (x *Backup) GetExclusiveSizeBytes() int64 {
+ if x != nil {
+ return x.ExclusiveSizeBytes
+ }
+ return 0
+}
+
+func (x *Backup) GetState() Backup_State {
+ if x != nil {
+ return x.State
+ }
+ return Backup_STATE_UNSPECIFIED
+}
+
+func (x *Backup) GetReferencingDatabases() []string {
+ if x != nil {
+ return x.ReferencingDatabases
+ }
+ return nil
+}
+
+func (x *Backup) GetEncryptionInfo() *EncryptionInfo {
+ if x != nil {
+ return x.EncryptionInfo
+ }
+ return nil
+}
+
+func (x *Backup) GetEncryptionInformation() []*EncryptionInfo {
+ if x != nil {
+ return x.EncryptionInformation
+ }
+ return nil
+}
+
+func (x *Backup) GetDatabaseDialect() DatabaseDialect {
+ if x != nil {
+ return x.DatabaseDialect
+ }
+ return DatabaseDialect_DATABASE_DIALECT_UNSPECIFIED
+}
+
+func (x *Backup) GetReferencingBackups() []string {
+ if x != nil {
+ return x.ReferencingBackups
+ }
+ return nil
+}
+
+func (x *Backup) GetMaxExpireTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.MaxExpireTime
+ }
+ return nil
+}
+
+func (x *Backup) GetBackupSchedules() []string {
+ if x != nil {
+ return x.BackupSchedules
+ }
+ return nil
+}
+
+func (x *Backup) GetIncrementalBackupChainId() string {
+ if x != nil {
+ return x.IncrementalBackupChainId
+ }
+ return ""
+}
+
+func (x *Backup) GetOldestVersionTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.OldestVersionTime
+ }
+ return nil
+}
+
+// The request for
+// [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup].
+type CreateBackupRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the instance in which the backup will be
+ // created. This must be the same instance that contains the database the
+ // backup will be created from. The backup will be stored in the
+ // location(s) specified in the instance configuration of this
+ // instance. Values are of the form
+ // `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Required. The id of the backup to be created. The `backup_id` appended to
+ // `parent` forms the full backup name of the form
+ // `projects//instances//backups/`.
+ BackupId string `protobuf:"bytes,2,opt,name=backup_id,json=backupId,proto3" json:"backup_id,omitempty"`
+ // Required. The backup to create.
+ Backup *Backup `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"`
+ // Optional. The encryption configuration used to encrypt the backup. If this
+ // field is not specified, the backup will use the same encryption
+ // configuration as the database by default, namely
+ // [encryption_type][google.spanner.admin.database.v1.CreateBackupEncryptionConfig.encryption_type]
+ // = `USE_DATABASE_ENCRYPTION`.
+ EncryptionConfig *CreateBackupEncryptionConfig `protobuf:"bytes,4,opt,name=encryption_config,json=encryptionConfig,proto3" json:"encryption_config,omitempty"`
+}
+
+func (x *CreateBackupRequest) Reset() {
+ *x = CreateBackupRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateBackupRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateBackupRequest) ProtoMessage() {}
+
+func (x *CreateBackupRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateBackupRequest.ProtoReflect.Descriptor instead.
+func (*CreateBackupRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *CreateBackupRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *CreateBackupRequest) GetBackupId() string {
+ if x != nil {
+ return x.BackupId
+ }
+ return ""
+}
+
+func (x *CreateBackupRequest) GetBackup() *Backup {
+ if x != nil {
+ return x.Backup
+ }
+ return nil
+}
+
+func (x *CreateBackupRequest) GetEncryptionConfig() *CreateBackupEncryptionConfig {
+ if x != nil {
+ return x.EncryptionConfig
+ }
+ return nil
+}
+
+// Metadata type for the operation returned by
+// [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup].
+type CreateBackupMetadata struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the backup being created.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // The name of the database the backup is created from.
+ Database string `protobuf:"bytes,2,opt,name=database,proto3" json:"database,omitempty"`
+ // The progress of the
+ // [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup]
+ // operation.
+ Progress *OperationProgress `protobuf:"bytes,3,opt,name=progress,proto3" json:"progress,omitempty"`
+ // The time at which cancellation of this operation was received.
+ // [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]
+ // starts asynchronous cancellation on a long-running operation. The server
+ // makes a best effort to cancel the operation, but success is not guaranteed.
+ // Clients can use
+ // [Operations.GetOperation][google.longrunning.Operations.GetOperation] or
+ // other methods to check whether the cancellation succeeded or whether the
+ // operation completed despite cancellation. On successful cancellation,
+ // the operation is not deleted; instead, it becomes an operation with
+ // an [Operation.error][google.longrunning.Operation.error] value with a
+ // [google.rpc.Status.code][google.rpc.Status.code] of 1,
+ // corresponding to `Code.CANCELLED`.
+ CancelTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=cancel_time,json=cancelTime,proto3" json:"cancel_time,omitempty"`
+}
+
+func (x *CreateBackupMetadata) Reset() {
+ *x = CreateBackupMetadata{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateBackupMetadata) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateBackupMetadata) ProtoMessage() {}
+
+func (x *CreateBackupMetadata) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateBackupMetadata.ProtoReflect.Descriptor instead.
+func (*CreateBackupMetadata) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *CreateBackupMetadata) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *CreateBackupMetadata) GetDatabase() string {
+ if x != nil {
+ return x.Database
+ }
+ return ""
+}
+
+func (x *CreateBackupMetadata) GetProgress() *OperationProgress {
+ if x != nil {
+ return x.Progress
+ }
+ return nil
+}
+
+func (x *CreateBackupMetadata) GetCancelTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CancelTime
+ }
+ return nil
+}
+
+// The request for
+// [CopyBackup][google.spanner.admin.database.v1.DatabaseAdmin.CopyBackup].
+type CopyBackupRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the destination instance that will contain the backup
+ // copy. Values are of the form: `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Required. The id of the backup copy.
+ // The `backup_id` appended to `parent` forms the full backup_uri of the form
+ // `projects//instances//backups/`.
+ BackupId string `protobuf:"bytes,2,opt,name=backup_id,json=backupId,proto3" json:"backup_id,omitempty"`
+ // Required. The source backup to be copied.
+ // The source backup needs to be in READY state for it to be copied.
+ // Once CopyBackup is in progress, the source backup cannot be deleted or
+ // cleaned up on expiration until CopyBackup is finished.
+ // Values are of the form:
+ // `projects//instances//backups/`.
+ SourceBackup string `protobuf:"bytes,3,opt,name=source_backup,json=sourceBackup,proto3" json:"source_backup,omitempty"`
+ // Required. The expiration time of the backup in microsecond granularity.
+ // The expiration time must be at least 6 hours and at most 366 days
+ // from the `create_time` of the source backup. Once the `expire_time` has
+ // passed, the backup is eligible to be automatically deleted by Cloud Spanner
+ // to free the resources used by the backup.
+ ExpireTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expire_time,json=expireTime,proto3" json:"expire_time,omitempty"`
+ // Optional. The encryption configuration used to encrypt the backup. If this
+ // field is not specified, the backup will use the same encryption
+ // configuration as the source backup by default, namely
+ // [encryption_type][google.spanner.admin.database.v1.CopyBackupEncryptionConfig.encryption_type]
+ // = `USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION`.
+ EncryptionConfig *CopyBackupEncryptionConfig `protobuf:"bytes,5,opt,name=encryption_config,json=encryptionConfig,proto3" json:"encryption_config,omitempty"`
+}
+
+func (x *CopyBackupRequest) Reset() {
+ *x = CopyBackupRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CopyBackupRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CopyBackupRequest) ProtoMessage() {}
+
+func (x *CopyBackupRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CopyBackupRequest.ProtoReflect.Descriptor instead.
+func (*CopyBackupRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *CopyBackupRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *CopyBackupRequest) GetBackupId() string {
+ if x != nil {
+ return x.BackupId
+ }
+ return ""
+}
+
+func (x *CopyBackupRequest) GetSourceBackup() string {
+ if x != nil {
+ return x.SourceBackup
+ }
+ return ""
+}
+
+func (x *CopyBackupRequest) GetExpireTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.ExpireTime
+ }
+ return nil
+}
+
+func (x *CopyBackupRequest) GetEncryptionConfig() *CopyBackupEncryptionConfig {
+ if x != nil {
+ return x.EncryptionConfig
+ }
+ return nil
+}
+
+// Metadata type for the operation returned by
+// [CopyBackup][google.spanner.admin.database.v1.DatabaseAdmin.CopyBackup].
+type CopyBackupMetadata struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the backup being created through the copy operation.
+ // Values are of the form
+ // `projects//instances//backups/`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // The name of the source backup that is being copied.
+ // Values are of the form
+ // `projects//instances//backups/`.
+ SourceBackup string `protobuf:"bytes,2,opt,name=source_backup,json=sourceBackup,proto3" json:"source_backup,omitempty"`
+ // The progress of the
+ // [CopyBackup][google.spanner.admin.database.v1.DatabaseAdmin.CopyBackup]
+ // operation.
+ Progress *OperationProgress `protobuf:"bytes,3,opt,name=progress,proto3" json:"progress,omitempty"`
+ // The time at which cancellation of CopyBackup operation was received.
+ // [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]
+ // starts asynchronous cancellation on a long-running operation. The server
+ // makes a best effort to cancel the operation, but success is not guaranteed.
+ // Clients can use
+ // [Operations.GetOperation][google.longrunning.Operations.GetOperation] or
+ // other methods to check whether the cancellation succeeded or whether the
+ // operation completed despite cancellation. On successful cancellation,
+ // the operation is not deleted; instead, it becomes an operation with
+ // an [Operation.error][google.longrunning.Operation.error] value with a
+ // [google.rpc.Status.code][google.rpc.Status.code] of 1,
+ // corresponding to `Code.CANCELLED`.
+ CancelTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=cancel_time,json=cancelTime,proto3" json:"cancel_time,omitempty"`
+}
+
+func (x *CopyBackupMetadata) Reset() {
+ *x = CopyBackupMetadata{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CopyBackupMetadata) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CopyBackupMetadata) ProtoMessage() {}
+
+func (x *CopyBackupMetadata) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CopyBackupMetadata.ProtoReflect.Descriptor instead.
+func (*CopyBackupMetadata) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *CopyBackupMetadata) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *CopyBackupMetadata) GetSourceBackup() string {
+ if x != nil {
+ return x.SourceBackup
+ }
+ return ""
+}
+
+func (x *CopyBackupMetadata) GetProgress() *OperationProgress {
+ if x != nil {
+ return x.Progress
+ }
+ return nil
+}
+
+func (x *CopyBackupMetadata) GetCancelTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CancelTime
+ }
+ return nil
+}
+
+// The request for
+// [UpdateBackup][google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackup].
+type UpdateBackupRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The backup to update. `backup.name`, and the fields to be updated
+ // as specified by `update_mask` are required. Other fields are ignored.
+ // Update is only supported for the following fields:
+ // - `backup.expire_time`.
+ Backup *Backup `protobuf:"bytes,1,opt,name=backup,proto3" json:"backup,omitempty"`
+ // Required. A mask specifying which fields (e.g. `expire_time`) in the
+ // Backup resource should be updated. This mask is relative to the Backup
+ // resource, not to the request message. The field mask must always be
+ // specified; this prevents any future fields from being erased accidentally
+ // by clients that do not know about them.
+ UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
+}
+
+func (x *UpdateBackupRequest) Reset() {
+ *x = UpdateBackupRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateBackupRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateBackupRequest) ProtoMessage() {}
+
+func (x *UpdateBackupRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateBackupRequest.ProtoReflect.Descriptor instead.
+func (*UpdateBackupRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *UpdateBackupRequest) GetBackup() *Backup {
+ if x != nil {
+ return x.Backup
+ }
+ return nil
+}
+
+func (x *UpdateBackupRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
+ if x != nil {
+ return x.UpdateMask
+ }
+ return nil
+}
+
+// The request for
+// [GetBackup][google.spanner.admin.database.v1.DatabaseAdmin.GetBackup].
+type GetBackupRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. Name of the backup.
+ // Values are of the form
+ // `projects//instances//backups/`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *GetBackupRequest) Reset() {
+ *x = GetBackupRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetBackupRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetBackupRequest) ProtoMessage() {}
+
+func (x *GetBackupRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetBackupRequest.ProtoReflect.Descriptor instead.
+func (*GetBackupRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *GetBackupRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// The request for
+// [DeleteBackup][google.spanner.admin.database.v1.DatabaseAdmin.DeleteBackup].
+type DeleteBackupRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. Name of the backup to delete.
+ // Values are of the form
+ // `projects//instances//backups/`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *DeleteBackupRequest) Reset() {
+ *x = DeleteBackupRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DeleteBackupRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteBackupRequest) ProtoMessage() {}
+
+func (x *DeleteBackupRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteBackupRequest.ProtoReflect.Descriptor instead.
+func (*DeleteBackupRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *DeleteBackupRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// The request for
+// [ListBackups][google.spanner.admin.database.v1.DatabaseAdmin.ListBackups].
+type ListBackupsRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The instance to list backups from. Values are of the
+ // form `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // An expression that filters the list of returned backups.
+ //
+ // A filter expression consists of a field name, a comparison operator, and a
+ // value for filtering.
+ // The value must be a string, a number, or a boolean. The comparison operator
+ // must be one of: `<`, `>`, `<=`, `>=`, `!=`, `=`, or `:`.
+ // Colon `:` is the contains operator. Filter rules are not case sensitive.
+ //
+ // The following fields in the
+ // [Backup][google.spanner.admin.database.v1.Backup] are eligible for
+ // filtering:
+ //
+ // - `name`
+ // - `database`
+ // - `state`
+ // - `create_time` (and values are of the format YYYY-MM-DDTHH:MM:SSZ)
+ // - `expire_time` (and values are of the format YYYY-MM-DDTHH:MM:SSZ)
+ // - `version_time` (and values are of the format YYYY-MM-DDTHH:MM:SSZ)
+ // - `size_bytes`
+ // - `backup_schedules`
+ //
+ // You can combine multiple expressions by enclosing each expression in
+ // parentheses. By default, expressions are combined with AND logic, but
+ // you can specify AND, OR, and NOT logic explicitly.
+ //
+ // Here are a few examples:
+ //
+ // - `name:Howl` - The backup's name contains the string "howl".
+ // - `database:prod`
+ // - The database's name contains the string "prod".
+ // - `state:CREATING` - The backup is pending creation.
+ // - `state:READY` - The backup is fully created and ready for use.
+ // - `(name:howl) AND (create_time < \"2018-03-28T14:50:00Z\")`
+ // - The backup name contains the string "howl" and `create_time`
+ // of the backup is before 2018-03-28T14:50:00Z.
+ // - `expire_time < \"2018-03-28T14:50:00Z\"`
+ // - The backup `expire_time` is before 2018-03-28T14:50:00Z.
+ // - `size_bytes > 10000000000` - The backup's size is greater than 10GB
+ // - `backup_schedules:daily`
+ // - The backup is created from a schedule with "daily" in its name.
+ Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
+ // Number of backups to be returned in the response. If 0 or
+ // less, defaults to the server's maximum allowed page size.
+ PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ // If non-empty, `page_token` should contain a
+ // [next_page_token][google.spanner.admin.database.v1.ListBackupsResponse.next_page_token]
+ // from a previous
+ // [ListBackupsResponse][google.spanner.admin.database.v1.ListBackupsResponse]
+ // to the same `parent` and with the same `filter`.
+ PageToken string `protobuf:"bytes,4,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+}
+
+func (x *ListBackupsRequest) Reset() {
+ *x = ListBackupsRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListBackupsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListBackupsRequest) ProtoMessage() {}
+
+func (x *ListBackupsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListBackupsRequest.ProtoReflect.Descriptor instead.
+func (*ListBackupsRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *ListBackupsRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *ListBackupsRequest) GetFilter() string {
+ if x != nil {
+ return x.Filter
+ }
+ return ""
+}
+
+func (x *ListBackupsRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *ListBackupsRequest) GetPageToken() string {
+ if x != nil {
+ return x.PageToken
+ }
+ return ""
+}
+
+// The response for
+// [ListBackups][google.spanner.admin.database.v1.DatabaseAdmin.ListBackups].
+type ListBackupsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of matching backups. Backups returned are ordered by `create_time`
+ // in descending order, starting from the most recent `create_time`.
+ Backups []*Backup `protobuf:"bytes,1,rep,name=backups,proto3" json:"backups,omitempty"`
+ // `next_page_token` can be sent in a subsequent
+ // [ListBackups][google.spanner.admin.database.v1.DatabaseAdmin.ListBackups]
+ // call to fetch more of the matching backups.
+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+}
+
+func (x *ListBackupsResponse) Reset() {
+ *x = ListBackupsResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListBackupsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListBackupsResponse) ProtoMessage() {}
+
+func (x *ListBackupsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListBackupsResponse.ProtoReflect.Descriptor instead.
+func (*ListBackupsResponse) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *ListBackupsResponse) GetBackups() []*Backup {
+ if x != nil {
+ return x.Backups
+ }
+ return nil
+}
+
+func (x *ListBackupsResponse) GetNextPageToken() string {
+ if x != nil {
+ return x.NextPageToken
+ }
+ return ""
+}
+
+// The request for
+// [ListBackupOperations][google.spanner.admin.database.v1.DatabaseAdmin.ListBackupOperations].
+type ListBackupOperationsRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The instance of the backup operations. Values are of
+ // the form `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // An expression that filters the list of returned backup operations.
+ //
+ // A filter expression consists of a field name, a
+ // comparison operator, and a value for filtering.
+ // The value must be a string, a number, or a boolean. The comparison operator
+ // must be one of: `<`, `>`, `<=`, `>=`, `!=`, `=`, or `:`.
+ // Colon `:` is the contains operator. Filter rules are not case sensitive.
+ //
+ // The following fields in the [operation][google.longrunning.Operation]
+ // are eligible for filtering:
+ //
+ // - `name` - The name of the long-running operation
+ // - `done` - False if the operation is in progress, else true.
+ // - `metadata.@type` - the type of metadata. For example, the type string
+ // for
+ // [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]
+ // is
+ // `type.googleapis.com/google.spanner.admin.database.v1.CreateBackupMetadata`.
+ // - `metadata.` - any field in metadata.value.
+ // `metadata.@type` must be specified first if filtering on metadata
+ // fields.
+ // - `error` - Error associated with the long-running operation.
+ // - `response.@type` - the type of response.
+ // - `response.` - any field in response.value.
+ //
+ // You can combine multiple expressions by enclosing each expression in
+ // parentheses. By default, expressions are combined with AND logic, but
+ // you can specify AND, OR, and NOT logic explicitly.
+ //
+ // Here are a few examples:
+ //
+ // - `done:true` - The operation is complete.
+ // - `(metadata.@type=type.googleapis.com/google.spanner.admin.database.v1.CreateBackupMetadata) AND` \
+ // `metadata.database:prod` - Returns operations where:
+ // - The operation's metadata type is
+ // [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata].
+ // - The source database name of backup contains the string "prod".
+ // - `(metadata.@type=type.googleapis.com/google.spanner.admin.database.v1.CreateBackupMetadata) AND` \
+ // `(metadata.name:howl) AND` \
+ // `(metadata.progress.start_time < \"2018-03-28T14:50:00Z\") AND` \
+ // `(error:*)` - Returns operations where:
+ // - The operation's metadata type is
+ // [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata].
+ // - The backup name contains the string "howl".
+ // - The operation started before 2018-03-28T14:50:00Z.
+ // - The operation resulted in an error.
+ // - `(metadata.@type=type.googleapis.com/google.spanner.admin.database.v1.CopyBackupMetadata) AND` \
+ // `(metadata.source_backup:test) AND` \
+ // `(metadata.progress.start_time < \"2022-01-18T14:50:00Z\") AND` \
+ // `(error:*)` - Returns operations where:
+ // - The operation's metadata type is
+ // [CopyBackupMetadata][google.spanner.admin.database.v1.CopyBackupMetadata].
+ // - The source backup name contains the string "test".
+ // - The operation started before 2022-01-18T14:50:00Z.
+ // - The operation resulted in an error.
+ // - `((metadata.@type=type.googleapis.com/google.spanner.admin.database.v1.CreateBackupMetadata) AND` \
+ // `(metadata.database:test_db)) OR` \
+ // `((metadata.@type=type.googleapis.com/google.spanner.admin.database.v1.CopyBackupMetadata)
+ // AND` \
+ // `(metadata.source_backup:test_bkp)) AND` \
+ // `(error:*)` - Returns operations where:
+ // - The operation's metadata matches either of criteria:
+ // - The operation's metadata type is
+ // [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]
+ // AND the source database name of the backup contains the string
+ // "test_db"
+ // - The operation's metadata type is
+ // [CopyBackupMetadata][google.spanner.admin.database.v1.CopyBackupMetadata]
+ // AND the source backup name contains the string "test_bkp"
+ // - The operation resulted in an error.
+ Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
+ // Number of operations to be returned in the response. If 0 or
+ // less, defaults to the server's maximum allowed page size.
+ PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ // If non-empty, `page_token` should contain a
+ // [next_page_token][google.spanner.admin.database.v1.ListBackupOperationsResponse.next_page_token]
+ // from a previous
+ // [ListBackupOperationsResponse][google.spanner.admin.database.v1.ListBackupOperationsResponse]
+ // to the same `parent` and with the same `filter`.
+ PageToken string `protobuf:"bytes,4,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+}
+
+func (x *ListBackupOperationsRequest) Reset() {
+ *x = ListBackupOperationsRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListBackupOperationsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListBackupOperationsRequest) ProtoMessage() {}
+
+func (x *ListBackupOperationsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListBackupOperationsRequest.ProtoReflect.Descriptor instead.
+func (*ListBackupOperationsRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *ListBackupOperationsRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *ListBackupOperationsRequest) GetFilter() string {
+ if x != nil {
+ return x.Filter
+ }
+ return ""
+}
+
+func (x *ListBackupOperationsRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *ListBackupOperationsRequest) GetPageToken() string {
+ if x != nil {
+ return x.PageToken
+ }
+ return ""
+}
+
+// The response for
+// [ListBackupOperations][google.spanner.admin.database.v1.DatabaseAdmin.ListBackupOperations].
+type ListBackupOperationsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of matching backup [long-running
+ // operations][google.longrunning.Operation]. Each operation's name will be
+ // prefixed by the backup's name. The operation's
+ // [metadata][google.longrunning.Operation.metadata] field type
+ // `metadata.type_url` describes the type of the metadata. Operations returned
+ // include those that are pending or have completed/failed/canceled within the
+ // last 7 days. Operations returned are ordered by
+ // `operation.metadata.value.progress.start_time` in descending order starting
+ // from the most recently started operation.
+ Operations []*longrunningpb.Operation `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"`
+ // `next_page_token` can be sent in a subsequent
+ // [ListBackupOperations][google.spanner.admin.database.v1.DatabaseAdmin.ListBackupOperations]
+ // call to fetch more of the matching metadata.
+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+}
+
+func (x *ListBackupOperationsResponse) Reset() {
+ *x = ListBackupOperationsResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListBackupOperationsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListBackupOperationsResponse) ProtoMessage() {}
+
+func (x *ListBackupOperationsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListBackupOperationsResponse.ProtoReflect.Descriptor instead.
+func (*ListBackupOperationsResponse) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *ListBackupOperationsResponse) GetOperations() []*longrunningpb.Operation {
+ if x != nil {
+ return x.Operations
+ }
+ return nil
+}
+
+func (x *ListBackupOperationsResponse) GetNextPageToken() string {
+ if x != nil {
+ return x.NextPageToken
+ }
+ return ""
+}
+
+// Information about a backup.
+type BackupInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the backup.
+ Backup string `protobuf:"bytes,1,opt,name=backup,proto3" json:"backup,omitempty"`
+ // The backup contains an externally consistent copy of `source_database` at
+ // the timestamp specified by `version_time`. If the
+ // [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup]
+ // request did not specify `version_time`, the `version_time` of the backup is
+ // equivalent to the `create_time`.
+ VersionTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=version_time,json=versionTime,proto3" json:"version_time,omitempty"`
+ // The time the
+ // [CreateBackup][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup]
+ // request was received.
+ CreateTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"`
+ // Name of the database the backup was created from.
+ SourceDatabase string `protobuf:"bytes,3,opt,name=source_database,json=sourceDatabase,proto3" json:"source_database,omitempty"`
+}
+
+func (x *BackupInfo) Reset() {
+ *x = BackupInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BackupInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupInfo) ProtoMessage() {}
+
+func (x *BackupInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupInfo.ProtoReflect.Descriptor instead.
+func (*BackupInfo) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *BackupInfo) GetBackup() string {
+ if x != nil {
+ return x.Backup
+ }
+ return ""
+}
+
+func (x *BackupInfo) GetVersionTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.VersionTime
+ }
+ return nil
+}
+
+func (x *BackupInfo) GetCreateTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreateTime
+ }
+ return nil
+}
+
+func (x *BackupInfo) GetSourceDatabase() string {
+ if x != nil {
+ return x.SourceDatabase
+ }
+ return ""
+}
+
+// Encryption configuration for the backup to create.
+type CreateBackupEncryptionConfig struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The encryption type of the backup.
+ EncryptionType CreateBackupEncryptionConfig_EncryptionType `protobuf:"varint,1,opt,name=encryption_type,json=encryptionType,proto3,enum=google.spanner.admin.database.v1.CreateBackupEncryptionConfig_EncryptionType" json:"encryption_type,omitempty"`
+ // Optional. The Cloud KMS key that will be used to protect the backup.
+ // This field should be set only when
+ // [encryption_type][google.spanner.admin.database.v1.CreateBackupEncryptionConfig.encryption_type]
+ // is `CUSTOMER_MANAGED_ENCRYPTION`. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ KmsKeyName string `protobuf:"bytes,2,opt,name=kms_key_name,json=kmsKeyName,proto3" json:"kms_key_name,omitempty"`
+ // Optional. Specifies the KMS configuration for the one or more keys used to
+ // protect the backup. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ //
+ // The keys referenced by kms_key_names must fully cover all
+ // regions of the backup's instance configuration. Some examples:
+ // * For single region instance configs, specify a single regional
+ // location KMS key.
+ // * For multi-regional instance configs of type GOOGLE_MANAGED,
+ // either specify a multi-regional location KMS key or multiple regional
+ // location KMS keys that cover all regions in the instance config.
+ // * For an instance config of type USER_MANAGED, please specify only
+ // regional location KMS keys to cover each region in the instance config.
+ // Multi-regional location KMS keys are not supported for USER_MANAGED
+ // instance configs.
+ KmsKeyNames []string `protobuf:"bytes,3,rep,name=kms_key_names,json=kmsKeyNames,proto3" json:"kms_key_names,omitempty"`
+}
+
+func (x *CreateBackupEncryptionConfig) Reset() {
+ *x = CreateBackupEncryptionConfig{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateBackupEncryptionConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateBackupEncryptionConfig) ProtoMessage() {}
+
+func (x *CreateBackupEncryptionConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateBackupEncryptionConfig.ProtoReflect.Descriptor instead.
+func (*CreateBackupEncryptionConfig) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *CreateBackupEncryptionConfig) GetEncryptionType() CreateBackupEncryptionConfig_EncryptionType {
+ if x != nil {
+ return x.EncryptionType
+ }
+ return CreateBackupEncryptionConfig_ENCRYPTION_TYPE_UNSPECIFIED
+}
+
+func (x *CreateBackupEncryptionConfig) GetKmsKeyName() string {
+ if x != nil {
+ return x.KmsKeyName
+ }
+ return ""
+}
+
+func (x *CreateBackupEncryptionConfig) GetKmsKeyNames() []string {
+ if x != nil {
+ return x.KmsKeyNames
+ }
+ return nil
+}
+
+// Encryption configuration for the copied backup.
+type CopyBackupEncryptionConfig struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The encryption type of the backup.
+ EncryptionType CopyBackupEncryptionConfig_EncryptionType `protobuf:"varint,1,opt,name=encryption_type,json=encryptionType,proto3,enum=google.spanner.admin.database.v1.CopyBackupEncryptionConfig_EncryptionType" json:"encryption_type,omitempty"`
+ // Optional. The Cloud KMS key that will be used to protect the backup.
+ // This field should be set only when
+ // [encryption_type][google.spanner.admin.database.v1.CopyBackupEncryptionConfig.encryption_type]
+ // is `CUSTOMER_MANAGED_ENCRYPTION`. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ KmsKeyName string `protobuf:"bytes,2,opt,name=kms_key_name,json=kmsKeyName,proto3" json:"kms_key_name,omitempty"`
+ // Optional. Specifies the KMS configuration for the one or more keys used to
+ // protect the backup. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ // Kms keys specified can be in any order.
+ //
+ // The keys referenced by kms_key_names must fully cover all
+ // regions of the backup's instance configuration. Some examples:
+ // * For single region instance configs, specify a single regional
+ // location KMS key.
+ // * For multi-regional instance configs of type GOOGLE_MANAGED,
+ // either specify a multi-regional location KMS key or multiple regional
+ // location KMS keys that cover all regions in the instance config.
+ // * For an instance config of type USER_MANAGED, please specify only
+ // regional location KMS keys to cover each region in the instance config.
+ // Multi-regional location KMS keys are not supported for USER_MANAGED
+ // instance configs.
+ KmsKeyNames []string `protobuf:"bytes,3,rep,name=kms_key_names,json=kmsKeyNames,proto3" json:"kms_key_names,omitempty"`
+}
+
+func (x *CopyBackupEncryptionConfig) Reset() {
+ *x = CopyBackupEncryptionConfig{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CopyBackupEncryptionConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CopyBackupEncryptionConfig) ProtoMessage() {}
+
+func (x *CopyBackupEncryptionConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CopyBackupEncryptionConfig.ProtoReflect.Descriptor instead.
+func (*CopyBackupEncryptionConfig) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *CopyBackupEncryptionConfig) GetEncryptionType() CopyBackupEncryptionConfig_EncryptionType {
+ if x != nil {
+ return x.EncryptionType
+ }
+ return CopyBackupEncryptionConfig_ENCRYPTION_TYPE_UNSPECIFIED
+}
+
+func (x *CopyBackupEncryptionConfig) GetKmsKeyName() string {
+ if x != nil {
+ return x.KmsKeyName
+ }
+ return ""
+}
+
+func (x *CopyBackupEncryptionConfig) GetKmsKeyNames() []string {
+ if x != nil {
+ return x.KmsKeyNames
+ }
+ return nil
+}
+
+// The specification for full backups.
+// A full backup stores the entire contents of the database at a given
+// version time.
+type FullBackupSpec struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *FullBackupSpec) Reset() {
+ *x = FullBackupSpec{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FullBackupSpec) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FullBackupSpec) ProtoMessage() {}
+
+func (x *FullBackupSpec) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[15]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FullBackupSpec.ProtoReflect.Descriptor instead.
+func (*FullBackupSpec) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{15}
+}
+
+// The specification for incremental backup chains.
+// An incremental backup stores the delta of changes between a previous
+// backup and the database contents at a given version time. An
+// incremental backup chain consists of a full backup and zero or more
+// successive incremental backups. The first backup created for an
+// incremental backup chain is always a full backup.
+type IncrementalBackupSpec struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *IncrementalBackupSpec) Reset() {
+ *x = IncrementalBackupSpec{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *IncrementalBackupSpec) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IncrementalBackupSpec) ProtoMessage() {}
+
+func (x *IncrementalBackupSpec) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_proto_msgTypes[16]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use IncrementalBackupSpec.ProtoReflect.Descriptor instead.
+func (*IncrementalBackupSpec) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP(), []int{16}
+}
+
+var File_google_spanner_admin_database_v1_backup_proto protoreflect.FileDescriptor
+
+var file_google_spanner_admin_database_v1_backup_proto_rawDesc = []byte{
+ 0x0a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f,
+ 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+ 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69,
+ 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x23, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6c, 0x6f, 0x6e, 0x67, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e,
+ 0x67, 0x2f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xad, 0x0b, 0x0a, 0x06, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12,
+ 0x40, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x42, 0x24, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d,
+ 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
+ 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65,
+ 0x12, 0x3b, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+ 0x70, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+ 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54,
+ 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65,
+ 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x09, 0x73, 0x69,
+ 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x33, 0x0a, 0x13, 0x66, 0x72, 0x65, 0x65, 0x61,
+ 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0f,
+ 0x20, 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x11, 0x66, 0x72, 0x65, 0x65, 0x61,
+ 0x62, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x14,
+ 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62,
+ 0x79, 0x74, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52,
+ 0x12, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x76, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x79,
+ 0x74, 0x65, 0x73, 0x12, 0x49, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x53, 0x74, 0x61,
+ 0x74, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x5c,
+ 0x0a, 0x15, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x42, 0x27, 0xe0,
+ 0x41, 0x03, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x14, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63,
+ 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0x5e, 0x0a, 0x0f,
+ 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18,
+ 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73,
+ 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0e, 0x65, 0x6e,
+ 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x6c, 0x0a, 0x16,
+ 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x72,
+ 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x03,
+ 0xe0, 0x41, 0x03, 0x52, 0x15, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49,
+ 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x61, 0x0a, 0x10, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x18, 0x0a,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0f, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x56, 0x0a,
+ 0x13, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x03, 0xfa,
+ 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x52, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x42, 0x61,
+ 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x47, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x78, 0x70,
+ 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52,
+ 0x0d, 0x6d, 0x61, 0x78, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x58,
+ 0x0a, 0x10, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
+ 0x65, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x42, 0x2d, 0xe0, 0x41, 0x03, 0xfa, 0x41, 0x27,
+ 0x0a, 0x25, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x6e, 0x63, 0x72,
+ 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x63,
+ 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0,
+ 0x41, 0x03, 0x52, 0x18, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x42,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x4f, 0x0a, 0x13,
+ 0x6f, 0x6c, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74,
+ 0x69, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x11, 0x6f, 0x6c, 0x64, 0x65,
+ 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x37, 0x0a,
+ 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f,
+ 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a,
+ 0x08, 0x43, 0x52, 0x45, 0x41, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52,
+ 0x45, 0x41, 0x44, 0x59, 0x10, 0x02, 0x3a, 0x5c, 0xea, 0x41, 0x59, 0x0a, 0x1d, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x38, 0x70, 0x72, 0x6f, 0x6a,
+ 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x69,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
+ 0x63, 0x65, 0x7d, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x62, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x7d, 0x22, 0xb1, 0x02, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x06,
+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe0, 0x41,
+ 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x49, 0x6e, 0x73,
+ 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a,
+ 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x64, 0x12,
+ 0x45, 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06,
+ 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x70, 0x0a, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+ 0x67, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69,
+ 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x9e, 0x02, 0x0a, 0x14, 0x43, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x12, 0x36, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x22, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x24, 0xfa, 0x41, 0x21,
+ 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x08, 0x70,
+ 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61,
+ 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65,
+ 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3b, 0x0a, 0x0b,
+ 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63,
+ 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xf4, 0x02, 0x0a, 0x11, 0x43, 0x6f,
+ 0x70, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
+ 0x12, 0x20, 0x0a, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x49, 0x64, 0x12, 0x4a, 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x62, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x02, 0xfa, 0x41,
+ 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x40,
+ 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42,
+ 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65,
+ 0x12, 0x6e, 0x0a, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d,
+ 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43,
+ 0x6f, 0x70, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10,
+ 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x22, 0xa3, 0x02, 0x0a, 0x12, 0x43, 0x6f, 0x70, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x36, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x22, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+ 0x47, 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x22, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x4f, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67,
+ 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69,
+ 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70,
+ 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52,
+ 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x61, 0x6e,
+ 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x63,
+ 0x65, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45,
+ 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x62,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f,
+ 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65,
+ 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, 0x75, 0x70, 0x64,
+ 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x4d, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x42, 0x61,
+ 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x02, 0xfa, 0x41,
+ 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x50, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
+ 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x02,
+ 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xa9, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73,
+ 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
+ 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65,
+ 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67,
+ 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f,
+ 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54,
+ 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x81, 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x07,
+ 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61,
+ 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73,
+ 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f,
+ 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50,
+ 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xb2, 0x01, 0x0a, 0x1b, 0x4c, 0x69, 0x73,
+ 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65,
+ 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21,
+ 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
+ 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c,
+ 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65,
+ 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d,
+ 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x85, 0x01,
+ 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4f, 0x70, 0x65, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d,
+ 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x6e, 0x67,
+ 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a,
+ 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65,
+ 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x93, 0x02, 0x0a, 0x0a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3a, 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x42, 0x22, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+ 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12,
+ 0x3b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+ 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x0f,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x24, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x0e, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, 0xc8, 0x03, 0x0a, 0x1c,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x6e, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x7b, 0x0a, 0x0f,
+ 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x4d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73,
+ 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+ 0x54, 0x79, 0x70, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x6b, 0x6d, 0x73,
+ 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x29, 0xe0, 0x41, 0x01, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d,
+ 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x0a, 0x6b, 0x6d, 0x73, 0x4b,
+ 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x0d, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65,
+ 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0x29, 0xe0,
+ 0x41, 0x01, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43,
+ 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x0b, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79,
+ 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x0e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x4e, 0x43, 0x52,
+ 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50,
+ 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x53, 0x45,
+ 0x5f, 0x44, 0x41, 0x54, 0x41, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,
+ 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45,
+ 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54,
+ 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x45,
+ 0x52, 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x44, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,
+ 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x22, 0xd4, 0x03, 0x0a, 0x1a, 0x43, 0x6f, 0x70, 0x79, 0x42,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x79, 0x0a, 0x0f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x4b,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x6e, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x45, 0x6e, 0x63,
+ 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02,
+ 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65,
+ 0x12, 0x4b, 0x0a, 0x0c, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x29, 0xe0, 0x41, 0x01, 0xfa, 0x41, 0x23, 0x0a, 0x21,
+ 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
+ 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65,
+ 0x79, 0x52, 0x0a, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4d, 0x0a,
+ 0x0d, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03,
+ 0x20, 0x03, 0x28, 0x09, 0x42, 0x29, 0xe0, 0x41, 0x01, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69,
+ 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52,
+ 0x0b, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x9e, 0x01, 0x0a,
+ 0x0e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12,
+ 0x1f, 0x0a, 0x1b, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59,
+ 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
+ 0x12, 0x2b, 0x0a, 0x27, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x44,
+ 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f, 0x4f, 0x52, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50,
+ 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1d, 0x0a,
+ 0x19, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f,
+ 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b,
+ 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x45, 0x52, 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x44,
+ 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x22, 0x10, 0x0a,
+ 0x0e, 0x46, 0x75, 0x6c, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x70, 0x65, 0x63, 0x22,
+ 0x17, 0x0a, 0x15, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x42, 0x61,
+ 0x63, 0x6b, 0x75, 0x70, 0x53, 0x70, 0x65, 0x63, 0x42, 0xfd, 0x01, 0x0a, 0x24, 0x63, 0x6f, 0x6d,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x42, 0x0b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
+ 0x5a, 0x46, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x61, 0x70, 0x69,
+ 0x76, 0x31, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x70, 0x62, 0x3b, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x70, 0x62, 0xaa, 0x02, 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x56,
+ 0x31, 0xca, 0x02, 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64,
+ 0x5c, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x5c, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5c, 0x56, 0x31, 0xea, 0x02, 0x2b, 0x47, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x53, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x3a, 0x3a, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x3a, 0x3a, 0x44, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_spanner_admin_database_v1_backup_proto_rawDescOnce sync.Once
+ file_google_spanner_admin_database_v1_backup_proto_rawDescData = file_google_spanner_admin_database_v1_backup_proto_rawDesc
+)
+
+func file_google_spanner_admin_database_v1_backup_proto_rawDescGZIP() []byte {
+ file_google_spanner_admin_database_v1_backup_proto_rawDescOnce.Do(func() {
+ file_google_spanner_admin_database_v1_backup_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_spanner_admin_database_v1_backup_proto_rawDescData)
+ })
+ return file_google_spanner_admin_database_v1_backup_proto_rawDescData
+}
+
+var file_google_spanner_admin_database_v1_backup_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_google_spanner_admin_database_v1_backup_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
+var file_google_spanner_admin_database_v1_backup_proto_goTypes = []any{
+ (Backup_State)(0), // 0: google.spanner.admin.database.v1.Backup.State
+ (CreateBackupEncryptionConfig_EncryptionType)(0), // 1: google.spanner.admin.database.v1.CreateBackupEncryptionConfig.EncryptionType
+ (CopyBackupEncryptionConfig_EncryptionType)(0), // 2: google.spanner.admin.database.v1.CopyBackupEncryptionConfig.EncryptionType
+ (*Backup)(nil), // 3: google.spanner.admin.database.v1.Backup
+ (*CreateBackupRequest)(nil), // 4: google.spanner.admin.database.v1.CreateBackupRequest
+ (*CreateBackupMetadata)(nil), // 5: google.spanner.admin.database.v1.CreateBackupMetadata
+ (*CopyBackupRequest)(nil), // 6: google.spanner.admin.database.v1.CopyBackupRequest
+ (*CopyBackupMetadata)(nil), // 7: google.spanner.admin.database.v1.CopyBackupMetadata
+ (*UpdateBackupRequest)(nil), // 8: google.spanner.admin.database.v1.UpdateBackupRequest
+ (*GetBackupRequest)(nil), // 9: google.spanner.admin.database.v1.GetBackupRequest
+ (*DeleteBackupRequest)(nil), // 10: google.spanner.admin.database.v1.DeleteBackupRequest
+ (*ListBackupsRequest)(nil), // 11: google.spanner.admin.database.v1.ListBackupsRequest
+ (*ListBackupsResponse)(nil), // 12: google.spanner.admin.database.v1.ListBackupsResponse
+ (*ListBackupOperationsRequest)(nil), // 13: google.spanner.admin.database.v1.ListBackupOperationsRequest
+ (*ListBackupOperationsResponse)(nil), // 14: google.spanner.admin.database.v1.ListBackupOperationsResponse
+ (*BackupInfo)(nil), // 15: google.spanner.admin.database.v1.BackupInfo
+ (*CreateBackupEncryptionConfig)(nil), // 16: google.spanner.admin.database.v1.CreateBackupEncryptionConfig
+ (*CopyBackupEncryptionConfig)(nil), // 17: google.spanner.admin.database.v1.CopyBackupEncryptionConfig
+ (*FullBackupSpec)(nil), // 18: google.spanner.admin.database.v1.FullBackupSpec
+ (*IncrementalBackupSpec)(nil), // 19: google.spanner.admin.database.v1.IncrementalBackupSpec
+ (*timestamppb.Timestamp)(nil), // 20: google.protobuf.Timestamp
+ (*EncryptionInfo)(nil), // 21: google.spanner.admin.database.v1.EncryptionInfo
+ (DatabaseDialect)(0), // 22: google.spanner.admin.database.v1.DatabaseDialect
+ (*OperationProgress)(nil), // 23: google.spanner.admin.database.v1.OperationProgress
+ (*fieldmaskpb.FieldMask)(nil), // 24: google.protobuf.FieldMask
+ (*longrunningpb.Operation)(nil), // 25: google.longrunning.Operation
+}
+var file_google_spanner_admin_database_v1_backup_proto_depIdxs = []int32{
+ 20, // 0: google.spanner.admin.database.v1.Backup.version_time:type_name -> google.protobuf.Timestamp
+ 20, // 1: google.spanner.admin.database.v1.Backup.expire_time:type_name -> google.protobuf.Timestamp
+ 20, // 2: google.spanner.admin.database.v1.Backup.create_time:type_name -> google.protobuf.Timestamp
+ 0, // 3: google.spanner.admin.database.v1.Backup.state:type_name -> google.spanner.admin.database.v1.Backup.State
+ 21, // 4: google.spanner.admin.database.v1.Backup.encryption_info:type_name -> google.spanner.admin.database.v1.EncryptionInfo
+ 21, // 5: google.spanner.admin.database.v1.Backup.encryption_information:type_name -> google.spanner.admin.database.v1.EncryptionInfo
+ 22, // 6: google.spanner.admin.database.v1.Backup.database_dialect:type_name -> google.spanner.admin.database.v1.DatabaseDialect
+ 20, // 7: google.spanner.admin.database.v1.Backup.max_expire_time:type_name -> google.protobuf.Timestamp
+ 20, // 8: google.spanner.admin.database.v1.Backup.oldest_version_time:type_name -> google.protobuf.Timestamp
+ 3, // 9: google.spanner.admin.database.v1.CreateBackupRequest.backup:type_name -> google.spanner.admin.database.v1.Backup
+ 16, // 10: google.spanner.admin.database.v1.CreateBackupRequest.encryption_config:type_name -> google.spanner.admin.database.v1.CreateBackupEncryptionConfig
+ 23, // 11: google.spanner.admin.database.v1.CreateBackupMetadata.progress:type_name -> google.spanner.admin.database.v1.OperationProgress
+ 20, // 12: google.spanner.admin.database.v1.CreateBackupMetadata.cancel_time:type_name -> google.protobuf.Timestamp
+ 20, // 13: google.spanner.admin.database.v1.CopyBackupRequest.expire_time:type_name -> google.protobuf.Timestamp
+ 17, // 14: google.spanner.admin.database.v1.CopyBackupRequest.encryption_config:type_name -> google.spanner.admin.database.v1.CopyBackupEncryptionConfig
+ 23, // 15: google.spanner.admin.database.v1.CopyBackupMetadata.progress:type_name -> google.spanner.admin.database.v1.OperationProgress
+ 20, // 16: google.spanner.admin.database.v1.CopyBackupMetadata.cancel_time:type_name -> google.protobuf.Timestamp
+ 3, // 17: google.spanner.admin.database.v1.UpdateBackupRequest.backup:type_name -> google.spanner.admin.database.v1.Backup
+ 24, // 18: google.spanner.admin.database.v1.UpdateBackupRequest.update_mask:type_name -> google.protobuf.FieldMask
+ 3, // 19: google.spanner.admin.database.v1.ListBackupsResponse.backups:type_name -> google.spanner.admin.database.v1.Backup
+ 25, // 20: google.spanner.admin.database.v1.ListBackupOperationsResponse.operations:type_name -> google.longrunning.Operation
+ 20, // 21: google.spanner.admin.database.v1.BackupInfo.version_time:type_name -> google.protobuf.Timestamp
+ 20, // 22: google.spanner.admin.database.v1.BackupInfo.create_time:type_name -> google.protobuf.Timestamp
+ 1, // 23: google.spanner.admin.database.v1.CreateBackupEncryptionConfig.encryption_type:type_name -> google.spanner.admin.database.v1.CreateBackupEncryptionConfig.EncryptionType
+ 2, // 24: google.spanner.admin.database.v1.CopyBackupEncryptionConfig.encryption_type:type_name -> google.spanner.admin.database.v1.CopyBackupEncryptionConfig.EncryptionType
+ 25, // [25:25] is the sub-list for method output_type
+ 25, // [25:25] is the sub-list for method input_type
+ 25, // [25:25] is the sub-list for extension type_name
+ 25, // [25:25] is the sub-list for extension extendee
+ 0, // [0:25] is the sub-list for field type_name
+}
+
+func init() { file_google_spanner_admin_database_v1_backup_proto_init() }
+func file_google_spanner_admin_database_v1_backup_proto_init() {
+ if File_google_spanner_admin_database_v1_backup_proto != nil {
+ return
+ }
+ file_google_spanner_admin_database_v1_common_proto_init()
+ if !protoimpl.UnsafeEnabled {
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[0].Exporter = func(v any, i int) any {
+ switch v := v.(*Backup); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[1].Exporter = func(v any, i int) any {
+ switch v := v.(*CreateBackupRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[2].Exporter = func(v any, i int) any {
+ switch v := v.(*CreateBackupMetadata); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[3].Exporter = func(v any, i int) any {
+ switch v := v.(*CopyBackupRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[4].Exporter = func(v any, i int) any {
+ switch v := v.(*CopyBackupMetadata); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[5].Exporter = func(v any, i int) any {
+ switch v := v.(*UpdateBackupRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[6].Exporter = func(v any, i int) any {
+ switch v := v.(*GetBackupRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[7].Exporter = func(v any, i int) any {
+ switch v := v.(*DeleteBackupRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[8].Exporter = func(v any, i int) any {
+ switch v := v.(*ListBackupsRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[9].Exporter = func(v any, i int) any {
+ switch v := v.(*ListBackupsResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[10].Exporter = func(v any, i int) any {
+ switch v := v.(*ListBackupOperationsRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[11].Exporter = func(v any, i int) any {
+ switch v := v.(*ListBackupOperationsResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[12].Exporter = func(v any, i int) any {
+ switch v := v.(*BackupInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[13].Exporter = func(v any, i int) any {
+ switch v := v.(*CreateBackupEncryptionConfig); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[14].Exporter = func(v any, i int) any {
+ switch v := v.(*CopyBackupEncryptionConfig); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[15].Exporter = func(v any, i int) any {
+ switch v := v.(*FullBackupSpec); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_proto_msgTypes[16].Exporter = func(v any, i int) any {
+ switch v := v.(*IncrementalBackupSpec); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_spanner_admin_database_v1_backup_proto_rawDesc,
+ NumEnums: 3,
+ NumMessages: 17,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_google_spanner_admin_database_v1_backup_proto_goTypes,
+ DependencyIndexes: file_google_spanner_admin_database_v1_backup_proto_depIdxs,
+ EnumInfos: file_google_spanner_admin_database_v1_backup_proto_enumTypes,
+ MessageInfos: file_google_spanner_admin_database_v1_backup_proto_msgTypes,
+ }.Build()
+ File_google_spanner_admin_database_v1_backup_proto = out.File
+ file_google_spanner_admin_database_v1_backup_proto_rawDesc = nil
+ file_google_spanner_admin_database_v1_backup_proto_goTypes = nil
+ file_google_spanner_admin_database_v1_backup_proto_depIdxs = nil
+}
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/backup_schedule.pb.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/backup_schedule.pb.go
new file mode 100644
index 000000000000..fd7ca6b0dc38
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/backup_schedule.pb.go
@@ -0,0 +1,1080 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.34.2
+// protoc v4.25.3
+// source: google/spanner/admin/database/v1/backup_schedule.proto
+
+package databasepb
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+ fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Defines specifications of the backup schedule.
+type BackupScheduleSpec struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required.
+ //
+ // Types that are assignable to ScheduleSpec:
+ //
+ // *BackupScheduleSpec_CronSpec
+ ScheduleSpec isBackupScheduleSpec_ScheduleSpec `protobuf_oneof:"schedule_spec"`
+}
+
+func (x *BackupScheduleSpec) Reset() {
+ *x = BackupScheduleSpec{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BackupScheduleSpec) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupScheduleSpec) ProtoMessage() {}
+
+func (x *BackupScheduleSpec) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupScheduleSpec.ProtoReflect.Descriptor instead.
+func (*BackupScheduleSpec) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{0}
+}
+
+func (m *BackupScheduleSpec) GetScheduleSpec() isBackupScheduleSpec_ScheduleSpec {
+ if m != nil {
+ return m.ScheduleSpec
+ }
+ return nil
+}
+
+func (x *BackupScheduleSpec) GetCronSpec() *CrontabSpec {
+ if x, ok := x.GetScheduleSpec().(*BackupScheduleSpec_CronSpec); ok {
+ return x.CronSpec
+ }
+ return nil
+}
+
+type isBackupScheduleSpec_ScheduleSpec interface {
+ isBackupScheduleSpec_ScheduleSpec()
+}
+
+type BackupScheduleSpec_CronSpec struct {
+ // Cron style schedule specification.
+ CronSpec *CrontabSpec `protobuf:"bytes,1,opt,name=cron_spec,json=cronSpec,proto3,oneof"`
+}
+
+func (*BackupScheduleSpec_CronSpec) isBackupScheduleSpec_ScheduleSpec() {}
+
+// BackupSchedule expresses the automated backup creation specification for a
+// Spanner database.
+// Next ID: 10
+type BackupSchedule struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Identifier. Output only for the
+ // [CreateBackupSchedule][DatabaseAdmin.CreateBackupSchededule] operation.
+ // Required for the
+ // [UpdateBackupSchedule][google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackupSchedule]
+ // operation. A globally unique identifier for the backup schedule which
+ // cannot be changed. Values are of the form
+ // `projects//instances//databases//backupSchedules/[a-z][a-z0-9_\-]*[a-z0-9]`
+ // The final segment of the name must be between 2 and 60 characters in
+ // length.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Optional. The schedule specification based on which the backup creations
+ // are triggered.
+ Spec *BackupScheduleSpec `protobuf:"bytes,6,opt,name=spec,proto3" json:"spec,omitempty"`
+ // Optional. The retention duration of a backup that must be at least 6 hours
+ // and at most 366 days. The backup is eligible to be automatically deleted
+ // once the retention period has elapsed.
+ RetentionDuration *durationpb.Duration `protobuf:"bytes,3,opt,name=retention_duration,json=retentionDuration,proto3" json:"retention_duration,omitempty"`
+ // Optional. The encryption configuration that will be used to encrypt the
+ // backup. If this field is not specified, the backup will use the same
+ // encryption configuration as the database.
+ EncryptionConfig *CreateBackupEncryptionConfig `protobuf:"bytes,4,opt,name=encryption_config,json=encryptionConfig,proto3" json:"encryption_config,omitempty"`
+ // Required. Backup type spec determines the type of backup that is created by
+ // the backup schedule. Currently, only full backups are supported.
+ //
+ // Types that are assignable to BackupTypeSpec:
+ //
+ // *BackupSchedule_FullBackupSpec
+ // *BackupSchedule_IncrementalBackupSpec
+ BackupTypeSpec isBackupSchedule_BackupTypeSpec `protobuf_oneof:"backup_type_spec"`
+ // Output only. The timestamp at which the schedule was last updated.
+ // If the schedule has never been updated, this field contains the timestamp
+ // when the schedule was first created.
+ UpdateTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"`
+}
+
+func (x *BackupSchedule) Reset() {
+ *x = BackupSchedule{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *BackupSchedule) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*BackupSchedule) ProtoMessage() {}
+
+func (x *BackupSchedule) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use BackupSchedule.ProtoReflect.Descriptor instead.
+func (*BackupSchedule) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *BackupSchedule) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *BackupSchedule) GetSpec() *BackupScheduleSpec {
+ if x != nil {
+ return x.Spec
+ }
+ return nil
+}
+
+func (x *BackupSchedule) GetRetentionDuration() *durationpb.Duration {
+ if x != nil {
+ return x.RetentionDuration
+ }
+ return nil
+}
+
+func (x *BackupSchedule) GetEncryptionConfig() *CreateBackupEncryptionConfig {
+ if x != nil {
+ return x.EncryptionConfig
+ }
+ return nil
+}
+
+func (m *BackupSchedule) GetBackupTypeSpec() isBackupSchedule_BackupTypeSpec {
+ if m != nil {
+ return m.BackupTypeSpec
+ }
+ return nil
+}
+
+func (x *BackupSchedule) GetFullBackupSpec() *FullBackupSpec {
+ if x, ok := x.GetBackupTypeSpec().(*BackupSchedule_FullBackupSpec); ok {
+ return x.FullBackupSpec
+ }
+ return nil
+}
+
+func (x *BackupSchedule) GetIncrementalBackupSpec() *IncrementalBackupSpec {
+ if x, ok := x.GetBackupTypeSpec().(*BackupSchedule_IncrementalBackupSpec); ok {
+ return x.IncrementalBackupSpec
+ }
+ return nil
+}
+
+func (x *BackupSchedule) GetUpdateTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.UpdateTime
+ }
+ return nil
+}
+
+type isBackupSchedule_BackupTypeSpec interface {
+ isBackupSchedule_BackupTypeSpec()
+}
+
+type BackupSchedule_FullBackupSpec struct {
+ // The schedule creates only full backups.
+ FullBackupSpec *FullBackupSpec `protobuf:"bytes,7,opt,name=full_backup_spec,json=fullBackupSpec,proto3,oneof"`
+}
+
+type BackupSchedule_IncrementalBackupSpec struct {
+ // The schedule creates incremental backup chains.
+ IncrementalBackupSpec *IncrementalBackupSpec `protobuf:"bytes,8,opt,name=incremental_backup_spec,json=incrementalBackupSpec,proto3,oneof"`
+}
+
+func (*BackupSchedule_FullBackupSpec) isBackupSchedule_BackupTypeSpec() {}
+
+func (*BackupSchedule_IncrementalBackupSpec) isBackupSchedule_BackupTypeSpec() {}
+
+// CrontabSpec can be used to specify the version time and frequency at
+// which the backup should be created.
+type CrontabSpec struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. Textual representation of the crontab. User can customize the
+ // backup frequency and the backup version time using the cron
+ // expression. The version time must be in UTC timzeone.
+ //
+ // The backup will contain an externally consistent copy of the
+ // database at the version time. Allowed frequencies are 12 hour, 1 day,
+ // 1 week and 1 month. Examples of valid cron specifications:
+ // - `0 2/12 * * * ` : every 12 hours at (2, 14) hours past midnight in UTC.
+ // - `0 2,14 * * * ` : every 12 hours at (2,14) hours past midnight in UTC.
+ // - `0 2 * * * ` : once a day at 2 past midnight in UTC.
+ // - `0 2 * * 0 ` : once a week every Sunday at 2 past midnight in UTC.
+ // - `0 2 8 * * ` : once a month on 8th day at 2 past midnight in UTC.
+ Text string `protobuf:"bytes,1,opt,name=text,proto3" json:"text,omitempty"`
+ // Output only. The time zone of the times in `CrontabSpec.text`. Currently
+ // only UTC is supported.
+ TimeZone string `protobuf:"bytes,2,opt,name=time_zone,json=timeZone,proto3" json:"time_zone,omitempty"`
+ // Output only. Schedule backups will contain an externally consistent copy
+ // of the database at the version time specified in
+ // `schedule_spec.cron_spec`. However, Spanner may not initiate the creation
+ // of the scheduled backups at that version time. Spanner will initiate
+ // the creation of scheduled backups within the time window bounded by the
+ // version_time specified in `schedule_spec.cron_spec` and version_time +
+ // `creation_window`.
+ CreationWindow *durationpb.Duration `protobuf:"bytes,3,opt,name=creation_window,json=creationWindow,proto3" json:"creation_window,omitempty"`
+}
+
+func (x *CrontabSpec) Reset() {
+ *x = CrontabSpec{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CrontabSpec) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CrontabSpec) ProtoMessage() {}
+
+func (x *CrontabSpec) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CrontabSpec.ProtoReflect.Descriptor instead.
+func (*CrontabSpec) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *CrontabSpec) GetText() string {
+ if x != nil {
+ return x.Text
+ }
+ return ""
+}
+
+func (x *CrontabSpec) GetTimeZone() string {
+ if x != nil {
+ return x.TimeZone
+ }
+ return ""
+}
+
+func (x *CrontabSpec) GetCreationWindow() *durationpb.Duration {
+ if x != nil {
+ return x.CreationWindow
+ }
+ return nil
+}
+
+// The request for
+// [CreateBackupSchedule][google.spanner.admin.database.v1.DatabaseAdmin.CreateBackupSchedule].
+type CreateBackupScheduleRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the database that this backup schedule applies to.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Required. The Id to use for the backup schedule. The `backup_schedule_id`
+ // appended to `parent` forms the full backup schedule name of the form
+ // `projects//instances//databases//backupSchedules/`.
+ BackupScheduleId string `protobuf:"bytes,2,opt,name=backup_schedule_id,json=backupScheduleId,proto3" json:"backup_schedule_id,omitempty"`
+ // Required. The backup schedule to create.
+ BackupSchedule *BackupSchedule `protobuf:"bytes,3,opt,name=backup_schedule,json=backupSchedule,proto3" json:"backup_schedule,omitempty"`
+}
+
+func (x *CreateBackupScheduleRequest) Reset() {
+ *x = CreateBackupScheduleRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateBackupScheduleRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateBackupScheduleRequest) ProtoMessage() {}
+
+func (x *CreateBackupScheduleRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateBackupScheduleRequest.ProtoReflect.Descriptor instead.
+func (*CreateBackupScheduleRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *CreateBackupScheduleRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *CreateBackupScheduleRequest) GetBackupScheduleId() string {
+ if x != nil {
+ return x.BackupScheduleId
+ }
+ return ""
+}
+
+func (x *CreateBackupScheduleRequest) GetBackupSchedule() *BackupSchedule {
+ if x != nil {
+ return x.BackupSchedule
+ }
+ return nil
+}
+
+// The request for
+// [GetBackupSchedule][google.spanner.admin.database.v1.DatabaseAdmin.GetBackupSchedule].
+type GetBackupScheduleRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the schedule to retrieve.
+ // Values are of the form
+ // `projects//instances//databases//backupSchedules/`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *GetBackupScheduleRequest) Reset() {
+ *x = GetBackupScheduleRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetBackupScheduleRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetBackupScheduleRequest) ProtoMessage() {}
+
+func (x *GetBackupScheduleRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetBackupScheduleRequest.ProtoReflect.Descriptor instead.
+func (*GetBackupScheduleRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *GetBackupScheduleRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// The request for
+// [DeleteBackupSchedule][google.spanner.admin.database.v1.DatabaseAdmin.DeleteBackupSchedule].
+type DeleteBackupScheduleRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the schedule to delete.
+ // Values are of the form
+ // `projects//instances//databases//backupSchedules/`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *DeleteBackupScheduleRequest) Reset() {
+ *x = DeleteBackupScheduleRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DeleteBackupScheduleRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteBackupScheduleRequest) ProtoMessage() {}
+
+func (x *DeleteBackupScheduleRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteBackupScheduleRequest.ProtoReflect.Descriptor instead.
+func (*DeleteBackupScheduleRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *DeleteBackupScheduleRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// The request for
+// [ListBackupSchedules][google.spanner.admin.database.v1.DatabaseAdmin.ListBackupSchedules].
+type ListBackupSchedulesRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. Database is the parent resource whose backup schedules should be
+ // listed. Values are of the form
+ // projects//instances//databases/
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Optional. Number of backup schedules to be returned in the response. If 0
+ // or less, defaults to the server's maximum allowed page size.
+ PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ // Optional. If non-empty, `page_token` should contain a
+ // [next_page_token][google.spanner.admin.database.v1.ListBackupSchedulesResponse.next_page_token]
+ // from a previous
+ // [ListBackupSchedulesResponse][google.spanner.admin.database.v1.ListBackupSchedulesResponse]
+ // to the same `parent`.
+ PageToken string `protobuf:"bytes,4,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+}
+
+func (x *ListBackupSchedulesRequest) Reset() {
+ *x = ListBackupSchedulesRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListBackupSchedulesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListBackupSchedulesRequest) ProtoMessage() {}
+
+func (x *ListBackupSchedulesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListBackupSchedulesRequest.ProtoReflect.Descriptor instead.
+func (*ListBackupSchedulesRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ListBackupSchedulesRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *ListBackupSchedulesRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *ListBackupSchedulesRequest) GetPageToken() string {
+ if x != nil {
+ return x.PageToken
+ }
+ return ""
+}
+
+// The response for
+// [ListBackupSchedules][google.spanner.admin.database.v1.DatabaseAdmin.ListBackupSchedules].
+type ListBackupSchedulesResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of backup schedules for a database.
+ BackupSchedules []*BackupSchedule `protobuf:"bytes,1,rep,name=backup_schedules,json=backupSchedules,proto3" json:"backup_schedules,omitempty"`
+ // `next_page_token` can be sent in a subsequent
+ // [ListBackupSchedules][google.spanner.admin.database.v1.DatabaseAdmin.ListBackupSchedules]
+ // call to fetch more of the schedules.
+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+}
+
+func (x *ListBackupSchedulesResponse) Reset() {
+ *x = ListBackupSchedulesResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListBackupSchedulesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListBackupSchedulesResponse) ProtoMessage() {}
+
+func (x *ListBackupSchedulesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListBackupSchedulesResponse.ProtoReflect.Descriptor instead.
+func (*ListBackupSchedulesResponse) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *ListBackupSchedulesResponse) GetBackupSchedules() []*BackupSchedule {
+ if x != nil {
+ return x.BackupSchedules
+ }
+ return nil
+}
+
+func (x *ListBackupSchedulesResponse) GetNextPageToken() string {
+ if x != nil {
+ return x.NextPageToken
+ }
+ return ""
+}
+
+// The request for
+// [UpdateBackupScheduleRequest][google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackupSchedule].
+type UpdateBackupScheduleRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The backup schedule to update. `backup_schedule.name`, and the
+ // fields to be updated as specified by `update_mask` are required. Other
+ // fields are ignored.
+ BackupSchedule *BackupSchedule `protobuf:"bytes,1,opt,name=backup_schedule,json=backupSchedule,proto3" json:"backup_schedule,omitempty"`
+ // Required. A mask specifying which fields in the BackupSchedule resource
+ // should be updated. This mask is relative to the BackupSchedule resource,
+ // not to the request message. The field mask must always be
+ // specified; this prevents any future fields from being erased
+ // accidentally.
+ UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
+}
+
+func (x *UpdateBackupScheduleRequest) Reset() {
+ *x = UpdateBackupScheduleRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateBackupScheduleRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateBackupScheduleRequest) ProtoMessage() {}
+
+func (x *UpdateBackupScheduleRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateBackupScheduleRequest.ProtoReflect.Descriptor instead.
+func (*UpdateBackupScheduleRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *UpdateBackupScheduleRequest) GetBackupSchedule() *BackupSchedule {
+ if x != nil {
+ return x.BackupSchedule
+ }
+ return nil
+}
+
+func (x *UpdateBackupScheduleRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
+ if x != nil {
+ return x.UpdateMask
+ }
+ return nil
+}
+
+var File_google_spanner_admin_database_v1_backup_schedule_proto protoreflect.FileDescriptor
+
+var file_google_spanner_admin_database_v1_backup_schedule_proto_rawDesc = []byte{
+ 0x0a, 0x36, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f,
+ 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68,
+ 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61,
+ 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
+ 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x12, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x4c,
+ 0x0a, 0x09, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x6e, 0x74, 0x61, 0x62, 0x53, 0x70, 0x65, 0x63,
+ 0x48, 0x00, 0x52, 0x08, 0x63, 0x72, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x42, 0x0f, 0x0a, 0x0d,
+ 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x22, 0x88, 0x06,
+ 0x0a, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
+ 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03,
+ 0xe0, 0x41, 0x08, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x04, 0x73, 0x70, 0x65,
+ 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x53, 0x70, 0x65, 0x63, 0x42, 0x03, 0xe0,
+ 0x41, 0x01, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x4d, 0x0a, 0x12, 0x72, 0x65, 0x74, 0x65,
+ 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42,
+ 0x03, 0xe0, 0x41, 0x01, 0x52, 0x11, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x44,
+ 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x70, 0x0a, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5c, 0x0a, 0x10, 0x66, 0x75, 0x6c,
+ 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x07, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x53, 0x70, 0x65, 0x63, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x75, 0x6c, 0x6c, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x53, 0x70, 0x65, 0x63, 0x12, 0x71, 0x0a, 0x17, 0x69, 0x6e, 0x63, 0x72, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x70,
+ 0x65, 0x63, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x63, 0x72,
+ 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x70, 0x65,
+ 0x63, 0x48, 0x00, 0x52, 0x15, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c,
+ 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x70, 0x65, 0x63, 0x12, 0x40, 0x0a, 0x0b, 0x75, 0x70,
+ 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03,
+ 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x3a, 0xa5, 0x01, 0xea,
+ 0x41, 0xa1, 0x01, 0x0a, 0x25, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x57, 0x70, 0x72, 0x6f, 0x6a,
+ 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x69,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
+ 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x7b, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x7d, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75,
+ 0x6c, 0x65, 0x7d, 0x2a, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64,
+ 0x75, 0x6c, 0x65, 0x73, 0x32, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65,
+ 0x64, 0x75, 0x6c, 0x65, 0x42, 0x12, 0x0a, 0x10, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x74,
+ 0x79, 0x70, 0x65, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x22, 0x91, 0x01, 0x0a, 0x0b, 0x43, 0x72, 0x6f,
+ 0x6e, 0x74, 0x61, 0x62, 0x53, 0x70, 0x65, 0x63, 0x12, 0x17, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04, 0x74, 0x65, 0x78,
+ 0x74, 0x12, 0x20, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a,
+ 0x6f, 0x6e, 0x65, 0x12, 0x47, 0x0a, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
+ 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
+ 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0e, 0x63, 0x72,
+ 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x22, 0xf1, 0x01, 0x0a,
+ 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x06,
+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe0, 0x41,
+ 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x0a,
+ 0x12, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
+ 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x10,
+ 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x49, 0x64,
+ 0x12, 0x5e, 0x0a, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64,
+ 0x75, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
+ 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02,
+ 0x52, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
+ 0x22, 0x5d, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2d, 0xe0, 0x41, 0x02, 0xfa,
+ 0x41, 0x27, 0x0a, 0x25, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22,
+ 0x60, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2d, 0xe0, 0x41,
+ 0x02, 0xfa, 0x41, 0x27, 0x0a, 0x25, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x22, 0xa3, 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x42, 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65,
+ 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e,
+ 0x74, 0x12, 0x20, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x05, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53,
+ 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65,
+ 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x09, 0x70, 0x61,
+ 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xa2, 0x01, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74,
+ 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x10, 0x62, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64,
+ 0x75, 0x6c, 0x65, 0x52, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64,
+ 0x75, 0x6c, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67,
+ 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e,
+ 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xbf, 0x01, 0x0a,
+ 0x1b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5e, 0x0a, 0x0f,
+ 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73,
+ 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0e, 0x62, 0x61,
+ 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x0b,
+ 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x42, 0x03, 0xe0,
+ 0x41, 0x02, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x42, 0x85,
+ 0x02, 0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x13, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x46,
+ 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x67, 0x6f, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d, 0x69,
+ 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x31,
+ 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x70, 0x62, 0x3b, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x70, 0x62, 0xaa, 0x02, 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x56, 0x31, 0xca,
+ 0x02, 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x53,
+ 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x5c, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x5c, 0x56, 0x31, 0xea, 0x02, 0x2b, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65,
+ 0x72, 0x3a, 0x3a, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x3a, 0x3a, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescOnce sync.Once
+ file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescData = file_google_spanner_admin_database_v1_backup_schedule_proto_rawDesc
+)
+
+func file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescGZIP() []byte {
+ file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescOnce.Do(func() {
+ file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescData)
+ })
+ return file_google_spanner_admin_database_v1_backup_schedule_proto_rawDescData
+}
+
+var file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
+var file_google_spanner_admin_database_v1_backup_schedule_proto_goTypes = []any{
+ (*BackupScheduleSpec)(nil), // 0: google.spanner.admin.database.v1.BackupScheduleSpec
+ (*BackupSchedule)(nil), // 1: google.spanner.admin.database.v1.BackupSchedule
+ (*CrontabSpec)(nil), // 2: google.spanner.admin.database.v1.CrontabSpec
+ (*CreateBackupScheduleRequest)(nil), // 3: google.spanner.admin.database.v1.CreateBackupScheduleRequest
+ (*GetBackupScheduleRequest)(nil), // 4: google.spanner.admin.database.v1.GetBackupScheduleRequest
+ (*DeleteBackupScheduleRequest)(nil), // 5: google.spanner.admin.database.v1.DeleteBackupScheduleRequest
+ (*ListBackupSchedulesRequest)(nil), // 6: google.spanner.admin.database.v1.ListBackupSchedulesRequest
+ (*ListBackupSchedulesResponse)(nil), // 7: google.spanner.admin.database.v1.ListBackupSchedulesResponse
+ (*UpdateBackupScheduleRequest)(nil), // 8: google.spanner.admin.database.v1.UpdateBackupScheduleRequest
+ (*durationpb.Duration)(nil), // 9: google.protobuf.Duration
+ (*CreateBackupEncryptionConfig)(nil), // 10: google.spanner.admin.database.v1.CreateBackupEncryptionConfig
+ (*FullBackupSpec)(nil), // 11: google.spanner.admin.database.v1.FullBackupSpec
+ (*IncrementalBackupSpec)(nil), // 12: google.spanner.admin.database.v1.IncrementalBackupSpec
+ (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp
+ (*fieldmaskpb.FieldMask)(nil), // 14: google.protobuf.FieldMask
+}
+var file_google_spanner_admin_database_v1_backup_schedule_proto_depIdxs = []int32{
+ 2, // 0: google.spanner.admin.database.v1.BackupScheduleSpec.cron_spec:type_name -> google.spanner.admin.database.v1.CrontabSpec
+ 0, // 1: google.spanner.admin.database.v1.BackupSchedule.spec:type_name -> google.spanner.admin.database.v1.BackupScheduleSpec
+ 9, // 2: google.spanner.admin.database.v1.BackupSchedule.retention_duration:type_name -> google.protobuf.Duration
+ 10, // 3: google.spanner.admin.database.v1.BackupSchedule.encryption_config:type_name -> google.spanner.admin.database.v1.CreateBackupEncryptionConfig
+ 11, // 4: google.spanner.admin.database.v1.BackupSchedule.full_backup_spec:type_name -> google.spanner.admin.database.v1.FullBackupSpec
+ 12, // 5: google.spanner.admin.database.v1.BackupSchedule.incremental_backup_spec:type_name -> google.spanner.admin.database.v1.IncrementalBackupSpec
+ 13, // 6: google.spanner.admin.database.v1.BackupSchedule.update_time:type_name -> google.protobuf.Timestamp
+ 9, // 7: google.spanner.admin.database.v1.CrontabSpec.creation_window:type_name -> google.protobuf.Duration
+ 1, // 8: google.spanner.admin.database.v1.CreateBackupScheduleRequest.backup_schedule:type_name -> google.spanner.admin.database.v1.BackupSchedule
+ 1, // 9: google.spanner.admin.database.v1.ListBackupSchedulesResponse.backup_schedules:type_name -> google.spanner.admin.database.v1.BackupSchedule
+ 1, // 10: google.spanner.admin.database.v1.UpdateBackupScheduleRequest.backup_schedule:type_name -> google.spanner.admin.database.v1.BackupSchedule
+ 14, // 11: google.spanner.admin.database.v1.UpdateBackupScheduleRequest.update_mask:type_name -> google.protobuf.FieldMask
+ 12, // [12:12] is the sub-list for method output_type
+ 12, // [12:12] is the sub-list for method input_type
+ 12, // [12:12] is the sub-list for extension type_name
+ 12, // [12:12] is the sub-list for extension extendee
+ 0, // [0:12] is the sub-list for field type_name
+}
+
+func init() { file_google_spanner_admin_database_v1_backup_schedule_proto_init() }
+func file_google_spanner_admin_database_v1_backup_schedule_proto_init() {
+ if File_google_spanner_admin_database_v1_backup_schedule_proto != nil {
+ return
+ }
+ file_google_spanner_admin_database_v1_backup_proto_init()
+ if !protoimpl.UnsafeEnabled {
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[0].Exporter = func(v any, i int) any {
+ switch v := v.(*BackupScheduleSpec); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[1].Exporter = func(v any, i int) any {
+ switch v := v.(*BackupSchedule); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[2].Exporter = func(v any, i int) any {
+ switch v := v.(*CrontabSpec); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[3].Exporter = func(v any, i int) any {
+ switch v := v.(*CreateBackupScheduleRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[4].Exporter = func(v any, i int) any {
+ switch v := v.(*GetBackupScheduleRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[5].Exporter = func(v any, i int) any {
+ switch v := v.(*DeleteBackupScheduleRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[6].Exporter = func(v any, i int) any {
+ switch v := v.(*ListBackupSchedulesRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[7].Exporter = func(v any, i int) any {
+ switch v := v.(*ListBackupSchedulesResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[8].Exporter = func(v any, i int) any {
+ switch v := v.(*UpdateBackupScheduleRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[0].OneofWrappers = []any{
+ (*BackupScheduleSpec_CronSpec)(nil),
+ }
+ file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes[1].OneofWrappers = []any{
+ (*BackupSchedule_FullBackupSpec)(nil),
+ (*BackupSchedule_IncrementalBackupSpec)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_spanner_admin_database_v1_backup_schedule_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 9,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_google_spanner_admin_database_v1_backup_schedule_proto_goTypes,
+ DependencyIndexes: file_google_spanner_admin_database_v1_backup_schedule_proto_depIdxs,
+ MessageInfos: file_google_spanner_admin_database_v1_backup_schedule_proto_msgTypes,
+ }.Build()
+ File_google_spanner_admin_database_v1_backup_schedule_proto = out.File
+ file_google_spanner_admin_database_v1_backup_schedule_proto_rawDesc = nil
+ file_google_spanner_admin_database_v1_backup_schedule_proto_goTypes = nil
+ file_google_spanner_admin_database_v1_backup_schedule_proto_depIdxs = nil
+}
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/common.pb.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/common.pb.go
new file mode 100644
index 000000000000..ba93d9a2640e
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/common.pb.go
@@ -0,0 +1,567 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.34.2
+// protoc v4.25.3
+// source: google/spanner/admin/database/v1/common.proto
+
+package databasepb
+
+import (
+ reflect "reflect"
+ sync "sync"
+
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ status "google.golang.org/genproto/googleapis/rpc/status"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Indicates the dialect type of a database.
+type DatabaseDialect int32
+
+const (
+ // Default value. This value will create a database with the
+ // GOOGLE_STANDARD_SQL dialect.
+ DatabaseDialect_DATABASE_DIALECT_UNSPECIFIED DatabaseDialect = 0
+ // GoogleSQL supported SQL.
+ DatabaseDialect_GOOGLE_STANDARD_SQL DatabaseDialect = 1
+ // PostgreSQL supported SQL.
+ DatabaseDialect_POSTGRESQL DatabaseDialect = 2
+)
+
+// Enum value maps for DatabaseDialect.
+var (
+ DatabaseDialect_name = map[int32]string{
+ 0: "DATABASE_DIALECT_UNSPECIFIED",
+ 1: "GOOGLE_STANDARD_SQL",
+ 2: "POSTGRESQL",
+ }
+ DatabaseDialect_value = map[string]int32{
+ "DATABASE_DIALECT_UNSPECIFIED": 0,
+ "GOOGLE_STANDARD_SQL": 1,
+ "POSTGRESQL": 2,
+ }
+)
+
+func (x DatabaseDialect) Enum() *DatabaseDialect {
+ p := new(DatabaseDialect)
+ *p = x
+ return p
+}
+
+func (x DatabaseDialect) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (DatabaseDialect) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_common_proto_enumTypes[0].Descriptor()
+}
+
+func (DatabaseDialect) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_common_proto_enumTypes[0]
+}
+
+func (x DatabaseDialect) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use DatabaseDialect.Descriptor instead.
+func (DatabaseDialect) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_common_proto_rawDescGZIP(), []int{0}
+}
+
+// Possible encryption types.
+type EncryptionInfo_Type int32
+
+const (
+ // Encryption type was not specified, though data at rest remains encrypted.
+ EncryptionInfo_TYPE_UNSPECIFIED EncryptionInfo_Type = 0
+ // The data is encrypted at rest with a key that is
+ // fully managed by Google. No key version or status will be populated.
+ // This is the default state.
+ EncryptionInfo_GOOGLE_DEFAULT_ENCRYPTION EncryptionInfo_Type = 1
+ // The data is encrypted at rest with a key that is
+ // managed by the customer. The active version of the key. `kms_key_version`
+ // will be populated, and `encryption_status` may be populated.
+ EncryptionInfo_CUSTOMER_MANAGED_ENCRYPTION EncryptionInfo_Type = 2
+)
+
+// Enum value maps for EncryptionInfo_Type.
+var (
+ EncryptionInfo_Type_name = map[int32]string{
+ 0: "TYPE_UNSPECIFIED",
+ 1: "GOOGLE_DEFAULT_ENCRYPTION",
+ 2: "CUSTOMER_MANAGED_ENCRYPTION",
+ }
+ EncryptionInfo_Type_value = map[string]int32{
+ "TYPE_UNSPECIFIED": 0,
+ "GOOGLE_DEFAULT_ENCRYPTION": 1,
+ "CUSTOMER_MANAGED_ENCRYPTION": 2,
+ }
+)
+
+func (x EncryptionInfo_Type) Enum() *EncryptionInfo_Type {
+ p := new(EncryptionInfo_Type)
+ *p = x
+ return p
+}
+
+func (x EncryptionInfo_Type) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (EncryptionInfo_Type) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_common_proto_enumTypes[1].Descriptor()
+}
+
+func (EncryptionInfo_Type) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_common_proto_enumTypes[1]
+}
+
+func (x EncryptionInfo_Type) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use EncryptionInfo_Type.Descriptor instead.
+func (EncryptionInfo_Type) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_common_proto_rawDescGZIP(), []int{2, 0}
+}
+
+// Encapsulates progress related information for a Cloud Spanner long
+// running operation.
+type OperationProgress struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Percent completion of the operation.
+ // Values are between 0 and 100 inclusive.
+ ProgressPercent int32 `protobuf:"varint,1,opt,name=progress_percent,json=progressPercent,proto3" json:"progress_percent,omitempty"`
+ // Time the request was received.
+ StartTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
+ // If set, the time at which this operation failed or was completed
+ // successfully.
+ EndTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"`
+}
+
+func (x *OperationProgress) Reset() {
+ *x = OperationProgress{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_common_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *OperationProgress) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OperationProgress) ProtoMessage() {}
+
+func (x *OperationProgress) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_common_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use OperationProgress.ProtoReflect.Descriptor instead.
+func (*OperationProgress) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_common_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *OperationProgress) GetProgressPercent() int32 {
+ if x != nil {
+ return x.ProgressPercent
+ }
+ return 0
+}
+
+func (x *OperationProgress) GetStartTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.StartTime
+ }
+ return nil
+}
+
+func (x *OperationProgress) GetEndTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.EndTime
+ }
+ return nil
+}
+
+// Encryption configuration for a Cloud Spanner database.
+type EncryptionConfig struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The Cloud KMS key to be used for encrypting and decrypting
+ // the database. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ KmsKeyName string `protobuf:"bytes,2,opt,name=kms_key_name,json=kmsKeyName,proto3" json:"kms_key_name,omitempty"`
+ // Specifies the KMS configuration for the one or more keys used to encrypt
+ // the database. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ //
+ // The keys referenced by kms_key_names must fully cover all
+ // regions of the database instance configuration. Some examples:
+ // * For single region database instance configs, specify a single regional
+ // location KMS key.
+ // * For multi-regional database instance configs of type GOOGLE_MANAGED,
+ // either specify a multi-regional location KMS key or multiple regional
+ // location KMS keys that cover all regions in the instance config.
+ // * For a database instance config of type USER_MANAGED, please specify only
+ // regional location KMS keys to cover each region in the instance config.
+ // Multi-regional location KMS keys are not supported for USER_MANAGED
+ // instance configs.
+ KmsKeyNames []string `protobuf:"bytes,3,rep,name=kms_key_names,json=kmsKeyNames,proto3" json:"kms_key_names,omitempty"`
+}
+
+func (x *EncryptionConfig) Reset() {
+ *x = EncryptionConfig{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_common_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *EncryptionConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EncryptionConfig) ProtoMessage() {}
+
+func (x *EncryptionConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_common_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EncryptionConfig.ProtoReflect.Descriptor instead.
+func (*EncryptionConfig) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_common_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *EncryptionConfig) GetKmsKeyName() string {
+ if x != nil {
+ return x.KmsKeyName
+ }
+ return ""
+}
+
+func (x *EncryptionConfig) GetKmsKeyNames() []string {
+ if x != nil {
+ return x.KmsKeyNames
+ }
+ return nil
+}
+
+// Encryption information for a Cloud Spanner database or backup.
+type EncryptionInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Output only. The type of encryption.
+ EncryptionType EncryptionInfo_Type `protobuf:"varint,3,opt,name=encryption_type,json=encryptionType,proto3,enum=google.spanner.admin.database.v1.EncryptionInfo_Type" json:"encryption_type,omitempty"`
+ // Output only. If present, the status of a recent encrypt/decrypt call on
+ // underlying data for this database or backup. Regardless of status, data is
+ // always encrypted at rest.
+ EncryptionStatus *status.Status `protobuf:"bytes,4,opt,name=encryption_status,json=encryptionStatus,proto3" json:"encryption_status,omitempty"`
+ // Output only. A Cloud KMS key version that is being used to protect the
+ // database or backup.
+ KmsKeyVersion string `protobuf:"bytes,2,opt,name=kms_key_version,json=kmsKeyVersion,proto3" json:"kms_key_version,omitempty"`
+}
+
+func (x *EncryptionInfo) Reset() {
+ *x = EncryptionInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_common_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *EncryptionInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*EncryptionInfo) ProtoMessage() {}
+
+func (x *EncryptionInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_common_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use EncryptionInfo.ProtoReflect.Descriptor instead.
+func (*EncryptionInfo) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_common_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *EncryptionInfo) GetEncryptionType() EncryptionInfo_Type {
+ if x != nil {
+ return x.EncryptionType
+ }
+ return EncryptionInfo_TYPE_UNSPECIFIED
+}
+
+func (x *EncryptionInfo) GetEncryptionStatus() *status.Status {
+ if x != nil {
+ return x.EncryptionStatus
+ }
+ return nil
+}
+
+func (x *EncryptionInfo) GetKmsKeyVersion() string {
+ if x != nil {
+ return x.KmsKeyVersion
+ }
+ return ""
+}
+
+var File_google_spanner_admin_database_v1_common_proto protoreflect.FileDescriptor
+
+var file_google_spanner_admin_database_v1_common_proto_rawDesc = []byte{
+ 0x0a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f,
+ 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+ 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69,
+ 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74,
+ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb0, 0x01, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a,
+ 0x10, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
+ 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
+ 0x73, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72,
+ 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
+ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54,
+ 0x69, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+ 0x70, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xa8, 0x01, 0x0a, 0x10, 0x45,
+ 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
+ 0x48, 0x0a, 0x0c, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75,
+ 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x0a, 0x6b,
+ 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4a, 0x0a, 0x0d, 0x6b, 0x6d, 0x73,
+ 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09,
+ 0x42, 0x26, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43,
+ 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x0b, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79,
+ 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xf3, 0x02, 0x0a, 0x0e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x63, 0x0a, 0x0f, 0x65, 0x6e, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49,
+ 0x6e, 0x66, 0x6f, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0e, 0x65,
+ 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x44, 0x0a,
+ 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x03, 0xe0, 0x41,
+ 0x03, 0x52, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x12, 0x58, 0x0a, 0x0f, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x76,
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0xe0, 0x41,
+ 0x03, 0xfa, 0x41, 0x2a, 0x0a, 0x28, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72,
+ 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0d,
+ 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5c, 0x0a,
+ 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e,
+ 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x47,
+ 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f, 0x45, 0x4e,
+ 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x55,
+ 0x53, 0x54, 0x4f, 0x4d, 0x45, 0x52, 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x44, 0x5f, 0x45,
+ 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x2a, 0x5c, 0x0a, 0x0f, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x20,
+ 0x0a, 0x1c, 0x44, 0x41, 0x54, 0x41, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x44, 0x49, 0x41, 0x4c, 0x45,
+ 0x43, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
+ 0x12, 0x17, 0x0a, 0x13, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x4e, 0x44,
+ 0x41, 0x52, 0x44, 0x5f, 0x53, 0x51, 0x4c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x4f, 0x53,
+ 0x54, 0x47, 0x52, 0x45, 0x53, 0x51, 0x4c, 0x10, 0x02, 0x42, 0xa2, 0x04, 0xea, 0x41, 0x78, 0x0a,
+ 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b,
+ 0x65, 0x79, 0x12, 0x53, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72,
+ 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x2f, 0x7b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x6b, 0x65, 0x79, 0x52,
+ 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x7b, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x69, 0x6e, 0x67, 0x7d, 0x2f,
+ 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x73, 0x2f, 0x7b, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x6f, 0x5f, 0x6b, 0x65, 0x79, 0x7d, 0xea, 0x41, 0xa6, 0x01, 0x0a, 0x28, 0x63, 0x6c, 0x6f,
+ 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x7a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
+ 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x6b,
+ 0x65, 0x79, 0x52, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x7b, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x69, 0x6e,
+ 0x67, 0x7d, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x73, 0x2f, 0x7b, 0x63,
+ 0x72, 0x79, 0x70, 0x74, 0x6f, 0x5f, 0x6b, 0x65, 0x79, 0x7d, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x6f, 0x4b, 0x65, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x6f, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x7d, 0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50,
+ 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x46, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x31, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x70, 0x62, 0x3b, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x70, 0x62, 0xaa, 0x02,
+ 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x53, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5c, 0x41,
+ 0x64, 0x6d, 0x69, 0x6e, 0x5c, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5c, 0x56, 0x31,
+ 0xea, 0x02, 0x2b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64,
+ 0x3a, 0x3a, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x3a, 0x3a, 0x41, 0x64, 0x6d, 0x69, 0x6e,
+ 0x3a, 0x3a, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_spanner_admin_database_v1_common_proto_rawDescOnce sync.Once
+ file_google_spanner_admin_database_v1_common_proto_rawDescData = file_google_spanner_admin_database_v1_common_proto_rawDesc
+)
+
+func file_google_spanner_admin_database_v1_common_proto_rawDescGZIP() []byte {
+ file_google_spanner_admin_database_v1_common_proto_rawDescOnce.Do(func() {
+ file_google_spanner_admin_database_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_spanner_admin_database_v1_common_proto_rawDescData)
+ })
+ return file_google_spanner_admin_database_v1_common_proto_rawDescData
+}
+
+var file_google_spanner_admin_database_v1_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_google_spanner_admin_database_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_google_spanner_admin_database_v1_common_proto_goTypes = []any{
+ (DatabaseDialect)(0), // 0: google.spanner.admin.database.v1.DatabaseDialect
+ (EncryptionInfo_Type)(0), // 1: google.spanner.admin.database.v1.EncryptionInfo.Type
+ (*OperationProgress)(nil), // 2: google.spanner.admin.database.v1.OperationProgress
+ (*EncryptionConfig)(nil), // 3: google.spanner.admin.database.v1.EncryptionConfig
+ (*EncryptionInfo)(nil), // 4: google.spanner.admin.database.v1.EncryptionInfo
+ (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp
+ (*status.Status)(nil), // 6: google.rpc.Status
+}
+var file_google_spanner_admin_database_v1_common_proto_depIdxs = []int32{
+ 5, // 0: google.spanner.admin.database.v1.OperationProgress.start_time:type_name -> google.protobuf.Timestamp
+ 5, // 1: google.spanner.admin.database.v1.OperationProgress.end_time:type_name -> google.protobuf.Timestamp
+ 1, // 2: google.spanner.admin.database.v1.EncryptionInfo.encryption_type:type_name -> google.spanner.admin.database.v1.EncryptionInfo.Type
+ 6, // 3: google.spanner.admin.database.v1.EncryptionInfo.encryption_status:type_name -> google.rpc.Status
+ 4, // [4:4] is the sub-list for method output_type
+ 4, // [4:4] is the sub-list for method input_type
+ 4, // [4:4] is the sub-list for extension type_name
+ 4, // [4:4] is the sub-list for extension extendee
+ 0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_google_spanner_admin_database_v1_common_proto_init() }
+func file_google_spanner_admin_database_v1_common_proto_init() {
+ if File_google_spanner_admin_database_v1_common_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_google_spanner_admin_database_v1_common_proto_msgTypes[0].Exporter = func(v any, i int) any {
+ switch v := v.(*OperationProgress); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_common_proto_msgTypes[1].Exporter = func(v any, i int) any {
+ switch v := v.(*EncryptionConfig); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_common_proto_msgTypes[2].Exporter = func(v any, i int) any {
+ switch v := v.(*EncryptionInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_spanner_admin_database_v1_common_proto_rawDesc,
+ NumEnums: 2,
+ NumMessages: 3,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_google_spanner_admin_database_v1_common_proto_goTypes,
+ DependencyIndexes: file_google_spanner_admin_database_v1_common_proto_depIdxs,
+ EnumInfos: file_google_spanner_admin_database_v1_common_proto_enumTypes,
+ MessageInfos: file_google_spanner_admin_database_v1_common_proto_msgTypes,
+ }.Build()
+ File_google_spanner_admin_database_v1_common_proto = out.File
+ file_google_spanner_admin_database_v1_common_proto_rawDesc = nil
+ file_google_spanner_admin_database_v1_common_proto_goTypes = nil
+ file_google_spanner_admin_database_v1_common_proto_depIdxs = nil
+}
diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/spanner_database_admin.pb.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/spanner_database_admin.pb.go
new file mode 100644
index 000000000000..2be6d9793862
--- /dev/null
+++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/databasepb/spanner_database_admin.pb.go
@@ -0,0 +1,4807 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.34.2
+// protoc v4.25.3
+// source: google/spanner/admin/database/v1/spanner_database_admin.proto
+
+package databasepb
+
+import (
+ context "context"
+ reflect "reflect"
+ sync "sync"
+
+ iampb "cloud.google.com/go/iam/apiv1/iampb"
+ longrunningpb "cloud.google.com/go/longrunning/autogen/longrunningpb"
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+ fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Indicates the type of the restore source.
+type RestoreSourceType int32
+
+const (
+ // No restore associated.
+ RestoreSourceType_TYPE_UNSPECIFIED RestoreSourceType = 0
+ // A backup was used as the source of the restore.
+ RestoreSourceType_BACKUP RestoreSourceType = 1
+)
+
+// Enum value maps for RestoreSourceType.
+var (
+ RestoreSourceType_name = map[int32]string{
+ 0: "TYPE_UNSPECIFIED",
+ 1: "BACKUP",
+ }
+ RestoreSourceType_value = map[string]int32{
+ "TYPE_UNSPECIFIED": 0,
+ "BACKUP": 1,
+ }
+)
+
+func (x RestoreSourceType) Enum() *RestoreSourceType {
+ p := new(RestoreSourceType)
+ *p = x
+ return p
+}
+
+func (x RestoreSourceType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (RestoreSourceType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes[0].Descriptor()
+}
+
+func (RestoreSourceType) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes[0]
+}
+
+func (x RestoreSourceType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use RestoreSourceType.Descriptor instead.
+func (RestoreSourceType) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{0}
+}
+
+// Indicates the current state of the database.
+type Database_State int32
+
+const (
+ // Not specified.
+ Database_STATE_UNSPECIFIED Database_State = 0
+ // The database is still being created. Operations on the database may fail
+ // with `FAILED_PRECONDITION` in this state.
+ Database_CREATING Database_State = 1
+ // The database is fully created and ready for use.
+ Database_READY Database_State = 2
+ // The database is fully created and ready for use, but is still
+ // being optimized for performance and cannot handle full load.
+ //
+ // In this state, the database still references the backup
+ // it was restore from, preventing the backup
+ // from being deleted. When optimizations are complete, the full performance
+ // of the database will be restored, and the database will transition to
+ // `READY` state.
+ Database_READY_OPTIMIZING Database_State = 3
+)
+
+// Enum value maps for Database_State.
+var (
+ Database_State_name = map[int32]string{
+ 0: "STATE_UNSPECIFIED",
+ 1: "CREATING",
+ 2: "READY",
+ 3: "READY_OPTIMIZING",
+ }
+ Database_State_value = map[string]int32{
+ "STATE_UNSPECIFIED": 0,
+ "CREATING": 1,
+ "READY": 2,
+ "READY_OPTIMIZING": 3,
+ }
+)
+
+func (x Database_State) Enum() *Database_State {
+ p := new(Database_State)
+ *p = x
+ return p
+}
+
+func (x Database_State) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Database_State) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes[1].Descriptor()
+}
+
+func (Database_State) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes[1]
+}
+
+func (x Database_State) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Database_State.Descriptor instead.
+func (Database_State) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{1, 0}
+}
+
+// Encryption types for the database to be restored.
+type RestoreDatabaseEncryptionConfig_EncryptionType int32
+
+const (
+ // Unspecified. Do not use.
+ RestoreDatabaseEncryptionConfig_ENCRYPTION_TYPE_UNSPECIFIED RestoreDatabaseEncryptionConfig_EncryptionType = 0
+ // This is the default option when
+ // [encryption_config][google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig]
+ // is not specified.
+ RestoreDatabaseEncryptionConfig_USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION RestoreDatabaseEncryptionConfig_EncryptionType = 1
+ // Use Google default encryption.
+ RestoreDatabaseEncryptionConfig_GOOGLE_DEFAULT_ENCRYPTION RestoreDatabaseEncryptionConfig_EncryptionType = 2
+ // Use customer managed encryption. If specified, `kms_key_name` must
+ // must contain a valid Cloud KMS key.
+ RestoreDatabaseEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION RestoreDatabaseEncryptionConfig_EncryptionType = 3
+)
+
+// Enum value maps for RestoreDatabaseEncryptionConfig_EncryptionType.
+var (
+ RestoreDatabaseEncryptionConfig_EncryptionType_name = map[int32]string{
+ 0: "ENCRYPTION_TYPE_UNSPECIFIED",
+ 1: "USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION",
+ 2: "GOOGLE_DEFAULT_ENCRYPTION",
+ 3: "CUSTOMER_MANAGED_ENCRYPTION",
+ }
+ RestoreDatabaseEncryptionConfig_EncryptionType_value = map[string]int32{
+ "ENCRYPTION_TYPE_UNSPECIFIED": 0,
+ "USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION": 1,
+ "GOOGLE_DEFAULT_ENCRYPTION": 2,
+ "CUSTOMER_MANAGED_ENCRYPTION": 3,
+ }
+)
+
+func (x RestoreDatabaseEncryptionConfig_EncryptionType) Enum() *RestoreDatabaseEncryptionConfig_EncryptionType {
+ p := new(RestoreDatabaseEncryptionConfig_EncryptionType)
+ *p = x
+ return p
+}
+
+func (x RestoreDatabaseEncryptionConfig_EncryptionType) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (RestoreDatabaseEncryptionConfig_EncryptionType) Descriptor() protoreflect.EnumDescriptor {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes[2].Descriptor()
+}
+
+func (RestoreDatabaseEncryptionConfig_EncryptionType) Type() protoreflect.EnumType {
+ return &file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes[2]
+}
+
+func (x RestoreDatabaseEncryptionConfig_EncryptionType) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use RestoreDatabaseEncryptionConfig_EncryptionType.Descriptor instead.
+func (RestoreDatabaseEncryptionConfig_EncryptionType) EnumDescriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{18, 0}
+}
+
+// Information about the database restore.
+type RestoreInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The type of the restore source.
+ SourceType RestoreSourceType `protobuf:"varint,1,opt,name=source_type,json=sourceType,proto3,enum=google.spanner.admin.database.v1.RestoreSourceType" json:"source_type,omitempty"`
+ // Information about the source used to restore the database.
+ //
+ // Types that are assignable to SourceInfo:
+ //
+ // *RestoreInfo_BackupInfo
+ SourceInfo isRestoreInfo_SourceInfo `protobuf_oneof:"source_info"`
+}
+
+func (x *RestoreInfo) Reset() {
+ *x = RestoreInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RestoreInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RestoreInfo) ProtoMessage() {}
+
+func (x *RestoreInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RestoreInfo.ProtoReflect.Descriptor instead.
+func (*RestoreInfo) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *RestoreInfo) GetSourceType() RestoreSourceType {
+ if x != nil {
+ return x.SourceType
+ }
+ return RestoreSourceType_TYPE_UNSPECIFIED
+}
+
+func (m *RestoreInfo) GetSourceInfo() isRestoreInfo_SourceInfo {
+ if m != nil {
+ return m.SourceInfo
+ }
+ return nil
+}
+
+func (x *RestoreInfo) GetBackupInfo() *BackupInfo {
+ if x, ok := x.GetSourceInfo().(*RestoreInfo_BackupInfo); ok {
+ return x.BackupInfo
+ }
+ return nil
+}
+
+type isRestoreInfo_SourceInfo interface {
+ isRestoreInfo_SourceInfo()
+}
+
+type RestoreInfo_BackupInfo struct {
+ // Information about the backup used to restore the database. The backup
+ // may no longer exist.
+ BackupInfo *BackupInfo `protobuf:"bytes,2,opt,name=backup_info,json=backupInfo,proto3,oneof"`
+}
+
+func (*RestoreInfo_BackupInfo) isRestoreInfo_SourceInfo() {}
+
+// A Cloud Spanner database.
+type Database struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the database. Values are of the form
+ // `projects//instances//databases/`,
+ // where `` is as specified in the `CREATE DATABASE`
+ // statement. This name can be passed to other API methods to
+ // identify the database.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Output only. The current database state.
+ State Database_State `protobuf:"varint,2,opt,name=state,proto3,enum=google.spanner.admin.database.v1.Database_State" json:"state,omitempty"`
+ // Output only. If exists, the time at which the database creation started.
+ CreateTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"`
+ // Output only. Applicable only for restored databases. Contains information
+ // about the restore source.
+ RestoreInfo *RestoreInfo `protobuf:"bytes,4,opt,name=restore_info,json=restoreInfo,proto3" json:"restore_info,omitempty"`
+ // Output only. For databases that are using customer managed encryption, this
+ // field contains the encryption configuration for the database.
+ // For databases that are using Google default or other types of encryption,
+ // this field is empty.
+ EncryptionConfig *EncryptionConfig `protobuf:"bytes,5,opt,name=encryption_config,json=encryptionConfig,proto3" json:"encryption_config,omitempty"`
+ // Output only. For databases that are using customer managed encryption, this
+ // field contains the encryption information for the database, such as
+ // all Cloud KMS key versions that are in use. The `encryption_status' field
+ // inside of each `EncryptionInfo` is not populated.
+ //
+ // For databases that are using Google default or other types of encryption,
+ // this field is empty.
+ //
+ // This field is propagated lazily from the backend. There might be a delay
+ // from when a key version is being used and when it appears in this field.
+ EncryptionInfo []*EncryptionInfo `protobuf:"bytes,8,rep,name=encryption_info,json=encryptionInfo,proto3" json:"encryption_info,omitempty"`
+ // Output only. The period in which Cloud Spanner retains all versions of data
+ // for the database. This is the same as the value of version_retention_period
+ // database option set using
+ // [UpdateDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl].
+ // Defaults to 1 hour, if not set.
+ VersionRetentionPeriod string `protobuf:"bytes,6,opt,name=version_retention_period,json=versionRetentionPeriod,proto3" json:"version_retention_period,omitempty"`
+ // Output only. Earliest timestamp at which older versions of the data can be
+ // read. This value is continuously updated by Cloud Spanner and becomes stale
+ // the moment it is queried. If you are using this value to recover data, make
+ // sure to account for the time from the moment when the value is queried to
+ // the moment when you initiate the recovery.
+ EarliestVersionTime *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=earliest_version_time,json=earliestVersionTime,proto3" json:"earliest_version_time,omitempty"`
+ // Output only. The read-write region which contains the database's leader
+ // replicas.
+ //
+ // This is the same as the value of default_leader
+ // database option set using DatabaseAdmin.CreateDatabase or
+ // DatabaseAdmin.UpdateDatabaseDdl. If not explicitly set, this is empty.
+ DefaultLeader string `protobuf:"bytes,9,opt,name=default_leader,json=defaultLeader,proto3" json:"default_leader,omitempty"`
+ // Output only. The dialect of the Cloud Spanner Database.
+ DatabaseDialect DatabaseDialect `protobuf:"varint,10,opt,name=database_dialect,json=databaseDialect,proto3,enum=google.spanner.admin.database.v1.DatabaseDialect" json:"database_dialect,omitempty"`
+ // Whether drop protection is enabled for this database. Defaults to false,
+ // if not set. For more details, please see how to [prevent accidental
+ // database
+ // deletion](https://cloud.google.com/spanner/docs/prevent-database-deletion).
+ EnableDropProtection bool `protobuf:"varint,11,opt,name=enable_drop_protection,json=enableDropProtection,proto3" json:"enable_drop_protection,omitempty"`
+ // Output only. If true, the database is being updated. If false, there are no
+ // ongoing update operations for the database.
+ Reconciling bool `protobuf:"varint,12,opt,name=reconciling,proto3" json:"reconciling,omitempty"`
+}
+
+func (x *Database) Reset() {
+ *x = Database{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Database) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Database) ProtoMessage() {}
+
+func (x *Database) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Database.ProtoReflect.Descriptor instead.
+func (*Database) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Database) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *Database) GetState() Database_State {
+ if x != nil {
+ return x.State
+ }
+ return Database_STATE_UNSPECIFIED
+}
+
+func (x *Database) GetCreateTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreateTime
+ }
+ return nil
+}
+
+func (x *Database) GetRestoreInfo() *RestoreInfo {
+ if x != nil {
+ return x.RestoreInfo
+ }
+ return nil
+}
+
+func (x *Database) GetEncryptionConfig() *EncryptionConfig {
+ if x != nil {
+ return x.EncryptionConfig
+ }
+ return nil
+}
+
+func (x *Database) GetEncryptionInfo() []*EncryptionInfo {
+ if x != nil {
+ return x.EncryptionInfo
+ }
+ return nil
+}
+
+func (x *Database) GetVersionRetentionPeriod() string {
+ if x != nil {
+ return x.VersionRetentionPeriod
+ }
+ return ""
+}
+
+func (x *Database) GetEarliestVersionTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.EarliestVersionTime
+ }
+ return nil
+}
+
+func (x *Database) GetDefaultLeader() string {
+ if x != nil {
+ return x.DefaultLeader
+ }
+ return ""
+}
+
+func (x *Database) GetDatabaseDialect() DatabaseDialect {
+ if x != nil {
+ return x.DatabaseDialect
+ }
+ return DatabaseDialect_DATABASE_DIALECT_UNSPECIFIED
+}
+
+func (x *Database) GetEnableDropProtection() bool {
+ if x != nil {
+ return x.EnableDropProtection
+ }
+ return false
+}
+
+func (x *Database) GetReconciling() bool {
+ if x != nil {
+ return x.Reconciling
+ }
+ return false
+}
+
+// The request for
+// [ListDatabases][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases].
+type ListDatabasesRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The instance whose databases should be listed.
+ // Values are of the form `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Number of databases to be returned in the response. If 0 or less,
+ // defaults to the server's maximum allowed page size.
+ PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ // If non-empty, `page_token` should contain a
+ // [next_page_token][google.spanner.admin.database.v1.ListDatabasesResponse.next_page_token]
+ // from a previous
+ // [ListDatabasesResponse][google.spanner.admin.database.v1.ListDatabasesResponse].
+ PageToken string `protobuf:"bytes,4,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+}
+
+func (x *ListDatabasesRequest) Reset() {
+ *x = ListDatabasesRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListDatabasesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListDatabasesRequest) ProtoMessage() {}
+
+func (x *ListDatabasesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListDatabasesRequest.ProtoReflect.Descriptor instead.
+func (*ListDatabasesRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ListDatabasesRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *ListDatabasesRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *ListDatabasesRequest) GetPageToken() string {
+ if x != nil {
+ return x.PageToken
+ }
+ return ""
+}
+
+// The response for
+// [ListDatabases][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases].
+type ListDatabasesResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Databases that matched the request.
+ Databases []*Database `protobuf:"bytes,1,rep,name=databases,proto3" json:"databases,omitempty"`
+ // `next_page_token` can be sent in a subsequent
+ // [ListDatabases][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases]
+ // call to fetch more of the matching databases.
+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+}
+
+func (x *ListDatabasesResponse) Reset() {
+ *x = ListDatabasesResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListDatabasesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListDatabasesResponse) ProtoMessage() {}
+
+func (x *ListDatabasesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListDatabasesResponse.ProtoReflect.Descriptor instead.
+func (*ListDatabasesResponse) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ListDatabasesResponse) GetDatabases() []*Database {
+ if x != nil {
+ return x.Databases
+ }
+ return nil
+}
+
+func (x *ListDatabasesResponse) GetNextPageToken() string {
+ if x != nil {
+ return x.NextPageToken
+ }
+ return ""
+}
+
+// The request for
+// [CreateDatabase][google.spanner.admin.database.v1.DatabaseAdmin.CreateDatabase].
+type CreateDatabaseRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the instance that will serve the new database.
+ // Values are of the form `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Required. A `CREATE DATABASE` statement, which specifies the ID of the
+ // new database. The database ID must conform to the regular expression
+ // `[a-z][a-z0-9_\-]*[a-z0-9]` and be between 2 and 30 characters in length.
+ // If the database ID is a reserved word or if it contains a hyphen, the
+ // database ID must be enclosed in backticks (“ ` “).
+ CreateStatement string `protobuf:"bytes,2,opt,name=create_statement,json=createStatement,proto3" json:"create_statement,omitempty"`
+ // Optional. A list of DDL statements to run inside the newly created
+ // database. Statements can create tables, indexes, etc. These
+ // statements execute atomically with the creation of the database:
+ // if there is an error in any statement, the database is not created.
+ ExtraStatements []string `protobuf:"bytes,3,rep,name=extra_statements,json=extraStatements,proto3" json:"extra_statements,omitempty"`
+ // Optional. The encryption configuration for the database. If this field is
+ // not specified, Cloud Spanner will encrypt/decrypt all data at rest using
+ // Google default encryption.
+ EncryptionConfig *EncryptionConfig `protobuf:"bytes,4,opt,name=encryption_config,json=encryptionConfig,proto3" json:"encryption_config,omitempty"`
+ // Optional. The dialect of the Cloud Spanner Database.
+ DatabaseDialect DatabaseDialect `protobuf:"varint,5,opt,name=database_dialect,json=databaseDialect,proto3,enum=google.spanner.admin.database.v1.DatabaseDialect" json:"database_dialect,omitempty"`
+ // Optional. Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements in
+ // 'extra_statements' above.
+ // Contains a protobuf-serialized
+ // [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+ // To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+ // run `protoc` with --include_imports and --descriptor_set_out. For example,
+ // to generate for moon/shot/app.proto, run
+ // ```
+ //
+ // $protoc --proto_path=/app_path --proto_path=/lib_path \
+ // --include_imports \
+ // --descriptor_set_out=descriptors.data \
+ // moon/shot/app.proto
+ //
+ // ```
+ // For more details, see protobuffer [self
+ // description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+ ProtoDescriptors []byte `protobuf:"bytes,6,opt,name=proto_descriptors,json=protoDescriptors,proto3" json:"proto_descriptors,omitempty"`
+}
+
+func (x *CreateDatabaseRequest) Reset() {
+ *x = CreateDatabaseRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateDatabaseRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateDatabaseRequest) ProtoMessage() {}
+
+func (x *CreateDatabaseRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateDatabaseRequest.ProtoReflect.Descriptor instead.
+func (*CreateDatabaseRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *CreateDatabaseRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *CreateDatabaseRequest) GetCreateStatement() string {
+ if x != nil {
+ return x.CreateStatement
+ }
+ return ""
+}
+
+func (x *CreateDatabaseRequest) GetExtraStatements() []string {
+ if x != nil {
+ return x.ExtraStatements
+ }
+ return nil
+}
+
+func (x *CreateDatabaseRequest) GetEncryptionConfig() *EncryptionConfig {
+ if x != nil {
+ return x.EncryptionConfig
+ }
+ return nil
+}
+
+func (x *CreateDatabaseRequest) GetDatabaseDialect() DatabaseDialect {
+ if x != nil {
+ return x.DatabaseDialect
+ }
+ return DatabaseDialect_DATABASE_DIALECT_UNSPECIFIED
+}
+
+func (x *CreateDatabaseRequest) GetProtoDescriptors() []byte {
+ if x != nil {
+ return x.ProtoDescriptors
+ }
+ return nil
+}
+
+// Metadata type for the operation returned by
+// [CreateDatabase][google.spanner.admin.database.v1.DatabaseAdmin.CreateDatabase].
+type CreateDatabaseMetadata struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The database being created.
+ Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
+}
+
+func (x *CreateDatabaseMetadata) Reset() {
+ *x = CreateDatabaseMetadata{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *CreateDatabaseMetadata) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateDatabaseMetadata) ProtoMessage() {}
+
+func (x *CreateDatabaseMetadata) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use CreateDatabaseMetadata.ProtoReflect.Descriptor instead.
+func (*CreateDatabaseMetadata) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *CreateDatabaseMetadata) GetDatabase() string {
+ if x != nil {
+ return x.Database
+ }
+ return ""
+}
+
+// The request for
+// [GetDatabase][google.spanner.admin.database.v1.DatabaseAdmin.GetDatabase].
+type GetDatabaseRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the requested database. Values are of the form
+ // `projects//instances//databases/`.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *GetDatabaseRequest) Reset() {
+ *x = GetDatabaseRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetDatabaseRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDatabaseRequest) ProtoMessage() {}
+
+func (x *GetDatabaseRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetDatabaseRequest.ProtoReflect.Descriptor instead.
+func (*GetDatabaseRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *GetDatabaseRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// The request for
+// [UpdateDatabase][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase].
+type UpdateDatabaseRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The database to update.
+ // The `name` field of the database is of the form
+ // `projects//instances//databases/`.
+ Database *Database `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
+ // Required. The list of fields to update. Currently, only
+ // `enable_drop_protection` field can be updated.
+ UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
+}
+
+func (x *UpdateDatabaseRequest) Reset() {
+ *x = UpdateDatabaseRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateDatabaseRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateDatabaseRequest) ProtoMessage() {}
+
+func (x *UpdateDatabaseRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateDatabaseRequest.ProtoReflect.Descriptor instead.
+func (*UpdateDatabaseRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *UpdateDatabaseRequest) GetDatabase() *Database {
+ if x != nil {
+ return x.Database
+ }
+ return nil
+}
+
+func (x *UpdateDatabaseRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
+ if x != nil {
+ return x.UpdateMask
+ }
+ return nil
+}
+
+// Metadata type for the operation returned by
+// [UpdateDatabase][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase].
+type UpdateDatabaseMetadata struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The request for
+ // [UpdateDatabase][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase].
+ Request *UpdateDatabaseRequest `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"`
+ // The progress of the
+ // [UpdateDatabase][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase]
+ // operation.
+ Progress *OperationProgress `protobuf:"bytes,2,opt,name=progress,proto3" json:"progress,omitempty"`
+ // The time at which this operation was cancelled. If set, this operation is
+ // in the process of undoing itself (which is best-effort).
+ CancelTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=cancel_time,json=cancelTime,proto3" json:"cancel_time,omitempty"`
+}
+
+func (x *UpdateDatabaseMetadata) Reset() {
+ *x = UpdateDatabaseMetadata{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateDatabaseMetadata) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateDatabaseMetadata) ProtoMessage() {}
+
+func (x *UpdateDatabaseMetadata) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateDatabaseMetadata.ProtoReflect.Descriptor instead.
+func (*UpdateDatabaseMetadata) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *UpdateDatabaseMetadata) GetRequest() *UpdateDatabaseRequest {
+ if x != nil {
+ return x.Request
+ }
+ return nil
+}
+
+func (x *UpdateDatabaseMetadata) GetProgress() *OperationProgress {
+ if x != nil {
+ return x.Progress
+ }
+ return nil
+}
+
+func (x *UpdateDatabaseMetadata) GetCancelTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CancelTime
+ }
+ return nil
+}
+
+// Enqueues the given DDL statements to be applied, in order but not
+// necessarily all at once, to the database schema at some point (or
+// points) in the future. The server checks that the statements
+// are executable (syntactically valid, name tables that exist, etc.)
+// before enqueueing them, but they may still fail upon
+// later execution (e.g., if a statement from another batch of
+// statements is applied first and it conflicts in some way, or if
+// there is some data-related problem like a `NULL` value in a column to
+// which `NOT NULL` would be added). If a statement fails, all
+// subsequent statements in the batch are automatically cancelled.
+//
+// Each batch of statements is assigned a name which can be used with
+// the [Operations][google.longrunning.Operations] API to monitor
+// progress. See the
+// [operation_id][google.spanner.admin.database.v1.UpdateDatabaseDdlRequest.operation_id]
+// field for more details.
+type UpdateDatabaseDdlRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The database to update.
+ Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
+ // Required. DDL statements to be applied to the database.
+ Statements []string `protobuf:"bytes,2,rep,name=statements,proto3" json:"statements,omitempty"`
+ // If empty, the new update request is assigned an
+ // automatically-generated operation ID. Otherwise, `operation_id`
+ // is used to construct the name of the resulting
+ // [Operation][google.longrunning.Operation].
+ //
+ // Specifying an explicit operation ID simplifies determining
+ // whether the statements were executed in the event that the
+ // [UpdateDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl]
+ // call is replayed, or the return value is otherwise lost: the
+ // [database][google.spanner.admin.database.v1.UpdateDatabaseDdlRequest.database]
+ // and `operation_id` fields can be combined to form the
+ // [name][google.longrunning.Operation.name] of the resulting
+ // [longrunning.Operation][google.longrunning.Operation]:
+ // `/operations/`.
+ //
+ // `operation_id` should be unique within the database, and must be
+ // a valid identifier: `[a-z][a-z0-9_]*`. Note that
+ // automatically-generated operation IDs always begin with an
+ // underscore. If the named operation already exists,
+ // [UpdateDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl]
+ // returns `ALREADY_EXISTS`.
+ OperationId string `protobuf:"bytes,3,opt,name=operation_id,json=operationId,proto3" json:"operation_id,omitempty"`
+ // Optional. Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements.
+ // Contains a protobuf-serialized
+ // [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+ // To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+ // run `protoc` with --include_imports and --descriptor_set_out. For example,
+ // to generate for moon/shot/app.proto, run
+ // ```
+ //
+ // $protoc --proto_path=/app_path --proto_path=/lib_path \
+ // --include_imports \
+ // --descriptor_set_out=descriptors.data \
+ // moon/shot/app.proto
+ //
+ // ```
+ // For more details, see protobuffer [self
+ // description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+ ProtoDescriptors []byte `protobuf:"bytes,4,opt,name=proto_descriptors,json=protoDescriptors,proto3" json:"proto_descriptors,omitempty"`
+}
+
+func (x *UpdateDatabaseDdlRequest) Reset() {
+ *x = UpdateDatabaseDdlRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateDatabaseDdlRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateDatabaseDdlRequest) ProtoMessage() {}
+
+func (x *UpdateDatabaseDdlRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateDatabaseDdlRequest.ProtoReflect.Descriptor instead.
+func (*UpdateDatabaseDdlRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *UpdateDatabaseDdlRequest) GetDatabase() string {
+ if x != nil {
+ return x.Database
+ }
+ return ""
+}
+
+func (x *UpdateDatabaseDdlRequest) GetStatements() []string {
+ if x != nil {
+ return x.Statements
+ }
+ return nil
+}
+
+func (x *UpdateDatabaseDdlRequest) GetOperationId() string {
+ if x != nil {
+ return x.OperationId
+ }
+ return ""
+}
+
+func (x *UpdateDatabaseDdlRequest) GetProtoDescriptors() []byte {
+ if x != nil {
+ return x.ProtoDescriptors
+ }
+ return nil
+}
+
+// Action information extracted from a DDL statement. This proto is used to
+// display the brief info of the DDL statement for the operation
+// [UpdateDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl].
+type DdlStatementActionInfo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The action for the DDL statement, e.g. CREATE, ALTER, DROP, GRANT, etc.
+ // This field is a non-empty string.
+ Action string `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"`
+ // The entity type for the DDL statement, e.g. TABLE, INDEX, VIEW, etc.
+ // This field can be empty string for some DDL statement,
+ // e.g. for statement "ANALYZE", `entity_type` = "".
+ EntityType string `protobuf:"bytes,2,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"`
+ // The entity name(s) being operated on the DDL statement.
+ // E.g.
+ // 1. For statement "CREATE TABLE t1(...)", `entity_names` = ["t1"].
+ // 2. For statement "GRANT ROLE r1, r2 ...", `entity_names` = ["r1", "r2"].
+ // 3. For statement "ANALYZE", `entity_names` = [].
+ EntityNames []string `protobuf:"bytes,3,rep,name=entity_names,json=entityNames,proto3" json:"entity_names,omitempty"`
+}
+
+func (x *DdlStatementActionInfo) Reset() {
+ *x = DdlStatementActionInfo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DdlStatementActionInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DdlStatementActionInfo) ProtoMessage() {}
+
+func (x *DdlStatementActionInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DdlStatementActionInfo.ProtoReflect.Descriptor instead.
+func (*DdlStatementActionInfo) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *DdlStatementActionInfo) GetAction() string {
+ if x != nil {
+ return x.Action
+ }
+ return ""
+}
+
+func (x *DdlStatementActionInfo) GetEntityType() string {
+ if x != nil {
+ return x.EntityType
+ }
+ return ""
+}
+
+func (x *DdlStatementActionInfo) GetEntityNames() []string {
+ if x != nil {
+ return x.EntityNames
+ }
+ return nil
+}
+
+// Metadata type for the operation returned by
+// [UpdateDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl].
+type UpdateDatabaseDdlMetadata struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The database being modified.
+ Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
+ // For an update this list contains all the statements. For an
+ // individual statement, this list contains only that statement.
+ Statements []string `protobuf:"bytes,2,rep,name=statements,proto3" json:"statements,omitempty"`
+ // Reports the commit timestamps of all statements that have
+ // succeeded so far, where `commit_timestamps[i]` is the commit
+ // timestamp for the statement `statements[i]`.
+ CommitTimestamps []*timestamppb.Timestamp `protobuf:"bytes,3,rep,name=commit_timestamps,json=commitTimestamps,proto3" json:"commit_timestamps,omitempty"`
+ // Output only. When true, indicates that the operation is throttled e.g.
+ // due to resource constraints. When resources become available the operation
+ // will resume and this field will be false again.
+ Throttled bool `protobuf:"varint,4,opt,name=throttled,proto3" json:"throttled,omitempty"`
+ // The progress of the
+ // [UpdateDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl]
+ // operations. All DDL statements will have continuously updating progress,
+ // and `progress[i]` is the operation progress for `statements[i]`. Also,
+ // `progress[i]` will have start time and end time populated with commit
+ // timestamp of operation, as well as a progress of 100% once the operation
+ // has completed.
+ Progress []*OperationProgress `protobuf:"bytes,5,rep,name=progress,proto3" json:"progress,omitempty"`
+ // The brief action info for the DDL statements.
+ // `actions[i]` is the brief info for `statements[i]`.
+ Actions []*DdlStatementActionInfo `protobuf:"bytes,6,rep,name=actions,proto3" json:"actions,omitempty"`
+}
+
+func (x *UpdateDatabaseDdlMetadata) Reset() {
+ *x = UpdateDatabaseDdlMetadata{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateDatabaseDdlMetadata) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateDatabaseDdlMetadata) ProtoMessage() {}
+
+func (x *UpdateDatabaseDdlMetadata) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[11]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateDatabaseDdlMetadata.ProtoReflect.Descriptor instead.
+func (*UpdateDatabaseDdlMetadata) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *UpdateDatabaseDdlMetadata) GetDatabase() string {
+ if x != nil {
+ return x.Database
+ }
+ return ""
+}
+
+func (x *UpdateDatabaseDdlMetadata) GetStatements() []string {
+ if x != nil {
+ return x.Statements
+ }
+ return nil
+}
+
+func (x *UpdateDatabaseDdlMetadata) GetCommitTimestamps() []*timestamppb.Timestamp {
+ if x != nil {
+ return x.CommitTimestamps
+ }
+ return nil
+}
+
+func (x *UpdateDatabaseDdlMetadata) GetThrottled() bool {
+ if x != nil {
+ return x.Throttled
+ }
+ return false
+}
+
+func (x *UpdateDatabaseDdlMetadata) GetProgress() []*OperationProgress {
+ if x != nil {
+ return x.Progress
+ }
+ return nil
+}
+
+func (x *UpdateDatabaseDdlMetadata) GetActions() []*DdlStatementActionInfo {
+ if x != nil {
+ return x.Actions
+ }
+ return nil
+}
+
+// The request for
+// [DropDatabase][google.spanner.admin.database.v1.DatabaseAdmin.DropDatabase].
+type DropDatabaseRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The database to be dropped.
+ Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
+}
+
+func (x *DropDatabaseRequest) Reset() {
+ *x = DropDatabaseRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DropDatabaseRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DropDatabaseRequest) ProtoMessage() {}
+
+func (x *DropDatabaseRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[12]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DropDatabaseRequest.ProtoReflect.Descriptor instead.
+func (*DropDatabaseRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *DropDatabaseRequest) GetDatabase() string {
+ if x != nil {
+ return x.Database
+ }
+ return ""
+}
+
+// The request for
+// [GetDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDdl].
+type GetDatabaseDdlRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The database whose schema we wish to get.
+ // Values are of the form
+ // `projects//instances//databases/`
+ Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
+}
+
+func (x *GetDatabaseDdlRequest) Reset() {
+ *x = GetDatabaseDdlRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetDatabaseDdlRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDatabaseDdlRequest) ProtoMessage() {}
+
+func (x *GetDatabaseDdlRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[13]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetDatabaseDdlRequest.ProtoReflect.Descriptor instead.
+func (*GetDatabaseDdlRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *GetDatabaseDdlRequest) GetDatabase() string {
+ if x != nil {
+ return x.Database
+ }
+ return ""
+}
+
+// The response for
+// [GetDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDdl].
+type GetDatabaseDdlResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // A list of formatted DDL statements defining the schema of the database
+ // specified in the request.
+ Statements []string `protobuf:"bytes,1,rep,name=statements,proto3" json:"statements,omitempty"`
+ // Proto descriptors stored in the database.
+ // Contains a protobuf-serialized
+ // [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+ // For more details, see protobuffer [self
+ // description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+ ProtoDescriptors []byte `protobuf:"bytes,2,opt,name=proto_descriptors,json=protoDescriptors,proto3" json:"proto_descriptors,omitempty"`
+}
+
+func (x *GetDatabaseDdlResponse) Reset() {
+ *x = GetDatabaseDdlResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetDatabaseDdlResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetDatabaseDdlResponse) ProtoMessage() {}
+
+func (x *GetDatabaseDdlResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[14]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetDatabaseDdlResponse.ProtoReflect.Descriptor instead.
+func (*GetDatabaseDdlResponse) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *GetDatabaseDdlResponse) GetStatements() []string {
+ if x != nil {
+ return x.Statements
+ }
+ return nil
+}
+
+func (x *GetDatabaseDdlResponse) GetProtoDescriptors() []byte {
+ if x != nil {
+ return x.ProtoDescriptors
+ }
+ return nil
+}
+
+// The request for
+// [ListDatabaseOperations][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseOperations].
+type ListDatabaseOperationsRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The instance of the database operations.
+ // Values are of the form `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // An expression that filters the list of returned operations.
+ //
+ // A filter expression consists of a field name, a
+ // comparison operator, and a value for filtering.
+ // The value must be a string, a number, or a boolean. The comparison operator
+ // must be one of: `<`, `>`, `<=`, `>=`, `!=`, `=`, or `:`.
+ // Colon `:` is the contains operator. Filter rules are not case sensitive.
+ //
+ // The following fields in the [Operation][google.longrunning.Operation]
+ // are eligible for filtering:
+ //
+ // - `name` - The name of the long-running operation
+ // - `done` - False if the operation is in progress, else true.
+ // - `metadata.@type` - the type of metadata. For example, the type string
+ // for
+ // [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]
+ // is
+ // `type.googleapis.com/google.spanner.admin.database.v1.RestoreDatabaseMetadata`.
+ // - `metadata.` - any field in metadata.value.
+ // `metadata.@type` must be specified first, if filtering on metadata
+ // fields.
+ // - `error` - Error associated with the long-running operation.
+ // - `response.@type` - the type of response.
+ // - `response.` - any field in response.value.
+ //
+ // You can combine multiple expressions by enclosing each expression in
+ // parentheses. By default, expressions are combined with AND logic. However,
+ // you can specify AND, OR, and NOT logic explicitly.
+ //
+ // Here are a few examples:
+ //
+ // - `done:true` - The operation is complete.
+ // - `(metadata.@type=type.googleapis.com/google.spanner.admin.database.v1.RestoreDatabaseMetadata) AND` \
+ // `(metadata.source_type:BACKUP) AND` \
+ // `(metadata.backup_info.backup:backup_howl) AND` \
+ // `(metadata.name:restored_howl) AND` \
+ // `(metadata.progress.start_time < \"2018-03-28T14:50:00Z\") AND` \
+ // `(error:*)` - Return operations where:
+ // - The operation's metadata type is
+ // [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata].
+ // - The database is restored from a backup.
+ // - The backup name contains "backup_howl".
+ // - The restored database's name contains "restored_howl".
+ // - The operation started before 2018-03-28T14:50:00Z.
+ // - The operation resulted in an error.
+ Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
+ // Number of operations to be returned in the response. If 0 or
+ // less, defaults to the server's maximum allowed page size.
+ PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ // If non-empty, `page_token` should contain a
+ // [next_page_token][google.spanner.admin.database.v1.ListDatabaseOperationsResponse.next_page_token]
+ // from a previous
+ // [ListDatabaseOperationsResponse][google.spanner.admin.database.v1.ListDatabaseOperationsResponse]
+ // to the same `parent` and with the same `filter`.
+ PageToken string `protobuf:"bytes,4,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+}
+
+func (x *ListDatabaseOperationsRequest) Reset() {
+ *x = ListDatabaseOperationsRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListDatabaseOperationsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListDatabaseOperationsRequest) ProtoMessage() {}
+
+func (x *ListDatabaseOperationsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[15]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListDatabaseOperationsRequest.ProtoReflect.Descriptor instead.
+func (*ListDatabaseOperationsRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *ListDatabaseOperationsRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *ListDatabaseOperationsRequest) GetFilter() string {
+ if x != nil {
+ return x.Filter
+ }
+ return ""
+}
+
+func (x *ListDatabaseOperationsRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *ListDatabaseOperationsRequest) GetPageToken() string {
+ if x != nil {
+ return x.PageToken
+ }
+ return ""
+}
+
+// The response for
+// [ListDatabaseOperations][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseOperations].
+type ListDatabaseOperationsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The list of matching database [long-running
+ // operations][google.longrunning.Operation]. Each operation's name will be
+ // prefixed by the database's name. The operation's
+ // [metadata][google.longrunning.Operation.metadata] field type
+ // `metadata.type_url` describes the type of the metadata.
+ Operations []*longrunningpb.Operation `protobuf:"bytes,1,rep,name=operations,proto3" json:"operations,omitempty"`
+ // `next_page_token` can be sent in a subsequent
+ // [ListDatabaseOperations][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseOperations]
+ // call to fetch more of the matching metadata.
+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+}
+
+func (x *ListDatabaseOperationsResponse) Reset() {
+ *x = ListDatabaseOperationsResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListDatabaseOperationsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListDatabaseOperationsResponse) ProtoMessage() {}
+
+func (x *ListDatabaseOperationsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[16]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListDatabaseOperationsResponse.ProtoReflect.Descriptor instead.
+func (*ListDatabaseOperationsResponse) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *ListDatabaseOperationsResponse) GetOperations() []*longrunningpb.Operation {
+ if x != nil {
+ return x.Operations
+ }
+ return nil
+}
+
+func (x *ListDatabaseOperationsResponse) GetNextPageToken() string {
+ if x != nil {
+ return x.NextPageToken
+ }
+ return ""
+}
+
+// The request for
+// [RestoreDatabase][google.spanner.admin.database.v1.DatabaseAdmin.RestoreDatabase].
+type RestoreDatabaseRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the instance in which to create the
+ // restored database. This instance must be in the same project and
+ // have the same instance configuration as the instance containing
+ // the source backup. Values are of the form
+ // `projects//instances/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Required. The id of the database to create and restore to. This
+ // database must not already exist. The `database_id` appended to
+ // `parent` forms the full database name of the form
+ // `projects//instances//databases/`.
+ DatabaseId string `protobuf:"bytes,2,opt,name=database_id,json=databaseId,proto3" json:"database_id,omitempty"`
+ // Required. The source from which to restore.
+ //
+ // Types that are assignable to Source:
+ //
+ // *RestoreDatabaseRequest_Backup
+ Source isRestoreDatabaseRequest_Source `protobuf_oneof:"source"`
+ // Optional. An encryption configuration describing the encryption type and
+ // key resources in Cloud KMS used to encrypt/decrypt the database to restore
+ // to. If this field is not specified, the restored database will use the same
+ // encryption configuration as the backup by default, namely
+ // [encryption_type][google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.encryption_type]
+ // = `USE_CONFIG_DEFAULT_OR_BACKUP_ENCRYPTION`.
+ EncryptionConfig *RestoreDatabaseEncryptionConfig `protobuf:"bytes,4,opt,name=encryption_config,json=encryptionConfig,proto3" json:"encryption_config,omitempty"`
+}
+
+func (x *RestoreDatabaseRequest) Reset() {
+ *x = RestoreDatabaseRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RestoreDatabaseRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RestoreDatabaseRequest) ProtoMessage() {}
+
+func (x *RestoreDatabaseRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[17]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RestoreDatabaseRequest.ProtoReflect.Descriptor instead.
+func (*RestoreDatabaseRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *RestoreDatabaseRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *RestoreDatabaseRequest) GetDatabaseId() string {
+ if x != nil {
+ return x.DatabaseId
+ }
+ return ""
+}
+
+func (m *RestoreDatabaseRequest) GetSource() isRestoreDatabaseRequest_Source {
+ if m != nil {
+ return m.Source
+ }
+ return nil
+}
+
+func (x *RestoreDatabaseRequest) GetBackup() string {
+ if x, ok := x.GetSource().(*RestoreDatabaseRequest_Backup); ok {
+ return x.Backup
+ }
+ return ""
+}
+
+func (x *RestoreDatabaseRequest) GetEncryptionConfig() *RestoreDatabaseEncryptionConfig {
+ if x != nil {
+ return x.EncryptionConfig
+ }
+ return nil
+}
+
+type isRestoreDatabaseRequest_Source interface {
+ isRestoreDatabaseRequest_Source()
+}
+
+type RestoreDatabaseRequest_Backup struct {
+ // Name of the backup from which to restore. Values are of the form
+ // `projects//instances//backups/`.
+ Backup string `protobuf:"bytes,3,opt,name=backup,proto3,oneof"`
+}
+
+func (*RestoreDatabaseRequest_Backup) isRestoreDatabaseRequest_Source() {}
+
+// Encryption configuration for the restored database.
+type RestoreDatabaseEncryptionConfig struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The encryption type of the restored database.
+ EncryptionType RestoreDatabaseEncryptionConfig_EncryptionType `protobuf:"varint,1,opt,name=encryption_type,json=encryptionType,proto3,enum=google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig_EncryptionType" json:"encryption_type,omitempty"`
+ // Optional. The Cloud KMS key that will be used to encrypt/decrypt the
+ // restored database. This field should be set only when
+ // [encryption_type][google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.encryption_type]
+ // is `CUSTOMER_MANAGED_ENCRYPTION`. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ KmsKeyName string `protobuf:"bytes,2,opt,name=kms_key_name,json=kmsKeyName,proto3" json:"kms_key_name,omitempty"`
+ // Optional. Specifies the KMS configuration for the one or more keys used to
+ // encrypt the database. Values are of the form
+ // `projects//locations//keyRings//cryptoKeys/`.
+ //
+ // The keys referenced by kms_key_names must fully cover all
+ // regions of the database instance configuration. Some examples:
+ // * For single region database instance configs, specify a single regional
+ // location KMS key.
+ // * For multi-regional database instance configs of type GOOGLE_MANAGED,
+ // either specify a multi-regional location KMS key or multiple regional
+ // location KMS keys that cover all regions in the instance config.
+ // * For a database instance config of type USER_MANAGED, please specify only
+ // regional location KMS keys to cover each region in the instance config.
+ // Multi-regional location KMS keys are not supported for USER_MANAGED
+ // instance configs.
+ KmsKeyNames []string `protobuf:"bytes,3,rep,name=kms_key_names,json=kmsKeyNames,proto3" json:"kms_key_names,omitempty"`
+}
+
+func (x *RestoreDatabaseEncryptionConfig) Reset() {
+ *x = RestoreDatabaseEncryptionConfig{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[18]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RestoreDatabaseEncryptionConfig) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RestoreDatabaseEncryptionConfig) ProtoMessage() {}
+
+func (x *RestoreDatabaseEncryptionConfig) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[18]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RestoreDatabaseEncryptionConfig.ProtoReflect.Descriptor instead.
+func (*RestoreDatabaseEncryptionConfig) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *RestoreDatabaseEncryptionConfig) GetEncryptionType() RestoreDatabaseEncryptionConfig_EncryptionType {
+ if x != nil {
+ return x.EncryptionType
+ }
+ return RestoreDatabaseEncryptionConfig_ENCRYPTION_TYPE_UNSPECIFIED
+}
+
+func (x *RestoreDatabaseEncryptionConfig) GetKmsKeyName() string {
+ if x != nil {
+ return x.KmsKeyName
+ }
+ return ""
+}
+
+func (x *RestoreDatabaseEncryptionConfig) GetKmsKeyNames() []string {
+ if x != nil {
+ return x.KmsKeyNames
+ }
+ return nil
+}
+
+// Metadata type for the long-running operation returned by
+// [RestoreDatabase][google.spanner.admin.database.v1.DatabaseAdmin.RestoreDatabase].
+type RestoreDatabaseMetadata struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the database being created and restored to.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // The type of the restore source.
+ SourceType RestoreSourceType `protobuf:"varint,2,opt,name=source_type,json=sourceType,proto3,enum=google.spanner.admin.database.v1.RestoreSourceType" json:"source_type,omitempty"`
+ // Information about the source used to restore the database, as specified by
+ // `source` in
+ // [RestoreDatabaseRequest][google.spanner.admin.database.v1.RestoreDatabaseRequest].
+ //
+ // Types that are assignable to SourceInfo:
+ //
+ // *RestoreDatabaseMetadata_BackupInfo
+ SourceInfo isRestoreDatabaseMetadata_SourceInfo `protobuf_oneof:"source_info"`
+ // The progress of the
+ // [RestoreDatabase][google.spanner.admin.database.v1.DatabaseAdmin.RestoreDatabase]
+ // operation.
+ Progress *OperationProgress `protobuf:"bytes,4,opt,name=progress,proto3" json:"progress,omitempty"`
+ // The time at which cancellation of this operation was received.
+ // [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]
+ // starts asynchronous cancellation on a long-running operation. The server
+ // makes a best effort to cancel the operation, but success is not guaranteed.
+ // Clients can use
+ // [Operations.GetOperation][google.longrunning.Operations.GetOperation] or
+ // other methods to check whether the cancellation succeeded or whether the
+ // operation completed despite cancellation. On successful cancellation,
+ // the operation is not deleted; instead, it becomes an operation with
+ // an [Operation.error][google.longrunning.Operation.error] value with a
+ // [google.rpc.Status.code][google.rpc.Status.code] of 1, corresponding to
+ // `Code.CANCELLED`.
+ CancelTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=cancel_time,json=cancelTime,proto3" json:"cancel_time,omitempty"`
+ // If exists, the name of the long-running operation that will be used to
+ // track the post-restore optimization process to optimize the performance of
+ // the restored database, and remove the dependency on the restore source.
+ // The name is of the form
+ // `projects//instances//databases//operations/`
+ // where the is the name of database being created and restored to.
+ // The metadata type of the long-running operation is
+ // [OptimizeRestoredDatabaseMetadata][google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata].
+ // This long-running operation will be automatically created by the system
+ // after the RestoreDatabase long-running operation completes successfully.
+ // This operation will not be created if the restore was not successful.
+ OptimizeDatabaseOperationName string `protobuf:"bytes,6,opt,name=optimize_database_operation_name,json=optimizeDatabaseOperationName,proto3" json:"optimize_database_operation_name,omitempty"`
+}
+
+func (x *RestoreDatabaseMetadata) Reset() {
+ *x = RestoreDatabaseMetadata{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RestoreDatabaseMetadata) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RestoreDatabaseMetadata) ProtoMessage() {}
+
+func (x *RestoreDatabaseMetadata) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[19]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RestoreDatabaseMetadata.ProtoReflect.Descriptor instead.
+func (*RestoreDatabaseMetadata) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *RestoreDatabaseMetadata) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *RestoreDatabaseMetadata) GetSourceType() RestoreSourceType {
+ if x != nil {
+ return x.SourceType
+ }
+ return RestoreSourceType_TYPE_UNSPECIFIED
+}
+
+func (m *RestoreDatabaseMetadata) GetSourceInfo() isRestoreDatabaseMetadata_SourceInfo {
+ if m != nil {
+ return m.SourceInfo
+ }
+ return nil
+}
+
+func (x *RestoreDatabaseMetadata) GetBackupInfo() *BackupInfo {
+ if x, ok := x.GetSourceInfo().(*RestoreDatabaseMetadata_BackupInfo); ok {
+ return x.BackupInfo
+ }
+ return nil
+}
+
+func (x *RestoreDatabaseMetadata) GetProgress() *OperationProgress {
+ if x != nil {
+ return x.Progress
+ }
+ return nil
+}
+
+func (x *RestoreDatabaseMetadata) GetCancelTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CancelTime
+ }
+ return nil
+}
+
+func (x *RestoreDatabaseMetadata) GetOptimizeDatabaseOperationName() string {
+ if x != nil {
+ return x.OptimizeDatabaseOperationName
+ }
+ return ""
+}
+
+type isRestoreDatabaseMetadata_SourceInfo interface {
+ isRestoreDatabaseMetadata_SourceInfo()
+}
+
+type RestoreDatabaseMetadata_BackupInfo struct {
+ // Information about the backup used to restore the database.
+ BackupInfo *BackupInfo `protobuf:"bytes,3,opt,name=backup_info,json=backupInfo,proto3,oneof"`
+}
+
+func (*RestoreDatabaseMetadata_BackupInfo) isRestoreDatabaseMetadata_SourceInfo() {}
+
+// Metadata type for the long-running operation used to track the progress
+// of optimizations performed on a newly restored database. This long-running
+// operation is automatically created by the system after the successful
+// completion of a database restore, and cannot be cancelled.
+type OptimizeRestoredDatabaseMetadata struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Name of the restored database being optimized.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // The progress of the post-restore optimizations.
+ Progress *OperationProgress `protobuf:"bytes,2,opt,name=progress,proto3" json:"progress,omitempty"`
+}
+
+func (x *OptimizeRestoredDatabaseMetadata) Reset() {
+ *x = OptimizeRestoredDatabaseMetadata{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *OptimizeRestoredDatabaseMetadata) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OptimizeRestoredDatabaseMetadata) ProtoMessage() {}
+
+func (x *OptimizeRestoredDatabaseMetadata) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[20]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use OptimizeRestoredDatabaseMetadata.ProtoReflect.Descriptor instead.
+func (*OptimizeRestoredDatabaseMetadata) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *OptimizeRestoredDatabaseMetadata) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *OptimizeRestoredDatabaseMetadata) GetProgress() *OperationProgress {
+ if x != nil {
+ return x.Progress
+ }
+ return nil
+}
+
+// A Cloud Spanner database role.
+type DatabaseRole struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The name of the database role. Values are of the form
+ // `projects//instances//databases//databaseRoles/`
+ // where `` is as specified in the `CREATE ROLE` DDL statement.
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *DatabaseRole) Reset() {
+ *x = DatabaseRole{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DatabaseRole) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DatabaseRole) ProtoMessage() {}
+
+func (x *DatabaseRole) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[21]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DatabaseRole.ProtoReflect.Descriptor instead.
+func (*DatabaseRole) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *DatabaseRole) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+// The request for
+// [ListDatabaseRoles][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseRoles].
+type ListDatabaseRolesRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Required. The database whose roles should be listed.
+ // Values are of the form
+ // `projects//instances//databases/`.
+ Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ // Number of database roles to be returned in the response. If 0 or less,
+ // defaults to the server's maximum allowed page size.
+ PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ // If non-empty, `page_token` should contain a
+ // [next_page_token][google.spanner.admin.database.v1.ListDatabaseRolesResponse.next_page_token]
+ // from a previous
+ // [ListDatabaseRolesResponse][google.spanner.admin.database.v1.ListDatabaseRolesResponse].
+ PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+}
+
+func (x *ListDatabaseRolesRequest) Reset() {
+ *x = ListDatabaseRolesRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListDatabaseRolesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListDatabaseRolesRequest) ProtoMessage() {}
+
+func (x *ListDatabaseRolesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[22]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListDatabaseRolesRequest.ProtoReflect.Descriptor instead.
+func (*ListDatabaseRolesRequest) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *ListDatabaseRolesRequest) GetParent() string {
+ if x != nil {
+ return x.Parent
+ }
+ return ""
+}
+
+func (x *ListDatabaseRolesRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+func (x *ListDatabaseRolesRequest) GetPageToken() string {
+ if x != nil {
+ return x.PageToken
+ }
+ return ""
+}
+
+// The response for
+// [ListDatabaseRoles][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseRoles].
+type ListDatabaseRolesResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Database roles that matched the request.
+ DatabaseRoles []*DatabaseRole `protobuf:"bytes,1,rep,name=database_roles,json=databaseRoles,proto3" json:"database_roles,omitempty"`
+ // `next_page_token` can be sent in a subsequent
+ // [ListDatabaseRoles][google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseRoles]
+ // call to fetch more of the matching roles.
+ NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+}
+
+func (x *ListDatabaseRolesResponse) Reset() {
+ *x = ListDatabaseRolesResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListDatabaseRolesResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListDatabaseRolesResponse) ProtoMessage() {}
+
+func (x *ListDatabaseRolesResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[23]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListDatabaseRolesResponse.ProtoReflect.Descriptor instead.
+func (*ListDatabaseRolesResponse) Descriptor() ([]byte, []int) {
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *ListDatabaseRolesResponse) GetDatabaseRoles() []*DatabaseRole {
+ if x != nil {
+ return x.DatabaseRoles
+ }
+ return nil
+}
+
+func (x *ListDatabaseRolesResponse) GetNextPageToken() string {
+ if x != nil {
+ return x.NextPageToken
+ }
+ return ""
+}
+
+var File_google_spanner_admin_database_v1_spanner_database_admin_proto protoreflect.FileDescriptor
+
+var file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDesc = []byte{
+ 0x0a, 0x3d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f,
+ 0x76, 0x31, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+ 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e,
+ 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65,
+ 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76,
+ 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d,
+ 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d,
+ 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x1a, 0x23, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6c, 0x6f, 0x6e, 0x67, 0x72, 0x75, 0x6e,
+ 0x6e, 0x69, 0x6e, 0x67, 0x2f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63,
+ 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d,
+ 0x69, 0x6e, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x63,
+ 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x01, 0x0a, 0x0b,
+ 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x54, 0x0a, 0x0b, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
+ 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65,
+ 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70,
+ 0x65, 0x12, 0x4f, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x6e,
+ 0x66, 0x6f, 0x42, 0x0d, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66,
+ 0x6f, 0x22, 0x82, 0x08, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x17,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41,
+ 0x02, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x05, 0x73,
+ 0x74, 0x61, 0x74, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74,
+ 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61,
+ 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72,
+ 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x03, 0xe0, 0x41, 0x03,
+ 0x52, 0x0b, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x64, 0x0a,
+ 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41,
+ 0x03, 0x52, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x12, 0x5e, 0x0a, 0x0f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x03,
+ 0xe0, 0x41, 0x03, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49,
+ 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x18, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72,
+ 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18,
+ 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x16, 0x76, 0x65, 0x72, 0x73,
+ 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x69,
+ 0x6f, 0x64, 0x12, 0x53, 0x0a, 0x15, 0x65, 0x61, 0x72, 0x6c, 0x69, 0x65, 0x73, 0x74, 0x5f, 0x76,
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0,
+ 0x41, 0x03, 0x52, 0x13, 0x65, 0x61, 0x72, 0x6c, 0x69, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73,
+ 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75,
+ 0x6c, 0x74, 0x5f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4c, 0x65, 0x61,
+ 0x64, 0x65, 0x72, 0x12, 0x61, 0x0a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f,
+ 0x64, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x31, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61,
+ 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74,
+ 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44,
+ 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
+ 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x44, 0x72,
+ 0x6f, 0x70, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0b,
+ 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28,
+ 0x08, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0b, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c,
+ 0x69, 0x6e, 0x67, 0x22, 0x4d, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x15, 0x0a, 0x11,
+ 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
+ 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x45, 0x41, 0x54, 0x49, 0x4e, 0x47, 0x10,
+ 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10,
+ 0x52, 0x45, 0x41, 0x44, 0x59, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4d, 0x49, 0x5a, 0x49, 0x4e, 0x47,
+ 0x10, 0x03, 0x3a, 0x62, 0xea, 0x41, 0x5f, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x3c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x69, 0x6e, 0x73,
+ 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
+ 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x7b, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x7d, 0x22, 0x93, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
+ 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a,
+ 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x89, 0x01, 0x0a,
+ 0x15, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
+ 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73,
+ 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f,
+ 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50,
+ 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xb3, 0x03, 0x0a, 0x15, 0x43, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74,
+ 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0,
+ 0x41, 0x02, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x10, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0x03, 0xe0,
+ 0x41, 0x01, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
+ 0x6e, 0x74, 0x73, 0x12, 0x64, 0x0a, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x61, 0x0a, 0x10, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x64, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x0e, 0x32, 0x31, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44,
+ 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x0f, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x30, 0x0a, 0x11,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
+ 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x5a,
+ 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x24, 0xfa, 0x41, 0x21, 0x0a,
+ 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
+ 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, 0x51, 0x0a, 0x12, 0x47, 0x65,
+ 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x3b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27,
+ 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xa6, 0x01,
+ 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
+ 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d,
+ 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c,
+ 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xf9, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
+ 0x61, 0x12, 0x51, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f,
+ 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f,
+ 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
+ 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x69,
+ 0x6d, 0x65, 0x22, 0xd9, 0x01, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x64, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x43, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x42, 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, 0x73,
+ 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x70, 0x65,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x11,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
+ 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x74,
+ 0x0a, 0x16, 0x44, 0x64, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x63,
+ 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70,
+ 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e,
+ 0x61, 0x6d, 0x65, 0x73, 0x22, 0x8e, 0x03, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x64, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x12, 0x40, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x42, 0x24, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
+ 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x73, 0x12, 0x47, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x74,
+ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x12, 0x21, 0x0a,
+ 0x09, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
+ 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x09, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64,
+ 0x12, 0x4f, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,
+ 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
+ 0x73, 0x12, 0x52, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x64, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
+ 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x61, 0x63,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5a, 0x0a, 0x13, 0x44, 0x72, 0x6f, 0x70, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x08,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27,
+ 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x22, 0x5c, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x44, 0x64, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x08, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe0, 0x41,
+ 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22,
+ 0x65, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x64,
+ 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x73,
+ 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x44, 0x65, 0x73, 0x63, 0x72,
+ 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65,
+ 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21,
+ 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
+ 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c,
+ 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65,
+ 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d,
+ 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x87, 0x01,
+ 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x70,
+ 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x12, 0x3d, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6c, 0x6f,
+ 0x6e, 0x67, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12,
+ 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b,
+ 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61,
+ 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xbc, 0x02, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x74,
+ 0x6f, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x27, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f,
+ 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x06, 0x62, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x22, 0xfa, 0x41, 0x1f, 0x0a, 0x1d,
+ 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
+ 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52,
+ 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x73, 0x0a, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x03, 0xe0, 0x41, 0x01, 0x52, 0x10, 0x65, 0x6e, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x08, 0x0a, 0x06,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xde, 0x03, 0x0a, 0x1f, 0x52, 0x65, 0x73, 0x74, 0x6f,
+ 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x7e, 0x0a, 0x0f, 0x65, 0x6e,
+ 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x0e, 0x32, 0x50, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x54, 0x79, 0x70, 0x65, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0e, 0x65, 0x6e, 0x63, 0x72,
+ 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x6b, 0x6d,
+ 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x42, 0x29, 0xe0, 0x41, 0x01, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b,
+ 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x0a, 0x6b, 0x6d, 0x73,
+ 0x4b, 0x65, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4d, 0x0a, 0x0d, 0x6b, 0x6d, 0x73, 0x5f, 0x6b,
+ 0x65, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0x29,
+ 0xe0, 0x41, 0x01, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x0b, 0x6b, 0x6d, 0x73, 0x4b, 0x65,
+ 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x0e, 0x45, 0x6e, 0x63, 0x72, 0x79,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x4e, 0x43,
+ 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53,
+ 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x27, 0x55, 0x53,
+ 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54,
+ 0x5f, 0x4f, 0x52, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59,
+ 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x47, 0x4f, 0x4f, 0x47, 0x4c,
+ 0x45, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,
+ 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d,
+ 0x45, 0x52, 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x44, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59,
+ 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x22, 0xe0, 0x03, 0x0a, 0x17, 0x52, 0x65, 0x73, 0x74,
+ 0x6f, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x12, 0x38, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x42, 0x24, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x54, 0x0a,
+ 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54,
+ 0x79, 0x70, 0x65, 0x12, 0x4f, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x6e,
+ 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4f, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f,
+ 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f,
+ 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
+ 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x69,
+ 0x6d, 0x65, 0x12, 0x47, 0x0a, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x6f, 0x70,
+ 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x70,
+ 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0xad, 0x01, 0x0a, 0x20, 0x4f,
+ 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12,
+ 0x38, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x24, 0xfa,
+ 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4f, 0x0a, 0x08, 0x70, 0x72, 0x6f,
+ 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d,
+ 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f,
+ 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
+ 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x0c, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x7b, 0xea, 0x41, 0x78, 0x0a, 0x23, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x2f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x51,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x7d, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e,
+ 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x73, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x72, 0x6f, 0x6c, 0x65,
+ 0x7d, 0x22, 0x97, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f,
+ 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27,
+ 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x21, 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12,
+ 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
+ 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x9a, 0x01, 0x0a, 0x19,
+ 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65,
+ 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x0e, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c,
+ 0x65, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73,
+ 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f,
+ 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50,
+ 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x2a, 0x35, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x74,
+ 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a,
+ 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
+ 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x10, 0x01, 0x32,
+ 0x98, 0x31, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x41, 0x64, 0x6d, 0x69,
+ 0x6e, 0x12, 0xc0, 0x01, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x73, 0x12, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d,
+ 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
+ 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82,
+ 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x12, 0x2d, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65,
+ 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e,
+ 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x73, 0x12, 0xa4, 0x02, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x6e, 0x67, 0x72, 0x75,
+ 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
+ 0xb9, 0x01, 0xca, 0x41, 0x64, 0x0a, 0x29, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x12, 0x37, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xda, 0x41, 0x17, 0x70, 0x61, 0x72, 0x65,
+ 0x6e, 0x74, 0x2c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x3a, 0x01, 0x2a, 0x22, 0x2d, 0x2f, 0x76,
+ 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0xad, 0x01, 0x0a, 0x0b,
+ 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x34, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d,
+ 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
+ 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, 0x3c, 0xda,
+ 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x12, 0x2d, 0x2f, 0x76,
+ 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73,
+ 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xef, 0x01, 0x0a, 0x0e,
+ 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x37,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x6c, 0x6f, 0x6e, 0x67, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x84, 0x01, 0xca, 0x41, 0x22, 0x0a, 0x08, 0x44, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xda, 0x41,
+ 0x14, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
+ 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x42, 0x3a, 0x08, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x32, 0x36, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a,
+ 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0x9d, 0x02,
+ 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x44, 0x64, 0x6c, 0x12, 0x3a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x64, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x6e, 0x67, 0x72, 0x75, 0x6e,
+ 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xac,
+ 0x01, 0xca, 0x41, 0x53, 0x0a, 0x15, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69,
+ 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70,
+ 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x64, 0x6c, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xda, 0x41, 0x13, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x82, 0xd3, 0xe4,
+ 0x93, 0x02, 0x3a, 0x3a, 0x01, 0x2a, 0x32, 0x35, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
+ 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x64, 0x64, 0x6c, 0x12, 0xa3, 0x01,
+ 0x0a, 0x0c, 0x44, 0x72, 0x6f, 0x70, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x35,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x44, 0x72, 0x6f, 0x70, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x44, 0xda,
+ 0x41, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33,
+ 0x2a, 0x31, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73,
+ 0x2f, 0x2a, 0x7d, 0x12, 0xcd, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x44, 0x64, 0x6c, 0x12, 0x37, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x64, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x38, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x44, 0x64,
+ 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x48, 0xda, 0x41, 0x08, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x12, 0x35, 0x2f, 0x76,
+ 0x31, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a,
+ 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73,
+ 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f,
+ 0x64, 0x64, 0x6c, 0x12, 0xc2, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f,
+ 0x6c, 0x69, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61,
+ 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22,
+ 0xf6, 0x01, 0xda, 0x41, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x70, 0x6f,
+ 0x6c, 0x69, 0x63, 0x79, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0xdd, 0x01, 0x3a, 0x01, 0x2a, 0x5a, 0x41,
+ 0x3a, 0x01, 0x2a, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e,
+ 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63,
+ 0x79, 0x5a, 0x55, 0x3a, 0x01, 0x2a, 0x22, 0x50, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
+ 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x49,
+ 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3e, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73,
+ 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x73, 0x65, 0x74, 0x49,
+ 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0xbb, 0x02, 0x0a, 0x0c, 0x47, 0x65, 0x74,
+ 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x61, 0x6d,
+ 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f,
+ 0x6c, 0x69, 0x63, 0x79, 0x22, 0xef, 0x01, 0xda, 0x41, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0xdd, 0x01, 0x3a, 0x01, 0x2a, 0x5a, 0x41, 0x3a, 0x01,
+ 0x2a, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74,
+ 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x3a, 0x67, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5a,
+ 0x55, 0x3a, 0x01, 0x2a, 0x22, 0x50, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x67, 0x65, 0x74, 0x49, 0x61, 0x6d,
+ 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x3e, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a,
+ 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x67, 0x65, 0x74, 0x49, 0x61, 0x6d,
+ 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0xd4, 0x03, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x49,
+ 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x28, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65,
+ 0x73, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x49, 0x61, 0x6d, 0x50,
+ 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0xe8, 0x02, 0xda, 0x41, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x2c, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93,
+ 0x02, 0xca, 0x02, 0x3a, 0x01, 0x2a, 0x5a, 0x47, 0x3a, 0x01, 0x2a, 0x22, 0x42, 0x2f, 0x76, 0x31,
+ 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f,
+ 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x74, 0x65, 0x73,
+ 0x74, 0x49, 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5a,
+ 0x5b, 0x3a, 0x01, 0x2a, 0x22, 0x56, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x74, 0x65, 0x73, 0x74, 0x49, 0x61,
+ 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5a, 0x59, 0x3a, 0x01,
+ 0x2a, 0x22, 0x54, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74,
+ 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65,
+ 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x74, 0x65, 0x73, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d,
+ 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x44, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x72, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f,
+ 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x3a, 0x74, 0x65, 0x73, 0x74, 0x49,
+ 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x9f, 0x02,
+ 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x35,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6c,
+ 0x6f, 0x6e, 0x67, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb8, 0x01, 0xca, 0x41, 0x60, 0x0a, 0x27, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
+ 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x12, 0x35, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xda, 0x41, 0x17, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x2c, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2c, 0x62, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x5f, 0x69, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x35, 0x3a, 0x06, 0x62, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x22, 0x2b, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12,
+ 0xac, 0x02, 0x0a, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x33,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6c, 0x6f, 0x6e,
+ 0x67, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x22, 0xc9, 0x01, 0xca, 0x41, 0x5e, 0x0a, 0x27, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x12, 0x33, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65,
+ 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xda, 0x41, 0x2a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c,
+ 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x2c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2c, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x74,
+ 0x69, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x35, 0x3a, 0x01, 0x2a, 0x22, 0x30, 0x2f, 0x76,
+ 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x3a, 0x63, 0x6f, 0x70, 0x79, 0x12, 0xa5,
+ 0x01, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x32, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65,
+ 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x3a, 0xda, 0x41, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x12, 0x2b, 0x2f, 0x76, 0x31, 0x2f, 0x7b,
+ 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f,
+ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xc8, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x57, 0xda, 0x41, 0x12, 0x62, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x82,
+ 0xd3, 0xe4, 0x93, 0x02, 0x3c, 0x3a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x32, 0x32, 0x2f,
+ 0x76, 0x31, 0x2f, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x12, 0x99, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x12, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
+ 0x79, 0x22, 0x3a, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d,
+ 0x2a, 0x2b, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a,
+ 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73,
+ 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xb8, 0x01,
+ 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x34, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61,
+ 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31,
+ 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, 0xda, 0x41, 0x06, 0x70,
+ 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x12, 0x2b, 0x2f, 0x76, 0x31,
+ 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d,
+ 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0xb1, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x73,
+ 0x74, 0x6f, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x38, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x6c, 0x6f, 0x6e, 0x67, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x4f, 0x70, 0x65, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc4, 0x01, 0xca, 0x41, 0x65, 0x0a, 0x29, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69,
+ 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61,
+ 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x38, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73,
+ 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74,
+ 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0xda, 0x41, 0x19, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x5f, 0x69, 0x64, 0x2c, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x82, 0xd3, 0xe4, 0x93,
+ 0x02, 0x3a, 0x3a, 0x01, 0x2a, 0x22, 0x35, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65,
+ 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e,
+ 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x73, 0x3a, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0xe4, 0x01, 0x0a,
+ 0x16, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x65,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44,
+ 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
+ 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0xda, 0x41, 0x06, 0x70,
+ 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x12, 0x36, 0x2f, 0x76, 0x31,
+ 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x7d,
+ 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x12, 0xdc, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3d, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64,
+ 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e,
+ 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d,
+ 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
+ 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x45, 0xda, 0x41, 0x06,
+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x12, 0x34, 0x2f, 0x76,
+ 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63,
+ 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a,
+ 0x7d, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x12, 0xdc, 0x01, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x3a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
+ 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x22, 0x4e, 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93,
+ 0x02, 0x3f, 0x12, 0x3d, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d,
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73,
+ 0x2f, 0x2a, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x6f, 0x6c, 0x65,
+ 0x73, 0x12, 0x8e, 0x02, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x3d, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69,
+ 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72,
+ 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75,
+ 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e,
+ 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63,
+ 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x84, 0x01, 0xda, 0x41,
+ 0x29, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x2c, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x52,
+ 0x3a, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
+ 0x65, 0x22, 0x3f, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70,
+ 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e,
+ 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f,
+ 0x2a, 0x7d, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
+ 0x65, 0x73, 0x12, 0xd1, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x3a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63,
+ 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0x4e, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82,
+ 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x12, 0x3f, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65,
+ 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74,
+ 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75,
+ 0x6c, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0x90, 0x02, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12,
+ 0x3d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e,
+ 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76,
+ 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
+ 0x22, 0x86, 0x01, 0xda, 0x41, 0x1b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73,
+ 0x6b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x62, 0x3a, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f,
+ 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x32, 0x4f, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x62,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x6e,
+ 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xbd, 0x01, 0x0a, 0x14, 0x44, 0x65,
+ 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75,
+ 0x6c, 0x65, 0x12, 0x3d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e,
+ 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61,
+ 0x73, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b,
+ 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x4e, 0xda, 0x41, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x2a, 0x3f, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x6e,
+ 0x61, 0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x2a, 0x7d, 0x12, 0xe4, 0x01, 0x0a, 0x13, 0x4c, 0x69,
+ 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
+ 0x73, 0x12, 0x3c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e,
+ 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53,
+ 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x3d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e,
+ 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68,
+ 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x50,
+ 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x12,
+ 0x3f, 0x2f, 0x76, 0x31, 0x2f, 0x7b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x3d, 0x70, 0x72, 0x6f,
+ 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
+ 0x73, 0x2f, 0x2a, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x2a, 0x7d,
+ 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73,
+ 0x1a, 0x78, 0xca, 0x41, 0x16, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x5c, 0x68, 0x74,
+ 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2c, 0x68, 0x74, 0x74,
+ 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61,
+ 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x73, 0x70, 0x61,
+ 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x42, 0xd8, 0x02, 0xea, 0x41, 0x4a,
+ 0x0a, 0x1f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
+ 0x65, 0x12, 0x27, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f,
+ 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f,
+ 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x7d, 0x0a, 0x24, 0x63, 0x6f, 0x6d, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x61,
+ 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31,
+ 0x42, 0x19, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x46, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x67, 0x6f, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e,
+ 0x2f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x31, 0x2f,
+ 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x70, 0x62, 0x3b, 0x64, 0x61, 0x74, 0x61, 0x62,
+ 0x61, 0x73, 0x65, 0x70, 0x62, 0xaa, 0x02, 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43,
+ 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x6d,
+ 0x69, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02,
+ 0x26, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x53, 0x70,
+ 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x5c, 0x44, 0x61, 0x74, 0x61,
+ 0x62, 0x61, 0x73, 0x65, 0x5c, 0x56, 0x31, 0xea, 0x02, 0x2b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x53, 0x70, 0x61, 0x6e, 0x6e, 0x65, 0x72,
+ 0x3a, 0x3a, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x3a, 0x3a, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
+ 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescOnce sync.Once
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescData = file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDesc
+)
+
+func file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescGZIP() []byte {
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescOnce.Do(func() {
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescData)
+ })
+ return file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDescData
+}
+
+var file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
+var file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
+var file_google_spanner_admin_database_v1_spanner_database_admin_proto_goTypes = []any{
+ (RestoreSourceType)(0), // 0: google.spanner.admin.database.v1.RestoreSourceType
+ (Database_State)(0), // 1: google.spanner.admin.database.v1.Database.State
+ (RestoreDatabaseEncryptionConfig_EncryptionType)(0), // 2: google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.EncryptionType
+ (*RestoreInfo)(nil), // 3: google.spanner.admin.database.v1.RestoreInfo
+ (*Database)(nil), // 4: google.spanner.admin.database.v1.Database
+ (*ListDatabasesRequest)(nil), // 5: google.spanner.admin.database.v1.ListDatabasesRequest
+ (*ListDatabasesResponse)(nil), // 6: google.spanner.admin.database.v1.ListDatabasesResponse
+ (*CreateDatabaseRequest)(nil), // 7: google.spanner.admin.database.v1.CreateDatabaseRequest
+ (*CreateDatabaseMetadata)(nil), // 8: google.spanner.admin.database.v1.CreateDatabaseMetadata
+ (*GetDatabaseRequest)(nil), // 9: google.spanner.admin.database.v1.GetDatabaseRequest
+ (*UpdateDatabaseRequest)(nil), // 10: google.spanner.admin.database.v1.UpdateDatabaseRequest
+ (*UpdateDatabaseMetadata)(nil), // 11: google.spanner.admin.database.v1.UpdateDatabaseMetadata
+ (*UpdateDatabaseDdlRequest)(nil), // 12: google.spanner.admin.database.v1.UpdateDatabaseDdlRequest
+ (*DdlStatementActionInfo)(nil), // 13: google.spanner.admin.database.v1.DdlStatementActionInfo
+ (*UpdateDatabaseDdlMetadata)(nil), // 14: google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata
+ (*DropDatabaseRequest)(nil), // 15: google.spanner.admin.database.v1.DropDatabaseRequest
+ (*GetDatabaseDdlRequest)(nil), // 16: google.spanner.admin.database.v1.GetDatabaseDdlRequest
+ (*GetDatabaseDdlResponse)(nil), // 17: google.spanner.admin.database.v1.GetDatabaseDdlResponse
+ (*ListDatabaseOperationsRequest)(nil), // 18: google.spanner.admin.database.v1.ListDatabaseOperationsRequest
+ (*ListDatabaseOperationsResponse)(nil), // 19: google.spanner.admin.database.v1.ListDatabaseOperationsResponse
+ (*RestoreDatabaseRequest)(nil), // 20: google.spanner.admin.database.v1.RestoreDatabaseRequest
+ (*RestoreDatabaseEncryptionConfig)(nil), // 21: google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig
+ (*RestoreDatabaseMetadata)(nil), // 22: google.spanner.admin.database.v1.RestoreDatabaseMetadata
+ (*OptimizeRestoredDatabaseMetadata)(nil), // 23: google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata
+ (*DatabaseRole)(nil), // 24: google.spanner.admin.database.v1.DatabaseRole
+ (*ListDatabaseRolesRequest)(nil), // 25: google.spanner.admin.database.v1.ListDatabaseRolesRequest
+ (*ListDatabaseRolesResponse)(nil), // 26: google.spanner.admin.database.v1.ListDatabaseRolesResponse
+ (*BackupInfo)(nil), // 27: google.spanner.admin.database.v1.BackupInfo
+ (*timestamppb.Timestamp)(nil), // 28: google.protobuf.Timestamp
+ (*EncryptionConfig)(nil), // 29: google.spanner.admin.database.v1.EncryptionConfig
+ (*EncryptionInfo)(nil), // 30: google.spanner.admin.database.v1.EncryptionInfo
+ (DatabaseDialect)(0), // 31: google.spanner.admin.database.v1.DatabaseDialect
+ (*fieldmaskpb.FieldMask)(nil), // 32: google.protobuf.FieldMask
+ (*OperationProgress)(nil), // 33: google.spanner.admin.database.v1.OperationProgress
+ (*longrunningpb.Operation)(nil), // 34: google.longrunning.Operation
+ (*iampb.SetIamPolicyRequest)(nil), // 35: google.iam.v1.SetIamPolicyRequest
+ (*iampb.GetIamPolicyRequest)(nil), // 36: google.iam.v1.GetIamPolicyRequest
+ (*iampb.TestIamPermissionsRequest)(nil), // 37: google.iam.v1.TestIamPermissionsRequest
+ (*CreateBackupRequest)(nil), // 38: google.spanner.admin.database.v1.CreateBackupRequest
+ (*CopyBackupRequest)(nil), // 39: google.spanner.admin.database.v1.CopyBackupRequest
+ (*GetBackupRequest)(nil), // 40: google.spanner.admin.database.v1.GetBackupRequest
+ (*UpdateBackupRequest)(nil), // 41: google.spanner.admin.database.v1.UpdateBackupRequest
+ (*DeleteBackupRequest)(nil), // 42: google.spanner.admin.database.v1.DeleteBackupRequest
+ (*ListBackupsRequest)(nil), // 43: google.spanner.admin.database.v1.ListBackupsRequest
+ (*ListBackupOperationsRequest)(nil), // 44: google.spanner.admin.database.v1.ListBackupOperationsRequest
+ (*CreateBackupScheduleRequest)(nil), // 45: google.spanner.admin.database.v1.CreateBackupScheduleRequest
+ (*GetBackupScheduleRequest)(nil), // 46: google.spanner.admin.database.v1.GetBackupScheduleRequest
+ (*UpdateBackupScheduleRequest)(nil), // 47: google.spanner.admin.database.v1.UpdateBackupScheduleRequest
+ (*DeleteBackupScheduleRequest)(nil), // 48: google.spanner.admin.database.v1.DeleteBackupScheduleRequest
+ (*ListBackupSchedulesRequest)(nil), // 49: google.spanner.admin.database.v1.ListBackupSchedulesRequest
+ (*emptypb.Empty)(nil), // 50: google.protobuf.Empty
+ (*iampb.Policy)(nil), // 51: google.iam.v1.Policy
+ (*iampb.TestIamPermissionsResponse)(nil), // 52: google.iam.v1.TestIamPermissionsResponse
+ (*Backup)(nil), // 53: google.spanner.admin.database.v1.Backup
+ (*ListBackupsResponse)(nil), // 54: google.spanner.admin.database.v1.ListBackupsResponse
+ (*ListBackupOperationsResponse)(nil), // 55: google.spanner.admin.database.v1.ListBackupOperationsResponse
+ (*BackupSchedule)(nil), // 56: google.spanner.admin.database.v1.BackupSchedule
+ (*ListBackupSchedulesResponse)(nil), // 57: google.spanner.admin.database.v1.ListBackupSchedulesResponse
+}
+var file_google_spanner_admin_database_v1_spanner_database_admin_proto_depIdxs = []int32{
+ 0, // 0: google.spanner.admin.database.v1.RestoreInfo.source_type:type_name -> google.spanner.admin.database.v1.RestoreSourceType
+ 27, // 1: google.spanner.admin.database.v1.RestoreInfo.backup_info:type_name -> google.spanner.admin.database.v1.BackupInfo
+ 1, // 2: google.spanner.admin.database.v1.Database.state:type_name -> google.spanner.admin.database.v1.Database.State
+ 28, // 3: google.spanner.admin.database.v1.Database.create_time:type_name -> google.protobuf.Timestamp
+ 3, // 4: google.spanner.admin.database.v1.Database.restore_info:type_name -> google.spanner.admin.database.v1.RestoreInfo
+ 29, // 5: google.spanner.admin.database.v1.Database.encryption_config:type_name -> google.spanner.admin.database.v1.EncryptionConfig
+ 30, // 6: google.spanner.admin.database.v1.Database.encryption_info:type_name -> google.spanner.admin.database.v1.EncryptionInfo
+ 28, // 7: google.spanner.admin.database.v1.Database.earliest_version_time:type_name -> google.protobuf.Timestamp
+ 31, // 8: google.spanner.admin.database.v1.Database.database_dialect:type_name -> google.spanner.admin.database.v1.DatabaseDialect
+ 4, // 9: google.spanner.admin.database.v1.ListDatabasesResponse.databases:type_name -> google.spanner.admin.database.v1.Database
+ 29, // 10: google.spanner.admin.database.v1.CreateDatabaseRequest.encryption_config:type_name -> google.spanner.admin.database.v1.EncryptionConfig
+ 31, // 11: google.spanner.admin.database.v1.CreateDatabaseRequest.database_dialect:type_name -> google.spanner.admin.database.v1.DatabaseDialect
+ 4, // 12: google.spanner.admin.database.v1.UpdateDatabaseRequest.database:type_name -> google.spanner.admin.database.v1.Database
+ 32, // 13: google.spanner.admin.database.v1.UpdateDatabaseRequest.update_mask:type_name -> google.protobuf.FieldMask
+ 10, // 14: google.spanner.admin.database.v1.UpdateDatabaseMetadata.request:type_name -> google.spanner.admin.database.v1.UpdateDatabaseRequest
+ 33, // 15: google.spanner.admin.database.v1.UpdateDatabaseMetadata.progress:type_name -> google.spanner.admin.database.v1.OperationProgress
+ 28, // 16: google.spanner.admin.database.v1.UpdateDatabaseMetadata.cancel_time:type_name -> google.protobuf.Timestamp
+ 28, // 17: google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata.commit_timestamps:type_name -> google.protobuf.Timestamp
+ 33, // 18: google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata.progress:type_name -> google.spanner.admin.database.v1.OperationProgress
+ 13, // 19: google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata.actions:type_name -> google.spanner.admin.database.v1.DdlStatementActionInfo
+ 34, // 20: google.spanner.admin.database.v1.ListDatabaseOperationsResponse.operations:type_name -> google.longrunning.Operation
+ 21, // 21: google.spanner.admin.database.v1.RestoreDatabaseRequest.encryption_config:type_name -> google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig
+ 2, // 22: google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.encryption_type:type_name -> google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.EncryptionType
+ 0, // 23: google.spanner.admin.database.v1.RestoreDatabaseMetadata.source_type:type_name -> google.spanner.admin.database.v1.RestoreSourceType
+ 27, // 24: google.spanner.admin.database.v1.RestoreDatabaseMetadata.backup_info:type_name -> google.spanner.admin.database.v1.BackupInfo
+ 33, // 25: google.spanner.admin.database.v1.RestoreDatabaseMetadata.progress:type_name -> google.spanner.admin.database.v1.OperationProgress
+ 28, // 26: google.spanner.admin.database.v1.RestoreDatabaseMetadata.cancel_time:type_name -> google.protobuf.Timestamp
+ 33, // 27: google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata.progress:type_name -> google.spanner.admin.database.v1.OperationProgress
+ 24, // 28: google.spanner.admin.database.v1.ListDatabaseRolesResponse.database_roles:type_name -> google.spanner.admin.database.v1.DatabaseRole
+ 5, // 29: google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases:input_type -> google.spanner.admin.database.v1.ListDatabasesRequest
+ 7, // 30: google.spanner.admin.database.v1.DatabaseAdmin.CreateDatabase:input_type -> google.spanner.admin.database.v1.CreateDatabaseRequest
+ 9, // 31: google.spanner.admin.database.v1.DatabaseAdmin.GetDatabase:input_type -> google.spanner.admin.database.v1.GetDatabaseRequest
+ 10, // 32: google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase:input_type -> google.spanner.admin.database.v1.UpdateDatabaseRequest
+ 12, // 33: google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl:input_type -> google.spanner.admin.database.v1.UpdateDatabaseDdlRequest
+ 15, // 34: google.spanner.admin.database.v1.DatabaseAdmin.DropDatabase:input_type -> google.spanner.admin.database.v1.DropDatabaseRequest
+ 16, // 35: google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDdl:input_type -> google.spanner.admin.database.v1.GetDatabaseDdlRequest
+ 35, // 36: google.spanner.admin.database.v1.DatabaseAdmin.SetIamPolicy:input_type -> google.iam.v1.SetIamPolicyRequest
+ 36, // 37: google.spanner.admin.database.v1.DatabaseAdmin.GetIamPolicy:input_type -> google.iam.v1.GetIamPolicyRequest
+ 37, // 38: google.spanner.admin.database.v1.DatabaseAdmin.TestIamPermissions:input_type -> google.iam.v1.TestIamPermissionsRequest
+ 38, // 39: google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup:input_type -> google.spanner.admin.database.v1.CreateBackupRequest
+ 39, // 40: google.spanner.admin.database.v1.DatabaseAdmin.CopyBackup:input_type -> google.spanner.admin.database.v1.CopyBackupRequest
+ 40, // 41: google.spanner.admin.database.v1.DatabaseAdmin.GetBackup:input_type -> google.spanner.admin.database.v1.GetBackupRequest
+ 41, // 42: google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackup:input_type -> google.spanner.admin.database.v1.UpdateBackupRequest
+ 42, // 43: google.spanner.admin.database.v1.DatabaseAdmin.DeleteBackup:input_type -> google.spanner.admin.database.v1.DeleteBackupRequest
+ 43, // 44: google.spanner.admin.database.v1.DatabaseAdmin.ListBackups:input_type -> google.spanner.admin.database.v1.ListBackupsRequest
+ 20, // 45: google.spanner.admin.database.v1.DatabaseAdmin.RestoreDatabase:input_type -> google.spanner.admin.database.v1.RestoreDatabaseRequest
+ 18, // 46: google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseOperations:input_type -> google.spanner.admin.database.v1.ListDatabaseOperationsRequest
+ 44, // 47: google.spanner.admin.database.v1.DatabaseAdmin.ListBackupOperations:input_type -> google.spanner.admin.database.v1.ListBackupOperationsRequest
+ 25, // 48: google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseRoles:input_type -> google.spanner.admin.database.v1.ListDatabaseRolesRequest
+ 45, // 49: google.spanner.admin.database.v1.DatabaseAdmin.CreateBackupSchedule:input_type -> google.spanner.admin.database.v1.CreateBackupScheduleRequest
+ 46, // 50: google.spanner.admin.database.v1.DatabaseAdmin.GetBackupSchedule:input_type -> google.spanner.admin.database.v1.GetBackupScheduleRequest
+ 47, // 51: google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackupSchedule:input_type -> google.spanner.admin.database.v1.UpdateBackupScheduleRequest
+ 48, // 52: google.spanner.admin.database.v1.DatabaseAdmin.DeleteBackupSchedule:input_type -> google.spanner.admin.database.v1.DeleteBackupScheduleRequest
+ 49, // 53: google.spanner.admin.database.v1.DatabaseAdmin.ListBackupSchedules:input_type -> google.spanner.admin.database.v1.ListBackupSchedulesRequest
+ 6, // 54: google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases:output_type -> google.spanner.admin.database.v1.ListDatabasesResponse
+ 34, // 55: google.spanner.admin.database.v1.DatabaseAdmin.CreateDatabase:output_type -> google.longrunning.Operation
+ 4, // 56: google.spanner.admin.database.v1.DatabaseAdmin.GetDatabase:output_type -> google.spanner.admin.database.v1.Database
+ 34, // 57: google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase:output_type -> google.longrunning.Operation
+ 34, // 58: google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl:output_type -> google.longrunning.Operation
+ 50, // 59: google.spanner.admin.database.v1.DatabaseAdmin.DropDatabase:output_type -> google.protobuf.Empty
+ 17, // 60: google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDdl:output_type -> google.spanner.admin.database.v1.GetDatabaseDdlResponse
+ 51, // 61: google.spanner.admin.database.v1.DatabaseAdmin.SetIamPolicy:output_type -> google.iam.v1.Policy
+ 51, // 62: google.spanner.admin.database.v1.DatabaseAdmin.GetIamPolicy:output_type -> google.iam.v1.Policy
+ 52, // 63: google.spanner.admin.database.v1.DatabaseAdmin.TestIamPermissions:output_type -> google.iam.v1.TestIamPermissionsResponse
+ 34, // 64: google.spanner.admin.database.v1.DatabaseAdmin.CreateBackup:output_type -> google.longrunning.Operation
+ 34, // 65: google.spanner.admin.database.v1.DatabaseAdmin.CopyBackup:output_type -> google.longrunning.Operation
+ 53, // 66: google.spanner.admin.database.v1.DatabaseAdmin.GetBackup:output_type -> google.spanner.admin.database.v1.Backup
+ 53, // 67: google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackup:output_type -> google.spanner.admin.database.v1.Backup
+ 50, // 68: google.spanner.admin.database.v1.DatabaseAdmin.DeleteBackup:output_type -> google.protobuf.Empty
+ 54, // 69: google.spanner.admin.database.v1.DatabaseAdmin.ListBackups:output_type -> google.spanner.admin.database.v1.ListBackupsResponse
+ 34, // 70: google.spanner.admin.database.v1.DatabaseAdmin.RestoreDatabase:output_type -> google.longrunning.Operation
+ 19, // 71: google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseOperations:output_type -> google.spanner.admin.database.v1.ListDatabaseOperationsResponse
+ 55, // 72: google.spanner.admin.database.v1.DatabaseAdmin.ListBackupOperations:output_type -> google.spanner.admin.database.v1.ListBackupOperationsResponse
+ 26, // 73: google.spanner.admin.database.v1.DatabaseAdmin.ListDatabaseRoles:output_type -> google.spanner.admin.database.v1.ListDatabaseRolesResponse
+ 56, // 74: google.spanner.admin.database.v1.DatabaseAdmin.CreateBackupSchedule:output_type -> google.spanner.admin.database.v1.BackupSchedule
+ 56, // 75: google.spanner.admin.database.v1.DatabaseAdmin.GetBackupSchedule:output_type -> google.spanner.admin.database.v1.BackupSchedule
+ 56, // 76: google.spanner.admin.database.v1.DatabaseAdmin.UpdateBackupSchedule:output_type -> google.spanner.admin.database.v1.BackupSchedule
+ 50, // 77: google.spanner.admin.database.v1.DatabaseAdmin.DeleteBackupSchedule:output_type -> google.protobuf.Empty
+ 57, // 78: google.spanner.admin.database.v1.DatabaseAdmin.ListBackupSchedules:output_type -> google.spanner.admin.database.v1.ListBackupSchedulesResponse
+ 54, // [54:79] is the sub-list for method output_type
+ 29, // [29:54] is the sub-list for method input_type
+ 29, // [29:29] is the sub-list for extension type_name
+ 29, // [29:29] is the sub-list for extension extendee
+ 0, // [0:29] is the sub-list for field type_name
+}
+
+func init() { file_google_spanner_admin_database_v1_spanner_database_admin_proto_init() }
+func file_google_spanner_admin_database_v1_spanner_database_admin_proto_init() {
+ if File_google_spanner_admin_database_v1_spanner_database_admin_proto != nil {
+ return
+ }
+ file_google_spanner_admin_database_v1_backup_proto_init()
+ file_google_spanner_admin_database_v1_backup_schedule_proto_init()
+ file_google_spanner_admin_database_v1_common_proto_init()
+ if !protoimpl.UnsafeEnabled {
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[0].Exporter = func(v any, i int) any {
+ switch v := v.(*RestoreInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[1].Exporter = func(v any, i int) any {
+ switch v := v.(*Database); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[2].Exporter = func(v any, i int) any {
+ switch v := v.(*ListDatabasesRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[3].Exporter = func(v any, i int) any {
+ switch v := v.(*ListDatabasesResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[4].Exporter = func(v any, i int) any {
+ switch v := v.(*CreateDatabaseRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[5].Exporter = func(v any, i int) any {
+ switch v := v.(*CreateDatabaseMetadata); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[6].Exporter = func(v any, i int) any {
+ switch v := v.(*GetDatabaseRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[7].Exporter = func(v any, i int) any {
+ switch v := v.(*UpdateDatabaseRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[8].Exporter = func(v any, i int) any {
+ switch v := v.(*UpdateDatabaseMetadata); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[9].Exporter = func(v any, i int) any {
+ switch v := v.(*UpdateDatabaseDdlRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[10].Exporter = func(v any, i int) any {
+ switch v := v.(*DdlStatementActionInfo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[11].Exporter = func(v any, i int) any {
+ switch v := v.(*UpdateDatabaseDdlMetadata); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[12].Exporter = func(v any, i int) any {
+ switch v := v.(*DropDatabaseRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[13].Exporter = func(v any, i int) any {
+ switch v := v.(*GetDatabaseDdlRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[14].Exporter = func(v any, i int) any {
+ switch v := v.(*GetDatabaseDdlResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[15].Exporter = func(v any, i int) any {
+ switch v := v.(*ListDatabaseOperationsRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[16].Exporter = func(v any, i int) any {
+ switch v := v.(*ListDatabaseOperationsResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[17].Exporter = func(v any, i int) any {
+ switch v := v.(*RestoreDatabaseRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[18].Exporter = func(v any, i int) any {
+ switch v := v.(*RestoreDatabaseEncryptionConfig); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[19].Exporter = func(v any, i int) any {
+ switch v := v.(*RestoreDatabaseMetadata); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[20].Exporter = func(v any, i int) any {
+ switch v := v.(*OptimizeRestoredDatabaseMetadata); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[21].Exporter = func(v any, i int) any {
+ switch v := v.(*DatabaseRole); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[22].Exporter = func(v any, i int) any {
+ switch v := v.(*ListDatabaseRolesRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[23].Exporter = func(v any, i int) any {
+ switch v := v.(*ListDatabaseRolesResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[0].OneofWrappers = []any{
+ (*RestoreInfo_BackupInfo)(nil),
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[17].OneofWrappers = []any{
+ (*RestoreDatabaseRequest_Backup)(nil),
+ }
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes[19].OneofWrappers = []any{
+ (*RestoreDatabaseMetadata_BackupInfo)(nil),
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDesc,
+ NumEnums: 3,
+ NumMessages: 24,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_google_spanner_admin_database_v1_spanner_database_admin_proto_goTypes,
+ DependencyIndexes: file_google_spanner_admin_database_v1_spanner_database_admin_proto_depIdxs,
+ EnumInfos: file_google_spanner_admin_database_v1_spanner_database_admin_proto_enumTypes,
+ MessageInfos: file_google_spanner_admin_database_v1_spanner_database_admin_proto_msgTypes,
+ }.Build()
+ File_google_spanner_admin_database_v1_spanner_database_admin_proto = out.File
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_rawDesc = nil
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_goTypes = nil
+ file_google_spanner_admin_database_v1_spanner_database_admin_proto_depIdxs = nil
+}
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ context.Context
+var _ grpc.ClientConnInterface
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+const _ = grpc.SupportPackageIsVersion6
+
+// DatabaseAdminClient is the client API for DatabaseAdmin service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
+type DatabaseAdminClient interface {
+ // Lists Cloud Spanner databases.
+ ListDatabases(ctx context.Context, in *ListDatabasesRequest, opts ...grpc.CallOption) (*ListDatabasesResponse, error)
+ // Creates a new Cloud Spanner database and starts to prepare it for serving.
+ // The returned [long-running operation][google.longrunning.Operation] will
+ // have a name of the format `/operations/` and
+ // can be used to track preparation of the database. The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [CreateDatabaseMetadata][google.spanner.admin.database.v1.CreateDatabaseMetadata].
+ // The [response][google.longrunning.Operation.response] field type is
+ // [Database][google.spanner.admin.database.v1.Database], if successful.
+ CreateDatabase(ctx context.Context, in *CreateDatabaseRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error)
+ // Gets the state of a Cloud Spanner database.
+ GetDatabase(ctx context.Context, in *GetDatabaseRequest, opts ...grpc.CallOption) (*Database, error)
+ // Updates a Cloud Spanner database. The returned
+ // [long-running operation][google.longrunning.Operation] can be used to track
+ // the progress of updating the database. If the named database does not
+ // exist, returns `NOT_FOUND`.
+ //
+ // While the operation is pending:
+ //
+ // - The database's
+ // [reconciling][google.spanner.admin.database.v1.Database.reconciling]
+ // field is set to true.
+ // - Cancelling the operation is best-effort. If the cancellation succeeds,
+ // the operation metadata's
+ // [cancel_time][google.spanner.admin.database.v1.UpdateDatabaseMetadata.cancel_time]
+ // is set, the updates are reverted, and the operation terminates with a
+ // `CANCELLED` status.
+ // - New UpdateDatabase requests will return a `FAILED_PRECONDITION` error
+ // until the pending operation is done (returns successfully or with
+ // error).
+ // - Reading the database via the API continues to give the pre-request
+ // values.
+ //
+ // Upon completion of the returned operation:
+ //
+ // - The new values are in effect and readable via the API.
+ // - The database's
+ // [reconciling][google.spanner.admin.database.v1.Database.reconciling]
+ // field becomes false.
+ //
+ // The returned [long-running operation][google.longrunning.Operation] will
+ // have a name of the format
+ // `projects//instances//databases//operations/`
+ // and can be used to track the database modification. The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [UpdateDatabaseMetadata][google.spanner.admin.database.v1.UpdateDatabaseMetadata].
+ // The [response][google.longrunning.Operation.response] field type is
+ // [Database][google.spanner.admin.database.v1.Database], if successful.
+ UpdateDatabase(ctx context.Context, in *UpdateDatabaseRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error)
+ // Updates the schema of a Cloud Spanner database by
+ // creating/altering/dropping tables, columns, indexes, etc. The returned
+ // [long-running operation][google.longrunning.Operation] will have a name of
+ // the format `/operations/` and can be used to
+ // track execution of the schema change(s). The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [UpdateDatabaseDdlMetadata][google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata].
+ // The operation has no response.
+ UpdateDatabaseDdl(ctx context.Context, in *UpdateDatabaseDdlRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error)
+ // Drops (aka deletes) a Cloud Spanner database.
+ // Completed backups for the database will be retained according to their
+ // `expire_time`.
+ // Note: Cloud Spanner might continue to accept requests for a few seconds
+ // after the database has been deleted.
+ DropDatabase(ctx context.Context, in *DropDatabaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Returns the schema of a Cloud Spanner database as a list of formatted
+ // DDL statements. This method does not show pending schema updates, those may
+ // be queried using the [Operations][google.longrunning.Operations] API.
+ GetDatabaseDdl(ctx context.Context, in *GetDatabaseDdlRequest, opts ...grpc.CallOption) (*GetDatabaseDdlResponse, error)
+ // Sets the access control policy on a database or backup resource.
+ // Replaces any existing policy.
+ //
+ // Authorization requires `spanner.databases.setIamPolicy`
+ // permission on [resource][google.iam.v1.SetIamPolicyRequest.resource].
+ // For backups, authorization requires `spanner.backups.setIamPolicy`
+ // permission on [resource][google.iam.v1.SetIamPolicyRequest.resource].
+ SetIamPolicy(ctx context.Context, in *iampb.SetIamPolicyRequest, opts ...grpc.CallOption) (*iampb.Policy, error)
+ // Gets the access control policy for a database or backup resource.
+ // Returns an empty policy if a database or backup exists but does not have a
+ // policy set.
+ //
+ // Authorization requires `spanner.databases.getIamPolicy` permission on
+ // [resource][google.iam.v1.GetIamPolicyRequest.resource].
+ // For backups, authorization requires `spanner.backups.getIamPolicy`
+ // permission on [resource][google.iam.v1.GetIamPolicyRequest.resource].
+ GetIamPolicy(ctx context.Context, in *iampb.GetIamPolicyRequest, opts ...grpc.CallOption) (*iampb.Policy, error)
+ // Returns permissions that the caller has on the specified database or backup
+ // resource.
+ //
+ // Attempting this RPC on a non-existent Cloud Spanner database will
+ // result in a NOT_FOUND error if the user has
+ // `spanner.databases.list` permission on the containing Cloud
+ // Spanner instance. Otherwise returns an empty set of permissions.
+ // Calling this method on a backup that does not exist will
+ // result in a NOT_FOUND error if the user has
+ // `spanner.backups.list` permission on the containing instance.
+ TestIamPermissions(ctx context.Context, in *iampb.TestIamPermissionsRequest, opts ...grpc.CallOption) (*iampb.TestIamPermissionsResponse, error)
+ // Starts creating a new Cloud Spanner Backup.
+ // The returned backup [long-running operation][google.longrunning.Operation]
+ // will have a name of the format
+ // `projects//instances//backups//operations/`
+ // and can be used to track creation of the backup. The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata].
+ // The [response][google.longrunning.Operation.response] field type is
+ // [Backup][google.spanner.admin.database.v1.Backup], if successful.
+ // Cancelling the returned operation will stop the creation and delete the
+ // backup. There can be only one pending backup creation per database. Backup
+ // creation of different databases can run concurrently.
+ CreateBackup(ctx context.Context, in *CreateBackupRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error)
+ // Starts copying a Cloud Spanner Backup.
+ // The returned backup [long-running operation][google.longrunning.Operation]
+ // will have a name of the format
+ // `projects//instances//backups//operations/`
+ // and can be used to track copying of the backup. The operation is associated
+ // with the destination backup.
+ // The [metadata][google.longrunning.Operation.metadata] field type is
+ // [CopyBackupMetadata][google.spanner.admin.database.v1.CopyBackupMetadata].
+ // The [response][google.longrunning.Operation.response] field type is
+ // [Backup][google.spanner.admin.database.v1.Backup], if successful.
+ // Cancelling the returned operation will stop the copying and delete the
+ // destination backup. Concurrent CopyBackup requests can run on the same
+ // source backup.
+ CopyBackup(ctx context.Context, in *CopyBackupRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error)
+ // Gets metadata on a pending or completed
+ // [Backup][google.spanner.admin.database.v1.Backup].
+ GetBackup(ctx context.Context, in *GetBackupRequest, opts ...grpc.CallOption) (*Backup, error)
+ // Updates a pending or completed
+ // [Backup][google.spanner.admin.database.v1.Backup].
+ UpdateBackup(ctx context.Context, in *UpdateBackupRequest, opts ...grpc.CallOption) (*Backup, error)
+ // Deletes a pending or completed
+ // [Backup][google.spanner.admin.database.v1.Backup].
+ DeleteBackup(ctx context.Context, in *DeleteBackupRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Lists completed and pending backups.
+ // Backups returned are ordered by `create_time` in descending order,
+ // starting from the most recent `create_time`.
+ ListBackups(ctx context.Context, in *ListBackupsRequest, opts ...grpc.CallOption) (*ListBackupsResponse, error)
+ // Create a new database by restoring from a completed backup. The new
+ // database must be in the same project and in an instance with the same
+ // instance configuration as the instance containing
+ // the backup. The returned database [long-running
+ // operation][google.longrunning.Operation] has a name of the format
+ // `projects//instances//databases//operations/`,
+ // and can be used to track the progress of the operation, and to cancel it.
+ // The [metadata][google.longrunning.Operation.metadata] field type is
+ // [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata].
+ // The [response][google.longrunning.Operation.response] type
+ // is [Database][google.spanner.admin.database.v1.Database], if
+ // successful. Cancelling the returned operation will stop the restore and
+ // delete the database.
+ // There can be only one database being restored into an instance at a time.
+ // Once the restore operation completes, a new restore operation can be
+ // initiated, without waiting for the optimize operation associated with the
+ // first restore to complete.
+ RestoreDatabase(ctx context.Context, in *RestoreDatabaseRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error)
+ // Lists database [longrunning-operations][google.longrunning.Operation].
+ // A database operation has a name of the form
+ // `projects//instances//databases//operations/`.
+ // The long-running operation
+ // [metadata][google.longrunning.Operation.metadata] field type
+ // `metadata.type_url` describes the type of the metadata. Operations returned
+ // include those that have completed/failed/canceled within the last 7 days,
+ // and pending operations.
+ ListDatabaseOperations(ctx context.Context, in *ListDatabaseOperationsRequest, opts ...grpc.CallOption) (*ListDatabaseOperationsResponse, error)
+ // Lists the backup [long-running operations][google.longrunning.Operation] in
+ // the given instance. A backup operation has a name of the form
+ // `projects//instances//backups//operations/`.
+ // The long-running operation
+ // [metadata][google.longrunning.Operation.metadata] field type
+ // `metadata.type_url` describes the type of the metadata. Operations returned
+ // include those that have completed/failed/canceled within the last 7 days,
+ // and pending operations. Operations returned are ordered by
+ // `operation.metadata.value.progress.start_time` in descending order starting
+ // from the most recently started operation.
+ ListBackupOperations(ctx context.Context, in *ListBackupOperationsRequest, opts ...grpc.CallOption) (*ListBackupOperationsResponse, error)
+ // Lists Cloud Spanner database roles.
+ ListDatabaseRoles(ctx context.Context, in *ListDatabaseRolesRequest, opts ...grpc.CallOption) (*ListDatabaseRolesResponse, error)
+ // Creates a new backup schedule.
+ CreateBackupSchedule(ctx context.Context, in *CreateBackupScheduleRequest, opts ...grpc.CallOption) (*BackupSchedule, error)
+ // Gets backup schedule for the input schedule name.
+ GetBackupSchedule(ctx context.Context, in *GetBackupScheduleRequest, opts ...grpc.CallOption) (*BackupSchedule, error)
+ // Updates a backup schedule.
+ UpdateBackupSchedule(ctx context.Context, in *UpdateBackupScheduleRequest, opts ...grpc.CallOption) (*BackupSchedule, error)
+ // Deletes a backup schedule.
+ DeleteBackupSchedule(ctx context.Context, in *DeleteBackupScheduleRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+ // Lists all the backup schedules for the database.
+ ListBackupSchedules(ctx context.Context, in *ListBackupSchedulesRequest, opts ...grpc.CallOption) (*ListBackupSchedulesResponse, error)
+}
+
+type databaseAdminClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewDatabaseAdminClient(cc grpc.ClientConnInterface) DatabaseAdminClient {
+ return &databaseAdminClient{cc}
+}
+
+func (c *databaseAdminClient) ListDatabases(ctx context.Context, in *ListDatabasesRequest, opts ...grpc.CallOption) (*ListDatabasesResponse, error) {
+ out := new(ListDatabasesResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/ListDatabases", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) CreateDatabase(ctx context.Context, in *CreateDatabaseRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error) {
+ out := new(longrunningpb.Operation)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/CreateDatabase", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) GetDatabase(ctx context.Context, in *GetDatabaseRequest, opts ...grpc.CallOption) (*Database, error) {
+ out := new(Database)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/GetDatabase", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) UpdateDatabase(ctx context.Context, in *UpdateDatabaseRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error) {
+ out := new(longrunningpb.Operation)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateDatabase", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) UpdateDatabaseDdl(ctx context.Context, in *UpdateDatabaseDdlRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error) {
+ out := new(longrunningpb.Operation)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateDatabaseDdl", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) DropDatabase(ctx context.Context, in *DropDatabaseRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/DropDatabase", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) GetDatabaseDdl(ctx context.Context, in *GetDatabaseDdlRequest, opts ...grpc.CallOption) (*GetDatabaseDdlResponse, error) {
+ out := new(GetDatabaseDdlResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/GetDatabaseDdl", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) SetIamPolicy(ctx context.Context, in *iampb.SetIamPolicyRequest, opts ...grpc.CallOption) (*iampb.Policy, error) {
+ out := new(iampb.Policy)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/SetIamPolicy", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) GetIamPolicy(ctx context.Context, in *iampb.GetIamPolicyRequest, opts ...grpc.CallOption) (*iampb.Policy, error) {
+ out := new(iampb.Policy)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/GetIamPolicy", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) TestIamPermissions(ctx context.Context, in *iampb.TestIamPermissionsRequest, opts ...grpc.CallOption) (*iampb.TestIamPermissionsResponse, error) {
+ out := new(iampb.TestIamPermissionsResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/TestIamPermissions", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) CreateBackup(ctx context.Context, in *CreateBackupRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error) {
+ out := new(longrunningpb.Operation)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/CreateBackup", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) CopyBackup(ctx context.Context, in *CopyBackupRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error) {
+ out := new(longrunningpb.Operation)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/CopyBackup", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) GetBackup(ctx context.Context, in *GetBackupRequest, opts ...grpc.CallOption) (*Backup, error) {
+ out := new(Backup)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/GetBackup", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) UpdateBackup(ctx context.Context, in *UpdateBackupRequest, opts ...grpc.CallOption) (*Backup, error) {
+ out := new(Backup)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateBackup", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) DeleteBackup(ctx context.Context, in *DeleteBackupRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/DeleteBackup", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) ListBackups(ctx context.Context, in *ListBackupsRequest, opts ...grpc.CallOption) (*ListBackupsResponse, error) {
+ out := new(ListBackupsResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/ListBackups", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) RestoreDatabase(ctx context.Context, in *RestoreDatabaseRequest, opts ...grpc.CallOption) (*longrunningpb.Operation, error) {
+ out := new(longrunningpb.Operation)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/RestoreDatabase", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) ListDatabaseOperations(ctx context.Context, in *ListDatabaseOperationsRequest, opts ...grpc.CallOption) (*ListDatabaseOperationsResponse, error) {
+ out := new(ListDatabaseOperationsResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/ListDatabaseOperations", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) ListBackupOperations(ctx context.Context, in *ListBackupOperationsRequest, opts ...grpc.CallOption) (*ListBackupOperationsResponse, error) {
+ out := new(ListBackupOperationsResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/ListBackupOperations", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) ListDatabaseRoles(ctx context.Context, in *ListDatabaseRolesRequest, opts ...grpc.CallOption) (*ListDatabaseRolesResponse, error) {
+ out := new(ListDatabaseRolesResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/ListDatabaseRoles", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) CreateBackupSchedule(ctx context.Context, in *CreateBackupScheduleRequest, opts ...grpc.CallOption) (*BackupSchedule, error) {
+ out := new(BackupSchedule)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/CreateBackupSchedule", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) GetBackupSchedule(ctx context.Context, in *GetBackupScheduleRequest, opts ...grpc.CallOption) (*BackupSchedule, error) {
+ out := new(BackupSchedule)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/GetBackupSchedule", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) UpdateBackupSchedule(ctx context.Context, in *UpdateBackupScheduleRequest, opts ...grpc.CallOption) (*BackupSchedule, error) {
+ out := new(BackupSchedule)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateBackupSchedule", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) DeleteBackupSchedule(ctx context.Context, in *DeleteBackupScheduleRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+ out := new(emptypb.Empty)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/DeleteBackupSchedule", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *databaseAdminClient) ListBackupSchedules(ctx context.Context, in *ListBackupSchedulesRequest, opts ...grpc.CallOption) (*ListBackupSchedulesResponse, error) {
+ out := new(ListBackupSchedulesResponse)
+ err := c.cc.Invoke(ctx, "/google.spanner.admin.database.v1.DatabaseAdmin/ListBackupSchedules", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// DatabaseAdminServer is the server API for DatabaseAdmin service.
+type DatabaseAdminServer interface {
+ // Lists Cloud Spanner databases.
+ ListDatabases(context.Context, *ListDatabasesRequest) (*ListDatabasesResponse, error)
+ // Creates a new Cloud Spanner database and starts to prepare it for serving.
+ // The returned [long-running operation][google.longrunning.Operation] will
+ // have a name of the format `/operations/` and
+ // can be used to track preparation of the database. The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [CreateDatabaseMetadata][google.spanner.admin.database.v1.CreateDatabaseMetadata].
+ // The [response][google.longrunning.Operation.response] field type is
+ // [Database][google.spanner.admin.database.v1.Database], if successful.
+ CreateDatabase(context.Context, *CreateDatabaseRequest) (*longrunningpb.Operation, error)
+ // Gets the state of a Cloud Spanner database.
+ GetDatabase(context.Context, *GetDatabaseRequest) (*Database, error)
+ // Updates a Cloud Spanner database. The returned
+ // [long-running operation][google.longrunning.Operation] can be used to track
+ // the progress of updating the database. If the named database does not
+ // exist, returns `NOT_FOUND`.
+ //
+ // While the operation is pending:
+ //
+ // - The database's
+ // [reconciling][google.spanner.admin.database.v1.Database.reconciling]
+ // field is set to true.
+ // - Cancelling the operation is best-effort. If the cancellation succeeds,
+ // the operation metadata's
+ // [cancel_time][google.spanner.admin.database.v1.UpdateDatabaseMetadata.cancel_time]
+ // is set, the updates are reverted, and the operation terminates with a
+ // `CANCELLED` status.
+ // - New UpdateDatabase requests will return a `FAILED_PRECONDITION` error
+ // until the pending operation is done (returns successfully or with
+ // error).
+ // - Reading the database via the API continues to give the pre-request
+ // values.
+ //
+ // Upon completion of the returned operation:
+ //
+ // - The new values are in effect and readable via the API.
+ // - The database's
+ // [reconciling][google.spanner.admin.database.v1.Database.reconciling]
+ // field becomes false.
+ //
+ // The returned [long-running operation][google.longrunning.Operation] will
+ // have a name of the format
+ // `projects//instances//databases//operations/`
+ // and can be used to track the database modification. The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [UpdateDatabaseMetadata][google.spanner.admin.database.v1.UpdateDatabaseMetadata].
+ // The [response][google.longrunning.Operation.response] field type is
+ // [Database][google.spanner.admin.database.v1.Database], if successful.
+ UpdateDatabase(context.Context, *UpdateDatabaseRequest) (*longrunningpb.Operation, error)
+ // Updates the schema of a Cloud Spanner database by
+ // creating/altering/dropping tables, columns, indexes, etc. The returned
+ // [long-running operation][google.longrunning.Operation] will have a name of
+ // the format `/operations/` and can be used to
+ // track execution of the schema change(s). The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [UpdateDatabaseDdlMetadata][google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata].
+ // The operation has no response.
+ UpdateDatabaseDdl(context.Context, *UpdateDatabaseDdlRequest) (*longrunningpb.Operation, error)
+ // Drops (aka deletes) a Cloud Spanner database.
+ // Completed backups for the database will be retained according to their
+ // `expire_time`.
+ // Note: Cloud Spanner might continue to accept requests for a few seconds
+ // after the database has been deleted.
+ DropDatabase(context.Context, *DropDatabaseRequest) (*emptypb.Empty, error)
+ // Returns the schema of a Cloud Spanner database as a list of formatted
+ // DDL statements. This method does not show pending schema updates, those may
+ // be queried using the [Operations][google.longrunning.Operations] API.
+ GetDatabaseDdl(context.Context, *GetDatabaseDdlRequest) (*GetDatabaseDdlResponse, error)
+ // Sets the access control policy on a database or backup resource.
+ // Replaces any existing policy.
+ //
+ // Authorization requires `spanner.databases.setIamPolicy`
+ // permission on [resource][google.iam.v1.SetIamPolicyRequest.resource].
+ // For backups, authorization requires `spanner.backups.setIamPolicy`
+ // permission on [resource][google.iam.v1.SetIamPolicyRequest.resource].
+ SetIamPolicy(context.Context, *iampb.SetIamPolicyRequest) (*iampb.Policy, error)
+ // Gets the access control policy for a database or backup resource.
+ // Returns an empty policy if a database or backup exists but does not have a
+ // policy set.
+ //
+ // Authorization requires `spanner.databases.getIamPolicy` permission on
+ // [resource][google.iam.v1.GetIamPolicyRequest.resource].
+ // For backups, authorization requires `spanner.backups.getIamPolicy`
+ // permission on [resource][google.iam.v1.GetIamPolicyRequest.resource].
+ GetIamPolicy(context.Context, *iampb.GetIamPolicyRequest) (*iampb.Policy, error)
+ // Returns permissions that the caller has on the specified database or backup
+ // resource.
+ //
+ // Attempting this RPC on a non-existent Cloud Spanner database will
+ // result in a NOT_FOUND error if the user has
+ // `spanner.databases.list` permission on the containing Cloud
+ // Spanner instance. Otherwise returns an empty set of permissions.
+ // Calling this method on a backup that does not exist will
+ // result in a NOT_FOUND error if the user has
+ // `spanner.backups.list` permission on the containing instance.
+ TestIamPermissions(context.Context, *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error)
+ // Starts creating a new Cloud Spanner Backup.
+ // The returned backup [long-running operation][google.longrunning.Operation]
+ // will have a name of the format
+ // `projects//instances//backups//operations/`
+ // and can be used to track creation of the backup. The
+ // [metadata][google.longrunning.Operation.metadata] field type is
+ // [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata].
+ // The [response][google.longrunning.Operation.response] field type is
+ // [Backup][google.spanner.admin.database.v1.Backup], if successful.
+ // Cancelling the returned operation will stop the creation and delete the
+ // backup. There can be only one pending backup creation per database. Backup
+ // creation of different databases can run concurrently.
+ CreateBackup(context.Context, *CreateBackupRequest) (*longrunningpb.Operation, error)
+ // Starts copying a Cloud Spanner Backup.
+ // The returned backup [long-running operation][google.longrunning.Operation]
+ // will have a name of the format
+ // `projects//instances//backups//operations/