From 3e655116af54b344eeb5134b716f888f5a501731 Mon Sep 17 00:00:00 2001 From: Artem Gavrilov Date: Tue, 1 Nov 2022 13:17:50 +0200 Subject: [PATCH] PMM-10742 PMM-10470 PMM-10921 PMM-8553 PMM-10824 PMM-10944 Backups (#1320) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * PMM-10742 Fix pbmV2 error messages handling * PMM-10470 physical backup restore (#1317) * use describe-restore for restore metadata * allow restore on managed * increase time to cover for physical restores waits * revert interval * fix formatting * PMM-10470 Simplify backups cancel detection, fix restores * PMM-10470 Cleanup Co-authored-by: Artem Gavrilov * Remove invalid test * Improve validation * Fix * PMM-8553 List PITR timeranges (#1213) * generate proto files for pitr API Signed-off-by: michael.okoko * implement timeranges parsing and returns Signed-off-by: michael.okoko * move pitr components to location protobuf * add happy path tests * add tests for services * move pitr listing to artifacts service * fix endpoint url * abstract storage layer operations, add scaffold for tests * improve test cases * regenerate files * fix storage service test * regenerate files * update mock name * add timeline merges * satisfy go linter * fix mock naming * unexport compression types * regen files * rename timelines to timeranges * removed named returns * use artifact name as prefix * rename minio service to client * remove replica set from timeranges result * remove nolint directive * satisfy exhaust struct linter * recreate minio client in methods for consistency * better interface name * match file name to struct * improve comments * fix tests * remove extra call to FileStat previously, we will make an extra API call to storage to get each file's metadata. This is unnecessary as minio already provides same metadata in the original list call, hence we only need one API call to get all that info. * improve log message * fix tests * improved object names Signed-off-by: michael.okoko * Fix pbm backups * Cleanup * PMM-10824 restore pitr backups (#1300) * Added local storage support for MongoDB. * Added local storage support for MongoDB. * Added local storage support for MongoDB. * Added local storage support for MongoDB. * Added local storage support for MongoDB. * Fix linter suggestions. * Refactoring. * Refactoring. * Refactoring. * Refactoring. * Refactoring, improving tests. * Added license info. * Fix bug. * Fix linter warnings. * Fix linter warnings. * Added, improved tests. * Fix after merge. * Removed PMMServerLocationConfig, some minor changes. * Fix tests, add location prefix. * Fix tests. * Fix tests. * Set new agent version. * PMM-10824 Added restore PITR feature. * Fix after merge. * Fix after merge. * Fix after merge. * Fix after merge. * Upgrade dependencies. * Upgrade dependencies. * Added some precondition checks. * Fix after merge. * Fix after merge. * Fix tests. * Refactored, added tests. * Minor changes. * Refactoring. * Reformatting. * Minor changes. * Minor changes. * Fix after merge. * Added handling for another one pbm error. Co-authored-by: Fábio Silva * Backup fixes (#1329) Fix bugs, added tests * Prevent PITR restores for local storages * PMM-10944 Restart exporters after restore (#1344) * Restart agents after mongoDB restore * Add missing licence header * Regen * Refactoring * Fix test * Increase pbm timeouts, add logic to prevent overlapping of actions on pbm (#1347) * Prevent running restore if there are scheduled backups, wait for pbm ops complete before running restore. * Disable scheduled backups before starting restore * Make artifact as errored if we failed to start backup job * Update managed/services/backup/compatibility_helpers.go Co-authored-by: Michael Okoko <10512379+idoqo@users.noreply.github.com> Co-authored-by: Artem Gavrilov Co-authored-by: Michael Okoko <10512379+idoqo@users.noreply.github.com> * Fix * Remove server local storage from code (#1340) * Removed PMMServerLocationConfig from API. * Rename config PMMClient to Filesystem. * Rename config PMMClient to Filesystem. * Merge. * Minor changes. * Make backups API GA * Fix test * Renamed backupv1beta1 to backuppb in the code. (#1349) * Include backups and alerting APIs to swager.json * Refactoring * Check pmm agent version for pitr restore (#1356) * Check pmm-agent version for PITR restore. * Refactoring Co-authored-by: Artem Gavrilov * Fix time parsing format. (#1355) * Fix time parsing format. * Fix tests. * Changed PBM response parsing logic. * Changed format to constant. * Add todo Co-authored-by: Artem Gavrilov * Show correct error when artifact not ready for restore. (#1359) * Show correct error when artifact not ready for restore. * Add license header. Signed-off-by: michael.okoko Co-authored-by: Michael Okoko <10512379+idoqo@users.noreply.github.com> Co-authored-by: Fábio Silva Co-authored-by: michael.okoko Co-authored-by: Pavel Khripkov <94828791+PavelKhripkov@users.noreply.github.com> --- Makefile.include | 6 +- agent/agents/supervisor/supervisor.go | 24 + agent/client/client.go | 19 +- agent/client/deps.go | 1 + agent/client/mock_supervisor_test.go | 5 + agent/runner/jobs/backup_location.go | 14 +- agent/runner/jobs/deps.go | 19 + agent/runner/jobs/mongodb_backup_job.go | 30 +- agent/runner/jobs/mongodb_backup_job_test.go | 12 +- agent/runner/jobs/mongodb_restore_job.go | 136 +- agent/runner/jobs/pbm_helpers.go | 247 +- agent/runner/jobs/pbm_helpers_test.go | 100 +- api-tests/management/backup/backups_test.go | 2 +- api-tests/management/backup/locations_test.go | 50 +- api/agentpb/agent.pb.go | 262 +- api/agentpb/agent.proto | 10 +- api/agentpb/agent.validator.pb.go | 18 +- api/managementpb/backup/artifacts.pb.go | 469 ++- api/managementpb/backup/artifacts.pb.gw.go | 93 +- api/managementpb/backup/artifacts.proto | 28 +- .../backup/artifacts.validator.pb.go | 31 +- api/managementpb/backup/artifacts_grpc.pb.go | 51 +- api/managementpb/backup/backups.pb.go | 817 ++--- api/managementpb/backup/backups.pb.gw.go | 36 +- api/managementpb/backup/backups.proto | 6 +- .../backup/backups.validator.pb.go | 7 +- api/managementpb/backup/backups_grpc.pb.go | 36 +- api/managementpb/backup/common.pb.go | 50 +- api/managementpb/backup/common.proto | 4 +- .../backup/common.validator.pb.go | 2 +- api/managementpb/backup/errors.pb.go | 67 +- api/managementpb/backup/errors.proto | 4 +- .../backup/errors.validator.pb.go | 2 +- api/managementpb/backup/json/backup.json | 206 +- .../json/client/artifacts/artifacts_client.go | 39 + .../list_pitr_timeranges_parameters.go | 144 + .../list_pitr_timeranges_responses.go | 475 +++ .../backups/restore_backup_responses.go | 26 + .../locations/add_location_responses.go | 132 +- .../locations/change_location_responses.go | 132 +- .../locations/list_locations_responses.go | 132 +- .../test_location_config_responses.go | 132 +- api/managementpb/backup/locations.pb.go | 693 ++--- api/managementpb/backup/locations.pb.gw.go | 24 +- api/managementpb/backup/locations.proto | 46 +- .../backup/locations.validator.pb.go | 59 +- api/managementpb/backup/locations_grpc.pb.go | 24 +- api/managementpb/backup/restores.pb.go | 181 +- api/managementpb/backup/restores.pb.gw.go | 8 +- api/managementpb/backup/restores.proto | 4 +- .../backup/restores.validator.pb.go | 2 +- api/managementpb/backup/restores_grpc.pb.go | 8 +- api/swagger/swagger-dev-only.json | 162 +- api/swagger/swagger-dev.json | 162 +- api/swagger/swagger.json | 2641 +++++++++++++++++ descriptor.bin | Bin 652473 -> 656338 bytes managed/cmd/pmm-managed/main.go | 31 +- managed/models/database.go | 8 + managed/models/location_helpers.go | 18 +- managed/models/location_helpers_test.go | 22 +- managed/models/location_model.go | 24 +- managed/models/location_model_reform.go | 10 +- managed/models/restore_history_helpers.go | 16 +- .../models/restore_history_helpers_test.go | 12 +- managed/models/restore_history_model.go | 13 +- .../models/restore_history_model_reform.go | 13 +- managed/services/agents/jobs.go | 61 +- managed/services/backup/backup_service.go | 129 +- .../services/backup/backup_service_test.go | 391 ++- .../services/backup/compatibility_helpers.go | 15 - .../services/backup/compatibility_service.go | 2 +- managed/services/backup/deps.go | 21 +- managed/services/backup/errors.go | 45 + .../services/backup/mock_jobs_service_test.go | 10 +- .../backup/mock_pitr_location_client_test.go | 60 + .../mock_pitr_timerange_service_test.go | 39 + .../services/backup/pitr_timerange_service.go | 357 +++ .../backup/pitr_timerange_service_test.go | 495 +++ .../management/backup/artifacts_service.go | 104 +- .../backup/artifacts_service_test.go | 127 + .../management/backup/backups_service.go | 237 +- .../management/backup/backups_service_test.go | 62 +- managed/services/management/backup/deps.go | 10 +- .../management/backup/locations_service.go | 64 +- .../backup/locations_service_test.go | 122 +- .../backup/mock_backup_service_test.go | 15 +- .../mock_pitr_timerange_service_test.go | 40 + .../backup/restore_history_service.go | 28 +- managed/services/minio/client.go | 211 ++ managed/services/minio/service.go | 129 - 90 files changed, 8210 insertions(+), 2821 deletions(-) create mode 100644 agent/runner/jobs/deps.go create mode 100644 api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_parameters.go create mode 100644 api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_responses.go create mode 100644 managed/services/backup/errors.go create mode 100644 managed/services/backup/mock_pitr_location_client_test.go create mode 100644 managed/services/backup/mock_pitr_timerange_service_test.go create mode 100644 managed/services/backup/pitr_timerange_service.go create mode 100644 managed/services/backup/pitr_timerange_service_test.go create mode 100644 managed/services/management/backup/artifacts_service_test.go create mode 100644 managed/services/management/backup/mock_pitr_timerange_service_test.go create mode 100644 managed/services/minio/client.go delete mode 100644 managed/services/minio/service.go diff --git a/Makefile.include b/Makefile.include index 677a8e54f2..e3e97e52d1 100644 --- a/Makefile.include +++ b/Makefile.include @@ -57,13 +57,15 @@ gen: clean ## Generate files. done # generate public API spec, omit agentlocalpb (always private), - # and managementpb/dbaas, managementpb/ia, managementpb/alerting, managementpb/backup , managementpb/azure and qanpb (not v1 yet) + # and managementpb/dbaas, managementpb/ia, managementpb/azure and qanpb (not v1 yet) bin/swagger mixin --output=api/swagger/swagger.json \ api/swagger/header.json \ api/serverpb/json/serverpb.json \ api/userpb/json/userpb.json \ api/inventorypb/json/inventorypb.json \ - api/managementpb/json/managementpb.json + api/managementpb/json/managementpb.json \ + api/managementpb/backup/json/backup.json \ + api/managementpb/alerting/json/alerting.json bin/swagger validate api/swagger/swagger.json bin/swagger-order --output=api/swagger/swagger.json api/swagger/swagger.json diff --git a/agent/agents/supervisor/supervisor.go b/agent/agents/supervisor/supervisor.go index ecf329b774..478fbc2308 100644 --- a/agent/agents/supervisor/supervisor.go +++ b/agent/agents/supervisor/supervisor.go @@ -213,6 +213,30 @@ func (s *Supervisor) SetState(state *agentpb.SetStateRequest) { s.setBuiltinAgents(state.BuiltinAgents) } +// RestartAgents restarts all existing agents. +func (s *Supervisor) RestartAgents() { + s.rw.Lock() + defer s.rw.Unlock() + + for id, agent := range s.agentProcesses { + agent.cancel() + <-agent.done + + if err := s.startProcess(id, agent.requestedState, agent.listenPort); err != nil { + s.l.Errorf("Failed to restart Agent: %s.", err) + } + } + + for id, agent := range s.builtinAgents { + agent.cancel() + <-agent.done + + if err := s.startBuiltin(id, agent.requestedState); err != nil { + s.l.Errorf("Failed to restart Agent: %s.", err) + } + } +} + func (s *Supervisor) storeLastStatus(agentID string, status inventorypb.AgentStatus) { s.arw.Lock() defer s.arw.Unlock() diff --git a/agent/client/client.go b/agent/client/client.go index 9d3dcfd876..ae924d9d49 100644 --- a/agent/client/client.go +++ b/agent/client/client.go @@ -543,10 +543,10 @@ func (c *Client) handleStartJobRequest(p *agentpb.StartJobRequest) error { BucketName: cfg.S3Config.BucketName, BucketRegion: cfg.S3Config.BucketRegion, } - case *agentpb.StartJobRequest_MongoDBBackup_PmmClientConfig: - locationConfig.Type = jobs.PMMClientBackupLocationType - locationConfig.LocalStorageConfig = &jobs.PMMClientBackupLocationConfig{ - Path: cfg.PmmClientConfig.Path, + case *agentpb.StartJobRequest_MongoDBBackup_FilesystemConfig: + locationConfig.Type = jobs.FilesystemBackupLocationType + locationConfig.FilesystemStorageConfig = &jobs.FilesystemBackupLocationConfig{ + Path: cfg.FilesystemConfig.Path, } default: return errors.Errorf("unknown location config: %T", j.MongodbBackup.LocationConfig) @@ -575,10 +575,10 @@ func (c *Client) handleStartJobRequest(p *agentpb.StartJobRequest) error { BucketName: cfg.S3Config.BucketName, BucketRegion: cfg.S3Config.BucketRegion, } - case *agentpb.StartJobRequest_MongoDBRestoreBackup_PmmClientConfig: - locationConfig.Type = jobs.PMMClientBackupLocationType - locationConfig.LocalStorageConfig = &jobs.PMMClientBackupLocationConfig{ - Path: cfg.PmmClientConfig.Path, + case *agentpb.StartJobRequest_MongoDBRestoreBackup_FilesystemConfig: + locationConfig.Type = jobs.FilesystemBackupLocationType + locationConfig.FilesystemStorageConfig = &jobs.FilesystemBackupLocationConfig{ + Path: cfg.FilesystemConfig.Path, } default: return errors.Errorf("unknown location config: %T", j.MongodbRestoreBackup.LocationConfig) @@ -591,7 +591,8 @@ func (c *Client) handleStartJobRequest(p *agentpb.StartJobRequest) error { Port: int(j.MongodbRestoreBackup.Port), Socket: j.MongodbRestoreBackup.Socket, } - job = jobs.NewMongoDBRestoreJob(p.JobId, timeout, j.MongodbRestoreBackup.Name, dbConnCfg, locationConfig) + + job = jobs.NewMongoDBRestoreJob(p.JobId, timeout, j.MongodbRestoreBackup.Name, j.MongodbRestoreBackup.PitrTimestamp.AsTime(), dbConnCfg, locationConfig, c.supervisor) default: return errors.Errorf("unknown job type: %T", j) } diff --git a/agent/client/deps.go b/agent/client/deps.go index 2cd2e9d9d2..b0e5d0f216 100644 --- a/agent/client/deps.go +++ b/agent/client/deps.go @@ -46,6 +46,7 @@ type supervisor interface { Changes() <-chan *agentpb.StateChangedRequest QANRequests() <-chan *agentpb.QANCollectRequest SetState(*agentpb.SetStateRequest) + RestartAgents() AgentLogByID(string) ([]string, uint) // Collector added to use client as Prometheus collector prometheus.Collector diff --git a/agent/client/mock_supervisor_test.go b/agent/client/mock_supervisor_test.go index 1460ca2df4..4e9b8418bc 100644 --- a/agent/client/mock_supervisor_test.go +++ b/agent/client/mock_supervisor_test.go @@ -79,6 +79,11 @@ func (_m *mockSupervisor) QANRequests() <-chan *agentpb.QANCollectRequest { return r0 } +// RestartAgents provides a mock function with given fields: +func (_m *mockSupervisor) RestartAgents() { + _m.Called() +} + // SetState provides a mock function with given fields: _a0 func (_m *mockSupervisor) SetState(_a0 *agentpb.SetStateRequest) { _m.Called(_a0) diff --git a/agent/runner/jobs/backup_location.go b/agent/runner/jobs/backup_location.go index 08ed79f6ea..684525ae29 100644 --- a/agent/runner/jobs/backup_location.go +++ b/agent/runner/jobs/backup_location.go @@ -19,8 +19,8 @@ type BackupLocationType string // BackupLocation types. Same as in managed/models/location_model.go. const ( - S3BackupLocationType BackupLocationType = "s3" - PMMClientBackupLocationType BackupLocationType = "pmm-client" + S3BackupLocationType BackupLocationType = "s3" + FilesystemBackupLocationType BackupLocationType = "filesystem" ) // S3LocationConfig contains required properties for accessing S3 Bucket. @@ -32,14 +32,14 @@ type S3LocationConfig struct { BucketRegion string } -// PMMClientBackupLocationConfig contains config for local storage -type PMMClientBackupLocationConfig struct { +// FilesystemBackupLocationConfig contains config for local storage +type FilesystemBackupLocationConfig struct { Path string } // BackupLocationConfig groups all backup locations configs. type BackupLocationConfig struct { - Type BackupLocationType - S3Config *S3LocationConfig - LocalStorageConfig *PMMClientBackupLocationConfig + Type BackupLocationType + S3Config *S3LocationConfig + FilesystemStorageConfig *FilesystemBackupLocationConfig } diff --git a/agent/runner/jobs/deps.go b/agent/runner/jobs/deps.go new file mode 100644 index 0000000000..b161813b47 --- /dev/null +++ b/agent/runner/jobs/deps.go @@ -0,0 +1,19 @@ +// Copyright 2019 Percona 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 jobs + +type agentsRestarter interface { + RestartAgents() +} diff --git a/agent/runner/jobs/mongodb_backup_job.go b/agent/runner/jobs/mongodb_backup_job.go index 68252549eb..53ee3b7c4d 100644 --- a/agent/runner/jobs/mongodb_backup_job.go +++ b/agent/runner/jobs/mongodb_backup_job.go @@ -19,6 +19,7 @@ import ( "context" "io" "net/url" + "os" "os/exec" "sync/atomic" "time" @@ -28,7 +29,7 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "github.com/percona/pmm/api/agentpb" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" ) const ( @@ -48,7 +49,7 @@ type MongoDBBackupJob struct { locationConfig BackupLocationConfig pitr bool logChunkID uint32 - dataModel backupv1beta1.DataModel + dataModel backuppb.DataModel } // NewMongoDBBackupJob creates new Job for MongoDB backup. @@ -59,12 +60,12 @@ func NewMongoDBBackupJob( dbConfig DBConnConfig, locationConfig BackupLocationConfig, pitr bool, - dataModel backupv1beta1.DataModel, + dataModel backuppb.DataModel, ) (*MongoDBBackupJob, error) { - if dataModel != backupv1beta1.DataModel_PHYSICAL && dataModel != backupv1beta1.DataModel_LOGICAL { + if dataModel != backuppb.DataModel_PHYSICAL && dataModel != backuppb.DataModel_LOGICAL { return nil, errors.Errorf("'%s' is not a supported data model for MongoDB backups", dataModel) } - if dataModel != backupv1beta1.DataModel_LOGICAL && pitr { + if dataModel != backuppb.DataModel_LOGICAL && pitr { return nil, errors.Errorf("PITR is only supported for logical backups") } return &MongoDBBackupJob{ @@ -106,12 +107,19 @@ func (j *MongoDBBackupJob) Run(ctx context.Context, send Send) error { if err != nil { return errors.WithStack(err) } - if err := pbmConfigure(ctx, j.l, j.dbURL, conf); err != nil { + + confFile, err := writePBMConfigFile(conf) + if err != nil { + return errors.WithStack(err) + } + defer os.Remove(confFile) //nolint:errcheck + + if err := pbmConfigure(ctx, j.l, j.dbURL, confFile); err != nil { return errors.Wrap(err, "failed to configure pbm") } rCtx, cancel := context.WithTimeout(ctx, resyncTimeout) - if err := waitForPBMState(rCtx, j.l, j.dbURL, pbmNoRunningOperations); err != nil { + if err := waitForPBMNoRunningOperations(rCtx, j.l, j.dbURL); err != nil { cancel() return errors.Wrap(err, "failed to wait configuration completion") } @@ -131,7 +139,7 @@ func (j *MongoDBBackupJob) Run(ctx context.Context, send Send) error { } }() - if err := waitForPBMState(ctx, j.l, j.dbURL, pbmBackupFinished(pbmBackupOut.Name)); err != nil { + if err := waitForPBMBackup(ctx, j.l, j.dbURL, pbmBackupOut.Name); err != nil { j.sendLog(send, err.Error(), false) return errors.Wrap(err, "failed to wait backup completion") } @@ -156,11 +164,11 @@ func (j *MongoDBBackupJob) startBackup(ctx context.Context) (*pbmBackup, error) pbmArgs := []string{"backup"} switch j.dataModel { - case backupv1beta1.DataModel_PHYSICAL: + case backuppb.DataModel_PHYSICAL: pbmArgs = append(pbmArgs, "--type=physical") - case backupv1beta1.DataModel_LOGICAL: + case backuppb.DataModel_LOGICAL: pbmArgs = append(pbmArgs, "--type=logical") - case backupv1beta1.DataModel_DATA_MODEL_INVALID: + case backuppb.DataModel_DATA_MODEL_INVALID: default: return nil, errors.Errorf("'%s' is not a supported data model for backups", j.dataModel) } diff --git a/agent/runner/jobs/mongodb_backup_job_test.go b/agent/runner/jobs/mongodb_backup_job_test.go index 094b9c8d83..d8cc5b1ba2 100644 --- a/agent/runner/jobs/mongodb_backup_job_test.go +++ b/agent/runner/jobs/mongodb_backup_job_test.go @@ -20,7 +20,7 @@ import ( "github.com/stretchr/testify/assert" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" ) func TestCreateDBURL(t *testing.T) { @@ -83,33 +83,33 @@ func TestNewMongoDBBackupJob(t *testing.T) { tests := []struct { name string dbConfig DBConnConfig - dataModel backupv1beta1.DataModel + dataModel backuppb.DataModel pitr bool errMsg string }{ { name: "logical backup model", dbConfig: DBConnConfig{}, - dataModel: backupv1beta1.DataModel_LOGICAL, + dataModel: backuppb.DataModel_LOGICAL, errMsg: "", }, { name: "physical backup model", dbConfig: DBConnConfig{}, - dataModel: backupv1beta1.DataModel_PHYSICAL, + dataModel: backuppb.DataModel_PHYSICAL, errMsg: "", }, { name: "invalid backup model", dbConfig: DBConnConfig{}, - dataModel: backupv1beta1.DataModel_DATA_MODEL_INVALID, + dataModel: backuppb.DataModel_DATA_MODEL_INVALID, errMsg: "'DATA_MODEL_INVALID' is not a supported data model for MongoDB backups", }, { name: "pitr fails for physical backups", dbConfig: DBConnConfig{}, pitr: true, - dataModel: backupv1beta1.DataModel_PHYSICAL, + dataModel: backuppb.DataModel_PHYSICAL, errMsg: "PITR is only supported for logical backups", }, } diff --git a/agent/runner/jobs/mongodb_restore_job.go b/agent/runner/jobs/mongodb_restore_job.go index 325b7554bf..9758936e89 100644 --- a/agent/runner/jobs/mongodb_restore_job.go +++ b/agent/runner/jobs/mongodb_restore_job.go @@ -16,8 +16,11 @@ package jobs import ( "context" + "fmt" "net/url" + "os" "os/exec" + "strings" "time" "github.com/pkg/errors" @@ -27,25 +30,42 @@ import ( "github.com/percona/pmm/api/agentpb" ) +const ( + listCheckInterval = 1 * time.Second + maxListChecks = 100 +) + // MongoDBRestoreJob implements Job for MongoDB restore. type MongoDBRestoreJob struct { - id string - timeout time.Duration - l *logrus.Entry - name string - dbURL *url.URL - locationConfig BackupLocationConfig + id string + timeout time.Duration + l *logrus.Entry + name string + pitrTimestamp time.Time + dbURL *url.URL + locationConfig BackupLocationConfig + agentsRestarter agentsRestarter } // NewMongoDBRestoreJob creates new Job for MongoDB backup restore. -func NewMongoDBRestoreJob(id string, timeout time.Duration, name string, dbConfig DBConnConfig, locationConfig BackupLocationConfig) *MongoDBRestoreJob { +func NewMongoDBRestoreJob( + id string, + timeout time.Duration, + name string, + pitrTimestamp time.Time, + dbConfig DBConnConfig, + locationConfig BackupLocationConfig, + restarter agentsRestarter, +) *MongoDBRestoreJob { return &MongoDBRestoreJob{ - id: id, - timeout: timeout, - l: logrus.WithFields(logrus.Fields{"id": id, "type": "mongodb_restore", "name": name}), - name: name, - dbURL: createDBURL(dbConfig), - locationConfig: locationConfig, + id: id, + timeout: timeout, + l: logrus.WithFields(logrus.Fields{"id": id, "type": "mongodb_restore", "name": name}), + name: name, + pitrTimestamp: pitrTimestamp, + dbURL: createDBURL(dbConfig), + locationConfig: locationConfig, + agentsRestarter: restarter, } } @@ -74,28 +94,36 @@ func (j *MongoDBRestoreJob) Run(ctx context.Context, send Send) error { if err != nil { return errors.WithStack(err) } - if err := pbmConfigure(ctx, j.l, j.dbURL, conf); err != nil { + + confFile, err := writePBMConfigFile(conf) + if err != nil { + return errors.WithStack(err) + } + defer os.Remove(confFile) //nolint:errcheck + + if err := pbmConfigure(ctx, j.l, j.dbURL, confFile); err != nil { return errors.Wrap(err, "failed to configure pbm") } rCtx, cancel := context.WithTimeout(ctx, resyncTimeout) - if err := waitForPBMState(rCtx, j.l, j.dbURL, pbmNoRunningOperations); err != nil { + if err := waitForPBMNoRunningOperations(rCtx, j.l, j.dbURL); err != nil { cancel() return errors.Wrap(err, "failed to wait pbm configuration completion") } cancel() - backupName, err := j.findSnapshotName(ctx) + snapshot, err := j.findSnapshot(ctx) if err != nil { return errors.WithStack(err) } - restoreOut, err := j.startRestore(ctx, backupName) + defer j.agentsRestarter.RestartAgents() + restoreOut, err := j.startRestore(ctx, snapshot.Name) if err != nil { return errors.Wrap(err, "failed to start backup restore") } - if err := waitForPBMRestore(ctx, j.l, j.dbURL, restoreOut.Snapshot); err != nil { + if err := waitForPBMRestore(ctx, j.l, j.dbURL, restoreOut, snapshot.Type, confFile); err != nil { return errors.Wrap(err, "failed to wait backup restore completion") } @@ -110,29 +138,71 @@ func (j *MongoDBRestoreJob) Run(ctx context.Context, send Send) error { return nil } -func (j *MongoDBRestoreJob) findSnapshotName(ctx context.Context) (string, error) { +func (j *MongoDBRestoreJob) findSnapshot(ctx context.Context) (*pbmSnapshot, error) { j.l.Info("Finding backup entity name.") var list pbmList - if err := execPBMCommand(ctx, j.dbURL, &list, "list"); err != nil { - return "", err - } - - if len(list.Snapshots) == 0 { - return "", errors.New("failed to find backup entity") + ticker := time.NewTicker(listCheckInterval) + defer ticker.Stop() + + checks := 0 + for { + select { + case <-ticker.C: + checks++ + if err := execPBMCommand(ctx, j.dbURL, &list, "list"); err != nil { + return nil, err + } + + if len(list.Snapshots) == 0 { + j.l.Debugf("Try number %d of getting list of artifacts from PBM is failed.", checks) + if checks > maxListChecks { + return nil, errors.New("failed to find backup entity") + } + continue + } + + return &list.Snapshots[len(list.Snapshots)-1], nil + case <-ctx.Done(): + return nil, ctx.Err() + } } - - return list.Snapshots[len(list.Snapshots)-1].Name, nil } func (j *MongoDBRestoreJob) startRestore(ctx context.Context, backupName string) (*pbmRestore, error) { - j.l.Info("Starting backup restore.") + j.l.Infof("starting backup restore for: %s.", backupName) var restoreOutput pbmRestore - err := execPBMCommand(ctx, j.dbURL, &restoreOutput, "restore", backupName) - if err != nil { - return nil, errors.Wrapf(err, "pbm restore error: %v", err) + var err error + startTime := time.Now() + + ticker := time.NewTicker(statusCheckInterval) + defer ticker.Stop() + retryCount := 500 + + for { + select { + case <-ticker.C: + + if j.pitrTimestamp.Unix() == 0 { + err = execPBMCommand(ctx, j.dbURL, &restoreOutput, "restore", backupName) + } else { + err = execPBMCommand(ctx, j.dbURL, &restoreOutput, "restore", fmt.Sprintf(`--time=%s`, j.pitrTimestamp.Format("2006-01-02T15:04:05"))) + } + + if err != nil { + if strings.HasSuffix(err.Error(), "another operation in progress") && retryCount > 0 { + retryCount-- + continue + } + return nil, errors.Wrapf(err, "pbm restore error: %v", err) + } + + restoreOutput.StartedAt = startTime + return &restoreOutput, nil + + case <-ctx.Done(): + return nil, ctx.Err() + } } - - return &restoreOutput, nil } diff --git a/agent/runner/jobs/pbm_helpers.go b/agent/runner/jobs/pbm_helpers.go index f1f0938c0c..e516a4199b 100644 --- a/agent/runner/jobs/pbm_helpers.go +++ b/agent/runner/jobs/pbm_helpers.go @@ -22,6 +22,7 @@ import ( "os" "os/exec" "path" + "strings" "time" "github.com/pkg/errors" @@ -30,36 +31,38 @@ import ( ) const ( - // How many times check if backup/restore operation was started - maxBackupChecks = 10 - maxRestoreChecks = 10 - - cmdTimeout = time.Minute + cmdTimeout = 60 * time.Minute resyncTimeout = 5 * time.Minute - statusCheckInterval = 3 * time.Second + statusCheckInterval = 5 * time.Second + maxRestoreChecks = 100 ) type pbmSeverity int +type describeInfo struct { + Status string `json:"status"` + Error string `json:"error"` +} + const ( - pbmFatal pbmSeverity = iota - pbmError - pbmWarning - pbmInfo - pbmDebug + pbmFatalSeverity pbmSeverity = iota + pbmErrorSeverity + pbmWarningSeverity + pbmInfoSeverity + pbmDebugSeverity ) func (s pbmSeverity) String() string { switch s { - case pbmFatal: + case pbmFatalSeverity: return "F" - case pbmError: + case pbmErrorSeverity: return "E" - case pbmWarning: + case pbmWarningSeverity: return "W" - case pbmInfo: + case pbmInfoSeverity: return "I" - case pbmDebug: + case pbmDebugSeverity: return "D" default: return "" @@ -92,15 +95,18 @@ type pbmBackup struct { } type pbmRestore struct { - Snapshot string `json:"snapshot"` + StartedAt time.Time + Name string `json:"name"` + Snapshot string `json:"snapshot"` + PITR string `json:"point-in-time"` } type pbmSnapshot struct { Name string `json:"name"` Status string `json:"status"` - Error string `json:"error"` - CompleteTS int `json:"completeTS"` + RestoreTo int64 `json:"restoreTo"` PbmVersion string `json:"pbmVersion"` + Type string `json:"type"` } type pbmList struct { @@ -116,6 +122,7 @@ type pbmListRestore struct { Status string `json:"status"` Type string `json:"type"` Snapshot string `json:"snapshot"` + PITR int64 `json:"point-in-time"` Name string `json:"name"` Error string `json:"error"` } @@ -135,6 +142,7 @@ type pbmStatus struct { Nodes []struct { Host string `json:"host"` Agent string `json:"agent"` + Role string `json:"role"` Ok bool `json:"ok"` } `json:"nodes"` } `json:"cluster"` @@ -151,6 +159,10 @@ type pbmStatus struct { } `json:"running"` } +type pbmError struct { + Error string `json:"Error"` +} + func execPBMCommand(ctx context.Context, dbURL *url.URL, to interface{}, args ...string) error { nCtx, cancel := context.WithTimeout(ctx, cmdTimeout) defer cancel() @@ -160,9 +172,12 @@ func execPBMCommand(ctx context.Context, dbURL *url.URL, to interface{}, args .. b, err := cmd.Output() if err != nil { - var exitErr *exec.ExitError - if errors.As(err, &exitErr) { - return errors.New(string(exitErr.Stderr)) + // try to parse pbm error message + if len(b) != 0 { + var pbmErr pbmError + if e := json.Unmarshal(b, &pbmErr); e == nil { + return errors.New(pbmErr.Error) + } } return err } @@ -180,89 +195,97 @@ func retrieveLogs(ctx context.Context, dbURL *url.URL, event string) ([]pbmLogEn return logs, nil } -type pbmStatusCondition func(s pbmStatus) (bool, error) +func waitForPBMNoRunningOperations(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL) error { + l.Info("Waiting for no running pbm operations.") -func pbmNoRunningOperations(s pbmStatus) (bool, error) { - return s.Running.Status == "", nil -} + ticker := time.NewTicker(statusCheckInterval) + defer ticker.Stop() -func pbmBackupFinished(name string) pbmStatusCondition { - started := false - snapshotStarted := false - checks := 0 - return func(s pbmStatus) (bool, error) { - checks++ - if s.Running.Type == "backup" && s.Running.Name == name && s.Running.Status != "" { - started = true - } - if !started && checks > maxBackupChecks { - return false, errors.New("failed to start backup") - } - var snapshot *pbmSnapshot - for i, snap := range s.Backups.Snapshot { - if snap.Name == name { - snapshot = &s.Backups.Snapshot[i] - break + for { + select { + case <-ticker.C: + var status pbmStatus + if err := execPBMCommand(ctx, dbURL, &status, "status"); err != nil { + return errors.Wrapf(err, "pbm status error") } + if status.Running.Type == "" { + return nil + } + case <-ctx.Done(): + return ctx.Err() } - if snapshot == nil { - return false, nil - } - - switch snapshot.Status { - case "starting", "running", "dumpDone": - snapshotStarted = true - return false, nil - } - - if snapshotStarted && snapshot.Status == "error" { - return false, errors.New(snapshot.Error) - } - - return snapshot.Status == "done", nil } } -func waitForPBMState(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL, cond pbmStatusCondition) error { - l.Info("Waiting for pbm state condition.") - +func waitForPBMBackup(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL, name string) error { + l.Infof("waiting for pbm backup: %s", name) ticker := time.NewTicker(statusCheckInterval) defer ticker.Stop() + retryCount := 500 + for { select { case <-ticker.C: - var status pbmStatus - if err := execPBMCommand(ctx, dbURL, &status, "status"); err != nil { - return errors.Wrapf(err, "pbm status error") - } - done, err := cond(status) + var info describeInfo + err := execPBMCommand(ctx, dbURL, &info, "describe-backup", name) if err != nil { - return errors.Wrapf(err, "condition failed") + // for the first couple of seconds after backup process starts describe-backup command may return this error + if (strings.HasSuffix(err.Error(), "no such file") || + strings.HasSuffix(err.Error(), "file is empty")) && retryCount > 0 { + retryCount-- + continue + } + + return errors.Wrap(err, "failed to get backup status") } - if done { + + switch info.Status { + case "done": return nil + case "canceled": + return errors.New("backup was canceled") + case "error": + return errors.New(info.Error) } + case <-ctx.Done(): return ctx.Err() } } } -func waitForPBMRestore(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL, name string) error { - l.Info("Waiting for pbm restore.") +func findPITRRestore(list []pbmListRestore, restoreInfoPITRTime int64, startedAt time.Time) *pbmListRestore { + for i := len(list) - 1; i >= 0; i-- { + // TODO when PITR restore invoked with wrong timestamp pbm marks this restore operation as "snapshot" type. + if list[i].Type == "snapshot" && list[i].Snapshot != "" { + continue + } + // list[i].Name is a string which represents time the restore was started. + restoreStartedAt, err := time.Parse(time.RFC3339Nano, list[i].Name) + if err != nil { + continue + } + // Because of https://jira.percona.com/browse/PBM-723 to find our restore record in the list of all records we're checking: + // 1. We received PITR field as a response on starting process + // 2. There is a record with the same PITR field in the list of restoring records + // 3. Start time of this record is not before the time we asked for restoring. + if list[i].PITR == restoreInfoPITRTime && !restoreStartedAt.Before(startedAt) { + return &list[i] + } + } + return nil +} + +func findPITRRestoreName(ctx context.Context, dbURL *url.URL, restoreInfo *pbmRestore) (string, error) { + restoreInfoPITRTime, err := time.Parse("2006-01-02T15:04:05", restoreInfo.PITR) + if err != nil { + return "", err + } ticker := time.NewTicker(statusCheckInterval) defer ticker.Stop() - // @TODO Find from end (the newest one) until https://jira.percona.com/browse/PBM-723 is not done. - findRestore := func(list []pbmListRestore) *pbmListRestore { - for i := len(list) - 1; i >= 0; i-- { - if list[i].Snapshot == name { - return &list[i] - } - } - return nil - } + checks := 0 for { select { @@ -270,38 +293,74 @@ func waitForPBMRestore(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL checks++ var list []pbmListRestore if err := execPBMCommand(ctx, dbURL, &list, "list", "--restore"); err != nil { - return errors.Wrapf(err, "pbm status error") + return "", errors.Wrapf(err, "pbm status error") } - entry := findRestore(list) + entry := findPITRRestore(list, restoreInfoPITRTime.Unix(), restoreInfo.StartedAt) if entry == nil { if checks > maxRestoreChecks { - return errors.Errorf("failed to start restore") + return "", errors.Errorf("failed to start restore") } continue + } else { + return entry.Name, nil } - if entry.Status == "error" { - return errors.New(entry.Error) + case <-ctx.Done(): + return "", ctx.Err() + } + } +} + +func waitForPBMRestore(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL, restoreInfo *pbmRestore, backupType, confFile string) error { + l.Infof("waiting for pbm restore") + var name string + var err error + + // @TODO Do like this until https://jira.percona.com/browse/PBM-723 is not done. + if restoreInfo.PITR != "" { // TODO add more checks of PBM responses. + name, err = findPITRRestoreName(ctx, dbURL, restoreInfo) + if err != nil { + return err + } + } else { + name = restoreInfo.Name + } + + ticker := time.NewTicker(statusCheckInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + var info describeInfo + if backupType == "physical" { + err = execPBMCommand(ctx, dbURL, &info, "describe-restore", "--config="+confFile, name) + } else { + err = execPBMCommand(ctx, dbURL, &info, "describe-restore", name) } - if entry.Status == "done" { + if err != nil { + return errors.Wrap(err, "failed to get restore status") + } + + switch info.Status { + case "done": return nil + case "canceled": + return errors.New("restore was canceled") + case "error": + return errors.New(info.Error) } + case <-ctx.Done(): return ctx.Err() } } } -func pbmConfigure(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL, conf *PBMConfig) error { +func pbmConfigure(ctx context.Context, l logrus.FieldLogger, dbURL *url.URL, confFile string) error { l.Info("Configuring S3 location.") nCtx, cancel := context.WithTimeout(ctx, cmdTimeout) defer cancel() - confFile, err := writePBMConfigFile(conf) - if err != nil { - return errors.WithStack(err) - } - defer os.Remove(confFile) //nolint:errcheck - output, err := exec.CommandContext( //nolint:gosec nCtx, pbmBin, @@ -398,11 +457,11 @@ func createPBMConfig(locationConfig *BackupLocationConfig, prefix string, pitr b }, }, } - case PMMClientBackupLocationType: + case FilesystemBackupLocationType: conf.Storage = Storage{ Type: "filesystem", FileSystem: FileSystem{ - Path: path.Join(locationConfig.LocalStorageConfig.Path, prefix), + Path: path.Join(locationConfig.FilesystemStorageConfig.Path, prefix), }, } default: diff --git a/agent/runner/jobs/pbm_helpers_test.go b/agent/runner/jobs/pbm_helpers_test.go index cca86df9b7..38e8022e72 100644 --- a/agent/runner/jobs/pbm_helpers_test.go +++ b/agent/runner/jobs/pbm_helpers_test.go @@ -16,8 +16,10 @@ package jobs import ( "testing" + "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCreatePBMConfig(t *testing.T) { @@ -29,7 +31,7 @@ func TestCreatePBMConfig(t *testing.T) { BucketRegion: "test_region", } - pmmClientStorageConfig := PMMClientBackupLocationConfig{ + filesystemStorageConfig := FilesystemBackupLocationConfig{ Path: "/test/path", } @@ -69,9 +71,9 @@ func TestCreatePBMConfig(t *testing.T) { { name: "invalid location type", inputLocation: BackupLocationConfig{ - Type: BackupLocationType("invalid type"), - S3Config: &s3Config, - LocalStorageConfig: nil, + Type: BackupLocationType("invalid type"), + S3Config: &s3Config, + FilesystemStorageConfig: nil, }, inputPitr: true, output: nil, @@ -80,20 +82,20 @@ func TestCreatePBMConfig(t *testing.T) { { name: "s3 config type", inputLocation: BackupLocationConfig{ - Type: S3BackupLocationType, - S3Config: &s3Config, - LocalStorageConfig: nil, + Type: S3BackupLocationType, + S3Config: &s3Config, + FilesystemStorageConfig: nil, }, inputPitr: true, output: &expectedOutput1, errString: "", }, { - name: "pmm client config type", + name: "filesystem config type", inputLocation: BackupLocationConfig{ - Type: PMMClientBackupLocationType, - S3Config: nil, - LocalStorageConfig: &pmmClientStorageConfig, + Type: FilesystemBackupLocationType, + S3Config: nil, + FilesystemStorageConfig: &filesystemStorageConfig, }, inputPitr: false, output: &expectedOutput2, @@ -102,9 +104,9 @@ func TestCreatePBMConfig(t *testing.T) { { name: "ignores filled up config instead relying on config type", inputLocation: BackupLocationConfig{ - Type: PMMClientBackupLocationType, - S3Config: &s3Config, - LocalStorageConfig: &pmmClientStorageConfig, + Type: FilesystemBackupLocationType, + S3Config: &s3Config, + FilesystemStorageConfig: &filesystemStorageConfig, }, inputPitr: false, output: &expectedOutput2, @@ -123,3 +125,73 @@ func TestCreatePBMConfig(t *testing.T) { }) } } + +func TestFindPITRRestore(t *testing.T) { + // Tested func searches from the end, so we place records to be skipped at the end. + testList := []pbmListRestore{ + { + Name: "2022-10-11T14:53:19.000000001Z", + Type: "pitr", + PITR: 1000000000, + }, + { + Name: "2022-10-11T14:53:20.000000001Z", + Type: "pitr", + PITR: 1000000000, + }, + { + Name: "2022-error-11T14:53:20.000000001Z", + Type: "pitr", + PITR: 1000000000, + }, + { + Name: "2022-10-11T14:53:20.000000001Z", + Type: "snapshot", + }, + { + Name: "2022-10-11T14:53:20.000000010Z", + Type: "pitr", + PITR: 1000000001, + }, + } + + for _, tc := range []struct { + name string + restoreInfoPITRTime int64 + startedAtString string + expected *pbmListRestore + }{ + { + name: "case1", + restoreInfoPITRTime: 1000000000, + startedAtString: "2022-10-11T14:53:20.000000000Z", + expected: &pbmListRestore{Name: "2022-10-11T14:53:20.000000001Z", Type: "pitr", PITR: 1000000000}, + }, + { + name: "case2", + restoreInfoPITRTime: 1000000001, + startedAtString: "2022-10-11T14:53:20.000000002Z", + expected: &pbmListRestore{Name: "2022-10-11T14:53:20.000000010Z", Type: "pitr", PITR: 1000000001}, + }, + { + name: "case3", + restoreInfoPITRTime: 1000000002, + startedAtString: "2022-10-11T14:53:20.000000000Z", + expected: nil, + }, + { + name: "case4", + restoreInfoPITRTime: 1000000000, + startedAtString: "2022-10-11T14:53:20.000000020Z", + expected: nil, + }, + } { + t.Run(tc.name, func(t *testing.T) { + startedAt, err := time.Parse(time.RFC3339Nano, tc.startedAtString) + require.NoError(t, err) + + res := findPITRRestore(testList, tc.restoreInfoPITRTime, startedAt) + assert.Equal(t, tc.expected, res) + }) + } +} diff --git a/api-tests/management/backup/backups_test.go b/api-tests/management/backup/backups_test.go index d5836be67f..1e4169b456 100644 --- a/api-tests/management/backup/backups_test.go +++ b/api-tests/management/backup/backups_test.go @@ -68,7 +68,7 @@ func TestScheduleBackup(t *testing.T) { Body: locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, }, diff --git a/api-tests/management/backup/locations_test.go b/api-tests/management/backup/locations_test.go index 20eff0d63e..081c8eec8c 100644 --- a/api-tests/management/backup/locations_test.go +++ b/api-tests/management/backup/locations_test.go @@ -40,7 +40,7 @@ func TestAddLocation(t *testing.T) { Body: locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, }, @@ -102,14 +102,14 @@ func TestAddWrongLocation(t *testing.T) { resp, err := client.AddLocation(&locations.AddLocationParams{ Body: locations.AddLocationBody{ - Name: gofakeit.Name(), - Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{}, + Name: gofakeit.Name(), + Description: gofakeit.Question(), + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{}, }, Context: pmmapitests.Context, }) - pmmapitests.AssertAPIErrorf(t, err, 400, codes.InvalidArgument, "invalid field PmmClientConfig.Path: value '' must not be an empty string") + pmmapitests.AssertAPIErrorf(t, err, 400, codes.InvalidArgument, "invalid field FilesystemConfig.Path: value '' must not be an empty string") assert.Nil(t, resp) }) @@ -174,7 +174,7 @@ func TestAddWrongLocation(t *testing.T) { Body: locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, S3Config: &locations.AddLocationParamsBodyS3Config{ @@ -199,7 +199,7 @@ func TestListLocations(t *testing.T) { body := locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, } @@ -219,7 +219,7 @@ func TestListLocations(t *testing.T) { if loc.LocationID == addResp.Payload.LocationID { assert.Equal(t, body.Name, loc.Name) assert.Equal(t, body.Description, loc.Description) - assert.Equal(t, body.PMMClientConfig.Path, loc.PMMClientConfig.Path) + assert.Equal(t, body.FilesystemConfig.Path, loc.FilesystemConfig.Path) found = true } } @@ -240,11 +240,11 @@ func TestChangeLocation(t *testing.T) { assert.Equal(t, req.Description, loc.Description) } - if req.PMMClientConfig != nil { - require.NotNil(t, loc.PMMClientConfig) - assert.Equal(t, req.PMMClientConfig.Path, loc.PMMClientConfig.Path) + if req.FilesystemConfig != nil { + require.NotNil(t, loc.FilesystemConfig) + assert.Equal(t, req.FilesystemConfig.Path, loc.FilesystemConfig.Path) } else { - assert.Nil(t, loc.PMMClientConfig) + assert.Nil(t, loc.FilesystemConfig) } if req.S3Config != nil { @@ -270,7 +270,7 @@ func TestChangeLocation(t *testing.T) { addReqBody := locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, } @@ -284,7 +284,7 @@ func TestChangeLocation(t *testing.T) { updateBody := locations.ChangeLocationBody{ LocationID: resp.Payload.LocationID, Name: gofakeit.Name(), - PMMClientConfig: &locations.ChangeLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.ChangeLocationParamsBodyFilesystemConfig{ Path: "/tmp/nested", }, } @@ -306,7 +306,7 @@ func TestChangeLocation(t *testing.T) { addReqBody := locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, } @@ -340,8 +340,8 @@ func TestChangeLocation(t *testing.T) { require.NotNil(t, location) assert.Equal(t, location.Name, updateBody.Name) - require.NotNil(t, location.PMMClientConfig) - assert.Equal(t, addReqBody.PMMClientConfig.Path, location.PMMClientConfig.Path) + require.NotNil(t, location.FilesystemConfig) + assert.Equal(t, addReqBody.FilesystemConfig.Path, location.FilesystemConfig.Path) }) t.Run("change config type", func(t *testing.T) { @@ -354,7 +354,7 @@ func TestChangeLocation(t *testing.T) { addReqBody := locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, } @@ -393,7 +393,7 @@ func TestChangeLocation(t *testing.T) { addReqBody1 := locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, } @@ -407,7 +407,7 @@ func TestChangeLocation(t *testing.T) { addReqBody2 := locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, } @@ -421,7 +421,7 @@ func TestChangeLocation(t *testing.T) { updateBody := locations.ChangeLocationBody{ LocationID: resp2.Payload.LocationID, Name: addReqBody1.Name, - PMMClientConfig: &locations.ChangeLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.ChangeLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, } @@ -441,7 +441,7 @@ func TestRemoveLocation(t *testing.T) { Body: locations.AddLocationBody{ Name: gofakeit.Name(), Description: gofakeit.Question(), - PMMClientConfig: &locations.AddLocationParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.AddLocationParamsBodyFilesystemConfig{ Path: "/tmp", }, }, @@ -497,12 +497,12 @@ func TestLocationConfigValidation(t *testing.T) { resp, err := client.TestLocationConfig(&locations.TestLocationConfigParams{ Body: locations.TestLocationConfigBody{ - PMMClientConfig: &locations.TestLocationConfigParamsBodyPMMClientConfig{}, + FilesystemConfig: &locations.TestLocationConfigParamsBodyFilesystemConfig{}, }, Context: pmmapitests.Context, }) - pmmapitests.AssertAPIErrorf(t, err, 400, codes.InvalidArgument, "invalid field PmmClientConfig.Path: value '' must not be an empty string") + pmmapitests.AssertAPIErrorf(t, err, 400, codes.InvalidArgument, "invalid field FilesystemConfig.Path: value '' must not be an empty string") assert.Nil(t, resp) }) @@ -547,7 +547,7 @@ func TestLocationConfigValidation(t *testing.T) { resp, err := client.TestLocationConfig(&locations.TestLocationConfigParams{ Body: locations.TestLocationConfigBody{ - PMMClientConfig: &locations.TestLocationConfigParamsBodyPMMClientConfig{ + FilesystemConfig: &locations.TestLocationConfigParamsBodyFilesystemConfig{ Path: "/tmp", }, S3Config: &locations.TestLocationConfigParamsBodyS3Config{ diff --git a/api/agentpb/agent.pb.go b/api/agentpb/agent.pb.go index 1e3812c356..fc535ba3e7 100644 --- a/api/agentpb/agent.pb.go +++ b/api/agentpb/agent.pb.go @@ -2229,8 +2229,8 @@ func (x *S3LocationConfig) GetBucketRegion() string { return "" } -// LocalStorageConfig represents path for storing backup artifacts locally. -type PMMClientLocationConfig struct { +// FilesystemLocationConfig represents path for storing backup artifacts locally. +type FilesystemLocationConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -2238,8 +2238,8 @@ type PMMClientLocationConfig struct { Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` } -func (x *PMMClientLocationConfig) Reset() { - *x = PMMClientLocationConfig{} +func (x *FilesystemLocationConfig) Reset() { + *x = FilesystemLocationConfig{} if protoimpl.UnsafeEnabled { mi := &file_agentpb_agent_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2247,13 +2247,13 @@ func (x *PMMClientLocationConfig) Reset() { } } -func (x *PMMClientLocationConfig) String() string { +func (x *FilesystemLocationConfig) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PMMClientLocationConfig) ProtoMessage() {} +func (*FilesystemLocationConfig) ProtoMessage() {} -func (x *PMMClientLocationConfig) ProtoReflect() protoreflect.Message { +func (x *FilesystemLocationConfig) ProtoReflect() protoreflect.Message { mi := &file_agentpb_agent_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2265,12 +2265,12 @@ func (x *PMMClientLocationConfig) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PMMClientLocationConfig.ProtoReflect.Descriptor instead. -func (*PMMClientLocationConfig) Descriptor() ([]byte, []int) { +// Deprecated: Use FilesystemLocationConfig.ProtoReflect.Descriptor instead. +func (*FilesystemLocationConfig) Descriptor() ([]byte, []int) { return file_agentpb_agent_proto_rawDescGZIP(), []int{31} } -func (x *PMMClientLocationConfig) GetPath() string { +func (x *FilesystemLocationConfig) GetPath() string { if x != nil { return x.Path } @@ -5382,13 +5382,13 @@ type StartJobRequest_MongoDBBackup struct { // Enable Point-in-Time recovery feature. EnablePitr bool `protobuf:"varint,7,opt,name=enable_pitr,json=enablePitr,proto3" json:"enable_pitr,omitempty"` // Backup data model (physical or logical). - DataModel backup.DataModel `protobuf:"varint,8,opt,name=data_model,json=dataModel,proto3,enum=backup.v1beta1.DataModel" json:"data_model,omitempty"` + DataModel backup.DataModel `protobuf:"varint,8,opt,name=data_model,json=dataModel,proto3,enum=backup.v1.DataModel" json:"data_model,omitempty"` // Backup target location. // // Types that are assignable to LocationConfig: // // *StartJobRequest_MongoDBBackup_S3Config - // *StartJobRequest_MongoDBBackup_PmmClientConfig + // *StartJobRequest_MongoDBBackup_FilesystemConfig LocationConfig isStartJobRequest_MongoDBBackup_LocationConfig `protobuf_oneof:"location_config"` } @@ -5494,9 +5494,9 @@ func (x *StartJobRequest_MongoDBBackup) GetS3Config() *S3LocationConfig { return nil } -func (x *StartJobRequest_MongoDBBackup) GetPmmClientConfig() *PMMClientLocationConfig { - if x, ok := x.GetLocationConfig().(*StartJobRequest_MongoDBBackup_PmmClientConfig); ok { - return x.PmmClientConfig +func (x *StartJobRequest_MongoDBBackup) GetFilesystemConfig() *FilesystemLocationConfig { + if x, ok := x.GetLocationConfig().(*StartJobRequest_MongoDBBackup_FilesystemConfig); ok { + return x.FilesystemConfig } return nil } @@ -5509,13 +5509,13 @@ type StartJobRequest_MongoDBBackup_S3Config struct { S3Config *S3LocationConfig `protobuf:"bytes,10,opt,name=s3_config,json=s3Config,proto3,oneof"` } -type StartJobRequest_MongoDBBackup_PmmClientConfig struct { - PmmClientConfig *PMMClientLocationConfig `protobuf:"bytes,11,opt,name=pmm_client_config,json=pmmClientConfig,proto3,oneof"` +type StartJobRequest_MongoDBBackup_FilesystemConfig struct { + FilesystemConfig *FilesystemLocationConfig `protobuf:"bytes,11,opt,name=filesystem_config,json=filesystemConfig,proto3,oneof"` } func (*StartJobRequest_MongoDBBackup_S3Config) isStartJobRequest_MongoDBBackup_LocationConfig() {} -func (*StartJobRequest_MongoDBBackup_PmmClientConfig) isStartJobRequest_MongoDBBackup_LocationConfig() { +func (*StartJobRequest_MongoDBBackup_FilesystemConfig) isStartJobRequest_MongoDBBackup_LocationConfig() { } // MongoDBRestoreBackup is job for MongoDB restore backup service. @@ -5543,7 +5543,7 @@ type StartJobRequest_MongoDBRestoreBackup struct { // Types that are assignable to LocationConfig: // // *StartJobRequest_MongoDBRestoreBackup_S3Config - // *StartJobRequest_MongoDBRestoreBackup_PmmClientConfig + // *StartJobRequest_MongoDBRestoreBackup_FilesystemConfig LocationConfig isStartJobRequest_MongoDBRestoreBackup_LocationConfig `protobuf_oneof:"location_config"` } @@ -5642,9 +5642,9 @@ func (x *StartJobRequest_MongoDBRestoreBackup) GetS3Config() *S3LocationConfig { return nil } -func (x *StartJobRequest_MongoDBRestoreBackup) GetPmmClientConfig() *PMMClientLocationConfig { - if x, ok := x.GetLocationConfig().(*StartJobRequest_MongoDBRestoreBackup_PmmClientConfig); ok { - return x.PmmClientConfig +func (x *StartJobRequest_MongoDBRestoreBackup) GetFilesystemConfig() *FilesystemLocationConfig { + if x, ok := x.GetLocationConfig().(*StartJobRequest_MongoDBRestoreBackup_FilesystemConfig); ok { + return x.FilesystemConfig } return nil } @@ -5657,14 +5657,14 @@ type StartJobRequest_MongoDBRestoreBackup_S3Config struct { S3Config *S3LocationConfig `protobuf:"bytes,10,opt,name=s3_config,json=s3Config,proto3,oneof"` } -type StartJobRequest_MongoDBRestoreBackup_PmmClientConfig struct { - PmmClientConfig *PMMClientLocationConfig `protobuf:"bytes,11,opt,name=pmm_client_config,json=pmmClientConfig,proto3,oneof"` +type StartJobRequest_MongoDBRestoreBackup_FilesystemConfig struct { + FilesystemConfig *FilesystemLocationConfig `protobuf:"bytes,11,opt,name=filesystem_config,json=filesystemConfig,proto3,oneof"` } func (*StartJobRequest_MongoDBRestoreBackup_S3Config) isStartJobRequest_MongoDBRestoreBackup_LocationConfig() { } -func (*StartJobRequest_MongoDBRestoreBackup_PmmClientConfig) isStartJobRequest_MongoDBRestoreBackup_LocationConfig() { +func (*StartJobRequest_MongoDBRestoreBackup_FilesystemConfig) isStartJobRequest_MongoDBRestoreBackup_LocationConfig() { } // Error contains job error message. @@ -6928,108 +6928,108 @@ var file_agentpb_agent_proto_rawDesc = []byte{ 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, - 0x67, 0x69, 0x6f, 0x6e, 0x22, 0x2d, 0x0a, 0x17, 0x50, 0x4d, 0x4d, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, - 0x61, 0x74, 0x68, 0x22, 0xc9, 0x0c, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x33, - 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 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, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x12, 0x47, 0x0a, 0x0c, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x67, 0x65, 0x6e, - 0x74, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, - 0x0b, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x5d, 0x0a, 0x14, - 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x67, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x0a, 0x18, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x70, 0x61, 0x74, 0x68, 0x22, 0xc8, 0x0c, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, + 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, + 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 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, 0x52, 0x07, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x12, 0x47, 0x0a, 0x0c, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x4d, 0x0a, 0x0e, 0x6d, - 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0d, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, - 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x6f, 0x6e, - 0x67, 0x6f, 0x64, 0x62, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x63, 0x0a, 0x16, 0x6d, 0x6f, - 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x14, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, - 0x64, 0x62, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x1a, - 0xe2, 0x01, 0x0a, 0x0b, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, - 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, - 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, - 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x73, 0x33, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x92, 0x01, 0x0a, 0x12, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, - 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x8d, 0x03, 0x0a, 0x0d, 0x4d, 0x6f, - 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x75, - 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, - 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x63, - 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x70, 0x69, 0x74, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x50, 0x69, 0x74, 0x72, 0x12, 0x38, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, - 0x12, 0x36, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x33, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, - 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4c, 0x0a, 0x11, 0x70, 0x6d, 0x6d, 0x5f, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x4d, 0x4d, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0xfc, 0x02, 0x0a, 0x14, 0x4d, 0x6f, - 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0e, - 0x70, 0x69, 0x74, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 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, - 0x52, 0x0d, 0x70, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x73, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, + 0x52, 0x0b, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x5d, 0x0a, + 0x14, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x12, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x4d, 0x0a, 0x0e, + 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0d, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, + 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x6f, + 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x63, 0x0a, 0x16, 0x6d, + 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x48, 0x00, 0x52, 0x14, 0x6d, 0x6f, 0x6e, 0x67, + 0x6f, 0x64, 0x62, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x1a, 0xe2, 0x01, 0x0a, 0x0b, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x73, 0x33, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x92, 0x01, 0x0a, 0x12, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x1d, 0x0a, 0x0a, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, - 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4c, 0x0a, 0x11, 0x70, 0x6d, 0x6d, 0x5f, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x4d, 0x4d, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x48, 0x00, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, + 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x8a, 0x03, 0x0a, 0x0d, 0x4d, + 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x63, 0x6b, + 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x70, 0x69, 0x74, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x50, 0x69, 0x74, 0x72, 0x12, 0x33, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x09, + 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4e, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x48, 0x00, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0xfe, 0x02, 0x0a, 0x14, 0x4d, 0x6f, 0x6e, 0x67, + 0x6f, 0x44, 0x42, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x69, + 0x74, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 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, 0x52, 0x0d, + 0x70, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x36, 0x0a, + 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4e, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x48, 0x00, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x11, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x05, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x28, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, @@ -7351,7 +7351,7 @@ var ( (*JobStatusRequest)(nil), // 29: agent.JobStatusRequest (*JobStatusResponse)(nil), // 30: agent.JobStatusResponse (*S3LocationConfig)(nil), // 31: agent.S3LocationConfig - (*PMMClientLocationConfig)(nil), // 32: agent.PMMClientLocationConfig + (*FilesystemLocationConfig)(nil), // 32: agent.FilesystemLocationConfig (*StartJobRequest)(nil), // 33: agent.StartJobRequest (*StartJobResponse)(nil), // 34: agent.StartJobResponse (*StopJobRequest)(nil), // 35: agent.StopJobRequest @@ -7415,7 +7415,7 @@ var ( (inventorypb.ServiceType)(0), // 93: inventory.ServiceType (*status.Status)(nil), // 94: google.rpc.Status (inventorypb.AgentType)(0), // 95: inventory.AgentType - (backup.DataModel)(0), // 96: backup.v1beta1.DataModel + (backup.DataModel)(0), // 96: backup.v1.DataModel } ) @@ -7540,12 +7540,12 @@ var file_agentpb_agent_proto_depIdxs = []int32{ 1, // 117: agent.StartActionRequest.MongoDBQueryGetDiagnosticDataParams.text_files:type_name -> agent.TextFiles 31, // 118: agent.StartJobRequest.MySQLBackup.s3_config:type_name -> agent.S3LocationConfig 31, // 119: agent.StartJobRequest.MySQLRestoreBackup.s3_config:type_name -> agent.S3LocationConfig - 96, // 120: agent.StartJobRequest.MongoDBBackup.data_model:type_name -> backup.v1beta1.DataModel + 96, // 120: agent.StartJobRequest.MongoDBBackup.data_model:type_name -> backup.v1.DataModel 31, // 121: agent.StartJobRequest.MongoDBBackup.s3_config:type_name -> agent.S3LocationConfig - 32, // 122: agent.StartJobRequest.MongoDBBackup.pmm_client_config:type_name -> agent.PMMClientLocationConfig + 32, // 122: agent.StartJobRequest.MongoDBBackup.filesystem_config:type_name -> agent.FilesystemLocationConfig 89, // 123: agent.StartJobRequest.MongoDBRestoreBackup.pitr_timestamp:type_name -> google.protobuf.Timestamp 31, // 124: agent.StartJobRequest.MongoDBRestoreBackup.s3_config:type_name -> agent.S3LocationConfig - 32, // 125: agent.StartJobRequest.MongoDBRestoreBackup.pmm_client_config:type_name -> agent.PMMClientLocationConfig + 32, // 125: agent.StartJobRequest.MongoDBRestoreBackup.filesystem_config:type_name -> agent.FilesystemLocationConfig 83, // 126: agent.GetVersionsRequest.Software.mysqld:type_name -> agent.GetVersionsRequest.MySQLd 84, // 127: agent.GetVersionsRequest.Software.xtrabackup:type_name -> agent.GetVersionsRequest.Xtrabackup 85, // 128: agent.GetVersionsRequest.Software.xbcloud:type_name -> agent.GetVersionsRequest.Xbcloud @@ -7939,7 +7939,7 @@ func file_agentpb_agent_proto_init() { } } file_agentpb_agent_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PMMClientLocationConfig); i { + switch v := v.(*FilesystemLocationConfig); i { case 0: return &v.state case 1: @@ -8661,11 +8661,11 @@ func file_agentpb_agent_proto_init() { } file_agentpb_agent_proto_msgTypes[72].OneofWrappers = []interface{}{ (*StartJobRequest_MongoDBBackup_S3Config)(nil), - (*StartJobRequest_MongoDBBackup_PmmClientConfig)(nil), + (*StartJobRequest_MongoDBBackup_FilesystemConfig)(nil), } file_agentpb_agent_proto_msgTypes[73].OneofWrappers = []interface{}{ (*StartJobRequest_MongoDBRestoreBackup_S3Config)(nil), - (*StartJobRequest_MongoDBRestoreBackup_PmmClientConfig)(nil), + (*StartJobRequest_MongoDBRestoreBackup_FilesystemConfig)(nil), } file_agentpb_agent_proto_msgTypes[86].OneofWrappers = []interface{}{ (*GetVersionsRequest_Software_Mysqld)(nil), diff --git a/api/agentpb/agent.proto b/api/agentpb/agent.proto index b5418e494e..91a59ae193 100644 --- a/api/agentpb/agent.proto +++ b/api/agentpb/agent.proto @@ -474,8 +474,8 @@ message S3LocationConfig { string bucket_region = 5; } -// LocalStorageConfig represents path for storing backup artifacts locally. -message PMMClientLocationConfig { +// FilesystemLocationConfig represents path for storing backup artifacts locally. +message FilesystemLocationConfig { string path = 1; } @@ -528,11 +528,11 @@ message StartJobRequest { // Enable Point-in-Time recovery feature. bool enable_pitr = 7; // Backup data model (physical or logical). - backup.v1beta1.DataModel data_model = 8; + backup.v1.DataModel data_model = 8; // Backup target location. oneof location_config { S3LocationConfig s3_config = 10; - PMMClientLocationConfig pmm_client_config = 11; + FilesystemLocationConfig filesystem_config = 11; } } // MongoDBRestoreBackup is job for MongoDB restore backup service. @@ -554,7 +554,7 @@ message StartJobRequest { // Where backup is stored. oneof location_config { S3LocationConfig s3_config = 10; - PMMClientLocationConfig pmm_client_config = 11; + FilesystemLocationConfig filesystem_config = 11; } } string job_id = 1; diff --git a/api/agentpb/agent.validator.pb.go b/api/agentpb/agent.validator.pb.go index 36d570cdb4..a50c88d73d 100644 --- a/api/agentpb/agent.validator.pb.go +++ b/api/agentpb/agent.validator.pb.go @@ -556,7 +556,7 @@ func (this *S3LocationConfig) Validate() error { return nil } -func (this *PMMClientLocationConfig) Validate() error { +func (this *FilesystemLocationConfig) Validate() error { return nil } @@ -627,10 +627,10 @@ func (this *StartJobRequest_MongoDBBackup) Validate() error { } } } - if oneOfNester, ok := this.GetLocationConfig().(*StartJobRequest_MongoDBBackup_PmmClientConfig); ok { - if oneOfNester.PmmClientConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.PmmClientConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmClientConfig", err) + if oneOfNester, ok := this.GetLocationConfig().(*StartJobRequest_MongoDBBackup_FilesystemConfig); ok { + if oneOfNester.FilesystemConfig != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.FilesystemConfig); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("FilesystemConfig", err) } } } @@ -650,10 +650,10 @@ func (this *StartJobRequest_MongoDBRestoreBackup) Validate() error { } } } - if oneOfNester, ok := this.GetLocationConfig().(*StartJobRequest_MongoDBRestoreBackup_PmmClientConfig); ok { - if oneOfNester.PmmClientConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.PmmClientConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmClientConfig", err) + if oneOfNester, ok := this.GetLocationConfig().(*StartJobRequest_MongoDBRestoreBackup_FilesystemConfig); ok { + if oneOfNester.FilesystemConfig != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.FilesystemConfig); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("FilesystemConfig", err) } } } diff --git a/api/managementpb/backup/artifacts.pb.go b/api/managementpb/backup/artifacts.pb.go index f6ffe840a7..3ab76da9a0 100644 --- a/api/managementpb/backup/artifacts.pb.go +++ b/api/managementpb/backup/artifacts.pb.go @@ -4,7 +4,7 @@ // protoc (unknown) // source: managementpb/backup/artifacts.proto -package backupv1beta1 +package backupv1 import ( reflect "reflect" @@ -109,13 +109,13 @@ type Artifact struct { // Service name. ServiceName string `protobuf:"bytes,7,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // Backup data model. - DataModel DataModel `protobuf:"varint,8,opt,name=data_model,json=dataModel,proto3,enum=backup.v1beta1.DataModel" json:"data_model,omitempty"` + DataModel DataModel `protobuf:"varint,8,opt,name=data_model,json=dataModel,proto3,enum=backup.v1.DataModel" json:"data_model,omitempty"` // Backup status. - Status BackupStatus `protobuf:"varint,9,opt,name=status,proto3,enum=backup.v1beta1.BackupStatus" json:"status,omitempty"` + Status BackupStatus `protobuf:"varint,9,opt,name=status,proto3,enum=backup.v1.BackupStatus" json:"status,omitempty"` // Artifact creation time. CreatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` // Backup mode. - Mode BackupMode `protobuf:"varint,11,opt,name=mode,proto3,enum=backup.v1beta1.BackupMode" json:"mode,omitempty"` + Mode BackupMode `protobuf:"varint,11,opt,name=mode,proto3,enum=backup.v1.BackupMode" json:"mode,omitempty"` } func (x *Artifact) Reset() { @@ -407,107 +407,284 @@ func (*DeleteArtifactResponse) Descriptor() ([]byte, []int) { return file_managementpb_backup_artifacts_proto_rawDescGZIP(), []int{4} } +type PitrTimerange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // start_timestamp is the time of the first event in the PITR chunk. + StartTimestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"` + // end_timestamp is the time of the last event in the PITR chunk. + EndTimestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=end_timestamp,json=endTimestamp,proto3" json:"end_timestamp,omitempty"` +} + +func (x *PitrTimerange) Reset() { + *x = PitrTimerange{} + if protoimpl.UnsafeEnabled { + mi := &file_managementpb_backup_artifacts_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PitrTimerange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PitrTimerange) ProtoMessage() {} + +func (x *PitrTimerange) ProtoReflect() protoreflect.Message { + mi := &file_managementpb_backup_artifacts_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 PitrTimerange.ProtoReflect.Descriptor instead. +func (*PitrTimerange) Descriptor() ([]byte, []int) { + return file_managementpb_backup_artifacts_proto_rawDescGZIP(), []int{5} +} + +func (x *PitrTimerange) GetStartTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.StartTimestamp + } + return nil +} + +func (x *PitrTimerange) GetEndTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.EndTimestamp + } + return nil +} + +type ListPitrTimerangesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Artifact ID represents artifact whose location has PITR timeranges to be retrieved. + ArtifactId string `protobuf:"bytes,1,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"` +} + +func (x *ListPitrTimerangesRequest) Reset() { + *x = ListPitrTimerangesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_managementpb_backup_artifacts_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListPitrTimerangesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListPitrTimerangesRequest) ProtoMessage() {} + +func (x *ListPitrTimerangesRequest) ProtoReflect() protoreflect.Message { + mi := &file_managementpb_backup_artifacts_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 ListPitrTimerangesRequest.ProtoReflect.Descriptor instead. +func (*ListPitrTimerangesRequest) Descriptor() ([]byte, []int) { + return file_managementpb_backup_artifacts_proto_rawDescGZIP(), []int{6} +} + +func (x *ListPitrTimerangesRequest) GetArtifactId() string { + if x != nil { + return x.ArtifactId + } + return "" +} + +type ListPitrTimerangesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timeranges []*PitrTimerange `protobuf:"bytes,1,rep,name=timeranges,proto3" json:"timeranges,omitempty"` +} + +func (x *ListPitrTimerangesResponse) Reset() { + *x = ListPitrTimerangesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_managementpb_backup_artifacts_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListPitrTimerangesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListPitrTimerangesResponse) ProtoMessage() {} + +func (x *ListPitrTimerangesResponse) ProtoReflect() protoreflect.Message { + mi := &file_managementpb_backup_artifacts_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 ListPitrTimerangesResponse.ProtoReflect.Descriptor instead. +func (*ListPitrTimerangesResponse) Descriptor() ([]byte, []int) { + return file_managementpb_backup_artifacts_proto_rawDescGZIP(), []int{7} +} + +func (x *ListPitrTimerangesResponse) GetTimeranges() []*PitrTimerange { + if x != nil { + return x.Timeranges + } + return nil +} + var File_managementpb_backup_artifacts_proto protoreflect.FileDescriptor var file_managementpb_backup_artifacts_proto_rawDesc = []byte{ 0x0a, 0x23, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 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, 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, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xba, 0x03, 0x0a, 0x08, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, - 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, - 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, - 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, - 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, - 0x65, 0x6c, 0x12, 0x34, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, 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, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, - 0x6f, 0x64, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4f, 0x0a, 0x15, 0x4c, - 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x52, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0x5b, 0x0a, 0x15, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 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, 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, + 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xab, 0x03, 0x0a, 0x08, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x1f, + 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, + 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, 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, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x29, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, + 0x16, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4a, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x31, 0x0a, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x73, 0x22, 0x5b, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, + 0x0c, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, + 0x22, 0x18, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x95, 0x01, 0x0a, 0x0d, 0x50, + 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x43, 0x0a, 0x0f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x01, 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, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x3f, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 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, 0x0c, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x22, 0x3c, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x69, 0x74, 0x72, 0x54, 0x69, + 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, + 0x22, 0x56, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, + 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x74, 0x69, + 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2a, 0xf1, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x41, 0x43, + 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, + 0x49, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, + 0x1d, 0x0a, 0x19, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x18, + 0x0a, 0x14, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x50, 0x41, 0x55, 0x53, 0x45, 0x44, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x41, 0x43, 0x4b, + 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, + 0x53, 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, + 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x44, 0x45, + 0x4c, 0x45, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x06, 0x12, 0x22, 0x0a, 0x1e, 0x42, 0x41, 0x43, 0x4b, + 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, + 0x5f, 0x54, 0x4f, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x32, 0xbf, 0x03, 0x0a, + 0x09, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x83, 0x01, 0x0a, 0x0d, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x01, 0x2a, + 0x12, 0x88, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 0x74, 0x12, 0x20, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, - 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x72, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x2a, 0xf1, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, - 0x19, 0x0a, 0x15, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x41, - 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x5f, 0x50, - 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x42, 0x41, 0x43, - 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x41, 0x55, 0x53, 0x45, - 0x44, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x04, 0x12, 0x17, - 0x0a, 0x13, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x41, 0x43, 0x4b, 0x55, - 0x50, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x49, 0x4e, - 0x47, 0x10, 0x06, 0x12, 0x22, 0x0a, 0x1e, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x54, 0x4f, 0x5f, 0x44, - 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x32, 0xb0, 0x02, 0x0a, 0x09, 0x41, 0x72, 0x74, 0x69, - 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x8d, 0x01, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x24, 0x2f, 0x76, - 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x2f, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x2f, 0x4c, 0x69, - 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x92, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x25, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x26, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, - 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, - 0x2f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x42, 0xbb, 0x01, 0x0a, 0x12, 0x63, - 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x42, 0x0e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1a, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, + 0x22, 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x73, 0x2f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xa0, 0x01, 0x0a, 0x12, + 0x4c, 0x69, 0x73, 0x74, 0x50, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x12, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x50, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, + 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x3d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x37, 0x22, 0x32, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x49, 0x54, + 0x52, 0x54, 0x69, 0x6d, 0x65, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x42, 0x9d, + 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, + 0x42, 0x0e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, + 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, + 0x58, 0xaa, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x0a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -524,35 +701,43 @@ func file_managementpb_backup_artifacts_proto_rawDescGZIP() []byte { var ( file_managementpb_backup_artifacts_proto_enumTypes = make([]protoimpl.EnumInfo, 1) - file_managementpb_backup_artifacts_proto_msgTypes = make([]protoimpl.MessageInfo, 5) + file_managementpb_backup_artifacts_proto_msgTypes = make([]protoimpl.MessageInfo, 8) file_managementpb_backup_artifacts_proto_goTypes = []interface{}{ - (BackupStatus)(0), // 0: backup.v1beta1.BackupStatus - (*Artifact)(nil), // 1: backup.v1beta1.Artifact - (*ListArtifactsRequest)(nil), // 2: backup.v1beta1.ListArtifactsRequest - (*ListArtifactsResponse)(nil), // 3: backup.v1beta1.ListArtifactsResponse - (*DeleteArtifactRequest)(nil), // 4: backup.v1beta1.DeleteArtifactRequest - (*DeleteArtifactResponse)(nil), // 5: backup.v1beta1.DeleteArtifactResponse - (DataModel)(0), // 6: backup.v1beta1.DataModel - (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp - (BackupMode)(0), // 8: backup.v1beta1.BackupMode + (BackupStatus)(0), // 0: backup.v1.BackupStatus + (*Artifact)(nil), // 1: backup.v1.Artifact + (*ListArtifactsRequest)(nil), // 2: backup.v1.ListArtifactsRequest + (*ListArtifactsResponse)(nil), // 3: backup.v1.ListArtifactsResponse + (*DeleteArtifactRequest)(nil), // 4: backup.v1.DeleteArtifactRequest + (*DeleteArtifactResponse)(nil), // 5: backup.v1.DeleteArtifactResponse + (*PitrTimerange)(nil), // 6: backup.v1.PitrTimerange + (*ListPitrTimerangesRequest)(nil), // 7: backup.v1.ListPitrTimerangesRequest + (*ListPitrTimerangesResponse)(nil), // 8: backup.v1.ListPitrTimerangesResponse + (DataModel)(0), // 9: backup.v1.DataModel + (*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp + (BackupMode)(0), // 11: backup.v1.BackupMode } ) var file_managementpb_backup_artifacts_proto_depIdxs = []int32{ - 6, // 0: backup.v1beta1.Artifact.data_model:type_name -> backup.v1beta1.DataModel - 0, // 1: backup.v1beta1.Artifact.status:type_name -> backup.v1beta1.BackupStatus - 7, // 2: backup.v1beta1.Artifact.created_at:type_name -> google.protobuf.Timestamp - 8, // 3: backup.v1beta1.Artifact.mode:type_name -> backup.v1beta1.BackupMode - 1, // 4: backup.v1beta1.ListArtifactsResponse.artifacts:type_name -> backup.v1beta1.Artifact - 2, // 5: backup.v1beta1.Artifacts.ListArtifacts:input_type -> backup.v1beta1.ListArtifactsRequest - 4, // 6: backup.v1beta1.Artifacts.DeleteArtifact:input_type -> backup.v1beta1.DeleteArtifactRequest - 3, // 7: backup.v1beta1.Artifacts.ListArtifacts:output_type -> backup.v1beta1.ListArtifactsResponse - 5, // 8: backup.v1beta1.Artifacts.DeleteArtifact:output_type -> backup.v1beta1.DeleteArtifactResponse - 7, // [7:9] is the sub-list for method output_type - 5, // [5:7] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 9, // 0: backup.v1.Artifact.data_model:type_name -> backup.v1.DataModel + 0, // 1: backup.v1.Artifact.status:type_name -> backup.v1.BackupStatus + 10, // 2: backup.v1.Artifact.created_at:type_name -> google.protobuf.Timestamp + 11, // 3: backup.v1.Artifact.mode:type_name -> backup.v1.BackupMode + 1, // 4: backup.v1.ListArtifactsResponse.artifacts:type_name -> backup.v1.Artifact + 10, // 5: backup.v1.PitrTimerange.start_timestamp:type_name -> google.protobuf.Timestamp + 10, // 6: backup.v1.PitrTimerange.end_timestamp:type_name -> google.protobuf.Timestamp + 6, // 7: backup.v1.ListPitrTimerangesResponse.timeranges:type_name -> backup.v1.PitrTimerange + 2, // 8: backup.v1.Artifacts.ListArtifacts:input_type -> backup.v1.ListArtifactsRequest + 4, // 9: backup.v1.Artifacts.DeleteArtifact:input_type -> backup.v1.DeleteArtifactRequest + 7, // 10: backup.v1.Artifacts.ListPitrTimeranges:input_type -> backup.v1.ListPitrTimerangesRequest + 3, // 11: backup.v1.Artifacts.ListArtifacts:output_type -> backup.v1.ListArtifactsResponse + 5, // 12: backup.v1.Artifacts.DeleteArtifact:output_type -> backup.v1.DeleteArtifactResponse + 8, // 13: backup.v1.Artifacts.ListPitrTimeranges:output_type -> backup.v1.ListPitrTimerangesResponse + 11, // [11:14] is the sub-list for method output_type + 8, // [8:11] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_managementpb_backup_artifacts_proto_init() } @@ -622,6 +807,42 @@ func file_managementpb_backup_artifacts_proto_init() { return nil } } + file_managementpb_backup_artifacts_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PitrTimerange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_managementpb_backup_artifacts_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListPitrTimerangesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_managementpb_backup_artifacts_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListPitrTimerangesResponse); 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{ @@ -629,7 +850,7 @@ func file_managementpb_backup_artifacts_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_managementpb_backup_artifacts_proto_rawDesc, NumEnums: 1, - NumMessages: 5, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, diff --git a/api/managementpb/backup/artifacts.pb.gw.go b/api/managementpb/backup/artifacts.pb.gw.go index ca3cd17335..46c557ebcd 100644 --- a/api/managementpb/backup/artifacts.pb.gw.go +++ b/api/managementpb/backup/artifacts.pb.gw.go @@ -2,11 +2,11 @@ // source: managementpb/backup/artifacts.proto /* -Package backupv1beta1 is a reverse proxy. +Package backupv1 is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package backupv1beta1 +package backupv1 import ( "context" @@ -97,6 +97,38 @@ func local_request_Artifacts_DeleteArtifact_0(ctx context.Context, marshaler run return msg, metadata, err } +func request_Artifacts_ListPitrTimeranges_0(ctx context.Context, marshaler runtime.Marshaler, client ArtifactsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListPitrTimerangesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ListPitrTimeranges(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_Artifacts_ListPitrTimeranges_0(ctx context.Context, marshaler runtime.Marshaler, server ArtifactsServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListPitrTimerangesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ListPitrTimeranges(ctx, &protoReq) + return msg, metadata, err +} + // RegisterArtifactsHandlerServer registers the http handlers for service Artifacts to "mux". // UnaryRPC :call ArtifactsServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -110,7 +142,7 @@ func RegisterArtifactsHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Artifacts/ListArtifacts", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/List")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Artifacts/ListArtifacts", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/List")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -134,7 +166,7 @@ func RegisterArtifactsHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Artifacts/DeleteArtifact", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/Delete")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Artifacts/DeleteArtifact", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/Delete")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -150,6 +182,30 @@ func RegisterArtifactsHandlerServer(ctx context.Context, mux *runtime.ServeMux, forward_Artifacts_DeleteArtifact_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("POST", pattern_Artifacts_ListPitrTimeranges_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Artifacts/ListPitrTimeranges", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/ListPITRTimeranges")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Artifacts_ListPitrTimeranges_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_Artifacts_ListPitrTimeranges_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + return nil } @@ -196,7 +252,7 @@ func RegisterArtifactsHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Artifacts/ListArtifacts", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/List")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Artifacts/ListArtifacts", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/List")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -217,7 +273,7 @@ func RegisterArtifactsHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Artifacts/DeleteArtifact", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/Delete")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Artifacts/DeleteArtifact", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/Delete")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -232,6 +288,27 @@ func RegisterArtifactsHandlerClient(ctx context.Context, mux *runtime.ServeMux, forward_Artifacts_DeleteArtifact_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle("POST", pattern_Artifacts_ListPitrTimeranges_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Artifacts/ListPitrTimeranges", runtime.WithHTTPPathPattern("/v1/management/backup/Artifacts/ListPITRTimeranges")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Artifacts_ListPitrTimeranges_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_Artifacts_ListPitrTimeranges_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + return nil } @@ -239,10 +316,14 @@ var ( pattern_Artifacts_ListArtifacts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"v1", "management", "backup", "Artifacts", "List"}, "")) pattern_Artifacts_DeleteArtifact_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"v1", "management", "backup", "Artifacts", "Delete"}, "")) + + pattern_Artifacts_ListPitrTimeranges_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"v1", "management", "backup", "Artifacts", "ListPITRTimeranges"}, "")) ) var ( forward_Artifacts_ListArtifacts_0 = runtime.ForwardResponseMessage forward_Artifacts_DeleteArtifact_0 = runtime.ForwardResponseMessage + + forward_Artifacts_ListPitrTimeranges_0 = runtime.ForwardResponseMessage ) diff --git a/api/managementpb/backup/artifacts.proto b/api/managementpb/backup/artifacts.proto index fd19b76e21..bda0dba213 100644 --- a/api/managementpb/backup/artifacts.proto +++ b/api/managementpb/backup/artifacts.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package backup.v1beta1; +package backup.v1; -option go_package = "api/managementpb/backup;backupv1beta1"; +option go_package = "api/managementpb/backup;backupv1"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; @@ -61,6 +61,22 @@ message DeleteArtifactRequest { message DeleteArtifactResponse {} +message PitrTimerange { + // start_timestamp is the time of the first event in the PITR chunk. + google.protobuf.Timestamp start_timestamp = 1; + // end_timestamp is the time of the last event in the PITR chunk. + google.protobuf.Timestamp end_timestamp = 2; +} + +message ListPitrTimerangesRequest { + // Artifact ID represents artifact whose location has PITR timeranges to be retrieved. + string artifact_id = 1; +} + +message ListPitrTimerangesResponse { + repeated PitrTimerange timeranges = 1; +} + // Artifacts service provides public methods for managing backup artifacts. service Artifacts { // ListArtifacts returns a list of all backup artifacts. @@ -77,4 +93,12 @@ service Artifacts { body: "*" }; } + + // ListPitrTimeranges list the available MongoDB PITR timeranges in a given backup location + rpc ListPitrTimeranges(ListPitrTimerangesRequest) returns (ListPitrTimerangesResponse) { + option (google.api.http) = { + post: "/v1/management/backup/Artifacts/ListPITRTimeranges" + body: "*" + }; + } } diff --git a/api/managementpb/backup/artifacts.validator.pb.go b/api/managementpb/backup/artifacts.validator.pb.go index 953763345e..d0629e0f40 100644 --- a/api/managementpb/backup/artifacts.validator.pb.go +++ b/api/managementpb/backup/artifacts.validator.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: managementpb/backup/artifacts.proto -package backupv1beta1 +package backupv1 import ( fmt "fmt" @@ -51,3 +51,32 @@ func (this *DeleteArtifactRequest) Validate() error { func (this *DeleteArtifactResponse) Validate() error { return nil } + +func (this *PitrTimerange) Validate() error { + if this.StartTimestamp != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.StartTimestamp); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("StartTimestamp", err) + } + } + if this.EndTimestamp != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.EndTimestamp); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("EndTimestamp", err) + } + } + return nil +} + +func (this *ListPitrTimerangesRequest) Validate() error { + return nil +} + +func (this *ListPitrTimerangesResponse) Validate() error { + for _, item := range this.Timeranges { + if item != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(item); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("Timeranges", err) + } + } + } + return nil +} diff --git a/api/managementpb/backup/artifacts_grpc.pb.go b/api/managementpb/backup/artifacts_grpc.pb.go index cf412e404e..217ee737d2 100644 --- a/api/managementpb/backup/artifacts_grpc.pb.go +++ b/api/managementpb/backup/artifacts_grpc.pb.go @@ -4,7 +4,7 @@ // - protoc (unknown) // source: managementpb/backup/artifacts.proto -package backupv1beta1 +package backupv1 import ( context "context" @@ -27,6 +27,8 @@ type ArtifactsClient interface { ListArtifacts(ctx context.Context, in *ListArtifactsRequest, opts ...grpc.CallOption) (*ListArtifactsResponse, error) // DeleteArtifact deletes specified artifact. DeleteArtifact(ctx context.Context, in *DeleteArtifactRequest, opts ...grpc.CallOption) (*DeleteArtifactResponse, error) + // ListPitrTimeranges list the available MongoDB PITR timeranges in a given backup location + ListPitrTimeranges(ctx context.Context, in *ListPitrTimerangesRequest, opts ...grpc.CallOption) (*ListPitrTimerangesResponse, error) } type artifactsClient struct { @@ -39,7 +41,7 @@ func NewArtifactsClient(cc grpc.ClientConnInterface) ArtifactsClient { func (c *artifactsClient) ListArtifacts(ctx context.Context, in *ListArtifactsRequest, opts ...grpc.CallOption) (*ListArtifactsResponse, error) { out := new(ListArtifactsResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Artifacts/ListArtifacts", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Artifacts/ListArtifacts", in, out, opts...) if err != nil { return nil, err } @@ -48,7 +50,16 @@ func (c *artifactsClient) ListArtifacts(ctx context.Context, in *ListArtifactsRe func (c *artifactsClient) DeleteArtifact(ctx context.Context, in *DeleteArtifactRequest, opts ...grpc.CallOption) (*DeleteArtifactResponse, error) { out := new(DeleteArtifactResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Artifacts/DeleteArtifact", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Artifacts/DeleteArtifact", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *artifactsClient) ListPitrTimeranges(ctx context.Context, in *ListPitrTimerangesRequest, opts ...grpc.CallOption) (*ListPitrTimerangesResponse, error) { + out := new(ListPitrTimerangesResponse) + err := c.cc.Invoke(ctx, "/backup.v1.Artifacts/ListPitrTimeranges", in, out, opts...) if err != nil { return nil, err } @@ -63,6 +74,8 @@ type ArtifactsServer interface { ListArtifacts(context.Context, *ListArtifactsRequest) (*ListArtifactsResponse, error) // DeleteArtifact deletes specified artifact. DeleteArtifact(context.Context, *DeleteArtifactRequest) (*DeleteArtifactResponse, error) + // ListPitrTimeranges list the available MongoDB PITR timeranges in a given backup location + ListPitrTimeranges(context.Context, *ListPitrTimerangesRequest) (*ListPitrTimerangesResponse, error) mustEmbedUnimplementedArtifactsServer() } @@ -76,6 +89,10 @@ func (UnimplementedArtifactsServer) ListArtifacts(context.Context, *ListArtifact func (UnimplementedArtifactsServer) DeleteArtifact(context.Context, *DeleteArtifactRequest) (*DeleteArtifactResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteArtifact not implemented") } + +func (UnimplementedArtifactsServer) ListPitrTimeranges(context.Context, *ListPitrTimerangesRequest) (*ListPitrTimerangesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPitrTimeranges not implemented") +} func (UnimplementedArtifactsServer) mustEmbedUnimplementedArtifactsServer() {} // UnsafeArtifactsServer may be embedded to opt out of forward compatibility for this service. @@ -99,7 +116,7 @@ func _Artifacts_ListArtifacts_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Artifacts/ListArtifacts", + FullMethod: "/backup.v1.Artifacts/ListArtifacts", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ArtifactsServer).ListArtifacts(ctx, req.(*ListArtifactsRequest)) @@ -117,7 +134,7 @@ func _Artifacts_DeleteArtifact_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Artifacts/DeleteArtifact", + FullMethod: "/backup.v1.Artifacts/DeleteArtifact", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(ArtifactsServer).DeleteArtifact(ctx, req.(*DeleteArtifactRequest)) @@ -125,11 +142,29 @@ func _Artifacts_DeleteArtifact_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Artifacts_ListPitrTimeranges_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListPitrTimerangesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ArtifactsServer).ListPitrTimeranges(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/backup.v1.Artifacts/ListPitrTimeranges", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ArtifactsServer).ListPitrTimeranges(ctx, req.(*ListPitrTimerangesRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Artifacts_ServiceDesc is the grpc.ServiceDesc for Artifacts service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var Artifacts_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "backup.v1beta1.Artifacts", + ServiceName: "backup.v1.Artifacts", HandlerType: (*ArtifactsServer)(nil), Methods: []grpc.MethodDesc{ { @@ -140,6 +175,10 @@ var Artifacts_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteArtifact", Handler: _Artifacts_DeleteArtifact_Handler, }, + { + MethodName: "ListPitrTimeranges", + Handler: _Artifacts_ListPitrTimeranges_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "managementpb/backup/artifacts.proto", diff --git a/api/managementpb/backup/backups.pb.go b/api/managementpb/backup/backups.pb.go index 8cfc4213c9..23cb58019a 100644 --- a/api/managementpb/backup/backups.pb.go +++ b/api/managementpb/backup/backups.pb.go @@ -4,7 +4,7 @@ // protoc (unknown) // source: managementpb/backup/backups.proto -package backupv1beta1 +package backupv1 import ( reflect "reflect" @@ -47,7 +47,7 @@ type StartBackupRequest struct { // How many times to retry a failed backup before giving up. Retries uint32 `protobuf:"varint,6,opt,name=retries,proto3" json:"retries,omitempty"` // DataModel represents the data model used for the backup. - DataModel DataModel `protobuf:"varint,7,opt,name=data_model,json=dataModel,proto3,enum=backup.v1beta1.DataModel" json:"data_model,omitempty"` + DataModel DataModel `protobuf:"varint,7,opt,name=data_model,json=dataModel,proto3,enum=backup.v1.DataModel" json:"data_model,omitempty"` } func (x *StartBackupRequest) Reset() { @@ -291,6 +291,8 @@ type RestoreBackupRequest struct { ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` // Artifact id to restore. ArtifactId string `protobuf:"bytes,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"` + // Timestamp of PITR to restore to + PitrTimestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=pitr_timestamp,json=pitrTimestamp,proto3" json:"pitr_timestamp,omitempty"` } func (x *RestoreBackupRequest) Reset() { @@ -339,6 +341,13 @@ func (x *RestoreBackupRequest) GetArtifactId() string { return "" } +func (x *RestoreBackupRequest) GetPitrTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.PitrTimestamp + } + return nil +} + type RestoreBackupResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -418,7 +427,7 @@ type ScheduledBackup struct { // If scheduling is enabled. Enabled bool `protobuf:"varint,13,opt,name=enabled,proto3" json:"enabled,omitempty"` // Backup data model (physical or logical). - DataModel DataModel `protobuf:"varint,14,opt,name=data_model,json=dataModel,proto3,enum=backup.v1beta1.DataModel" json:"data_model,omitempty"` + DataModel DataModel `protobuf:"varint,14,opt,name=data_model,json=dataModel,proto3,enum=backup.v1.DataModel" json:"data_model,omitempty"` // Database vendor e.g. PostgreSQL, MongoDB, MySQL. Vendor string `protobuf:"bytes,15,opt,name=vendor,proto3" json:"vendor,omitempty"` // Last run. @@ -428,7 +437,7 @@ type ScheduledBackup struct { // How many artifacts keep. 0 - unlimited. Retention uint32 `protobuf:"varint,18,opt,name=retention,proto3" json:"retention,omitempty"` // Backup mode. - Mode BackupMode `protobuf:"varint,19,opt,name=mode,proto3,enum=backup.v1beta1.BackupMode" json:"mode,omitempty"` + Mode BackupMode `protobuf:"varint,19,opt,name=mode,proto3,enum=backup.v1.BackupMode" json:"mode,omitempty"` } func (x *ScheduledBackup) Reset() { @@ -615,9 +624,9 @@ type ScheduleBackupRequest struct { // How many artifacts keep. 0 - unlimited. Retention uint32 `protobuf:"varint,10,opt,name=retention,proto3" json:"retention,omitempty"` // Backup mode. - Mode BackupMode `protobuf:"varint,11,opt,name=mode,proto3,enum=backup.v1beta1.BackupMode" json:"mode,omitempty"` + Mode BackupMode `protobuf:"varint,11,opt,name=mode,proto3,enum=backup.v1.BackupMode" json:"mode,omitempty"` // Backup data model (physical or logical). - DataModel DataModel `protobuf:"varint,12,opt,name=data_model,json=dataModel,proto3,enum=backup.v1beta1.DataModel" json:"data_model,omitempty"` + DataModel DataModel `protobuf:"varint,12,opt,name=data_model,json=dataModel,proto3,enum=backup.v1.DataModel" json:"data_model,omitempty"` } func (x *ScheduleBackupRequest) Reset() { @@ -1288,120 +1297,123 @@ var File_managementpb_backup_backups_proto protoreflect.FileDescriptor var file_managementpb_backup_backups_proto_rawDesc = []byte{ 0x0a, 0x21, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, - 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x1a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x6d, 0x77, 0x69, 0x74, 0x6b, 0x6f, 0x77, 0x2f, 0x67, 0x6f, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 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, 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, 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, 0x1e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, - 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x69, 0x6e, 0x76, 0x65, - 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x70, 0x62, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb0, 0x02, 0x0a, 0x12, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x25, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, - 0x02, 0x58, 0x01, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x05, 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, 0x52, 0x0d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x12, 0x38, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, - 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x36, 0x0a, 0x13, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x49, 0x64, 0x22, 0x50, 0x0a, 0x25, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0b, - 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x49, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x26, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2d, 0x0a, 0x05, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4d, 0x79, 0x53, 0x51, - 0x4c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x05, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x12, - 0x33, 0x0a, 0x07, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x19, 0x2e, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, - 0x67, 0x6f, 0x44, 0x42, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x6e, - 0x67, 0x6f, 0x64, 0x62, 0x22, 0x66, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0a, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, - 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x22, 0x36, 0x0a, 0x15, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x49, 0x64, 0x22, 0xe7, 0x05, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, - 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, - 0x72, 0x74, 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, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x65, - 0x74, 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0b, 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, 0x52, 0x0d, 0x72, - 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, - 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x72, - 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x12, 0x38, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, - 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, - 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, - 0x6f, 0x72, 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x10, - 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, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x75, 0x6e, 0x12, 0x35, 0x0a, 0x08, 0x6e, 0x65, 0x78, - 0x74, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x1a, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, + 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x36, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x77, 0x69, 0x74, 0x6b, + 0x6f, 0x77, 0x2f, 0x67, 0x6f, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 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, 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, 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, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, + 0x70, 0x62, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0xab, 0x02, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x72, 0x74, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, + 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x27, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x0a, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x18, 0x05, 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, 0x52, 0x0d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x33, 0x0a, 0x0a, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x14, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, + 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x22, 0x36, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x72, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x22, 0x50, 0x0a, 0x25, 0x4c, 0x69, 0x73, + 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, + 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, + 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x22, 0x8c, 0x01, 0x0a, 0x26, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, + 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, + 0x79, 0x2e, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x05, + 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x12, 0x33, 0x0a, 0x07, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, + 0x72, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x22, 0xa9, 0x01, 0x0a, 0x14, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, + 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0b, 0x61, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x49, 0x64, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x69, 0x74, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 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, 0x6e, 0x65, 0x78, 0x74, 0x52, 0x75, 0x6e, - 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, - 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x87, - 0x04, 0x0a, 0x15, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, 0x69, 0x74, 0x72, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x36, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x64, 0x22, 0xdd, + 0x05, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, + 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 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, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0b, 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, 0x52, 0x0d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x33, 0x0a, 0x0a, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, + 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, + 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, + 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x5f, + 0x72, 0x75, 0x6e, 0x18, 0x10, 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, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x75, 0x6e, 0x12, 0x35, + 0x0a, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x11, 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, 0x6e, 0x65, + 0x78, 0x74, 0x52, 0x75, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x15, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0xfd, + 0x03, 0x0a, 0x15, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, @@ -1426,236 +1438,228 @@ var file_managementpb_backup_backups_proto_rawDesc = []byte{ 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, - 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x38, - 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, - 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x48, 0x0a, 0x16, 0x53, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x49, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x6c, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4c, 0x0a, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x10, 0x73, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x22, - 0xb6, 0x04, 0x0a, 0x1c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x36, 0x0a, 0x13, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, - 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 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, 0x42, 0x6f, 0x6f, 0x6c, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x45, - 0x0a, 0x0f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 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, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x30, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x18, 0x07, 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, 0x52, 0x0d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x09, - 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, + 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, + 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, + 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x22, 0x48, + 0x0a, 0x16, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x67, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x10, + 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, + 0x22, 0xb6, 0x04, 0x0a, 0x1c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x36, 0x0a, 0x13, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, + 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 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, 0x42, 0x6f, 0x6f, + 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, + 0x45, 0x0a, 0x0f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 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, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x30, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x72, - 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1f, 0x0a, 0x1d, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x0a, 0x1c, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x13, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x11, - 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, - 0x64, 0x22, 0x1f, 0x0a, 0x1d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x67, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, - 0x01, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, - 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x51, 0x0a, 0x0f, 0x47, - 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, - 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x6f, - 0x67, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, - 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x39, - 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, - 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x68, - 0x75, 0x6e, 0x6b, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x80, 0x11, 0x0a, 0x07, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0xf3, 0x03, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x72, 0x74, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x22, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9a, - 0x03, 0x92, 0x41, 0xe8, 0x02, 0x1a, 0xe5, 0x02, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x72, 0x65, - 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, - 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, - 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x66, - 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x3a, 0x0a, 0x45, - 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, - 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, - 0x45, 0x44, 0x20, 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x20, - 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, - 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0a, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, - 0x49, 0x44, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x20, 0x2d, 0x20, - 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x20, 0x61, 0x6e, 0x64, 0x20, 0x78, 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x0a, 0x45, 0x52, 0x52, - 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, - 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x20, - 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20, - 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x77, - 0x69, 0x74, 0x68, 0x20, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x61, - 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x28, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xd8, 0x01, 0x0a, 0x1e, - 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x35, - 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x82, 0x05, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, - 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa3, 0x04, 0x92, 0x41, 0xef, 0x03, 0x1a, 0xec, 0x03, 0x43, - 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, - 0x61, 0x73, 0x6f, 0x6e, 0x3a, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, - 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, - 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x45, 0x44, 0x20, 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, - 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, - 0x43, 0x4b, 0x55, 0x50, 0x20, 0x2d, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, - 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x78, 0x74, 0x72, - 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x78, 0x62, 0x63, 0x6c, - 0x6f, 0x75, 0x64, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, - 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, - 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x20, 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, - 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x4d, 0x79, 0x53, 0x51, 0x4c, - 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, - 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x52, - 0x47, 0x45, 0x54, 0x5f, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x20, 0x2d, 0x20, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x20, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, - 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, - 0x66, 0x61, 0x63, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, - 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x2a, 0x22, 0x25, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, - 0x2f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x92, 0x01, 0x0a, 0x0e, - 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x25, - 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0e, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x07, 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, 0x52, 0x0d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x3a, 0x0a, + 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, + 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1f, 0x0a, 0x1d, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x0a, 0x1c, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x13, 0x73, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, + 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x49, 0x64, 0x22, 0x1f, 0x0a, 0x1d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x67, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, + 0x58, 0x01, 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x4c, 0x0a, 0x0f, + 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x27, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x22, 0x39, 0x0a, 0x08, 0x4c, 0x6f, + 0x67, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0xb0, 0x10, 0x0a, 0x07, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x73, 0x12, 0xe9, 0x03, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x72, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x12, 0x1d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x9a, 0x03, 0x92, 0x41, 0xe8, 0x02, 0x1a, 0xe5, 0x02, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, + 0x6e, 0x67, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x43, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x20, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x3a, + 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, + 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, + 0x4c, 0x4c, 0x45, 0x44, 0x20, 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, + 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x20, + 0x2d, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x78, 0x62, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x0a, 0x45, + 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, + 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, + 0x50, 0x20, 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x20, 0x69, + 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x3a, 0x01, 0x2a, - 0x12, 0xa9, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x2b, 0x2e, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, 0x22, 0x2b, 0x2f, 0x76, - 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0xae, 0x01, 0x0a, - 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x2c, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xce, 0x01, + 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, + 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x12, 0x30, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, + 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, + 0x74, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x22, 0x3c, 0x2f, + 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x4c, 0x69, 0x73, + 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, + 0x62, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0xf8, + 0x04, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x12, 0x1f, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0xa3, 0x04, 0x92, 0x41, 0xef, 0x03, 0x1a, 0xec, 0x03, 0x43, 0x6f, 0x75, + 0x6c, 0x64, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, + 0x6f, 0x6e, 0x3a, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x58, + 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, + 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x45, 0x44, 0x20, 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, + 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, + 0x55, 0x50, 0x20, 0x2d, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x78, 0x62, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x43, + 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, + 0x43, 0x4b, 0x55, 0x50, 0x20, 0x2d, 0x20, 0x78, 0x74, 0x72, 0x61, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, + 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x0a, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, + 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, + 0x54, 0x5f, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x20, 0x2d, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x20, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, + 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x69, 0x6e, + 0x67, 0x20, 0x61, 0x20, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x22, + 0x25, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x88, 0x01, 0x0a, 0x0e, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x20, 0x2e, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, + 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, + 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, + 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x9f, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x26, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x30, 0x22, 0x2b, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0xa4, 0x01, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x12, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x2d, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0xae, 0x01, + 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0xa4, 0x01, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x2c, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, - 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x2d, 0x2f, 0x76, - 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x7c, - 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x1e, 0x2e, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, - 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, - 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x2a, 0x22, 0x25, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x28, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x32, 0x22, 0x2d, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x73, 0x2f, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x42, 0xb9, 0x01, 0x0a, - 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x42, 0x0c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1a, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x2f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, + 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x72, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, + 0x19, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4c, + 0x6f, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x22, 0x25, + 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x2f, 0x47, 0x65, + 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x3a, 0x01, 0x2a, 0x42, 0x9b, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, + 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, + 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, + 0x31, 0xe2, 0x02, 0x15, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0a, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1673,30 +1677,30 @@ func file_managementpb_backup_backups_proto_rawDescGZIP() []byte { var ( file_managementpb_backup_backups_proto_msgTypes = make([]protoimpl.MessageInfo, 18) file_managementpb_backup_backups_proto_goTypes = []interface{}{ - (*StartBackupRequest)(nil), // 0: backup.v1beta1.StartBackupRequest - (*StartBackupResponse)(nil), // 1: backup.v1beta1.StartBackupResponse - (*ListArtifactCompatibleServicesRequest)(nil), // 2: backup.v1beta1.ListArtifactCompatibleServicesRequest - (*ListArtifactCompatibleServicesResponse)(nil), // 3: backup.v1beta1.ListArtifactCompatibleServicesResponse - (*RestoreBackupRequest)(nil), // 4: backup.v1beta1.RestoreBackupRequest - (*RestoreBackupResponse)(nil), // 5: backup.v1beta1.RestoreBackupResponse - (*ScheduledBackup)(nil), // 6: backup.v1beta1.ScheduledBackup - (*ScheduleBackupRequest)(nil), // 7: backup.v1beta1.ScheduleBackupRequest - (*ScheduleBackupResponse)(nil), // 8: backup.v1beta1.ScheduleBackupResponse - (*ListScheduledBackupsRequest)(nil), // 9: backup.v1beta1.ListScheduledBackupsRequest - (*ListScheduledBackupsResponse)(nil), // 10: backup.v1beta1.ListScheduledBackupsResponse - (*ChangeScheduledBackupRequest)(nil), // 11: backup.v1beta1.ChangeScheduledBackupRequest - (*ChangeScheduledBackupResponse)(nil), // 12: backup.v1beta1.ChangeScheduledBackupResponse - (*RemoveScheduledBackupRequest)(nil), // 13: backup.v1beta1.RemoveScheduledBackupRequest - (*RemoveScheduledBackupResponse)(nil), // 14: backup.v1beta1.RemoveScheduledBackupResponse - (*GetLogsRequest)(nil), // 15: backup.v1beta1.GetLogsRequest - (*GetLogsResponse)(nil), // 16: backup.v1beta1.GetLogsResponse - (*LogChunk)(nil), // 17: backup.v1beta1.LogChunk + (*StartBackupRequest)(nil), // 0: backup.v1.StartBackupRequest + (*StartBackupResponse)(nil), // 1: backup.v1.StartBackupResponse + (*ListArtifactCompatibleServicesRequest)(nil), // 2: backup.v1.ListArtifactCompatibleServicesRequest + (*ListArtifactCompatibleServicesResponse)(nil), // 3: backup.v1.ListArtifactCompatibleServicesResponse + (*RestoreBackupRequest)(nil), // 4: backup.v1.RestoreBackupRequest + (*RestoreBackupResponse)(nil), // 5: backup.v1.RestoreBackupResponse + (*ScheduledBackup)(nil), // 6: backup.v1.ScheduledBackup + (*ScheduleBackupRequest)(nil), // 7: backup.v1.ScheduleBackupRequest + (*ScheduleBackupResponse)(nil), // 8: backup.v1.ScheduleBackupResponse + (*ListScheduledBackupsRequest)(nil), // 9: backup.v1.ListScheduledBackupsRequest + (*ListScheduledBackupsResponse)(nil), // 10: backup.v1.ListScheduledBackupsResponse + (*ChangeScheduledBackupRequest)(nil), // 11: backup.v1.ChangeScheduledBackupRequest + (*ChangeScheduledBackupResponse)(nil), // 12: backup.v1.ChangeScheduledBackupResponse + (*RemoveScheduledBackupRequest)(nil), // 13: backup.v1.RemoveScheduledBackupRequest + (*RemoveScheduledBackupResponse)(nil), // 14: backup.v1.RemoveScheduledBackupResponse + (*GetLogsRequest)(nil), // 15: backup.v1.GetLogsRequest + (*GetLogsResponse)(nil), // 16: backup.v1.GetLogsResponse + (*LogChunk)(nil), // 17: backup.v1.LogChunk (*durationpb.Duration)(nil), // 18: google.protobuf.Duration - (DataModel)(0), // 19: backup.v1beta1.DataModel + (DataModel)(0), // 19: backup.v1.DataModel (*inventorypb.MySQLService)(nil), // 20: inventory.MySQLService (*inventorypb.MongoDBService)(nil), // 21: inventory.MongoDBService (*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp - (BackupMode)(0), // 23: backup.v1beta1.BackupMode + (BackupMode)(0), // 23: backup.v1.BackupMode (*wrapperspb.BoolValue)(nil), // 24: google.protobuf.BoolValue (*wrapperspb.StringValue)(nil), // 25: google.protobuf.StringValue (*wrapperspb.UInt32Value)(nil), // 26: google.protobuf.UInt32Value @@ -1704,51 +1708,52 @@ var ( ) var file_managementpb_backup_backups_proto_depIdxs = []int32{ - 18, // 0: backup.v1beta1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration - 19, // 1: backup.v1beta1.StartBackupRequest.data_model:type_name -> backup.v1beta1.DataModel - 20, // 2: backup.v1beta1.ListArtifactCompatibleServicesResponse.mysql:type_name -> inventory.MySQLService - 21, // 3: backup.v1beta1.ListArtifactCompatibleServicesResponse.mongodb:type_name -> inventory.MongoDBService - 22, // 4: backup.v1beta1.ScheduledBackup.start_time:type_name -> google.protobuf.Timestamp - 18, // 5: backup.v1beta1.ScheduledBackup.retry_interval:type_name -> google.protobuf.Duration - 19, // 6: backup.v1beta1.ScheduledBackup.data_model:type_name -> backup.v1beta1.DataModel - 22, // 7: backup.v1beta1.ScheduledBackup.last_run:type_name -> google.protobuf.Timestamp - 22, // 8: backup.v1beta1.ScheduledBackup.next_run:type_name -> google.protobuf.Timestamp - 23, // 9: backup.v1beta1.ScheduledBackup.mode:type_name -> backup.v1beta1.BackupMode - 22, // 10: backup.v1beta1.ScheduleBackupRequest.start_time:type_name -> google.protobuf.Timestamp - 18, // 11: backup.v1beta1.ScheduleBackupRequest.retry_interval:type_name -> google.protobuf.Duration - 23, // 12: backup.v1beta1.ScheduleBackupRequest.mode:type_name -> backup.v1beta1.BackupMode - 19, // 13: backup.v1beta1.ScheduleBackupRequest.data_model:type_name -> backup.v1beta1.DataModel - 6, // 14: backup.v1beta1.ListScheduledBackupsResponse.scheduled_backups:type_name -> backup.v1beta1.ScheduledBackup - 24, // 15: backup.v1beta1.ChangeScheduledBackupRequest.enabled:type_name -> google.protobuf.BoolValue - 25, // 16: backup.v1beta1.ChangeScheduledBackupRequest.cron_expression:type_name -> google.protobuf.StringValue - 22, // 17: backup.v1beta1.ChangeScheduledBackupRequest.start_time:type_name -> google.protobuf.Timestamp - 25, // 18: backup.v1beta1.ChangeScheduledBackupRequest.name:type_name -> google.protobuf.StringValue - 25, // 19: backup.v1beta1.ChangeScheduledBackupRequest.description:type_name -> google.protobuf.StringValue - 18, // 20: backup.v1beta1.ChangeScheduledBackupRequest.retry_interval:type_name -> google.protobuf.Duration - 26, // 21: backup.v1beta1.ChangeScheduledBackupRequest.retries:type_name -> google.protobuf.UInt32Value - 26, // 22: backup.v1beta1.ChangeScheduledBackupRequest.retention:type_name -> google.protobuf.UInt32Value - 17, // 23: backup.v1beta1.GetLogsResponse.logs:type_name -> backup.v1beta1.LogChunk - 0, // 24: backup.v1beta1.Backups.StartBackup:input_type -> backup.v1beta1.StartBackupRequest - 2, // 25: backup.v1beta1.Backups.ListArtifactCompatibleServices:input_type -> backup.v1beta1.ListArtifactCompatibleServicesRequest - 4, // 26: backup.v1beta1.Backups.RestoreBackup:input_type -> backup.v1beta1.RestoreBackupRequest - 7, // 27: backup.v1beta1.Backups.ScheduleBackup:input_type -> backup.v1beta1.ScheduleBackupRequest - 9, // 28: backup.v1beta1.Backups.ListScheduledBackups:input_type -> backup.v1beta1.ListScheduledBackupsRequest - 11, // 29: backup.v1beta1.Backups.ChangeScheduledBackup:input_type -> backup.v1beta1.ChangeScheduledBackupRequest - 13, // 30: backup.v1beta1.Backups.RemoveScheduledBackup:input_type -> backup.v1beta1.RemoveScheduledBackupRequest - 15, // 31: backup.v1beta1.Backups.GetLogs:input_type -> backup.v1beta1.GetLogsRequest - 1, // 32: backup.v1beta1.Backups.StartBackup:output_type -> backup.v1beta1.StartBackupResponse - 3, // 33: backup.v1beta1.Backups.ListArtifactCompatibleServices:output_type -> backup.v1beta1.ListArtifactCompatibleServicesResponse - 5, // 34: backup.v1beta1.Backups.RestoreBackup:output_type -> backup.v1beta1.RestoreBackupResponse - 8, // 35: backup.v1beta1.Backups.ScheduleBackup:output_type -> backup.v1beta1.ScheduleBackupResponse - 10, // 36: backup.v1beta1.Backups.ListScheduledBackups:output_type -> backup.v1beta1.ListScheduledBackupsResponse - 12, // 37: backup.v1beta1.Backups.ChangeScheduledBackup:output_type -> backup.v1beta1.ChangeScheduledBackupResponse - 14, // 38: backup.v1beta1.Backups.RemoveScheduledBackup:output_type -> backup.v1beta1.RemoveScheduledBackupResponse - 16, // 39: backup.v1beta1.Backups.GetLogs:output_type -> backup.v1beta1.GetLogsResponse - 32, // [32:40] is the sub-list for method output_type - 24, // [24:32] is the sub-list for method input_type - 24, // [24:24] is the sub-list for extension type_name - 24, // [24:24] is the sub-list for extension extendee - 0, // [0:24] is the sub-list for field type_name + 18, // 0: backup.v1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration + 19, // 1: backup.v1.StartBackupRequest.data_model:type_name -> backup.v1.DataModel + 20, // 2: backup.v1.ListArtifactCompatibleServicesResponse.mysql:type_name -> inventory.MySQLService + 21, // 3: backup.v1.ListArtifactCompatibleServicesResponse.mongodb:type_name -> inventory.MongoDBService + 22, // 4: backup.v1.RestoreBackupRequest.pitr_timestamp:type_name -> google.protobuf.Timestamp + 22, // 5: backup.v1.ScheduledBackup.start_time:type_name -> google.protobuf.Timestamp + 18, // 6: backup.v1.ScheduledBackup.retry_interval:type_name -> google.protobuf.Duration + 19, // 7: backup.v1.ScheduledBackup.data_model:type_name -> backup.v1.DataModel + 22, // 8: backup.v1.ScheduledBackup.last_run:type_name -> google.protobuf.Timestamp + 22, // 9: backup.v1.ScheduledBackup.next_run:type_name -> google.protobuf.Timestamp + 23, // 10: backup.v1.ScheduledBackup.mode:type_name -> backup.v1.BackupMode + 22, // 11: backup.v1.ScheduleBackupRequest.start_time:type_name -> google.protobuf.Timestamp + 18, // 12: backup.v1.ScheduleBackupRequest.retry_interval:type_name -> google.protobuf.Duration + 23, // 13: backup.v1.ScheduleBackupRequest.mode:type_name -> backup.v1.BackupMode + 19, // 14: backup.v1.ScheduleBackupRequest.data_model:type_name -> backup.v1.DataModel + 6, // 15: backup.v1.ListScheduledBackupsResponse.scheduled_backups:type_name -> backup.v1.ScheduledBackup + 24, // 16: backup.v1.ChangeScheduledBackupRequest.enabled:type_name -> google.protobuf.BoolValue + 25, // 17: backup.v1.ChangeScheduledBackupRequest.cron_expression:type_name -> google.protobuf.StringValue + 22, // 18: backup.v1.ChangeScheduledBackupRequest.start_time:type_name -> google.protobuf.Timestamp + 25, // 19: backup.v1.ChangeScheduledBackupRequest.name:type_name -> google.protobuf.StringValue + 25, // 20: backup.v1.ChangeScheduledBackupRequest.description:type_name -> google.protobuf.StringValue + 18, // 21: backup.v1.ChangeScheduledBackupRequest.retry_interval:type_name -> google.protobuf.Duration + 26, // 22: backup.v1.ChangeScheduledBackupRequest.retries:type_name -> google.protobuf.UInt32Value + 26, // 23: backup.v1.ChangeScheduledBackupRequest.retention:type_name -> google.protobuf.UInt32Value + 17, // 24: backup.v1.GetLogsResponse.logs:type_name -> backup.v1.LogChunk + 0, // 25: backup.v1.Backups.StartBackup:input_type -> backup.v1.StartBackupRequest + 2, // 26: backup.v1.Backups.ListArtifactCompatibleServices:input_type -> backup.v1.ListArtifactCompatibleServicesRequest + 4, // 27: backup.v1.Backups.RestoreBackup:input_type -> backup.v1.RestoreBackupRequest + 7, // 28: backup.v1.Backups.ScheduleBackup:input_type -> backup.v1.ScheduleBackupRequest + 9, // 29: backup.v1.Backups.ListScheduledBackups:input_type -> backup.v1.ListScheduledBackupsRequest + 11, // 30: backup.v1.Backups.ChangeScheduledBackup:input_type -> backup.v1.ChangeScheduledBackupRequest + 13, // 31: backup.v1.Backups.RemoveScheduledBackup:input_type -> backup.v1.RemoveScheduledBackupRequest + 15, // 32: backup.v1.Backups.GetLogs:input_type -> backup.v1.GetLogsRequest + 1, // 33: backup.v1.Backups.StartBackup:output_type -> backup.v1.StartBackupResponse + 3, // 34: backup.v1.Backups.ListArtifactCompatibleServices:output_type -> backup.v1.ListArtifactCompatibleServicesResponse + 5, // 35: backup.v1.Backups.RestoreBackup:output_type -> backup.v1.RestoreBackupResponse + 8, // 36: backup.v1.Backups.ScheduleBackup:output_type -> backup.v1.ScheduleBackupResponse + 10, // 37: backup.v1.Backups.ListScheduledBackups:output_type -> backup.v1.ListScheduledBackupsResponse + 12, // 38: backup.v1.Backups.ChangeScheduledBackup:output_type -> backup.v1.ChangeScheduledBackupResponse + 14, // 39: backup.v1.Backups.RemoveScheduledBackup:output_type -> backup.v1.RemoveScheduledBackupResponse + 16, // 40: backup.v1.Backups.GetLogs:output_type -> backup.v1.GetLogsResponse + 33, // [33:41] is the sub-list for method output_type + 25, // [25:33] 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_managementpb_backup_backups_proto_init() } diff --git a/api/managementpb/backup/backups.pb.gw.go b/api/managementpb/backup/backups.pb.gw.go index 5588af913b..8bf08a13a2 100644 --- a/api/managementpb/backup/backups.pb.gw.go +++ b/api/managementpb/backup/backups.pb.gw.go @@ -2,11 +2,11 @@ // source: managementpb/backup/backups.proto /* -Package backupv1beta1 is a reverse proxy. +Package backupv1 is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package backupv1beta1 +package backupv1 import ( "context" @@ -302,7 +302,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/StartBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Start")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/StartBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Start")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -326,7 +326,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/ListArtifactCompatibleServices", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListArtifactCompatibleServices")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/ListArtifactCompatibleServices", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListArtifactCompatibleServices")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -350,7 +350,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/RestoreBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Restore")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/RestoreBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Restore")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -374,7 +374,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/ScheduleBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Schedule")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/ScheduleBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Schedule")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -398,7 +398,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/ListScheduledBackups", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListScheduled")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/ListScheduledBackups", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListScheduled")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -422,7 +422,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/ChangeScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ChangeScheduled")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/ChangeScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ChangeScheduled")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -446,7 +446,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/RemoveScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/RemoveScheduled")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/RemoveScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/RemoveScheduled")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -470,7 +470,7 @@ func RegisterBackupsHandlerServer(ctx context.Context, mux *runtime.ServeMux, se inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Backups/GetLogs", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/GetLogs")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Backups/GetLogs", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/GetLogs")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -532,7 +532,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/StartBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Start")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/StartBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Start")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -553,7 +553,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/ListArtifactCompatibleServices", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListArtifactCompatibleServices")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/ListArtifactCompatibleServices", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListArtifactCompatibleServices")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -574,7 +574,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/RestoreBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Restore")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/RestoreBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Restore")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -595,7 +595,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/ScheduleBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Schedule")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/ScheduleBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/Schedule")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -616,7 +616,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/ListScheduledBackups", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListScheduled")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/ListScheduledBackups", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ListScheduled")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -637,7 +637,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/ChangeScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ChangeScheduled")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/ChangeScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/ChangeScheduled")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -658,7 +658,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/RemoveScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/RemoveScheduled")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/RemoveScheduledBackup", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/RemoveScheduled")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -679,7 +679,7 @@ func RegisterBackupsHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Backups/GetLogs", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/GetLogs")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Backups/GetLogs", runtime.WithHTTPPathPattern("/v1/management/backup/Backups/GetLogs")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return diff --git a/api/managementpb/backup/backups.proto b/api/managementpb/backup/backups.proto index 43019e481f..84b4488766 100644 --- a/api/managementpb/backup/backups.proto +++ b/api/managementpb/backup/backups.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package backup.v1beta1; +package backup.v1; -option go_package = "api/managementpb/backup;backupv1beta1"; +option go_package = "api/managementpb/backup;backupv1"; import "protoc-gen-openapiv2/options/annotations.proto"; import "github.com/mwitkow/go-proto-validators/validator.proto"; @@ -70,6 +70,8 @@ message RestoreBackupRequest { string_not_empty: true } ]; + // Timestamp of PITR to restore to + google.protobuf.Timestamp pitr_timestamp = 3; } message RestoreBackupResponse { diff --git a/api/managementpb/backup/backups.validator.pb.go b/api/managementpb/backup/backups.validator.pb.go index cdddc8947d..ffb3bad316 100644 --- a/api/managementpb/backup/backups.validator.pb.go +++ b/api/managementpb/backup/backups.validator.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: managementpb/backup/backups.proto -package backupv1beta1 +package backupv1 import ( fmt "fmt" @@ -77,6 +77,11 @@ func (this *RestoreBackupRequest) Validate() error { if this.ArtifactId == "" { return github_com_mwitkow_go_proto_validators.FieldError("ArtifactId", fmt.Errorf(`value '%v' must not be an empty string`, this.ArtifactId)) } + if this.PitrTimestamp != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PitrTimestamp); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("PitrTimestamp", err) + } + } return nil } diff --git a/api/managementpb/backup/backups_grpc.pb.go b/api/managementpb/backup/backups_grpc.pb.go index 077ba9bf31..3f0c64c6d6 100644 --- a/api/managementpb/backup/backups_grpc.pb.go +++ b/api/managementpb/backup/backups_grpc.pb.go @@ -4,7 +4,7 @@ // - protoc (unknown) // source: managementpb/backup/backups.proto -package backupv1beta1 +package backupv1 import ( context "context" @@ -51,7 +51,7 @@ func NewBackupsClient(cc grpc.ClientConnInterface) BackupsClient { func (c *backupsClient) StartBackup(ctx context.Context, in *StartBackupRequest, opts ...grpc.CallOption) (*StartBackupResponse, error) { out := new(StartBackupResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/StartBackup", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/StartBackup", in, out, opts...) if err != nil { return nil, err } @@ -60,7 +60,7 @@ func (c *backupsClient) StartBackup(ctx context.Context, in *StartBackupRequest, func (c *backupsClient) ListArtifactCompatibleServices(ctx context.Context, in *ListArtifactCompatibleServicesRequest, opts ...grpc.CallOption) (*ListArtifactCompatibleServicesResponse, error) { out := new(ListArtifactCompatibleServicesResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/ListArtifactCompatibleServices", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/ListArtifactCompatibleServices", in, out, opts...) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func (c *backupsClient) ListArtifactCompatibleServices(ctx context.Context, in * func (c *backupsClient) RestoreBackup(ctx context.Context, in *RestoreBackupRequest, opts ...grpc.CallOption) (*RestoreBackupResponse, error) { out := new(RestoreBackupResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/RestoreBackup", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/RestoreBackup", in, out, opts...) if err != nil { return nil, err } @@ -78,7 +78,7 @@ func (c *backupsClient) RestoreBackup(ctx context.Context, in *RestoreBackupRequ func (c *backupsClient) ScheduleBackup(ctx context.Context, in *ScheduleBackupRequest, opts ...grpc.CallOption) (*ScheduleBackupResponse, error) { out := new(ScheduleBackupResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/ScheduleBackup", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/ScheduleBackup", in, out, opts...) if err != nil { return nil, err } @@ -87,7 +87,7 @@ func (c *backupsClient) ScheduleBackup(ctx context.Context, in *ScheduleBackupRe func (c *backupsClient) ListScheduledBackups(ctx context.Context, in *ListScheduledBackupsRequest, opts ...grpc.CallOption) (*ListScheduledBackupsResponse, error) { out := new(ListScheduledBackupsResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/ListScheduledBackups", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/ListScheduledBackups", in, out, opts...) if err != nil { return nil, err } @@ -96,7 +96,7 @@ func (c *backupsClient) ListScheduledBackups(ctx context.Context, in *ListSchedu func (c *backupsClient) ChangeScheduledBackup(ctx context.Context, in *ChangeScheduledBackupRequest, opts ...grpc.CallOption) (*ChangeScheduledBackupResponse, error) { out := new(ChangeScheduledBackupResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/ChangeScheduledBackup", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/ChangeScheduledBackup", in, out, opts...) if err != nil { return nil, err } @@ -105,7 +105,7 @@ func (c *backupsClient) ChangeScheduledBackup(ctx context.Context, in *ChangeSch func (c *backupsClient) RemoveScheduledBackup(ctx context.Context, in *RemoveScheduledBackupRequest, opts ...grpc.CallOption) (*RemoveScheduledBackupResponse, error) { out := new(RemoveScheduledBackupResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/RemoveScheduledBackup", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/RemoveScheduledBackup", in, out, opts...) if err != nil { return nil, err } @@ -114,7 +114,7 @@ func (c *backupsClient) RemoveScheduledBackup(ctx context.Context, in *RemoveSch func (c *backupsClient) GetLogs(ctx context.Context, in *GetLogsRequest, opts ...grpc.CallOption) (*GetLogsResponse, error) { out := new(GetLogsResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Backups/GetLogs", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Backups/GetLogs", in, out, opts...) if err != nil { return nil, err } @@ -201,7 +201,7 @@ func _Backups_StartBackup_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/StartBackup", + FullMethod: "/backup.v1.Backups/StartBackup", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).StartBackup(ctx, req.(*StartBackupRequest)) @@ -219,7 +219,7 @@ func _Backups_ListArtifactCompatibleServices_Handler(srv interface{}, ctx contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/ListArtifactCompatibleServices", + FullMethod: "/backup.v1.Backups/ListArtifactCompatibleServices", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).ListArtifactCompatibleServices(ctx, req.(*ListArtifactCompatibleServicesRequest)) @@ -237,7 +237,7 @@ func _Backups_RestoreBackup_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/RestoreBackup", + FullMethod: "/backup.v1.Backups/RestoreBackup", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).RestoreBackup(ctx, req.(*RestoreBackupRequest)) @@ -255,7 +255,7 @@ func _Backups_ScheduleBackup_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/ScheduleBackup", + FullMethod: "/backup.v1.Backups/ScheduleBackup", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).ScheduleBackup(ctx, req.(*ScheduleBackupRequest)) @@ -273,7 +273,7 @@ func _Backups_ListScheduledBackups_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/ListScheduledBackups", + FullMethod: "/backup.v1.Backups/ListScheduledBackups", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).ListScheduledBackups(ctx, req.(*ListScheduledBackupsRequest)) @@ -291,7 +291,7 @@ func _Backups_ChangeScheduledBackup_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/ChangeScheduledBackup", + FullMethod: "/backup.v1.Backups/ChangeScheduledBackup", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).ChangeScheduledBackup(ctx, req.(*ChangeScheduledBackupRequest)) @@ -309,7 +309,7 @@ func _Backups_RemoveScheduledBackup_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/RemoveScheduledBackup", + FullMethod: "/backup.v1.Backups/RemoveScheduledBackup", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).RemoveScheduledBackup(ctx, req.(*RemoveScheduledBackupRequest)) @@ -327,7 +327,7 @@ func _Backups_GetLogs_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Backups/GetLogs", + FullMethod: "/backup.v1.Backups/GetLogs", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BackupsServer).GetLogs(ctx, req.(*GetLogsRequest)) @@ -339,7 +339,7 @@ func _Backups_GetLogs_Handler(srv interface{}, ctx context.Context, dec func(int // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var Backups_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "backup.v1beta1.Backups", + ServiceName: "backup.v1.Backups", HandlerType: (*BackupsServer)(nil), Methods: []grpc.MethodDesc{ { diff --git a/api/managementpb/backup/common.pb.go b/api/managementpb/backup/common.pb.go index ef854c20e9..099c919d2f 100644 --- a/api/managementpb/backup/common.pb.go +++ b/api/managementpb/backup/common.pb.go @@ -4,7 +4,7 @@ // protoc (unknown) // source: managementpb/backup/common.proto -package backupv1beta1 +package backupv1 import ( reflect "reflect" @@ -129,29 +129,27 @@ var File_managementpb_backup_common_proto protoreflect.FileDescriptor var file_managementpb_backup_common_proto_rawDesc = []byte{ 0x0a, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2a, 0x3e, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, - 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x49, 0x4e, - 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x48, 0x59, 0x53, 0x49, - 0x43, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x4f, 0x47, 0x49, 0x43, 0x41, 0x4c, - 0x10, 0x02, 0x2a, 0x4e, 0x0a, 0x0a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x65, - 0x12, 0x17, 0x0a, 0x13, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, - 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4e, 0x41, - 0x50, 0x53, 0x48, 0x4f, 0x54, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x43, 0x52, 0x45, - 0x4d, 0x45, 0x4e, 0x54, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x54, 0x52, - 0x10, 0x03, 0x42, 0xb8, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x0e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, - 0x1a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x12, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2a, 0x3e, 0x0a, + 0x09, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, + 0x54, 0x41, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x4c, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, + 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x48, 0x59, 0x53, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x01, + 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x4f, 0x47, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x02, 0x2a, 0x4e, 0x0a, + 0x0a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x42, + 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, + 0x49, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, + 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x41, + 0x4c, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x49, 0x54, 0x52, 0x10, 0x03, 0x42, 0x9a, 0x01, + 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x42, + 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, + 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3b, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x09, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0a, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -169,8 +167,8 @@ func file_managementpb_backup_common_proto_rawDescGZIP() []byte { var ( file_managementpb_backup_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2) file_managementpb_backup_common_proto_goTypes = []interface{}{ - (DataModel)(0), // 0: backup.v1beta1.DataModel - (BackupMode)(0), // 1: backup.v1beta1.BackupMode + (DataModel)(0), // 0: backup.v1.DataModel + (BackupMode)(0), // 1: backup.v1.BackupMode } ) diff --git a/api/managementpb/backup/common.proto b/api/managementpb/backup/common.proto index 7fc35f2a57..4816a7c502 100644 --- a/api/managementpb/backup/common.proto +++ b/api/managementpb/backup/common.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package backup.v1beta1; +package backup.v1; -option go_package = "api/managementpb/backup;backupv1beta1"; +option go_package = "api/managementpb/backup;backupv1"; // DataModel is a model used for performing a backup. enum DataModel { diff --git a/api/managementpb/backup/common.validator.pb.go b/api/managementpb/backup/common.validator.pb.go index 793e08bce3..c71aefa7ed 100644 --- a/api/managementpb/backup/common.validator.pb.go +++ b/api/managementpb/backup/common.validator.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: managementpb/backup/common.proto -package backupv1beta1 +package backupv1 import ( fmt "fmt" diff --git a/api/managementpb/backup/errors.pb.go b/api/managementpb/backup/errors.pb.go index 53c4c987dc..ab906ad3bd 100644 --- a/api/managementpb/backup/errors.pb.go +++ b/api/managementpb/backup/errors.pb.go @@ -4,7 +4,7 @@ // protoc (unknown) // source: managementpb/backup/errors.proto -package backupv1beta1 +package backupv1 import ( reflect "reflect" @@ -88,7 +88,7 @@ type Error struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Code ErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=backup.v1beta1.ErrorCode" json:"code,omitempty"` + Code ErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=backup.v1.ErrorCode" json:"code,omitempty"` } func (x *Error) Reset() { @@ -135,36 +135,33 @@ var File_managementpb_backup_errors_proto protoreflect.FileDescriptor var file_managementpb_backup_errors_proto_rawDesc = []byte{ 0x0a, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x22, 0x36, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x04, 0x63, - 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x2a, 0xc1, 0x01, 0x0a, 0x09, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, - 0x12, 0x27, 0x0a, 0x23, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x58, - 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, - 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x52, 0x52, - 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, - 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, - 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, - 0x55, 0x50, 0x10, 0x03, 0x12, 0x28, 0x0a, 0x24, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, - 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, - 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x4d, 0x59, 0x53, 0x51, 0x4c, 0x10, 0x04, 0x42, 0xb8, - 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1a, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x74, 0x6f, 0x12, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x22, 0x31, 0x0a, + 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x28, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, + 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, + 0x2a, 0xc1, 0x01, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, + 0x0a, 0x12, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, + 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x27, 0x0a, 0x23, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, + 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x5f, + 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, + 0x21, 0x0a, 0x1d, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, + 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x58, 0x54, 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, + 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, + 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x58, 0x54, + 0x52, 0x41, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x10, 0x03, 0x12, 0x28, 0x0a, 0x24, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x41, + 0x54, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x4d, 0x59, 0x53, + 0x51, 0x4c, 0x10, 0x04, 0x42, 0x9a, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0xa2, 0x02, + 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, 0x31, + 0xca, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -183,13 +180,13 @@ var ( file_managementpb_backup_errors_proto_enumTypes = make([]protoimpl.EnumInfo, 1) file_managementpb_backup_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 1) file_managementpb_backup_errors_proto_goTypes = []interface{}{ - (ErrorCode)(0), // 0: backup.v1beta1.ErrorCode - (*Error)(nil), // 1: backup.v1beta1.Error + (ErrorCode)(0), // 0: backup.v1.ErrorCode + (*Error)(nil), // 1: backup.v1.Error } ) var file_managementpb_backup_errors_proto_depIdxs = []int32{ - 0, // 0: backup.v1beta1.Error.code:type_name -> backup.v1beta1.ErrorCode + 0, // 0: backup.v1.Error.code:type_name -> backup.v1.ErrorCode 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name diff --git a/api/managementpb/backup/errors.proto b/api/managementpb/backup/errors.proto index 919fb3aff6..0e1b1b9e50 100644 --- a/api/managementpb/backup/errors.proto +++ b/api/managementpb/backup/errors.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package backup.v1beta1; +package backup.v1; -option go_package = "api/managementpb/backup;backupv1beta1"; +option go_package = "api/managementpb/backup;backupv1"; // ErrorCode is a set of specific errors that are not present in the standard set of errors // and returned in the details field of the response. diff --git a/api/managementpb/backup/errors.validator.pb.go b/api/managementpb/backup/errors.validator.pb.go index cedf20614a..1ca646ed22 100644 --- a/api/managementpb/backup/errors.validator.pb.go +++ b/api/managementpb/backup/errors.validator.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: managementpb/backup/errors.proto -package backupv1beta1 +package backupv1 import ( fmt "fmt" diff --git a/api/managementpb/backup/json/backup.json b/api/managementpb/backup/json/backup.json index e54dce7db0..167c179c55 100644 --- a/api/managementpb/backup/json/backup.json +++ b/api/managementpb/backup/json/backup.json @@ -235,6 +235,94 @@ } } }, + "/v1/management/backup/Artifacts/ListPITRTimeranges": { + "post": { + "tags": [ + "Artifacts" + ], + "summary": "ListPitrTimeranges list the available MongoDB PITR timeranges in a given backup location", + "operationId": "ListPitrTimeranges", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "description": "Artifact ID represents artifact whose location has PITR timeranges to be retrieved.", + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "timeranges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "end_timestamp": { + "description": "end_timestamp is the time of the last event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 1 + }, + "start_timestamp": { + "description": "start_timestamp is the time of the first event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 0 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + }, + "message": { + "type": "string", + "x-order": 1 + } + } + } + } + } + } + }, "/v1/management/backup/Backups/ChangeScheduled": { "post": { "tags": [ @@ -898,6 +986,12 @@ "type": "string", "x-order": 1 }, + "pitr_timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp of PITR to restore to", + "x-order": 2 + }, "service_id": { "description": "Service identifier where backup should be restored.", "type": "string", @@ -1226,13 +1320,8 @@ "type": "string", "x-order": 1 }, - "name": { - "type": "string", - "title": "Location name", - "x-order": 0 - }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -1242,16 +1331,10 @@ }, "x-order": 2 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 3 + "name": { + "type": "string", + "title": "Location name", + "x-order": 0 }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", @@ -1274,7 +1357,7 @@ "x-order": 2 } }, - "x-order": 4 + "x-order": 3 } } } @@ -1347,18 +1430,8 @@ "type": "string", "x-order": 2 }, - "location_id": { - "description": "Machine-readable ID.", - "type": "string", - "x-order": 0 - }, - "name": { - "type": "string", - "title": "Location name", - "x-order": 1 - }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -1368,16 +1441,15 @@ }, "x-order": 3 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 4 + "location_id": { + "description": "Machine-readable ID.", + "type": "string", + "x-order": 0 + }, + "name": { + "type": "string", + "title": "Location name", + "x-order": 1 }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", @@ -1400,7 +1472,7 @@ "x-order": 2 } }, - "x-order": 5 + "x-order": 4 } } } @@ -1481,18 +1553,8 @@ "title": "Short description", "x-order": 2 }, - "location_id": { - "description": "Machine-readable ID.", - "type": "string", - "x-order": 0 - }, - "name": { - "type": "string", - "title": "Location name", - "x-order": 1 - }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -1502,16 +1564,15 @@ }, "x-order": 3 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 4 + "location_id": { + "description": "Machine-readable ID.", + "type": "string", + "x-order": 0 + }, + "name": { + "type": "string", + "title": "Location name", + "x-order": 1 }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", @@ -1534,7 +1595,7 @@ "x-order": 2 } }, - "x-order": 5 + "x-order": 4 } } }, @@ -1662,8 +1723,8 @@ "schema": { "type": "object", "properties": { - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -1673,17 +1734,6 @@ }, "x-order": 0 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 1 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -1705,7 +1755,7 @@ "x-order": 2 } }, - "x-order": 2 + "x-order": 1 } } } diff --git a/api/managementpb/backup/json/client/artifacts/artifacts_client.go b/api/managementpb/backup/json/client/artifacts/artifacts_client.go index dc0ba0e959..c423279259 100644 --- a/api/managementpb/backup/json/client/artifacts/artifacts_client.go +++ b/api/managementpb/backup/json/client/artifacts/artifacts_client.go @@ -32,6 +32,8 @@ type ClientService interface { ListArtifacts(params *ListArtifactsParams, opts ...ClientOption) (*ListArtifactsOK, error) + ListPitrTimeranges(params *ListPitrTimerangesParams, opts ...ClientOption) (*ListPitrTimerangesOK, error) + SetTransport(transport runtime.ClientTransport) } @@ -109,6 +111,43 @@ func (a *Client) ListArtifacts(params *ListArtifactsParams, opts ...ClientOption return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +ListPitrTimeranges lists pitr timeranges list the available mongo DB p i t r timeranges in a given backup location +*/ +func (a *Client) ListPitrTimeranges(params *ListPitrTimerangesParams, opts ...ClientOption) (*ListPitrTimerangesOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewListPitrTimerangesParams() + } + op := &runtime.ClientOperation{ + ID: "ListPitrTimeranges", + Method: "POST", + PathPattern: "/v1/management/backup/Artifacts/ListPITRTimeranges", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListPitrTimerangesReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + success, ok := result.(*ListPitrTimerangesOK) + if ok { + return success, nil + } + // unexpected success response + unexpectedSuccess := result.(*ListPitrTimerangesDefault) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + // SetTransport changes the transport on the client func (a *Client) SetTransport(transport runtime.ClientTransport) { a.transport = transport diff --git a/api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_parameters.go b/api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_parameters.go new file mode 100644 index 0000000000..66e1f4cf57 --- /dev/null +++ b/api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_parameters.go @@ -0,0 +1,144 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package artifacts + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewListPitrTimerangesParams creates a new ListPitrTimerangesParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewListPitrTimerangesParams() *ListPitrTimerangesParams { + return &ListPitrTimerangesParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListPitrTimerangesParamsWithTimeout creates a new ListPitrTimerangesParams object +// with the ability to set a timeout on a request. +func NewListPitrTimerangesParamsWithTimeout(timeout time.Duration) *ListPitrTimerangesParams { + return &ListPitrTimerangesParams{ + timeout: timeout, + } +} + +// NewListPitrTimerangesParamsWithContext creates a new ListPitrTimerangesParams object +// with the ability to set a context for a request. +func NewListPitrTimerangesParamsWithContext(ctx context.Context) *ListPitrTimerangesParams { + return &ListPitrTimerangesParams{ + Context: ctx, + } +} + +// NewListPitrTimerangesParamsWithHTTPClient creates a new ListPitrTimerangesParams object +// with the ability to set a custom HTTPClient for a request. +func NewListPitrTimerangesParamsWithHTTPClient(client *http.Client) *ListPitrTimerangesParams { + return &ListPitrTimerangesParams{ + HTTPClient: client, + } +} + +/* +ListPitrTimerangesParams contains all the parameters to send to the API endpoint + + for the list pitr timeranges operation. + + Typically these are written to a http.Request. +*/ +type ListPitrTimerangesParams struct { + // Body. + Body ListPitrTimerangesBody + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list pitr timeranges params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListPitrTimerangesParams) WithDefaults() *ListPitrTimerangesParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list pitr timeranges params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListPitrTimerangesParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list pitr timeranges params +func (o *ListPitrTimerangesParams) WithTimeout(timeout time.Duration) *ListPitrTimerangesParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list pitr timeranges params +func (o *ListPitrTimerangesParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list pitr timeranges params +func (o *ListPitrTimerangesParams) WithContext(ctx context.Context) *ListPitrTimerangesParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list pitr timeranges params +func (o *ListPitrTimerangesParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list pitr timeranges params +func (o *ListPitrTimerangesParams) WithHTTPClient(client *http.Client) *ListPitrTimerangesParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list pitr timeranges params +func (o *ListPitrTimerangesParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the list pitr timeranges params +func (o *ListPitrTimerangesParams) WithBody(body ListPitrTimerangesBody) *ListPitrTimerangesParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the list pitr timeranges params +func (o *ListPitrTimerangesParams) SetBody(body ListPitrTimerangesBody) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *ListPitrTimerangesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_responses.go b/api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_responses.go new file mode 100644 index 0000000000..1cd2d69336 --- /dev/null +++ b/api/managementpb/backup/json/client/artifacts/list_pitr_timeranges_responses.go @@ -0,0 +1,475 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package artifacts + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ListPitrTimerangesReader is a Reader for the ListPitrTimeranges structure. +type ListPitrTimerangesReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListPitrTimerangesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 200: + result := NewListPitrTimerangesOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListPitrTimerangesDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListPitrTimerangesOK creates a ListPitrTimerangesOK with default headers values +func NewListPitrTimerangesOK() *ListPitrTimerangesOK { + return &ListPitrTimerangesOK{} +} + +/* +ListPitrTimerangesOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListPitrTimerangesOK struct { + Payload *ListPitrTimerangesOKBody +} + +func (o *ListPitrTimerangesOK) Error() string { + return fmt.Sprintf("[POST /v1/management/backup/Artifacts/ListPITRTimeranges][%d] listPitrTimerangesOk %+v", 200, o.Payload) +} + +func (o *ListPitrTimerangesOK) GetPayload() *ListPitrTimerangesOKBody { + return o.Payload +} + +func (o *ListPitrTimerangesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListPitrTimerangesOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewListPitrTimerangesDefault creates a ListPitrTimerangesDefault with default headers values +func NewListPitrTimerangesDefault(code int) *ListPitrTimerangesDefault { + return &ListPitrTimerangesDefault{ + _statusCode: code, + } +} + +/* +ListPitrTimerangesDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListPitrTimerangesDefault struct { + _statusCode int + + Payload *ListPitrTimerangesDefaultBody +} + +// Code gets the status code for the list pitr timeranges default response +func (o *ListPitrTimerangesDefault) Code() int { + return o._statusCode +} + +func (o *ListPitrTimerangesDefault) Error() string { + return fmt.Sprintf("[POST /v1/management/backup/Artifacts/ListPITRTimeranges][%d] ListPitrTimeranges default %+v", o._statusCode, o.Payload) +} + +func (o *ListPitrTimerangesDefault) GetPayload() *ListPitrTimerangesDefaultBody { + return o.Payload +} + +func (o *ListPitrTimerangesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListPitrTimerangesDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +/* +ListPitrTimerangesBody list pitr timeranges body +swagger:model ListPitrTimerangesBody +*/ +type ListPitrTimerangesBody struct { + // Artifact ID represents artifact whose location has PITR timeranges to be retrieved. + ArtifactID string `json:"artifact_id,omitempty"` +} + +// Validate validates this list pitr timeranges body +func (o *ListPitrTimerangesBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list pitr timeranges body based on context it is used +func (o *ListPitrTimerangesBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListPitrTimerangesBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListPitrTimerangesBody) UnmarshalBinary(b []byte) error { + var res ListPitrTimerangesBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListPitrTimerangesDefaultBody list pitr timeranges default body +swagger:model ListPitrTimerangesDefaultBody +*/ +type ListPitrTimerangesDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListPitrTimerangesDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list pitr timeranges default body +func (o *ListPitrTimerangesDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListPitrTimerangesDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ListPitrTimeranges default" + "." + "details" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ListPitrTimeranges default" + "." + "details" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list pitr timeranges default body based on the context it is used +func (o *ListPitrTimerangesDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListPitrTimerangesDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("ListPitrTimeranges default" + "." + "details" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("ListPitrTimeranges default" + "." + "details" + "." + strconv.Itoa(i)) + } + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListPitrTimerangesDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListPitrTimerangesDefaultBody) UnmarshalBinary(b []byte) error { + var res ListPitrTimerangesDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListPitrTimerangesDefaultBodyDetailsItems0 list pitr timeranges default body details items0 +swagger:model ListPitrTimerangesDefaultBodyDetailsItems0 +*/ +type ListPitrTimerangesDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` +} + +// Validate validates this list pitr timeranges default body details items0 +func (o *ListPitrTimerangesDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list pitr timeranges default body details items0 based on context it is used +func (o *ListPitrTimerangesDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListPitrTimerangesDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListPitrTimerangesDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListPitrTimerangesDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListPitrTimerangesOKBody list pitr timeranges OK body +swagger:model ListPitrTimerangesOKBody +*/ +type ListPitrTimerangesOKBody struct { + // timeranges + Timeranges []*ListPitrTimerangesOKBodyTimerangesItems0 `json:"timeranges"` +} + +// Validate validates this list pitr timeranges OK body +func (o *ListPitrTimerangesOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateTimeranges(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListPitrTimerangesOKBody) validateTimeranges(formats strfmt.Registry) error { + if swag.IsZero(o.Timeranges) { // not required + return nil + } + + for i := 0; i < len(o.Timeranges); i++ { + if swag.IsZero(o.Timeranges[i]) { // not required + continue + } + + if o.Timeranges[i] != nil { + if err := o.Timeranges[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("listPitrTimerangesOk" + "." + "timeranges" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("listPitrTimerangesOk" + "." + "timeranges" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list pitr timeranges OK body based on the context it is used +func (o *ListPitrTimerangesOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateTimeranges(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListPitrTimerangesOKBody) contextValidateTimeranges(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Timeranges); i++ { + if o.Timeranges[i] != nil { + if err := o.Timeranges[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("listPitrTimerangesOk" + "." + "timeranges" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("listPitrTimerangesOk" + "." + "timeranges" + "." + strconv.Itoa(i)) + } + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListPitrTimerangesOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListPitrTimerangesOKBody) UnmarshalBinary(b []byte) error { + var res ListPitrTimerangesOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListPitrTimerangesOKBodyTimerangesItems0 list pitr timeranges OK body timeranges items0 +swagger:model ListPitrTimerangesOKBodyTimerangesItems0 +*/ +type ListPitrTimerangesOKBodyTimerangesItems0 struct { + // start_timestamp is the time of the first event in the PITR chunk. + // Format: date-time + StartTimestamp strfmt.DateTime `json:"start_timestamp,omitempty"` + + // end_timestamp is the time of the last event in the PITR chunk. + // Format: date-time + EndTimestamp strfmt.DateTime `json:"end_timestamp,omitempty"` +} + +// Validate validates this list pitr timeranges OK body timeranges items0 +func (o *ListPitrTimerangesOKBodyTimerangesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateStartTimestamp(formats); err != nil { + res = append(res, err) + } + + if err := o.validateEndTimestamp(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListPitrTimerangesOKBodyTimerangesItems0) validateStartTimestamp(formats strfmt.Registry) error { + if swag.IsZero(o.StartTimestamp) { // not required + return nil + } + + if err := validate.FormatOf("start_timestamp", "body", "date-time", o.StartTimestamp.String(), formats); err != nil { + return err + } + + return nil +} + +func (o *ListPitrTimerangesOKBodyTimerangesItems0) validateEndTimestamp(formats strfmt.Registry) error { + if swag.IsZero(o.EndTimestamp) { // not required + return nil + } + + if err := validate.FormatOf("end_timestamp", "body", "date-time", o.EndTimestamp.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this list pitr timeranges OK body timeranges items0 based on context it is used +func (o *ListPitrTimerangesOKBodyTimerangesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListPitrTimerangesOKBodyTimerangesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListPitrTimerangesOKBodyTimerangesItems0) UnmarshalBinary(b []byte) error { + var res ListPitrTimerangesOKBodyTimerangesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/managementpb/backup/json/client/backups/restore_backup_responses.go b/api/managementpb/backup/json/client/backups/restore_backup_responses.go index 608b6e352c..39085e7f15 100644 --- a/api/managementpb/backup/json/client/backups/restore_backup_responses.go +++ b/api/managementpb/backup/json/client/backups/restore_backup_responses.go @@ -15,6 +15,7 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" + "github.com/go-openapi/validate" ) // RestoreBackupReader is a Reader for the RestoreBackup structure. @@ -128,10 +129,35 @@ type RestoreBackupBody struct { // Artifact id to restore. ArtifactID string `json:"artifact_id,omitempty"` + + // Timestamp of PITR to restore to + // Format: date-time + PitrTimestamp strfmt.DateTime `json:"pitr_timestamp,omitempty"` } // Validate validates this restore backup body func (o *RestoreBackupBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validatePitrTimestamp(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *RestoreBackupBody) validatePitrTimestamp(formats strfmt.Registry) error { + if swag.IsZero(o.PitrTimestamp) { // not required + return nil + } + + if err := validate.FormatOf("body"+"."+"pitr_timestamp", "body", "date-time", o.PitrTimestamp.String(), formats); err != nil { + return err + } + return nil } diff --git a/api/managementpb/backup/json/client/locations/add_location_responses.go b/api/managementpb/backup/json/client/locations/add_location_responses.go index 541af9a52d..9267795dda 100644 --- a/api/managementpb/backup/json/client/locations/add_location_responses.go +++ b/api/managementpb/backup/json/client/locations/add_location_responses.go @@ -129,11 +129,8 @@ type AddLocationBody struct { // description Description string `json:"description,omitempty"` - // pmm client config - PMMClientConfig *AddLocationParamsBodyPMMClientConfig `json:"pmm_client_config,omitempty"` - - // pmm server config - PMMServerConfig *AddLocationParamsBodyPMMServerConfig `json:"pmm_server_config,omitempty"` + // filesystem config + FilesystemConfig *AddLocationParamsBodyFilesystemConfig `json:"filesystem_config,omitempty"` // s3 config S3Config *AddLocationParamsBodyS3Config `json:"s3_config,omitempty"` @@ -143,11 +140,7 @@ type AddLocationBody struct { func (o *AddLocationBody) Validate(formats strfmt.Registry) error { var res []error - if err := o.validatePMMClientConfig(formats); err != nil { - res = append(res, err) - } - - if err := o.validatePMMServerConfig(formats); err != nil { + if err := o.validateFilesystemConfig(formats); err != nil { res = append(res, err) } @@ -161,36 +154,17 @@ func (o *AddLocationBody) Validate(formats strfmt.Registry) error { return nil } -func (o *AddLocationBody) validatePMMClientConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMClientConfig) { // not required +func (o *AddLocationBody) validateFilesystemConfig(formats strfmt.Registry) error { + if swag.IsZero(o.FilesystemConfig) { // not required return nil } - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.Validate(formats); err != nil { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.Validate(formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_client_config") + return ve.ValidateName("body" + "." + "filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *AddLocationBody) validatePMMServerConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMServerConfig) { // not required - return nil - } - - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_server_config") + return ce.ValidateName("body" + "." + "filesystem_config") } return err } @@ -222,11 +196,7 @@ func (o *AddLocationBody) validateS3Config(formats strfmt.Registry) error { func (o *AddLocationBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error - if err := o.contextValidatePMMClientConfig(ctx, formats); err != nil { - res = append(res, err) - } - - if err := o.contextValidatePMMServerConfig(ctx, formats); err != nil { + if err := o.contextValidateFilesystemConfig(ctx, formats); err != nil { res = append(res, err) } @@ -240,28 +210,13 @@ func (o *AddLocationBody) ContextValidate(ctx context.Context, formats strfmt.Re return nil } -func (o *AddLocationBody) contextValidatePMMClientConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.ContextValidate(ctx, formats); err != nil { +func (o *AddLocationBody) contextValidateFilesystemConfig(ctx context.Context, formats strfmt.Registry) error { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_client_config") + return ve.ValidateName("body" + "." + "filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *AddLocationBody) contextValidatePMMServerConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.ContextValidate(ctx, formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_server_config") + return ce.ValidateName("body" + "." + "filesystem_config") } return err } @@ -482,63 +437,26 @@ func (o *AddLocationOKBody) UnmarshalBinary(b []byte) error { } /* -AddLocationParamsBodyPMMClientConfig PMMClientLocationConfig represents file system config inside pmm-client. -swagger:model AddLocationParamsBodyPMMClientConfig -*/ -type AddLocationParamsBodyPMMClientConfig struct { - // path - Path string `json:"path,omitempty"` -} - -// Validate validates this add location params body PMM client config -func (o *AddLocationParamsBodyPMMClientConfig) Validate(formats strfmt.Registry) error { - return nil -} - -// ContextValidate validates this add location params body PMM client config based on context it is used -func (o *AddLocationParamsBodyPMMClientConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { - return nil -} - -// MarshalBinary interface implementation -func (o *AddLocationParamsBodyPMMClientConfig) MarshalBinary() ([]byte, error) { - if o == nil { - return nil, nil - } - return swag.WriteJSON(o) -} - -// UnmarshalBinary interface implementation -func (o *AddLocationParamsBodyPMMClientConfig) UnmarshalBinary(b []byte) error { - var res AddLocationParamsBodyPMMClientConfig - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *o = res - return nil -} - -/* -AddLocationParamsBodyPMMServerConfig PMMServerLocationConfig represents file system config inside pmm-server. -swagger:model AddLocationParamsBodyPMMServerConfig +AddLocationParamsBodyFilesystemConfig FilesystemLocationConfig represents file system location config. +swagger:model AddLocationParamsBodyFilesystemConfig */ -type AddLocationParamsBodyPMMServerConfig struct { +type AddLocationParamsBodyFilesystemConfig struct { // path Path string `json:"path,omitempty"` } -// Validate validates this add location params body PMM server config -func (o *AddLocationParamsBodyPMMServerConfig) Validate(formats strfmt.Registry) error { +// Validate validates this add location params body filesystem config +func (o *AddLocationParamsBodyFilesystemConfig) Validate(formats strfmt.Registry) error { return nil } -// ContextValidate validates this add location params body PMM server config based on context it is used -func (o *AddLocationParamsBodyPMMServerConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { +// ContextValidate validates this add location params body filesystem config based on context it is used +func (o *AddLocationParamsBodyFilesystemConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { return nil } // MarshalBinary interface implementation -func (o *AddLocationParamsBodyPMMServerConfig) MarshalBinary() ([]byte, error) { +func (o *AddLocationParamsBodyFilesystemConfig) MarshalBinary() ([]byte, error) { if o == nil { return nil, nil } @@ -546,8 +464,8 @@ func (o *AddLocationParamsBodyPMMServerConfig) MarshalBinary() ([]byte, error) { } // UnmarshalBinary interface implementation -func (o *AddLocationParamsBodyPMMServerConfig) UnmarshalBinary(b []byte) error { - var res AddLocationParamsBodyPMMServerConfig +func (o *AddLocationParamsBodyFilesystemConfig) UnmarshalBinary(b []byte) error { + var res AddLocationParamsBodyFilesystemConfig if err := swag.ReadJSON(b, &res); err != nil { return err } diff --git a/api/managementpb/backup/json/client/locations/change_location_responses.go b/api/managementpb/backup/json/client/locations/change_location_responses.go index 9f71cf16f4..fa79790e0f 100644 --- a/api/managementpb/backup/json/client/locations/change_location_responses.go +++ b/api/managementpb/backup/json/client/locations/change_location_responses.go @@ -130,11 +130,8 @@ type ChangeLocationBody struct { // description Description string `json:"description,omitempty"` - // pmm client config - PMMClientConfig *ChangeLocationParamsBodyPMMClientConfig `json:"pmm_client_config,omitempty"` - - // pmm server config - PMMServerConfig *ChangeLocationParamsBodyPMMServerConfig `json:"pmm_server_config,omitempty"` + // filesystem config + FilesystemConfig *ChangeLocationParamsBodyFilesystemConfig `json:"filesystem_config,omitempty"` // s3 config S3Config *ChangeLocationParamsBodyS3Config `json:"s3_config,omitempty"` @@ -144,11 +141,7 @@ type ChangeLocationBody struct { func (o *ChangeLocationBody) Validate(formats strfmt.Registry) error { var res []error - if err := o.validatePMMClientConfig(formats); err != nil { - res = append(res, err) - } - - if err := o.validatePMMServerConfig(formats); err != nil { + if err := o.validateFilesystemConfig(formats); err != nil { res = append(res, err) } @@ -162,36 +155,17 @@ func (o *ChangeLocationBody) Validate(formats strfmt.Registry) error { return nil } -func (o *ChangeLocationBody) validatePMMClientConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMClientConfig) { // not required +func (o *ChangeLocationBody) validateFilesystemConfig(formats strfmt.Registry) error { + if swag.IsZero(o.FilesystemConfig) { // not required return nil } - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.Validate(formats); err != nil { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.Validate(formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_client_config") + return ve.ValidateName("body" + "." + "filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *ChangeLocationBody) validatePMMServerConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMServerConfig) { // not required - return nil - } - - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_server_config") + return ce.ValidateName("body" + "." + "filesystem_config") } return err } @@ -223,11 +197,7 @@ func (o *ChangeLocationBody) validateS3Config(formats strfmt.Registry) error { func (o *ChangeLocationBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error - if err := o.contextValidatePMMClientConfig(ctx, formats); err != nil { - res = append(res, err) - } - - if err := o.contextValidatePMMServerConfig(ctx, formats); err != nil { + if err := o.contextValidateFilesystemConfig(ctx, formats); err != nil { res = append(res, err) } @@ -241,28 +211,13 @@ func (o *ChangeLocationBody) ContextValidate(ctx context.Context, formats strfmt return nil } -func (o *ChangeLocationBody) contextValidatePMMClientConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.ContextValidate(ctx, formats); err != nil { +func (o *ChangeLocationBody) contextValidateFilesystemConfig(ctx context.Context, formats strfmt.Registry) error { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_client_config") + return ve.ValidateName("body" + "." + "filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *ChangeLocationBody) contextValidatePMMServerConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.ContextValidate(ctx, formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_server_config") + return ce.ValidateName("body" + "." + "filesystem_config") } return err } @@ -446,63 +401,26 @@ func (o *ChangeLocationDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error } /* -ChangeLocationParamsBodyPMMClientConfig PMMClientLocationConfig represents file system config inside pmm-client. -swagger:model ChangeLocationParamsBodyPMMClientConfig -*/ -type ChangeLocationParamsBodyPMMClientConfig struct { - // path - Path string `json:"path,omitempty"` -} - -// Validate validates this change location params body PMM client config -func (o *ChangeLocationParamsBodyPMMClientConfig) Validate(formats strfmt.Registry) error { - return nil -} - -// ContextValidate validates this change location params body PMM client config based on context it is used -func (o *ChangeLocationParamsBodyPMMClientConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { - return nil -} - -// MarshalBinary interface implementation -func (o *ChangeLocationParamsBodyPMMClientConfig) MarshalBinary() ([]byte, error) { - if o == nil { - return nil, nil - } - return swag.WriteJSON(o) -} - -// UnmarshalBinary interface implementation -func (o *ChangeLocationParamsBodyPMMClientConfig) UnmarshalBinary(b []byte) error { - var res ChangeLocationParamsBodyPMMClientConfig - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *o = res - return nil -} - -/* -ChangeLocationParamsBodyPMMServerConfig PMMServerLocationConfig represents file system config inside pmm-server. -swagger:model ChangeLocationParamsBodyPMMServerConfig +ChangeLocationParamsBodyFilesystemConfig FilesystemLocationConfig represents file system location config. +swagger:model ChangeLocationParamsBodyFilesystemConfig */ -type ChangeLocationParamsBodyPMMServerConfig struct { +type ChangeLocationParamsBodyFilesystemConfig struct { // path Path string `json:"path,omitempty"` } -// Validate validates this change location params body PMM server config -func (o *ChangeLocationParamsBodyPMMServerConfig) Validate(formats strfmt.Registry) error { +// Validate validates this change location params body filesystem config +func (o *ChangeLocationParamsBodyFilesystemConfig) Validate(formats strfmt.Registry) error { return nil } -// ContextValidate validates this change location params body PMM server config based on context it is used -func (o *ChangeLocationParamsBodyPMMServerConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { +// ContextValidate validates this change location params body filesystem config based on context it is used +func (o *ChangeLocationParamsBodyFilesystemConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { return nil } // MarshalBinary interface implementation -func (o *ChangeLocationParamsBodyPMMServerConfig) MarshalBinary() ([]byte, error) { +func (o *ChangeLocationParamsBodyFilesystemConfig) MarshalBinary() ([]byte, error) { if o == nil { return nil, nil } @@ -510,8 +428,8 @@ func (o *ChangeLocationParamsBodyPMMServerConfig) MarshalBinary() ([]byte, error } // UnmarshalBinary interface implementation -func (o *ChangeLocationParamsBodyPMMServerConfig) UnmarshalBinary(b []byte) error { - var res ChangeLocationParamsBodyPMMServerConfig +func (o *ChangeLocationParamsBodyFilesystemConfig) UnmarshalBinary(b []byte) error { + var res ChangeLocationParamsBodyFilesystemConfig if err := swag.ReadJSON(b, &res); err != nil { return err } diff --git a/api/managementpb/backup/json/client/locations/list_locations_responses.go b/api/managementpb/backup/json/client/locations/list_locations_responses.go index 4400e58783..a005e9b029 100644 --- a/api/managementpb/backup/json/client/locations/list_locations_responses.go +++ b/api/managementpb/backup/json/client/locations/list_locations_responses.go @@ -371,11 +371,8 @@ type ListLocationsOKBodyLocationsItems0 struct { // Short description Description string `json:"description,omitempty"` - // pmm client config - PMMClientConfig *ListLocationsOKBodyLocationsItems0PMMClientConfig `json:"pmm_client_config,omitempty"` - - // pmm server config - PMMServerConfig *ListLocationsOKBodyLocationsItems0PMMServerConfig `json:"pmm_server_config,omitempty"` + // filesystem config + FilesystemConfig *ListLocationsOKBodyLocationsItems0FilesystemConfig `json:"filesystem_config,omitempty"` // s3 config S3Config *ListLocationsOKBodyLocationsItems0S3Config `json:"s3_config,omitempty"` @@ -385,11 +382,7 @@ type ListLocationsOKBodyLocationsItems0 struct { func (o *ListLocationsOKBodyLocationsItems0) Validate(formats strfmt.Registry) error { var res []error - if err := o.validatePMMClientConfig(formats); err != nil { - res = append(res, err) - } - - if err := o.validatePMMServerConfig(formats); err != nil { + if err := o.validateFilesystemConfig(formats); err != nil { res = append(res, err) } @@ -403,36 +396,17 @@ func (o *ListLocationsOKBodyLocationsItems0) Validate(formats strfmt.Registry) e return nil } -func (o *ListLocationsOKBodyLocationsItems0) validatePMMClientConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMClientConfig) { // not required +func (o *ListLocationsOKBodyLocationsItems0) validateFilesystemConfig(formats strfmt.Registry) error { + if swag.IsZero(o.FilesystemConfig) { // not required return nil } - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.Validate(formats); err != nil { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.Validate(formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("pmm_client_config") + return ve.ValidateName("filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *ListLocationsOKBodyLocationsItems0) validatePMMServerConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMServerConfig) { // not required - return nil - } - - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("pmm_server_config") + return ce.ValidateName("filesystem_config") } return err } @@ -464,11 +438,7 @@ func (o *ListLocationsOKBodyLocationsItems0) validateS3Config(formats strfmt.Reg func (o *ListLocationsOKBodyLocationsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error - if err := o.contextValidatePMMClientConfig(ctx, formats); err != nil { - res = append(res, err) - } - - if err := o.contextValidatePMMServerConfig(ctx, formats); err != nil { + if err := o.contextValidateFilesystemConfig(ctx, formats); err != nil { res = append(res, err) } @@ -482,28 +452,13 @@ func (o *ListLocationsOKBodyLocationsItems0) ContextValidate(ctx context.Context return nil } -func (o *ListLocationsOKBodyLocationsItems0) contextValidatePMMClientConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.ContextValidate(ctx, formats); err != nil { +func (o *ListLocationsOKBodyLocationsItems0) contextValidateFilesystemConfig(ctx context.Context, formats strfmt.Registry) error { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("pmm_client_config") + return ve.ValidateName("filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *ListLocationsOKBodyLocationsItems0) contextValidatePMMServerConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.ContextValidate(ctx, formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("pmm_server_config") + return ce.ValidateName("filesystem_config") } return err } @@ -546,63 +501,26 @@ func (o *ListLocationsOKBodyLocationsItems0) UnmarshalBinary(b []byte) error { } /* -ListLocationsOKBodyLocationsItems0PMMClientConfig PMMClientLocationConfig represents file system config inside pmm-client. -swagger:model ListLocationsOKBodyLocationsItems0PMMClientConfig -*/ -type ListLocationsOKBodyLocationsItems0PMMClientConfig struct { - // path - Path string `json:"path,omitempty"` -} - -// Validate validates this list locations OK body locations items0 PMM client config -func (o *ListLocationsOKBodyLocationsItems0PMMClientConfig) Validate(formats strfmt.Registry) error { - return nil -} - -// ContextValidate validates this list locations OK body locations items0 PMM client config based on context it is used -func (o *ListLocationsOKBodyLocationsItems0PMMClientConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { - return nil -} - -// MarshalBinary interface implementation -func (o *ListLocationsOKBodyLocationsItems0PMMClientConfig) MarshalBinary() ([]byte, error) { - if o == nil { - return nil, nil - } - return swag.WriteJSON(o) -} - -// UnmarshalBinary interface implementation -func (o *ListLocationsOKBodyLocationsItems0PMMClientConfig) UnmarshalBinary(b []byte) error { - var res ListLocationsOKBodyLocationsItems0PMMClientConfig - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *o = res - return nil -} - -/* -ListLocationsOKBodyLocationsItems0PMMServerConfig PMMServerLocationConfig represents file system config inside pmm-server. -swagger:model ListLocationsOKBodyLocationsItems0PMMServerConfig +ListLocationsOKBodyLocationsItems0FilesystemConfig FilesystemLocationConfig represents file system location config. +swagger:model ListLocationsOKBodyLocationsItems0FilesystemConfig */ -type ListLocationsOKBodyLocationsItems0PMMServerConfig struct { +type ListLocationsOKBodyLocationsItems0FilesystemConfig struct { // path Path string `json:"path,omitempty"` } -// Validate validates this list locations OK body locations items0 PMM server config -func (o *ListLocationsOKBodyLocationsItems0PMMServerConfig) Validate(formats strfmt.Registry) error { +// Validate validates this list locations OK body locations items0 filesystem config +func (o *ListLocationsOKBodyLocationsItems0FilesystemConfig) Validate(formats strfmt.Registry) error { return nil } -// ContextValidate validates this list locations OK body locations items0 PMM server config based on context it is used -func (o *ListLocationsOKBodyLocationsItems0PMMServerConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { +// ContextValidate validates this list locations OK body locations items0 filesystem config based on context it is used +func (o *ListLocationsOKBodyLocationsItems0FilesystemConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { return nil } // MarshalBinary interface implementation -func (o *ListLocationsOKBodyLocationsItems0PMMServerConfig) MarshalBinary() ([]byte, error) { +func (o *ListLocationsOKBodyLocationsItems0FilesystemConfig) MarshalBinary() ([]byte, error) { if o == nil { return nil, nil } @@ -610,8 +528,8 @@ func (o *ListLocationsOKBodyLocationsItems0PMMServerConfig) MarshalBinary() ([]b } // UnmarshalBinary interface implementation -func (o *ListLocationsOKBodyLocationsItems0PMMServerConfig) UnmarshalBinary(b []byte) error { - var res ListLocationsOKBodyLocationsItems0PMMServerConfig +func (o *ListLocationsOKBodyLocationsItems0FilesystemConfig) UnmarshalBinary(b []byte) error { + var res ListLocationsOKBodyLocationsItems0FilesystemConfig if err := swag.ReadJSON(b, &res); err != nil { return err } diff --git a/api/managementpb/backup/json/client/locations/test_location_config_responses.go b/api/managementpb/backup/json/client/locations/test_location_config_responses.go index 30b30ae21d..42948149c1 100644 --- a/api/managementpb/backup/json/client/locations/test_location_config_responses.go +++ b/api/managementpb/backup/json/client/locations/test_location_config_responses.go @@ -121,11 +121,8 @@ TestLocationConfigBody test location config body swagger:model TestLocationConfigBody */ type TestLocationConfigBody struct { - // pmm client config - PMMClientConfig *TestLocationConfigParamsBodyPMMClientConfig `json:"pmm_client_config,omitempty"` - - // pmm server config - PMMServerConfig *TestLocationConfigParamsBodyPMMServerConfig `json:"pmm_server_config,omitempty"` + // filesystem config + FilesystemConfig *TestLocationConfigParamsBodyFilesystemConfig `json:"filesystem_config,omitempty"` // s3 config S3Config *TestLocationConfigParamsBodyS3Config `json:"s3_config,omitempty"` @@ -135,11 +132,7 @@ type TestLocationConfigBody struct { func (o *TestLocationConfigBody) Validate(formats strfmt.Registry) error { var res []error - if err := o.validatePMMClientConfig(formats); err != nil { - res = append(res, err) - } - - if err := o.validatePMMServerConfig(formats); err != nil { + if err := o.validateFilesystemConfig(formats); err != nil { res = append(res, err) } @@ -153,36 +146,17 @@ func (o *TestLocationConfigBody) Validate(formats strfmt.Registry) error { return nil } -func (o *TestLocationConfigBody) validatePMMClientConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMClientConfig) { // not required +func (o *TestLocationConfigBody) validateFilesystemConfig(formats strfmt.Registry) error { + if swag.IsZero(o.FilesystemConfig) { // not required return nil } - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.Validate(formats); err != nil { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.Validate(formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_client_config") + return ve.ValidateName("body" + "." + "filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *TestLocationConfigBody) validatePMMServerConfig(formats strfmt.Registry) error { - if swag.IsZero(o.PMMServerConfig) { // not required - return nil - } - - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_server_config") + return ce.ValidateName("body" + "." + "filesystem_config") } return err } @@ -214,11 +188,7 @@ func (o *TestLocationConfigBody) validateS3Config(formats strfmt.Registry) error func (o *TestLocationConfigBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error - if err := o.contextValidatePMMClientConfig(ctx, formats); err != nil { - res = append(res, err) - } - - if err := o.contextValidatePMMServerConfig(ctx, formats); err != nil { + if err := o.contextValidateFilesystemConfig(ctx, formats); err != nil { res = append(res, err) } @@ -232,28 +202,13 @@ func (o *TestLocationConfigBody) ContextValidate(ctx context.Context, formats st return nil } -func (o *TestLocationConfigBody) contextValidatePMMClientConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMClientConfig != nil { - if err := o.PMMClientConfig.ContextValidate(ctx, formats); err != nil { +func (o *TestLocationConfigBody) contextValidateFilesystemConfig(ctx context.Context, formats strfmt.Registry) error { + if o.FilesystemConfig != nil { + if err := o.FilesystemConfig.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_client_config") + return ve.ValidateName("body" + "." + "filesystem_config") } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_client_config") - } - return err - } - } - - return nil -} - -func (o *TestLocationConfigBody) contextValidatePMMServerConfig(ctx context.Context, formats strfmt.Registry) error { - if o.PMMServerConfig != nil { - if err := o.PMMServerConfig.ContextValidate(ctx, formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("body" + "." + "pmm_server_config") - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName("body" + "." + "pmm_server_config") + return ce.ValidateName("body" + "." + "filesystem_config") } return err } @@ -437,63 +392,26 @@ func (o *TestLocationConfigDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) e } /* -TestLocationConfigParamsBodyPMMClientConfig PMMClientLocationConfig represents file system config inside pmm-client. -swagger:model TestLocationConfigParamsBodyPMMClientConfig -*/ -type TestLocationConfigParamsBodyPMMClientConfig struct { - // path - Path string `json:"path,omitempty"` -} - -// Validate validates this test location config params body PMM client config -func (o *TestLocationConfigParamsBodyPMMClientConfig) Validate(formats strfmt.Registry) error { - return nil -} - -// ContextValidate validates this test location config params body PMM client config based on context it is used -func (o *TestLocationConfigParamsBodyPMMClientConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { - return nil -} - -// MarshalBinary interface implementation -func (o *TestLocationConfigParamsBodyPMMClientConfig) MarshalBinary() ([]byte, error) { - if o == nil { - return nil, nil - } - return swag.WriteJSON(o) -} - -// UnmarshalBinary interface implementation -func (o *TestLocationConfigParamsBodyPMMClientConfig) UnmarshalBinary(b []byte) error { - var res TestLocationConfigParamsBodyPMMClientConfig - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *o = res - return nil -} - -/* -TestLocationConfigParamsBodyPMMServerConfig PMMServerLocationConfig represents file system config inside pmm-server. -swagger:model TestLocationConfigParamsBodyPMMServerConfig +TestLocationConfigParamsBodyFilesystemConfig FilesystemLocationConfig represents file system location config. +swagger:model TestLocationConfigParamsBodyFilesystemConfig */ -type TestLocationConfigParamsBodyPMMServerConfig struct { +type TestLocationConfigParamsBodyFilesystemConfig struct { // path Path string `json:"path,omitempty"` } -// Validate validates this test location config params body PMM server config -func (o *TestLocationConfigParamsBodyPMMServerConfig) Validate(formats strfmt.Registry) error { +// Validate validates this test location config params body filesystem config +func (o *TestLocationConfigParamsBodyFilesystemConfig) Validate(formats strfmt.Registry) error { return nil } -// ContextValidate validates this test location config params body PMM server config based on context it is used -func (o *TestLocationConfigParamsBodyPMMServerConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { +// ContextValidate validates this test location config params body filesystem config based on context it is used +func (o *TestLocationConfigParamsBodyFilesystemConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { return nil } // MarshalBinary interface implementation -func (o *TestLocationConfigParamsBodyPMMServerConfig) MarshalBinary() ([]byte, error) { +func (o *TestLocationConfigParamsBodyFilesystemConfig) MarshalBinary() ([]byte, error) { if o == nil { return nil, nil } @@ -501,8 +419,8 @@ func (o *TestLocationConfigParamsBodyPMMServerConfig) MarshalBinary() ([]byte, e } // UnmarshalBinary interface implementation -func (o *TestLocationConfigParamsBodyPMMServerConfig) UnmarshalBinary(b []byte) error { - var res TestLocationConfigParamsBodyPMMServerConfig +func (o *TestLocationConfigParamsBodyFilesystemConfig) UnmarshalBinary(b []byte) error { + var res TestLocationConfigParamsBodyFilesystemConfig if err := swag.ReadJSON(b, &res); err != nil { return err } diff --git a/api/managementpb/backup/locations.pb.go b/api/managementpb/backup/locations.pb.go index 1acd5309f7..5e01d3c555 100644 --- a/api/managementpb/backup/locations.pb.go +++ b/api/managementpb/backup/locations.pb.go @@ -4,7 +4,7 @@ // protoc (unknown) // source: managementpb/backup/locations.proto -package backupv1beta1 +package backupv1 import ( reflect "reflect" @@ -23,8 +23,8 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// PMMServerLocationConfig represents file system config inside pmm-server. -type PMMServerLocationConfig struct { +// FilesystemLocationConfig represents file system location config. +type FilesystemLocationConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -32,8 +32,8 @@ type PMMServerLocationConfig struct { Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` } -func (x *PMMServerLocationConfig) Reset() { - *x = PMMServerLocationConfig{} +func (x *FilesystemLocationConfig) Reset() { + *x = FilesystemLocationConfig{} if protoimpl.UnsafeEnabled { mi := &file_managementpb_backup_locations_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -41,13 +41,13 @@ func (x *PMMServerLocationConfig) Reset() { } } -func (x *PMMServerLocationConfig) String() string { +func (x *FilesystemLocationConfig) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PMMServerLocationConfig) ProtoMessage() {} +func (*FilesystemLocationConfig) ProtoMessage() {} -func (x *PMMServerLocationConfig) ProtoReflect() protoreflect.Message { +func (x *FilesystemLocationConfig) ProtoReflect() protoreflect.Message { mi := &file_managementpb_backup_locations_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -59,60 +59,12 @@ func (x *PMMServerLocationConfig) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PMMServerLocationConfig.ProtoReflect.Descriptor instead. -func (*PMMServerLocationConfig) Descriptor() ([]byte, []int) { +// Deprecated: Use FilesystemLocationConfig.ProtoReflect.Descriptor instead. +func (*FilesystemLocationConfig) Descriptor() ([]byte, []int) { return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{0} } -func (x *PMMServerLocationConfig) GetPath() string { - if x != nil { - return x.Path - } - return "" -} - -// PMMClientLocationConfig represents file system config inside pmm-client. -type PMMClientLocationConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` -} - -func (x *PMMClientLocationConfig) Reset() { - *x = PMMClientLocationConfig{} - if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PMMClientLocationConfig) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PMMClientLocationConfig) ProtoMessage() {} - -func (x *PMMClientLocationConfig) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_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 PMMClientLocationConfig.ProtoReflect.Descriptor instead. -func (*PMMClientLocationConfig) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{1} -} - -func (x *PMMClientLocationConfig) GetPath() string { +func (x *FilesystemLocationConfig) GetPath() string { if x != nil { return x.Path } @@ -134,7 +86,7 @@ type S3LocationConfig struct { func (x *S3LocationConfig) Reset() { *x = S3LocationConfig{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[2] + mi := &file_managementpb_backup_locations_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -147,7 +99,7 @@ func (x *S3LocationConfig) String() string { func (*S3LocationConfig) ProtoMessage() {} func (x *S3LocationConfig) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[2] + mi := &file_managementpb_backup_locations_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -160,7 +112,7 @@ func (x *S3LocationConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use S3LocationConfig.ProtoReflect.Descriptor instead. func (*S3LocationConfig) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{2} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{1} } func (x *S3LocationConfig) GetEndpoint() string { @@ -205,8 +157,7 @@ type Location struct { Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` // Types that are assignable to Config: // - // *Location_PmmClientConfig - // *Location_PmmServerConfig + // *Location_FilesystemConfig // *Location_S3Config Config isLocation_Config `protobuf_oneof:"config"` } @@ -214,7 +165,7 @@ type Location struct { func (x *Location) Reset() { *x = Location{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[3] + mi := &file_managementpb_backup_locations_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -227,7 +178,7 @@ func (x *Location) String() string { func (*Location) ProtoMessage() {} func (x *Location) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[3] + mi := &file_managementpb_backup_locations_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -240,7 +191,7 @@ func (x *Location) ProtoReflect() protoreflect.Message { // Deprecated: Use Location.ProtoReflect.Descriptor instead. func (*Location) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{3} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{2} } func (x *Location) GetLocationId() string { @@ -271,17 +222,9 @@ func (m *Location) GetConfig() isLocation_Config { return nil } -func (x *Location) GetPmmClientConfig() *PMMClientLocationConfig { - if x, ok := x.GetConfig().(*Location_PmmClientConfig); ok { - return x.PmmClientConfig - } - return nil -} - -// Deprecated: Do not use. -func (x *Location) GetPmmServerConfig() *PMMServerLocationConfig { - if x, ok := x.GetConfig().(*Location_PmmServerConfig); ok { - return x.PmmServerConfig +func (x *Location) GetFilesystemConfig() *FilesystemLocationConfig { + if x, ok := x.GetConfig().(*Location_FilesystemConfig); ok { + return x.FilesystemConfig } return nil } @@ -297,22 +240,15 @@ type isLocation_Config interface { isLocation_Config() } -type Location_PmmClientConfig struct { - PmmClientConfig *PMMClientLocationConfig `protobuf:"bytes,4,opt,name=pmm_client_config,json=pmmClientConfig,proto3,oneof"` -} - -type Location_PmmServerConfig struct { - // Deprecated: Do not use. - PmmServerConfig *PMMServerLocationConfig `protobuf:"bytes,5,opt,name=pmm_server_config,json=pmmServerConfig,proto3,oneof"` +type Location_FilesystemConfig struct { + FilesystemConfig *FilesystemLocationConfig `protobuf:"bytes,4,opt,name=filesystem_config,json=filesystemConfig,proto3,oneof"` } type Location_S3Config struct { - S3Config *S3LocationConfig `protobuf:"bytes,6,opt,name=s3_config,json=s3Config,proto3,oneof"` + S3Config *S3LocationConfig `protobuf:"bytes,5,opt,name=s3_config,json=s3Config,proto3,oneof"` } -func (*Location_PmmClientConfig) isLocation_Config() {} - -func (*Location_PmmServerConfig) isLocation_Config() {} +func (*Location_FilesystemConfig) isLocation_Config() {} func (*Location_S3Config) isLocation_Config() {} @@ -325,7 +261,7 @@ type ListLocationsRequest struct { func (x *ListLocationsRequest) Reset() { *x = ListLocationsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[4] + mi := &file_managementpb_backup_locations_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -338,7 +274,7 @@ func (x *ListLocationsRequest) String() string { func (*ListLocationsRequest) ProtoMessage() {} func (x *ListLocationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[4] + mi := &file_managementpb_backup_locations_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -351,7 +287,7 @@ func (x *ListLocationsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLocationsRequest.ProtoReflect.Descriptor instead. func (*ListLocationsRequest) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{4} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{3} } type ListLocationsResponse struct { @@ -365,7 +301,7 @@ type ListLocationsResponse struct { func (x *ListLocationsResponse) Reset() { *x = ListLocationsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[5] + mi := &file_managementpb_backup_locations_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -378,7 +314,7 @@ func (x *ListLocationsResponse) String() string { func (*ListLocationsResponse) ProtoMessage() {} func (x *ListLocationsResponse) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[5] + mi := &file_managementpb_backup_locations_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -391,7 +327,7 @@ func (x *ListLocationsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLocationsResponse.ProtoReflect.Descriptor instead. func (*ListLocationsResponse) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{5} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{4} } func (x *ListLocationsResponse) GetLocations() []*Location { @@ -409,20 +345,16 @@ type AddLocationRequest struct { // Location name Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // PMM-client file system configuration. Exactly one config should be set. - PmmClientConfig *PMMClientLocationConfig `protobuf:"bytes,3,opt,name=pmm_client_config,json=pmmClientConfig,proto3" json:"pmm_client_config,omitempty"` - // PMM-server file system configuration. Exactly one config should be set. - // - // Deprecated: Do not use. - PmmServerConfig *PMMServerLocationConfig `protobuf:"bytes,4,opt,name=pmm_server_config,json=pmmServerConfig,proto3" json:"pmm_server_config,omitempty"` + // Filesystem location configuration. Exactly one config should be set. + FilesystemConfig *FilesystemLocationConfig `protobuf:"bytes,3,opt,name=filesystem_config,json=filesystemConfig,proto3" json:"filesystem_config,omitempty"` // S3 Bucket configuration. Exactly one config should be set. - S3Config *S3LocationConfig `protobuf:"bytes,5,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` + S3Config *S3LocationConfig `protobuf:"bytes,4,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` } func (x *AddLocationRequest) Reset() { *x = AddLocationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[6] + mi := &file_managementpb_backup_locations_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -435,7 +367,7 @@ func (x *AddLocationRequest) String() string { func (*AddLocationRequest) ProtoMessage() {} func (x *AddLocationRequest) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[6] + mi := &file_managementpb_backup_locations_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -448,7 +380,7 @@ func (x *AddLocationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddLocationRequest.ProtoReflect.Descriptor instead. func (*AddLocationRequest) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{6} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{5} } func (x *AddLocationRequest) GetName() string { @@ -465,17 +397,9 @@ func (x *AddLocationRequest) GetDescription() string { return "" } -func (x *AddLocationRequest) GetPmmClientConfig() *PMMClientLocationConfig { - if x != nil { - return x.PmmClientConfig - } - return nil -} - -// Deprecated: Do not use. -func (x *AddLocationRequest) GetPmmServerConfig() *PMMServerLocationConfig { +func (x *AddLocationRequest) GetFilesystemConfig() *FilesystemLocationConfig { if x != nil { - return x.PmmServerConfig + return x.FilesystemConfig } return nil } @@ -499,7 +423,7 @@ type AddLocationResponse struct { func (x *AddLocationResponse) Reset() { *x = AddLocationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[7] + mi := &file_managementpb_backup_locations_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -512,7 +436,7 @@ func (x *AddLocationResponse) String() string { func (*AddLocationResponse) ProtoMessage() {} func (x *AddLocationResponse) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[7] + mi := &file_managementpb_backup_locations_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -525,7 +449,7 @@ func (x *AddLocationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddLocationResponse.ProtoReflect.Descriptor instead. func (*AddLocationResponse) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{7} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{6} } func (x *AddLocationResponse) GetLocationId() string { @@ -545,20 +469,16 @@ type ChangeLocationRequest struct { // Location name Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - // PMM-client file system configuration. Exactly one config should be set. - PmmClientConfig *PMMClientLocationConfig `protobuf:"bytes,4,opt,name=pmm_client_config,json=pmmClientConfig,proto3" json:"pmm_client_config,omitempty"` - // PMM-server file system configuration. Exactly one config should be set. - // - // Deprecated: Do not use. - PmmServerConfig *PMMServerLocationConfig `protobuf:"bytes,5,opt,name=pmm_server_config,json=pmmServerConfig,proto3" json:"pmm_server_config,omitempty"` + // Filesystem location configuration. Exactly one config should be set. + FilesystemConfig *FilesystemLocationConfig `protobuf:"bytes,4,opt,name=filesystem_config,json=filesystemConfig,proto3" json:"filesystem_config,omitempty"` // S3 Bucket configuration. Exactly one config should be set. - S3Config *S3LocationConfig `protobuf:"bytes,6,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` + S3Config *S3LocationConfig `protobuf:"bytes,5,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` } func (x *ChangeLocationRequest) Reset() { *x = ChangeLocationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[8] + mi := &file_managementpb_backup_locations_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -571,7 +491,7 @@ func (x *ChangeLocationRequest) String() string { func (*ChangeLocationRequest) ProtoMessage() {} func (x *ChangeLocationRequest) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[8] + mi := &file_managementpb_backup_locations_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -584,7 +504,7 @@ func (x *ChangeLocationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeLocationRequest.ProtoReflect.Descriptor instead. func (*ChangeLocationRequest) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{8} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{7} } func (x *ChangeLocationRequest) GetLocationId() string { @@ -608,17 +528,9 @@ func (x *ChangeLocationRequest) GetDescription() string { return "" } -func (x *ChangeLocationRequest) GetPmmClientConfig() *PMMClientLocationConfig { - if x != nil { - return x.PmmClientConfig - } - return nil -} - -// Deprecated: Do not use. -func (x *ChangeLocationRequest) GetPmmServerConfig() *PMMServerLocationConfig { +func (x *ChangeLocationRequest) GetFilesystemConfig() *FilesystemLocationConfig { if x != nil { - return x.PmmServerConfig + return x.FilesystemConfig } return nil } @@ -639,7 +551,7 @@ type ChangeLocationResponse struct { func (x *ChangeLocationResponse) Reset() { *x = ChangeLocationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[9] + mi := &file_managementpb_backup_locations_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -652,7 +564,7 @@ func (x *ChangeLocationResponse) String() string { func (*ChangeLocationResponse) ProtoMessage() {} func (x *ChangeLocationResponse) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[9] + mi := &file_managementpb_backup_locations_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -665,7 +577,7 @@ func (x *ChangeLocationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeLocationResponse.ProtoReflect.Descriptor instead. func (*ChangeLocationResponse) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{9} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{8} } type RemoveLocationRequest struct { @@ -682,7 +594,7 @@ type RemoveLocationRequest struct { func (x *RemoveLocationRequest) Reset() { *x = RemoveLocationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[10] + mi := &file_managementpb_backup_locations_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -695,7 +607,7 @@ func (x *RemoveLocationRequest) String() string { func (*RemoveLocationRequest) ProtoMessage() {} func (x *RemoveLocationRequest) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[10] + mi := &file_managementpb_backup_locations_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -708,7 +620,7 @@ func (x *RemoveLocationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveLocationRequest.ProtoReflect.Descriptor instead. func (*RemoveLocationRequest) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{10} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{9} } func (x *RemoveLocationRequest) GetLocationId() string { @@ -734,7 +646,7 @@ type RemoveLocationResponse struct { func (x *RemoveLocationResponse) Reset() { *x = RemoveLocationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[11] + mi := &file_managementpb_backup_locations_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -747,7 +659,7 @@ func (x *RemoveLocationResponse) String() string { func (*RemoveLocationResponse) ProtoMessage() {} func (x *RemoveLocationResponse) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[11] + mi := &file_managementpb_backup_locations_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -760,7 +672,7 @@ func (x *RemoveLocationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveLocationResponse.ProtoReflect.Descriptor instead. func (*RemoveLocationResponse) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{11} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{10} } type TestLocationConfigRequest struct { @@ -768,20 +680,16 @@ type TestLocationConfigRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // PMM-client file system configuration. Exactly one config should be set. - PmmClientConfig *PMMClientLocationConfig `protobuf:"bytes,1,opt,name=pmm_client_config,json=pmmClientConfig,proto3" json:"pmm_client_config,omitempty"` - // PMM-server file system configuration. Exactly one config should be set. - // - // Deprecated: Do not use. - PmmServerConfig *PMMServerLocationConfig `protobuf:"bytes,2,opt,name=pmm_server_config,json=pmmServerConfig,proto3" json:"pmm_server_config,omitempty"` + // Filesystem location configuration. Exactly one config should be set. + FilesystemConfig *FilesystemLocationConfig `protobuf:"bytes,1,opt,name=filesystem_config,json=filesystemConfig,proto3" json:"filesystem_config,omitempty"` // S3 Bucket configuration. Exactly one config should be set. - S3Config *S3LocationConfig `protobuf:"bytes,3,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` + S3Config *S3LocationConfig `protobuf:"bytes,2,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` } func (x *TestLocationConfigRequest) Reset() { *x = TestLocationConfigRequest{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[12] + mi := &file_managementpb_backup_locations_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -794,7 +702,7 @@ func (x *TestLocationConfigRequest) String() string { func (*TestLocationConfigRequest) ProtoMessage() {} func (x *TestLocationConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[12] + mi := &file_managementpb_backup_locations_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -807,20 +715,12 @@ func (x *TestLocationConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TestLocationConfigRequest.ProtoReflect.Descriptor instead. func (*TestLocationConfigRequest) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{12} -} - -func (x *TestLocationConfigRequest) GetPmmClientConfig() *PMMClientLocationConfig { - if x != nil { - return x.PmmClientConfig - } - return nil + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{11} } -// Deprecated: Do not use. -func (x *TestLocationConfigRequest) GetPmmServerConfig() *PMMServerLocationConfig { +func (x *TestLocationConfigRequest) GetFilesystemConfig() *FilesystemLocationConfig { if x != nil { - return x.PmmServerConfig + return x.FilesystemConfig } return nil } @@ -841,7 +741,7 @@ type TestLocationConfigResponse struct { func (x *TestLocationConfigResponse) Reset() { *x = TestLocationConfigResponse{} if protoimpl.UnsafeEnabled { - mi := &file_managementpb_backup_locations_proto_msgTypes[13] + mi := &file_managementpb_backup_locations_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -854,7 +754,7 @@ func (x *TestLocationConfigResponse) String() string { func (*TestLocationConfigResponse) ProtoMessage() {} func (x *TestLocationConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_managementpb_backup_locations_proto_msgTypes[13] + mi := &file_managementpb_backup_locations_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -867,7 +767,7 @@ func (x *TestLocationConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TestLocationConfigResponse.ProtoReflect.Descriptor instead. func (*TestLocationConfigResponse) Descriptor() ([]byte, []int) { - return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{13} + return file_managementpb_backup_locations_proto_rawDescGZIP(), []int{12} } var File_managementpb_backup_locations_proto protoreflect.FileDescriptor @@ -875,192 +775,159 @@ var File_managementpb_backup_locations_proto protoreflect.FileDescriptor var file_managementpb_backup_locations_proto_rawDesc = []byte{ 0x0a, 0x23, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x1a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x6d, 0x77, 0x69, 0x74, 0x6b, 0x6f, 0x77, 0x2f, 0x67, 0x6f, 0x2d, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 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, 0x22, 0x35, 0x0a, 0x17, 0x50, - 0x4d, 0x4d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x04, 0x70, 0x61, - 0x74, 0x68, 0x22, 0x35, 0x0a, 0x17, 0x50, 0x4d, 0x4d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, - 0x02, 0x58, 0x01, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0xad, 0x01, 0x0a, 0x10, 0x53, 0x33, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x22, - 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, - 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, - 0x12, 0x27, 0x0a, 0x0b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x0a, 0x62, - 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xde, 0x02, 0x0a, 0x08, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, - 0x11, 0x70, 0x6d, 0x6d, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x4d, 0x4d, 0x43, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x48, 0x00, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x11, 0x70, 0x6d, 0x6d, 0x5f, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x50, 0x4d, 0x4d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x02, 0x18, 0x01, 0x48, 0x00, 0x52, 0x0f, - 0x70, 0x6d, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x3f, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x42, 0x08, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x16, 0x0a, 0x14, 0x4c, 0x69, - 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x4f, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x09, 0x6c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0xbf, 0x02, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x11, 0x70, 0x6d, 0x6d, 0x5f, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x4d, 0x4d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, 0x70, 0x6d, - 0x6d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x57, 0x0a, - 0x11, 0x70, 0x6d, 0x6d, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x4d, 0x4d, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x33, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x36, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xe3, 0x02, - 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, - 0x1f, 0x02, 0x58, 0x01, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x11, 0x70, 0x6d, 0x6d, 0x5f, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x50, 0x4d, 0x4d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x57, 0x0a, 0x11, 0x70, - 0x6d, 0x6d, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x4d, 0x4d, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, - 0x02, 0x18, 0x01, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x0a, - 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x18, 0x0a, - 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x88, 0x02, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x53, 0x0a, 0x11, 0x70, 0x6d, 0x6d, 0x5f, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x50, 0x4d, 0x4d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x57, 0x0a, 0x11, 0x70, 0x6d, - 0x6d, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x4d, 0x4d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x02, - 0x18, 0x01, 0x52, 0x0f, 0x70, 0x6d, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x3d, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x22, 0x1c, 0x0a, 0x1a, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0xf3, 0x05, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x8d, - 0x01, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, + 0x1a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x77, 0x69, + 0x74, 0x6b, 0x6f, 0x77, 0x2f, 0x67, 0x6f, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 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, 0x22, 0x36, 0x0a, 0x18, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0xad, + 0x01, 0x0a, 0x10, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x22, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x08, 0x65, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, + 0x02, 0x58, 0x01, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x25, + 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, + 0x58, 0x01, 0x52, 0x0a, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xfb, + 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x48, 0x00, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x42, 0x08, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x16, 0x0a, 0x14, + 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0x4a, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0xde, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x50, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, + 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x22, 0x36, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x82, 0x02, 0x0a, 0x15, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, + 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x50, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x18, + 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0xa7, 0x01, 0x0a, 0x19, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x50, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x33, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x33, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x08, 0x73, 0x33, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x1c, 0x0a, 0x1a, + 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc0, 0x05, 0x0a, 0x09, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x83, 0x01, 0x0a, 0x0d, 0x4c, 0x69, 0x73, + 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x2e, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x86, - 0x01, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, - 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, - 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2f, 0x41, 0x64, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x92, 0x01, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x7c, + 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x2e, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x28, 0x22, 0x23, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x41, 0x64, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x88, 0x01, 0x0a, + 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x20, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x26, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x2b, 0x22, 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x92, 0x01, 0x0a, - 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x25, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x3a, 0x01, - 0x2a, 0x12, 0xa2, 0x01, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x2a, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, + 0x74, 0x1a, 0x21, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, 0x76, + 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x2f, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x88, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x3a, 0x01, 0x2a, 0x42, 0xbb, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x0e, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, - 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3b, - 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, - 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x3a, + 0x01, 0x2a, 0x12, 0x98, 0x01, 0x0a, 0x12, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x25, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x2a, + 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, + 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3a, 0x01, 0x2a, 0x42, 0x9d, 0x01, + 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x42, + 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, + 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, + 0xaa, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x0a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1076,54 +943,49 @@ func file_managementpb_backup_locations_proto_rawDescGZIP() []byte { } var ( - file_managementpb_backup_locations_proto_msgTypes = make([]protoimpl.MessageInfo, 14) + file_managementpb_backup_locations_proto_msgTypes = make([]protoimpl.MessageInfo, 13) file_managementpb_backup_locations_proto_goTypes = []interface{}{ - (*PMMServerLocationConfig)(nil), // 0: backup.v1beta1.PMMServerLocationConfig - (*PMMClientLocationConfig)(nil), // 1: backup.v1beta1.PMMClientLocationConfig - (*S3LocationConfig)(nil), // 2: backup.v1beta1.S3LocationConfig - (*Location)(nil), // 3: backup.v1beta1.Location - (*ListLocationsRequest)(nil), // 4: backup.v1beta1.ListLocationsRequest - (*ListLocationsResponse)(nil), // 5: backup.v1beta1.ListLocationsResponse - (*AddLocationRequest)(nil), // 6: backup.v1beta1.AddLocationRequest - (*AddLocationResponse)(nil), // 7: backup.v1beta1.AddLocationResponse - (*ChangeLocationRequest)(nil), // 8: backup.v1beta1.ChangeLocationRequest - (*ChangeLocationResponse)(nil), // 9: backup.v1beta1.ChangeLocationResponse - (*RemoveLocationRequest)(nil), // 10: backup.v1beta1.RemoveLocationRequest - (*RemoveLocationResponse)(nil), // 11: backup.v1beta1.RemoveLocationResponse - (*TestLocationConfigRequest)(nil), // 12: backup.v1beta1.TestLocationConfigRequest - (*TestLocationConfigResponse)(nil), // 13: backup.v1beta1.TestLocationConfigResponse + (*FilesystemLocationConfig)(nil), // 0: backup.v1.FilesystemLocationConfig + (*S3LocationConfig)(nil), // 1: backup.v1.S3LocationConfig + (*Location)(nil), // 2: backup.v1.Location + (*ListLocationsRequest)(nil), // 3: backup.v1.ListLocationsRequest + (*ListLocationsResponse)(nil), // 4: backup.v1.ListLocationsResponse + (*AddLocationRequest)(nil), // 5: backup.v1.AddLocationRequest + (*AddLocationResponse)(nil), // 6: backup.v1.AddLocationResponse + (*ChangeLocationRequest)(nil), // 7: backup.v1.ChangeLocationRequest + (*ChangeLocationResponse)(nil), // 8: backup.v1.ChangeLocationResponse + (*RemoveLocationRequest)(nil), // 9: backup.v1.RemoveLocationRequest + (*RemoveLocationResponse)(nil), // 10: backup.v1.RemoveLocationResponse + (*TestLocationConfigRequest)(nil), // 11: backup.v1.TestLocationConfigRequest + (*TestLocationConfigResponse)(nil), // 12: backup.v1.TestLocationConfigResponse } ) var file_managementpb_backup_locations_proto_depIdxs = []int32{ - 1, // 0: backup.v1beta1.Location.pmm_client_config:type_name -> backup.v1beta1.PMMClientLocationConfig - 0, // 1: backup.v1beta1.Location.pmm_server_config:type_name -> backup.v1beta1.PMMServerLocationConfig - 2, // 2: backup.v1beta1.Location.s3_config:type_name -> backup.v1beta1.S3LocationConfig - 3, // 3: backup.v1beta1.ListLocationsResponse.locations:type_name -> backup.v1beta1.Location - 1, // 4: backup.v1beta1.AddLocationRequest.pmm_client_config:type_name -> backup.v1beta1.PMMClientLocationConfig - 0, // 5: backup.v1beta1.AddLocationRequest.pmm_server_config:type_name -> backup.v1beta1.PMMServerLocationConfig - 2, // 6: backup.v1beta1.AddLocationRequest.s3_config:type_name -> backup.v1beta1.S3LocationConfig - 1, // 7: backup.v1beta1.ChangeLocationRequest.pmm_client_config:type_name -> backup.v1beta1.PMMClientLocationConfig - 0, // 8: backup.v1beta1.ChangeLocationRequest.pmm_server_config:type_name -> backup.v1beta1.PMMServerLocationConfig - 2, // 9: backup.v1beta1.ChangeLocationRequest.s3_config:type_name -> backup.v1beta1.S3LocationConfig - 1, // 10: backup.v1beta1.TestLocationConfigRequest.pmm_client_config:type_name -> backup.v1beta1.PMMClientLocationConfig - 0, // 11: backup.v1beta1.TestLocationConfigRequest.pmm_server_config:type_name -> backup.v1beta1.PMMServerLocationConfig - 2, // 12: backup.v1beta1.TestLocationConfigRequest.s3_config:type_name -> backup.v1beta1.S3LocationConfig - 4, // 13: backup.v1beta1.Locations.ListLocations:input_type -> backup.v1beta1.ListLocationsRequest - 6, // 14: backup.v1beta1.Locations.AddLocation:input_type -> backup.v1beta1.AddLocationRequest - 8, // 15: backup.v1beta1.Locations.ChangeLocation:input_type -> backup.v1beta1.ChangeLocationRequest - 10, // 16: backup.v1beta1.Locations.RemoveLocation:input_type -> backup.v1beta1.RemoveLocationRequest - 12, // 17: backup.v1beta1.Locations.TestLocationConfig:input_type -> backup.v1beta1.TestLocationConfigRequest - 5, // 18: backup.v1beta1.Locations.ListLocations:output_type -> backup.v1beta1.ListLocationsResponse - 7, // 19: backup.v1beta1.Locations.AddLocation:output_type -> backup.v1beta1.AddLocationResponse - 9, // 20: backup.v1beta1.Locations.ChangeLocation:output_type -> backup.v1beta1.ChangeLocationResponse - 11, // 21: backup.v1beta1.Locations.RemoveLocation:output_type -> backup.v1beta1.RemoveLocationResponse - 13, // 22: backup.v1beta1.Locations.TestLocationConfig:output_type -> backup.v1beta1.TestLocationConfigResponse - 18, // [18:23] is the sub-list for method output_type - 13, // [13:18] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 0, // 0: backup.v1.Location.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig + 1, // 1: backup.v1.Location.s3_config:type_name -> backup.v1.S3LocationConfig + 2, // 2: backup.v1.ListLocationsResponse.locations:type_name -> backup.v1.Location + 0, // 3: backup.v1.AddLocationRequest.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig + 1, // 4: backup.v1.AddLocationRequest.s3_config:type_name -> backup.v1.S3LocationConfig + 0, // 5: backup.v1.ChangeLocationRequest.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig + 1, // 6: backup.v1.ChangeLocationRequest.s3_config:type_name -> backup.v1.S3LocationConfig + 0, // 7: backup.v1.TestLocationConfigRequest.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig + 1, // 8: backup.v1.TestLocationConfigRequest.s3_config:type_name -> backup.v1.S3LocationConfig + 3, // 9: backup.v1.Locations.ListLocations:input_type -> backup.v1.ListLocationsRequest + 5, // 10: backup.v1.Locations.AddLocation:input_type -> backup.v1.AddLocationRequest + 7, // 11: backup.v1.Locations.ChangeLocation:input_type -> backup.v1.ChangeLocationRequest + 9, // 12: backup.v1.Locations.RemoveLocation:input_type -> backup.v1.RemoveLocationRequest + 11, // 13: backup.v1.Locations.TestLocationConfig:input_type -> backup.v1.TestLocationConfigRequest + 4, // 14: backup.v1.Locations.ListLocations:output_type -> backup.v1.ListLocationsResponse + 6, // 15: backup.v1.Locations.AddLocation:output_type -> backup.v1.AddLocationResponse + 8, // 16: backup.v1.Locations.ChangeLocation:output_type -> backup.v1.ChangeLocationResponse + 10, // 17: backup.v1.Locations.RemoveLocation:output_type -> backup.v1.RemoveLocationResponse + 12, // 18: backup.v1.Locations.TestLocationConfig:output_type -> backup.v1.TestLocationConfigResponse + 14, // [14:19] is the sub-list for method output_type + 9, // [9:14] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_managementpb_backup_locations_proto_init() } @@ -1133,7 +995,7 @@ func file_managementpb_backup_locations_proto_init() { } if !protoimpl.UnsafeEnabled { file_managementpb_backup_locations_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PMMServerLocationConfig); i { + switch v := v.(*FilesystemLocationConfig); i { case 0: return &v.state case 1: @@ -1145,18 +1007,6 @@ func file_managementpb_backup_locations_proto_init() { } } file_managementpb_backup_locations_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PMMClientLocationConfig); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_managementpb_backup_locations_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*S3LocationConfig); i { case 0: return &v.state @@ -1168,7 +1018,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Location); i { case 0: return &v.state @@ -1180,7 +1030,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListLocationsRequest); i { case 0: return &v.state @@ -1192,7 +1042,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListLocationsResponse); i { case 0: return &v.state @@ -1204,7 +1054,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddLocationRequest); i { case 0: return &v.state @@ -1216,7 +1066,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AddLocationResponse); i { case 0: return &v.state @@ -1228,7 +1078,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChangeLocationRequest); i { case 0: return &v.state @@ -1240,7 +1090,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChangeLocationResponse); i { case 0: return &v.state @@ -1252,7 +1102,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RemoveLocationRequest); i { case 0: return &v.state @@ -1264,7 +1114,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RemoveLocationResponse); i { case 0: return &v.state @@ -1276,7 +1126,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TestLocationConfigRequest); i { case 0: return &v.state @@ -1288,7 +1138,7 @@ func file_managementpb_backup_locations_proto_init() { return nil } } - file_managementpb_backup_locations_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_managementpb_backup_locations_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TestLocationConfigResponse); i { case 0: return &v.state @@ -1301,9 +1151,8 @@ func file_managementpb_backup_locations_proto_init() { } } } - file_managementpb_backup_locations_proto_msgTypes[3].OneofWrappers = []interface{}{ - (*Location_PmmClientConfig)(nil), - (*Location_PmmServerConfig)(nil), + file_managementpb_backup_locations_proto_msgTypes[2].OneofWrappers = []interface{}{ + (*Location_FilesystemConfig)(nil), (*Location_S3Config)(nil), } type x struct{} @@ -1312,7 +1161,7 @@ func file_managementpb_backup_locations_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_managementpb_backup_locations_proto_rawDesc, NumEnums: 0, - NumMessages: 14, + NumMessages: 13, NumExtensions: 0, NumServices: 1, }, diff --git a/api/managementpb/backup/locations.pb.gw.go b/api/managementpb/backup/locations.pb.gw.go index 1551fc8548..75eec019b6 100644 --- a/api/managementpb/backup/locations.pb.gw.go +++ b/api/managementpb/backup/locations.pb.gw.go @@ -2,11 +2,11 @@ // source: managementpb/backup/locations.proto /* -Package backupv1beta1 is a reverse proxy. +Package backupv1 is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package backupv1beta1 +package backupv1 import ( "context" @@ -206,7 +206,7 @@ func RegisterLocationsHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Locations/ListLocations", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/List")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Locations/ListLocations", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/List")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -230,7 +230,7 @@ func RegisterLocationsHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Locations/AddLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Add")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Locations/AddLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Add")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -254,7 +254,7 @@ func RegisterLocationsHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Locations/ChangeLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Change")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Locations/ChangeLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Change")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -278,7 +278,7 @@ func RegisterLocationsHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Locations/RemoveLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Remove")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Locations/RemoveLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Remove")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -302,7 +302,7 @@ func RegisterLocationsHandlerServer(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.Locations/TestLocationConfig", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/TestConfig")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.Locations/TestLocationConfig", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/TestConfig")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -364,7 +364,7 @@ func RegisterLocationsHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Locations/ListLocations", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/List")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Locations/ListLocations", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/List")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -385,7 +385,7 @@ func RegisterLocationsHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Locations/AddLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Add")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Locations/AddLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Add")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -406,7 +406,7 @@ func RegisterLocationsHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Locations/ChangeLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Change")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Locations/ChangeLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Change")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -427,7 +427,7 @@ func RegisterLocationsHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Locations/RemoveLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Remove")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Locations/RemoveLocation", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/Remove")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -448,7 +448,7 @@ func RegisterLocationsHandlerClient(ctx context.Context, mux *runtime.ServeMux, inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.Locations/TestLocationConfig", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/TestConfig")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.Locations/TestLocationConfig", runtime.WithHTTPPathPattern("/v1/management/backup/Locations/TestConfig")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return diff --git a/api/managementpb/backup/locations.proto b/api/managementpb/backup/locations.proto index daedd951f4..d00daf3f82 100644 --- a/api/managementpb/backup/locations.proto +++ b/api/managementpb/backup/locations.proto @@ -1,23 +1,14 @@ syntax = "proto3"; -package backup.v1beta1; +package backup.v1; -option go_package = "api/managementpb/backup;backupv1beta1"; +option go_package = "api/managementpb/backup;backupv1"; import "github.com/mwitkow/go-proto-validators/validator.proto"; import "google/api/annotations.proto"; -// PMMServerLocationConfig represents file system config inside pmm-server. -message PMMServerLocationConfig { - string path = 1 [ - (validator.field) = { - string_not_empty: true - } - ]; -} - -// PMMClientLocationConfig represents file system config inside pmm-client. -message PMMClientLocationConfig { +// FilesystemLocationConfig represents file system location config. +message FilesystemLocationConfig { string path = 1 [ (validator.field) = { string_not_empty: true @@ -58,9 +49,8 @@ message Location { // Short description string description = 3; oneof config { - PMMClientLocationConfig pmm_client_config = 4; - PMMServerLocationConfig pmm_server_config = 5 [deprecated = true]; - S3LocationConfig s3_config = 6; + FilesystemLocationConfig filesystem_config = 4; + S3LocationConfig s3_config = 5; } } @@ -78,12 +68,10 @@ message AddLocationRequest { } ]; string description = 2; - // PMM-client file system configuration. Exactly one config should be set. - PMMClientLocationConfig pmm_client_config = 3; - // PMM-server file system configuration. Exactly one config should be set. - PMMServerLocationConfig pmm_server_config = 4 [deprecated = true]; + // Filesystem location configuration. Exactly one config should be set. + FilesystemLocationConfig filesystem_config = 3; // S3 Bucket configuration. Exactly one config should be set. - S3LocationConfig s3_config = 5; + S3LocationConfig s3_config = 4; } message AddLocationResponse { @@ -101,12 +89,10 @@ message ChangeLocationRequest { // Location name string name = 2; string description = 3; - // PMM-client file system configuration. Exactly one config should be set. - PMMClientLocationConfig pmm_client_config = 4; - // PMM-server file system configuration. Exactly one config should be set. - PMMServerLocationConfig pmm_server_config = 5 [deprecated = true]; + // Filesystem location configuration. Exactly one config should be set. + FilesystemLocationConfig filesystem_config = 4; // S3 Bucket configuration. Exactly one config should be set. - S3LocationConfig s3_config = 6; + S3LocationConfig s3_config = 5; } message ChangeLocationResponse {} @@ -121,12 +107,10 @@ message RemoveLocationRequest { message RemoveLocationResponse {} message TestLocationConfigRequest { - // PMM-client file system configuration. Exactly one config should be set. - PMMClientLocationConfig pmm_client_config = 1; - // PMM-server file system configuration. Exactly one config should be set. - PMMServerLocationConfig pmm_server_config = 2 [deprecated = true]; + // Filesystem location configuration. Exactly one config should be set. + FilesystemLocationConfig filesystem_config = 1; // S3 Bucket configuration. Exactly one config should be set. - S3LocationConfig s3_config = 3; + S3LocationConfig s3_config = 2; } message TestLocationConfigResponse {} diff --git a/api/managementpb/backup/locations.validator.pb.go b/api/managementpb/backup/locations.validator.pb.go index 23252104e5..621e29fcb3 100644 --- a/api/managementpb/backup/locations.validator.pb.go +++ b/api/managementpb/backup/locations.validator.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: managementpb/backup/locations.proto -package backupv1beta1 +package backupv1 import ( fmt "fmt" @@ -20,14 +20,7 @@ var ( _ = math.Inf ) -func (this *PMMServerLocationConfig) Validate() error { - if this.Path == "" { - return github_com_mwitkow_go_proto_validators.FieldError("Path", fmt.Errorf(`value '%v' must not be an empty string`, this.Path)) - } - return nil -} - -func (this *PMMClientLocationConfig) Validate() error { +func (this *FilesystemLocationConfig) Validate() error { if this.Path == "" { return github_com_mwitkow_go_proto_validators.FieldError("Path", fmt.Errorf(`value '%v' must not be an empty string`, this.Path)) } @@ -51,17 +44,10 @@ func (this *S3LocationConfig) Validate() error { } func (this *Location) Validate() error { - if oneOfNester, ok := this.GetConfig().(*Location_PmmClientConfig); ok { - if oneOfNester.PmmClientConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.PmmClientConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmClientConfig", err) - } - } - } - if oneOfNester, ok := this.GetConfig().(*Location_PmmServerConfig); ok { - if oneOfNester.PmmServerConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.PmmServerConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmServerConfig", err) + if oneOfNester, ok := this.GetConfig().(*Location_FilesystemConfig); ok { + if oneOfNester.FilesystemConfig != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.FilesystemConfig); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("FilesystemConfig", err) } } } @@ -94,14 +80,9 @@ func (this *AddLocationRequest) Validate() error { if this.Name == "" { return github_com_mwitkow_go_proto_validators.FieldError("Name", fmt.Errorf(`value '%v' must not be an empty string`, this.Name)) } - if this.PmmClientConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PmmClientConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmClientConfig", err) - } - } - if this.PmmServerConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PmmServerConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmServerConfig", err) + if this.FilesystemConfig != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.FilesystemConfig); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("FilesystemConfig", err) } } if this.S3Config != nil { @@ -120,14 +101,9 @@ func (this *ChangeLocationRequest) Validate() error { if this.LocationId == "" { return github_com_mwitkow_go_proto_validators.FieldError("LocationId", fmt.Errorf(`value '%v' must not be an empty string`, this.LocationId)) } - if this.PmmClientConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PmmClientConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmClientConfig", err) - } - } - if this.PmmServerConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PmmServerConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmServerConfig", err) + if this.FilesystemConfig != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.FilesystemConfig); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("FilesystemConfig", err) } } if this.S3Config != nil { @@ -151,14 +127,9 @@ func (this *RemoveLocationResponse) Validate() error { } func (this *TestLocationConfigRequest) Validate() error { - if this.PmmClientConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PmmClientConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmClientConfig", err) - } - } - if this.PmmServerConfig != nil { - if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.PmmServerConfig); err != nil { - return github_com_mwitkow_go_proto_validators.FieldError("PmmServerConfig", err) + if this.FilesystemConfig != nil { + if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.FilesystemConfig); err != nil { + return github_com_mwitkow_go_proto_validators.FieldError("FilesystemConfig", err) } } if this.S3Config != nil { diff --git a/api/managementpb/backup/locations_grpc.pb.go b/api/managementpb/backup/locations_grpc.pb.go index 54c7ee33d8..1202d08527 100644 --- a/api/managementpb/backup/locations_grpc.pb.go +++ b/api/managementpb/backup/locations_grpc.pb.go @@ -4,7 +4,7 @@ // - protoc (unknown) // source: managementpb/backup/locations.proto -package backupv1beta1 +package backupv1 import ( context "context" @@ -45,7 +45,7 @@ func NewLocationsClient(cc grpc.ClientConnInterface) LocationsClient { func (c *locationsClient) ListLocations(ctx context.Context, in *ListLocationsRequest, opts ...grpc.CallOption) (*ListLocationsResponse, error) { out := new(ListLocationsResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Locations/ListLocations", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Locations/ListLocations", in, out, opts...) if err != nil { return nil, err } @@ -54,7 +54,7 @@ func (c *locationsClient) ListLocations(ctx context.Context, in *ListLocationsRe func (c *locationsClient) AddLocation(ctx context.Context, in *AddLocationRequest, opts ...grpc.CallOption) (*AddLocationResponse, error) { out := new(AddLocationResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Locations/AddLocation", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Locations/AddLocation", in, out, opts...) if err != nil { return nil, err } @@ -63,7 +63,7 @@ func (c *locationsClient) AddLocation(ctx context.Context, in *AddLocationReques func (c *locationsClient) ChangeLocation(ctx context.Context, in *ChangeLocationRequest, opts ...grpc.CallOption) (*ChangeLocationResponse, error) { out := new(ChangeLocationResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Locations/ChangeLocation", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Locations/ChangeLocation", in, out, opts...) if err != nil { return nil, err } @@ -72,7 +72,7 @@ func (c *locationsClient) ChangeLocation(ctx context.Context, in *ChangeLocation func (c *locationsClient) RemoveLocation(ctx context.Context, in *RemoveLocationRequest, opts ...grpc.CallOption) (*RemoveLocationResponse, error) { out := new(RemoveLocationResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Locations/RemoveLocation", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Locations/RemoveLocation", in, out, opts...) if err != nil { return nil, err } @@ -81,7 +81,7 @@ func (c *locationsClient) RemoveLocation(ctx context.Context, in *RemoveLocation func (c *locationsClient) TestLocationConfig(ctx context.Context, in *TestLocationConfigRequest, opts ...grpc.CallOption) (*TestLocationConfigResponse, error) { out := new(TestLocationConfigResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.Locations/TestLocationConfig", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.Locations/TestLocationConfig", in, out, opts...) if err != nil { return nil, err } @@ -150,7 +150,7 @@ func _Locations_ListLocations_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Locations/ListLocations", + FullMethod: "/backup.v1.Locations/ListLocations", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(LocationsServer).ListLocations(ctx, req.(*ListLocationsRequest)) @@ -168,7 +168,7 @@ func _Locations_AddLocation_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Locations/AddLocation", + FullMethod: "/backup.v1.Locations/AddLocation", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(LocationsServer).AddLocation(ctx, req.(*AddLocationRequest)) @@ -186,7 +186,7 @@ func _Locations_ChangeLocation_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Locations/ChangeLocation", + FullMethod: "/backup.v1.Locations/ChangeLocation", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(LocationsServer).ChangeLocation(ctx, req.(*ChangeLocationRequest)) @@ -204,7 +204,7 @@ func _Locations_RemoveLocation_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Locations/RemoveLocation", + FullMethod: "/backup.v1.Locations/RemoveLocation", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(LocationsServer).RemoveLocation(ctx, req.(*RemoveLocationRequest)) @@ -222,7 +222,7 @@ func _Locations_TestLocationConfig_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.Locations/TestLocationConfig", + FullMethod: "/backup.v1.Locations/TestLocationConfig", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(LocationsServer).TestLocationConfig(ctx, req.(*TestLocationConfigRequest)) @@ -234,7 +234,7 @@ func _Locations_TestLocationConfig_Handler(srv interface{}, ctx context.Context, // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var Locations_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "backup.v1beta1.Locations", + ServiceName: "backup.v1.Locations", HandlerType: (*LocationsServer)(nil), Methods: []grpc.MethodDesc{ { diff --git a/api/managementpb/backup/restores.pb.go b/api/managementpb/backup/restores.pb.go index 70699f5ffa..afd47285f7 100644 --- a/api/managementpb/backup/restores.pb.go +++ b/api/managementpb/backup/restores.pb.go @@ -4,7 +4,7 @@ // protoc (unknown) // source: managementpb/backup/restores.proto -package backupv1beta1 +package backupv1 import ( reflect "reflect" @@ -99,9 +99,9 @@ type RestoreHistoryItem struct { // Service name. ServiceName string `protobuf:"bytes,8,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // Backup data model. - DataModel DataModel `protobuf:"varint,9,opt,name=data_model,json=dataModel,proto3,enum=backup.v1beta1.DataModel" json:"data_model,omitempty"` + DataModel DataModel `protobuf:"varint,9,opt,name=data_model,json=dataModel,proto3,enum=backup.v1.DataModel" json:"data_model,omitempty"` // Restore status. - Status RestoreStatus `protobuf:"varint,10,opt,name=status,proto3,enum=backup.v1beta1.RestoreStatus" json:"status,omitempty"` + Status RestoreStatus `protobuf:"varint,10,opt,name=status,proto3,enum=backup.v1.RestoreStatus" json:"status,omitempty"` // Restore start time. StartedAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"` // Restore finish time. @@ -314,84 +314,81 @@ var File_managementpb_backup_restores_proto protoreflect.FileDescriptor var file_managementpb_backup_restores_proto_rawDesc = []byte{ 0x0a, 0x22, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 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, 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, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, - 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf1, 0x03, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, - 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x61, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, - 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x38, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, - 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x35, 0x0a, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x0b, 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, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3b, 0x0a, 0x0b, - 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x52, 0x0a, 0x66, - 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x41, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x56, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, - 0x6f, 0x72, 0x79, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2a, 0x81, - 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, - 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, - 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, - 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, - 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x54, - 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, - 0x10, 0x03, 0x32, 0xb4, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, - 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0xa1, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x29, 0x2e, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 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, 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, 0x20, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0xe7, 0x03, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, + 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, + 0x64, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x64, + 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x14, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x12, 0x30, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x18, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x18, 0x0b, 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, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3b, 0x0a, + 0x0b, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, 0x52, 0x0a, + 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x41, 0x74, 0x22, 0x1b, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x22, 0x29, 0x2f, 0x76, 0x31, - 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x2f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, - 0x79, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x42, 0xba, 0x01, 0x0a, 0x12, 0x63, 0x6f, - 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x42, 0x0d, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, - 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, - 0x72, 0x63, 0x6f, 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, - 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x0e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, - 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1a, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x51, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, + 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2a, 0x81, 0x01, 0x0a, 0x0d, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, + 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x52, 0x45, 0x53, 0x54, + 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x5f, 0x50, 0x52, + 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x53, 0x54, + 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, + 0x53, 0x53, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x32, 0xaa, + 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x12, 0x97, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x24, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, + 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2e, 0x22, 0x29, 0x2f, + 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2f, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x2f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x01, 0x2a, 0x42, 0x9c, 0x01, 0x0a, 0x0d, + 0x63, 0x6f, 0x6d, 0x2e, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x52, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x65, 0x72, 0x63, 0x6f, + 0x6e, 0x61, 0x2f, 0x70, 0x6d, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3b, 0x62, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x42, 0x58, 0x58, 0xaa, 0x02, 0x09, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x09, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x15, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5c, 0x56, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0a, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -410,23 +407,23 @@ var ( file_managementpb_backup_restores_proto_enumTypes = make([]protoimpl.EnumInfo, 1) file_managementpb_backup_restores_proto_msgTypes = make([]protoimpl.MessageInfo, 3) file_managementpb_backup_restores_proto_goTypes = []interface{}{ - (RestoreStatus)(0), // 0: backup.v1beta1.RestoreStatus - (*RestoreHistoryItem)(nil), // 1: backup.v1beta1.RestoreHistoryItem - (*ListRestoreHistoryRequest)(nil), // 2: backup.v1beta1.ListRestoreHistoryRequest - (*ListRestoreHistoryResponse)(nil), // 3: backup.v1beta1.ListRestoreHistoryResponse - (DataModel)(0), // 4: backup.v1beta1.DataModel + (RestoreStatus)(0), // 0: backup.v1.RestoreStatus + (*RestoreHistoryItem)(nil), // 1: backup.v1.RestoreHistoryItem + (*ListRestoreHistoryRequest)(nil), // 2: backup.v1.ListRestoreHistoryRequest + (*ListRestoreHistoryResponse)(nil), // 3: backup.v1.ListRestoreHistoryResponse + (DataModel)(0), // 4: backup.v1.DataModel (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp } ) var file_managementpb_backup_restores_proto_depIdxs = []int32{ - 4, // 0: backup.v1beta1.RestoreHistoryItem.data_model:type_name -> backup.v1beta1.DataModel - 0, // 1: backup.v1beta1.RestoreHistoryItem.status:type_name -> backup.v1beta1.RestoreStatus - 5, // 2: backup.v1beta1.RestoreHistoryItem.started_at:type_name -> google.protobuf.Timestamp - 5, // 3: backup.v1beta1.RestoreHistoryItem.finished_at:type_name -> google.protobuf.Timestamp - 1, // 4: backup.v1beta1.ListRestoreHistoryResponse.items:type_name -> backup.v1beta1.RestoreHistoryItem - 2, // 5: backup.v1beta1.RestoreHistory.ListRestoreHistory:input_type -> backup.v1beta1.ListRestoreHistoryRequest - 3, // 6: backup.v1beta1.RestoreHistory.ListRestoreHistory:output_type -> backup.v1beta1.ListRestoreHistoryResponse + 4, // 0: backup.v1.RestoreHistoryItem.data_model:type_name -> backup.v1.DataModel + 0, // 1: backup.v1.RestoreHistoryItem.status:type_name -> backup.v1.RestoreStatus + 5, // 2: backup.v1.RestoreHistoryItem.started_at:type_name -> google.protobuf.Timestamp + 5, // 3: backup.v1.RestoreHistoryItem.finished_at:type_name -> google.protobuf.Timestamp + 1, // 4: backup.v1.ListRestoreHistoryResponse.items:type_name -> backup.v1.RestoreHistoryItem + 2, // 5: backup.v1.RestoreHistory.ListRestoreHistory:input_type -> backup.v1.ListRestoreHistoryRequest + 3, // 6: backup.v1.RestoreHistory.ListRestoreHistory:output_type -> backup.v1.ListRestoreHistoryResponse 6, // [6:7] is the sub-list for method output_type 5, // [5:6] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name diff --git a/api/managementpb/backup/restores.pb.gw.go b/api/managementpb/backup/restores.pb.gw.go index c564f3251b..0c2265442b 100644 --- a/api/managementpb/backup/restores.pb.gw.go +++ b/api/managementpb/backup/restores.pb.gw.go @@ -2,11 +2,11 @@ // source: managementpb/backup/restores.proto /* -Package backupv1beta1 is a reverse proxy. +Package backupv1 is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package backupv1beta1 +package backupv1 import ( "context" @@ -78,7 +78,7 @@ func RegisterRestoreHistoryHandlerServer(ctx context.Context, mux *runtime.Serve inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1beta1.RestoreHistory/ListRestoreHistory", runtime.WithHTTPPathPattern("/v1/management/backup/RestoreHistory/List")) + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/backup.v1.RestoreHistory/ListRestoreHistory", runtime.WithHTTPPathPattern("/v1/management/backup/RestoreHistory/List")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return @@ -140,7 +140,7 @@ func RegisterRestoreHistoryHandlerClient(ctx context.Context, mux *runtime.Serve inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1beta1.RestoreHistory/ListRestoreHistory", runtime.WithHTTPPathPattern("/v1/management/backup/RestoreHistory/List")) + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/backup.v1.RestoreHistory/ListRestoreHistory", runtime.WithHTTPPathPattern("/v1/management/backup/RestoreHistory/List")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return diff --git a/api/managementpb/backup/restores.proto b/api/managementpb/backup/restores.proto index 5526462ef1..abf52da594 100644 --- a/api/managementpb/backup/restores.proto +++ b/api/managementpb/backup/restores.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package backup.v1beta1; +package backup.v1; -option go_package = "api/managementpb/backup;backupv1beta1"; +option go_package = "api/managementpb/backup;backupv1"; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; diff --git a/api/managementpb/backup/restores.validator.pb.go b/api/managementpb/backup/restores.validator.pb.go index e9080d17b4..878dbf322b 100644 --- a/api/managementpb/backup/restores.validator.pb.go +++ b/api/managementpb/backup/restores.validator.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: managementpb/backup/restores.proto -package backupv1beta1 +package backupv1 import ( fmt "fmt" diff --git a/api/managementpb/backup/restores_grpc.pb.go b/api/managementpb/backup/restores_grpc.pb.go index 0b9ff8c078..e89355fff9 100644 --- a/api/managementpb/backup/restores_grpc.pb.go +++ b/api/managementpb/backup/restores_grpc.pb.go @@ -4,7 +4,7 @@ // - protoc (unknown) // source: managementpb/backup/restores.proto -package backupv1beta1 +package backupv1 import ( context "context" @@ -37,7 +37,7 @@ func NewRestoreHistoryClient(cc grpc.ClientConnInterface) RestoreHistoryClient { func (c *restoreHistoryClient) ListRestoreHistory(ctx context.Context, in *ListRestoreHistoryRequest, opts ...grpc.CallOption) (*ListRestoreHistoryResponse, error) { out := new(ListRestoreHistoryResponse) - err := c.cc.Invoke(ctx, "/backup.v1beta1.RestoreHistory/ListRestoreHistory", in, out, opts...) + err := c.cc.Invoke(ctx, "/backup.v1.RestoreHistory/ListRestoreHistory", in, out, opts...) if err != nil { return nil, err } @@ -82,7 +82,7 @@ func _RestoreHistory_ListRestoreHistory_Handler(srv interface{}, ctx context.Con } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/backup.v1beta1.RestoreHistory/ListRestoreHistory", + FullMethod: "/backup.v1.RestoreHistory/ListRestoreHistory", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(RestoreHistoryServer).ListRestoreHistory(ctx, req.(*ListRestoreHistoryRequest)) @@ -94,7 +94,7 @@ func _RestoreHistory_ListRestoreHistory_Handler(srv interface{}, ctx context.Con // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var RestoreHistory_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "backup.v1beta1.RestoreHistory", + ServiceName: "backup.v1.RestoreHistory", HandlerType: (*RestoreHistoryServer)(nil), Methods: []grpc.MethodDesc{ { diff --git a/api/swagger/swagger-dev-only.json b/api/swagger/swagger-dev-only.json index e62a4dd408..3ae3b9b180 100644 --- a/api/swagger/swagger-dev-only.json +++ b/api/swagger/swagger-dev-only.json @@ -7379,6 +7379,94 @@ } } }, + "/v1/management/backup/Artifacts/ListPITRTimeranges": { + "post": { + "tags": [ + "Artifacts" + ], + "summary": "ListPitrTimeranges list the available MongoDB PITR timeranges in a given backup location", + "operationId": "ListPitrTimeranges", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "description": "Artifact ID represents artifact whose location has PITR timeranges to be retrieved.", + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "timeranges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "start_timestamp": { + "description": "start_timestamp is the time of the first event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "end_timestamp": { + "description": "end_timestamp is the time of the last event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 1 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/management/backup/Backups/ChangeScheduled": { "post": { "tags": [ @@ -8046,6 +8134,12 @@ "description": "Artifact id to restore.", "type": "string", "x-order": 1 + }, + "pitr_timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp of PITR to restore to", + "x-order": 2 } } } @@ -8375,8 +8469,8 @@ "type": "string", "x-order": 1 }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -8386,17 +8480,6 @@ }, "x-order": 2 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 3 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -8418,7 +8501,7 @@ "x-order": 3 } }, - "x-order": 4 + "x-order": 3 } } } @@ -8501,8 +8584,8 @@ "type": "string", "x-order": 2 }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -8512,17 +8595,6 @@ }, "x-order": 3 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 4 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -8544,7 +8616,7 @@ "x-order": 3 } }, - "x-order": 5 + "x-order": 4 } } } @@ -8635,8 +8707,8 @@ "title": "Short description", "x-order": 2 }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -8646,17 +8718,6 @@ }, "x-order": 3 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 4 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -8678,7 +8739,7 @@ "x-order": 3 } }, - "x-order": 5 + "x-order": 4 } } }, @@ -8806,8 +8867,8 @@ "schema": { "type": "object", "properties": { - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -8817,17 +8878,6 @@ }, "x-order": 0 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 1 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -8849,7 +8899,7 @@ "x-order": 3 } }, - "x-order": 2 + "x-order": 1 } } } diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index ef34cb4187..508f06e970 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -27855,6 +27855,94 @@ } } }, + "/v1/management/backup/Artifacts/ListPITRTimeranges": { + "post": { + "tags": [ + "Artifacts" + ], + "summary": "ListPitrTimeranges list the available MongoDB PITR timeranges in a given backup location", + "operationId": "ListPitrTimeranges", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "description": "Artifact ID represents artifact whose location has PITR timeranges to be retrieved.", + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "timeranges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "start_timestamp": { + "description": "start_timestamp is the time of the first event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "end_timestamp": { + "description": "end_timestamp is the time of the last event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 1 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/management/backup/Backups/ChangeScheduled": { "post": { "tags": [ @@ -28522,6 +28610,12 @@ "description": "Artifact id to restore.", "type": "string", "x-order": 1 + }, + "pitr_timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp of PITR to restore to", + "x-order": 2 } } } @@ -28851,8 +28945,8 @@ "type": "string", "x-order": 1 }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -28862,17 +28956,6 @@ }, "x-order": 2 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 3 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -28894,7 +28977,7 @@ "x-order": 3 } }, - "x-order": 4 + "x-order": 3 } } } @@ -28977,8 +29060,8 @@ "type": "string", "x-order": 2 }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -28988,17 +29071,6 @@ }, "x-order": 3 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 4 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -29020,7 +29092,7 @@ "x-order": 3 } }, - "x-order": 5 + "x-order": 4 } } } @@ -29111,8 +29183,8 @@ "title": "Short description", "x-order": 2 }, - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -29122,17 +29194,6 @@ }, "x-order": 3 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 4 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -29154,7 +29215,7 @@ "x-order": 3 } }, - "x-order": 5 + "x-order": 4 } } }, @@ -29282,8 +29343,8 @@ "schema": { "type": "object", "properties": { - "pmm_client_config": { - "description": "PMMClientLocationConfig represents file system config inside pmm-client.", + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", "type": "object", "properties": { "path": { @@ -29293,17 +29354,6 @@ }, "x-order": 0 }, - "pmm_server_config": { - "description": "PMMServerLocationConfig represents file system config inside pmm-server.", - "type": "object", - "properties": { - "path": { - "type": "string", - "x-order": 0 - } - }, - "x-order": 1 - }, "s3_config": { "description": "S3LocationConfig represents S3 bucket configuration.", "type": "object", @@ -29325,7 +29375,7 @@ "x-order": 3 } }, - "x-order": 2 + "x-order": 1 } } } diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 46252169d7..5002f16c96 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -20491,6 +20491,2632 @@ } } }, + "/v1/management/alerting/Rules/Create": { + "post": { + "tags": [ + "Alerting" + ], + "summary": "CreateRule creates alerting rule from the given template.", + "operationId": "CreateRule", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "template_name": { + "description": "Template name.", + "type": "string", + "x-order": 0 + }, + "name": { + "description": "Rule name.", + "type": "string", + "x-order": 1 + }, + "group": { + "description": "Rule group name.", + "type": "string", + "x-order": 2 + }, + "folder_uid": { + "description": "Folder UID.", + "type": "string", + "x-order": 3 + }, + "params": { + "description": "Rule parameters. All template parameters should be set.", + "type": "array", + "items": { + "description": "ParamValue represents a single rule parameter value.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "type": { + "description": "ParamType represents template parameter type.", + "type": "string", + "default": "PARAM_TYPE_INVALID", + "enum": [ + "PARAM_TYPE_INVALID", + "BOOL", + "FLOAT", + "STRING" + ], + "x-order": 1 + }, + "bool": { + "description": "Bool value.", + "type": "boolean", + "x-order": 2 + }, + "float": { + "description": "Float value.", + "type": "number", + "format": "double", + "x-order": 3 + }, + "string": { + "description": "String value.", + "type": "string", + "x-order": 4 + } + } + }, + "x-order": 4 + }, + "for": { + "description": "Rule duration. Should be set.", + "type": "string", + "x-order": 5 + }, + "severity": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_INVALID", + "enum": [ + "SEVERITY_INVALID", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, + "custom_labels": { + "description": "All custom labels to add or remove (with empty values) to default labels from template.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 7 + }, + "filters": { + "description": "Filters.", + "type": "array", + "items": { + "description": "Filter represents a single filter condition.", + "type": "object", + "properties": { + "type": { + "description": "FilterType represents filter matching type.", + "type": "string", + "default": "FILTER_TYPE_INVALID", + "enum": [ + "FILTER_TYPE_INVALID", + "MATCH", + "MISMATCH" + ], + "x-order": 0 + }, + "label": { + "type": "string", + "x-order": 1 + }, + "regexp": { + "type": "string", + "x-order": 2 + } + } + }, + "x-order": 8 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/alerting/Templates/Create": { + "post": { + "tags": [ + "Alerting" + ], + "summary": "CreateTemplate creates a new template.", + "operationId": "CreateTemplate", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "yaml": { + "description": "YAML (or JSON) template file content.", + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/alerting/Templates/Delete": { + "post": { + "tags": [ + "Alerting" + ], + "summary": "DeleteTemplate deletes existing, previously created via API.", + "operationId": "DeleteTemplate", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/alerting/Templates/List": { + "post": { + "tags": [ + "Alerting" + ], + "summary": "ListTemplates returns a list of all collected alert rule templates.", + "operationId": "ListTemplates", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "reload": { + "description": "If true, template files will be re-read from disk.", + "type": "boolean", + "x-order": 0 + }, + "page_params": { + "description": "PageParams represents page request parameters for pagination.", + "type": "object", + "properties": { + "page_size": { + "description": "Maximum number of results per page.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "index": { + "description": "Index of the requested page, starts from 0.", + "type": "integer", + "format": "int32", + "x-order": 1 + } + }, + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "templates": { + "type": "array", + "items": { + "description": "Template represents Alert Template that is used to create Alert Rule.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID).", + "type": "string", + "x-order": 0 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 1 + }, + "expr": { + "description": "PromQL query expression with templating parameters.", + "type": "string", + "x-order": 2 + }, + "params": { + "description": "Query parameters definitions.", + "type": "array", + "items": { + "description": "ParamDefinition represents a single query parameter.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "summary": { + "description": "Short human-readable parameter summary.", + "type": "string", + "x-order": 1 + }, + "unit": { + "description": "ParamUnit represents template parameter unit.\n\n - PARAM_UNIT_INVALID: Invalid, unknown or absent.\n - PERCENTAGE: %\n - SECONDS: s", + "type": "string", + "default": "PARAM_UNIT_INVALID", + "enum": [ + "PARAM_UNIT_INVALID", + "PERCENTAGE", + "SECONDS" + ], + "x-order": 2 + }, + "type": { + "description": "ParamType represents template parameter type.", + "type": "string", + "default": "PARAM_TYPE_INVALID", + "enum": [ + "PARAM_TYPE_INVALID", + "BOOL", + "FLOAT", + "STRING" + ], + "x-order": 3 + }, + "bool": { + "description": "BoolParamDefinition represents boolean parameter's default value.", + "type": "object", + "properties": { + "default": { + "description": "BooleanFlag represent a command to set some boolean property to true,\nto false, or avoid changing that property.\n\n - DO_NOT_CHANGE: Do not change boolean property. Default value.\n - TRUE: True.\n - FALSE: False.", + "type": "string", + "default": "DO_NOT_CHANGE", + "enum": [ + "DO_NOT_CHANGE", + "TRUE", + "FALSE" + ], + "x-order": 0 + } + }, + "x-order": 4 + }, + "float": { + "description": "FloatParamDefinition represents float parameter's default value and valid range.", + "type": "object", + "properties": { + "has_default": { + "description": "True if default value is set.", + "type": "boolean", + "x-order": 0 + }, + "default": { + "description": "Default value if has_default is true.", + "type": "number", + "format": "double", + "x-order": 1 + }, + "has_min": { + "description": "True if minimal valid value is set.", + "type": "boolean", + "x-order": 2 + }, + "min": { + "description": "Minimal valid value (inclusive) if has_min is true.", + "type": "number", + "format": "double", + "x-order": 3 + }, + "has_max": { + "description": "True if maximal valid value is set.", + "type": "boolean", + "x-order": 4 + }, + "max": { + "description": "Maximal valid value (inclusive) if has_max is true.", + "type": "number", + "format": "double", + "x-order": 5 + } + }, + "x-order": 5 + }, + "string": { + "description": "StringParamDefinition represents string parameter's default value.", + "type": "object", + "properties": { + "has_default": { + "description": "True if default value is set.", + "type": "boolean", + "x-order": 0 + }, + "default": { + "description": "Default value if has_default is true.", + "type": "string", + "x-order": 1 + } + }, + "x-order": 6 + } + } + }, + "x-order": 3 + }, + "for": { + "description": "Default duration value.", + "type": "string", + "x-order": 4 + }, + "severity": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_INVALID", + "enum": [ + "SEVERITY_INVALID", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 5 + }, + "labels": { + "description": "Labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 6 + }, + "annotations": { + "description": "Annotations.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 7 + }, + "source": { + "description": "TemplateSource defines template source.\n\n - BUILT_IN: Template that is shipped with PMM Server releases.\n - SAAS: Template that is downloaded from check.percona.com.\n - USER_FILE: Templated loaded from user-suplied file.\n - USER_API: Templated created via API.", + "type": "string", + "default": "TEMPLATE_SOURCE_INVALID", + "enum": [ + "TEMPLATE_SOURCE_INVALID", + "BUILT_IN", + "SAAS", + "USER_FILE", + "USER_API" + ], + "x-order": 8 + }, + "created_at": { + "description": "Template creation time. Empty for built-in and SaaS templates.", + "type": "string", + "format": "date-time", + "x-order": 9 + }, + "yaml": { + "description": "YAML (or JSON) template file content. Empty for built-in and SaaS templates.", + "type": "string", + "x-order": 10 + } + } + }, + "x-order": 0 + }, + "totals": { + "description": "PageTotals represents total values for pagination.", + "type": "object", + "properties": { + "total_items": { + "description": "Total number of results.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "total_pages": { + "description": "Total number of pages.", + "type": "integer", + "format": "int32", + "x-order": 1 + } + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/alerting/Templates/Update": { + "post": { + "tags": [ + "Alerting" + ], + "summary": "UpdateTemplate updates existing template, previously created via API.", + "operationId": "UpdateTemplate", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID).", + "type": "string", + "x-order": 0 + }, + "yaml": { + "description": "YAML (or JSON) template file content.", + "type": "string", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Artifacts/Delete": { + "post": { + "tags": [ + "Artifacts" + ], + "summary": "DeleteArtifact deletes specified artifact.", + "operationId": "DeleteArtifact", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "description": "Machine-readable artifact ID.", + "type": "string", + "x-order": 0 + }, + "remove_files": { + "description": "Removes all the backup files associated with artifact if flag is set.", + "type": "boolean", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Artifacts/List": { + "post": { + "tags": [ + "Artifacts" + ], + "summary": "ListArtifacts returns a list of all backup artifacts.", + "operationId": "ListArtifacts", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "artifacts": { + "type": "array", + "items": { + "description": "Artifact represents single backup artifact.", + "type": "object", + "properties": { + "artifact_id": { + "description": "Machine-readable artifact ID.", + "type": "string", + "x-order": 0 + }, + "name": { + "type": "string", + "title": "Artifact name", + "x-order": 1 + }, + "vendor": { + "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL.", + "type": "string", + "x-order": 2 + }, + "location_id": { + "description": "Machine-readable location ID.", + "type": "string", + "x-order": 3 + }, + "location_name": { + "description": "Location name.", + "type": "string", + "x-order": 4 + }, + "service_id": { + "description": "Machine-readable service ID.", + "type": "string", + "x-order": 5 + }, + "service_name": { + "description": "Service name.", + "type": "string", + "x-order": 6 + }, + "data_model": { + "description": "DataModel is a model used for performing a backup.", + "type": "string", + "default": "DATA_MODEL_INVALID", + "enum": [ + "DATA_MODEL_INVALID", + "PHYSICAL", + "LOGICAL" + ], + "x-order": 7 + }, + "status": { + "description": "BackupStatus shows the current status of execution of backup.", + "type": "string", + "default": "BACKUP_STATUS_INVALID", + "enum": [ + "BACKUP_STATUS_INVALID", + "BACKUP_STATUS_PENDING", + "BACKUP_STATUS_IN_PROGRESS", + "BACKUP_STATUS_PAUSED", + "BACKUP_STATUS_SUCCESS", + "BACKUP_STATUS_ERROR", + "BACKUP_STATUS_DELETING", + "BACKUP_STATUS_FAILED_TO_DELETE" + ], + "x-order": 8 + }, + "created_at": { + "description": "Artifact creation time.", + "type": "string", + "format": "date-time", + "x-order": 9 + }, + "mode": { + "description": "BackupMode specifies backup mode.", + "type": "string", + "default": "BACKUP_MODE_INVALID", + "enum": [ + "BACKUP_MODE_INVALID", + "SNAPSHOT", + "INCREMENTAL", + "PITR" + ], + "x-order": 10 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Artifacts/ListPITRTimeranges": { + "post": { + "tags": [ + "Artifacts" + ], + "summary": "ListPitrTimeranges list the available MongoDB PITR timeranges in a given backup location", + "operationId": "ListPitrTimeranges", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "description": "Artifact ID represents artifact whose location has PITR timeranges to be retrieved.", + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "timeranges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "start_timestamp": { + "description": "start_timestamp is the time of the first event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 0 + }, + "end_timestamp": { + "description": "end_timestamp is the time of the last event in the PITR chunk.", + "type": "string", + "format": "date-time", + "x-order": 1 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/ChangeScheduled": { + "post": { + "tags": [ + "Backups" + ], + "summary": "ChangeScheduledBackup changes existing scheduled backup.", + "operationId": "ChangeScheduledBackup", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "scheduled_backup_id": { + "type": "string", + "x-order": 0 + }, + "enabled": { + "type": "boolean", + "x-order": 1 + }, + "cron_expression": { + "description": "How often backup should be run in cron format.", + "type": "string", + "x-order": 2 + }, + "start_time": { + "description": "First backup wouldn't happen before this time.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "name": { + "description": "Name of backup.", + "type": "string", + "x-order": 4 + }, + "description": { + "description": "Human-readable description.", + "type": "string", + "x-order": 5 + }, + "retry_interval": { + "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h.", + "type": "string", + "x-order": 6 + }, + "retries": { + "description": "How many times to retry a failed backup before giving up.", + "type": "integer", + "format": "int64", + "x-order": 7 + }, + "retention": { + "description": "How many artifacts keep. 0 - unlimited.", + "type": "integer", + "format": "int64", + "x-order": 8 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/GetLogs": { + "post": { + "tags": [ + "Backups" + ], + "summary": "GetLogs returns logs for provided artifact.", + "operationId": "GetLogs", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "type": "string", + "x-order": 0 + }, + "offset": { + "type": "integer", + "format": "int64", + "x-order": 1 + }, + "limit": { + "type": "integer", + "format": "int64", + "x-order": 2 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "description": "LogChunk represent one chunk of logs.", + "type": "object", + "properties": { + "chunk_id": { + "type": "integer", + "format": "int64", + "x-order": 0 + }, + "data": { + "type": "string", + "x-order": 1 + } + } + }, + "x-order": 0 + }, + "end": { + "type": "boolean", + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/ListArtifactCompatibleServices": { + "post": { + "tags": [ + "Backups" + ], + "summary": "ListArtifactCompatibleServices lists compatible services for restoring a backup.", + "operationId": "ListArtifactCompatibleServices", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "description": "Artifact id used to determine restore compatibility.", + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "mysql": { + "type": "array", + "items": { + "description": "MySQLService represents a generic MySQL instance.", + "type": "object", + "properties": { + "service_id": { + "description": "Unique randomly generated instance identifier.", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "Unique across all Services user-defined name.", + "type": "string", + "x-order": 1 + }, + "node_id": { + "description": "Node identifier where this instance runs.", + "type": "string", + "x-order": 2 + }, + "address": { + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required.", + "type": "string", + "x-order": 3 + }, + "port": { + "description": "Access port.\nPort is required when the address present.", + "type": "integer", + "format": "int64", + "x-order": 4 + }, + "socket": { + "description": "Access unix socket.\nAddress (and port) or socket is required.", + "type": "string", + "x-order": 5 + }, + "environment": { + "description": "Environment name.", + "type": "string", + "x-order": 6 + }, + "cluster": { + "description": "Cluster name.", + "type": "string", + "x-order": 7 + }, + "replication_set": { + "description": "Replication set name.", + "type": "string", + "x-order": 8 + }, + "custom_labels": { + "description": "Custom user-assigned labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 9 + } + } + }, + "x-order": 0 + }, + "mongodb": { + "type": "array", + "items": { + "description": "MongoDBService represents a generic MongoDB instance.", + "type": "object", + "properties": { + "service_id": { + "description": "Unique randomly generated instance identifier.", + "type": "string", + "x-order": 0 + }, + "service_name": { + "description": "Unique across all Services user-defined name.", + "type": "string", + "x-order": 1 + }, + "node_id": { + "description": "Node identifier where this instance runs.", + "type": "string", + "x-order": 2 + }, + "address": { + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required.", + "type": "string", + "x-order": 3 + }, + "port": { + "description": "Access port.\nPort is required when the address present.", + "type": "integer", + "format": "int64", + "x-order": 4 + }, + "socket": { + "description": "Access unix socket.\nAddress (and port) or socket is required.", + "type": "string", + "x-order": 5 + }, + "environment": { + "description": "Environment name.", + "type": "string", + "x-order": 6 + }, + "cluster": { + "description": "Cluster name.", + "type": "string", + "x-order": 7 + }, + "replication_set": { + "description": "Replication set name.", + "type": "string", + "x-order": 8 + }, + "custom_labels": { + "description": "Custom user-assigned labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 9 + } + } + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/ListScheduled": { + "post": { + "tags": [ + "Backups" + ], + "summary": "ListScheduledBackups returns all scheduled backups.", + "operationId": "ListScheduledBackups", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "scheduled_backups": { + "type": "array", + "items": { + "description": "ScheduledBackup represents scheduled task for backup.", + "type": "object", + "properties": { + "scheduled_backup_id": { + "description": "Machine-readable ID.", + "type": "string", + "x-order": 0 + }, + "service_id": { + "description": "Machine-readable service ID.", + "type": "string", + "x-order": 1 + }, + "service_name": { + "description": "Service name.", + "type": "string", + "x-order": 2 + }, + "location_id": { + "description": "Machine-readable location ID.", + "type": "string", + "x-order": 3 + }, + "location_name": { + "description": "Location name.", + "type": "string", + "x-order": 4 + }, + "cron_expression": { + "description": "How often backup will be run in cron format.", + "type": "string", + "x-order": 5 + }, + "start_time": { + "description": "First backup wouldn't happen before this time.", + "type": "string", + "format": "date-time", + "x-order": 6 + }, + "name": { + "description": "Artifact name.", + "type": "string", + "x-order": 7 + }, + "description": { + "description": "Description.", + "type": "string", + "x-order": 8 + }, + "retry_interval": { + "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h.", + "type": "string", + "x-order": 9 + }, + "retries": { + "description": "How many times to retry a failed backup before giving up.", + "type": "integer", + "format": "int64", + "x-order": 10 + }, + "enabled": { + "description": "If scheduling is enabled.", + "type": "boolean", + "x-order": 11 + }, + "data_model": { + "description": "DataModel is a model used for performing a backup.", + "type": "string", + "default": "DATA_MODEL_INVALID", + "enum": [ + "DATA_MODEL_INVALID", + "PHYSICAL", + "LOGICAL" + ], + "x-order": 12 + }, + "vendor": { + "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL.", + "type": "string", + "x-order": 13 + }, + "last_run": { + "description": "Last run.", + "type": "string", + "format": "date-time", + "x-order": 14 + }, + "next_run": { + "description": "Next run.", + "type": "string", + "format": "date-time", + "x-order": 15 + }, + "retention": { + "description": "How many artifacts keep. 0 - unlimited.", + "type": "integer", + "format": "int64", + "x-order": 16 + }, + "mode": { + "description": "BackupMode specifies backup mode.", + "type": "string", + "default": "BACKUP_MODE_INVALID", + "enum": [ + "BACKUP_MODE_INVALID", + "SNAPSHOT", + "INCREMENTAL", + "PITR" + ], + "x-order": 17 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/RemoveScheduled": { + "post": { + "tags": [ + "Backups" + ], + "summary": "RemoveScheduledBackup removes existing scheduled backup.", + "operationId": "RemoveScheduledBackup", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "scheduled_backup_id": { + "type": "string", + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/Restore": { + "post": { + "description": "Could return the Error message in the details containing specific ErrorCode indicating failure reason:\nERROR_CODE_XTRABACKUP_NOT_INSTALLED - xtrabackup is not installed on the service\nERROR_CODE_INVALID_XTRABACKUP - different versions of xtrabackup and xbcloud\nERROR_CODE_INCOMPATIBLE_XTRABACKUP - xtrabackup is not compatible with MySQL for taking a backup\nERROR_CODE_INCOMPATIBLE_TARGET_MYSQL - target MySQL version is not compatible with the artifact for performing a restore of the backup", + "tags": [ + "Backups" + ], + "summary": "RestoreBackup requests the backup restore.", + "operationId": "RestoreBackup", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "service_id": { + "description": "Service identifier where backup should be restored.", + "type": "string", + "x-order": 0 + }, + "artifact_id": { + "description": "Artifact id to restore.", + "type": "string", + "x-order": 1 + }, + "pitr_timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp of PITR to restore to", + "x-order": 2 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "restore_id": { + "description": "Unique restore identifier.", + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/Schedule": { + "post": { + "tags": [ + "Backups" + ], + "summary": "ScheduleBackup schedules repeated backup.", + "operationId": "ScheduleBackup", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "service_id": { + "description": "Service identifier where backup should be performed.", + "type": "string", + "x-order": 0 + }, + "location_id": { + "description": "Machine-readable location ID.", + "type": "string", + "x-order": 1 + }, + "cron_expression": { + "description": "How often backup should be run in cron format.", + "type": "string", + "x-order": 2 + }, + "start_time": { + "description": "First backup wouldn't happen before this time.", + "type": "string", + "format": "date-time", + "x-order": 3 + }, + "name": { + "description": "Name of backup.", + "type": "string", + "x-order": 4 + }, + "description": { + "description": "Human-readable description.", + "type": "string", + "x-order": 5 + }, + "retry_interval": { + "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h.", + "type": "string", + "x-order": 6 + }, + "retries": { + "description": "How many times to retry a failed backup before giving up.", + "type": "integer", + "format": "int64", + "x-order": 7 + }, + "enabled": { + "description": "If scheduling is enabled.", + "type": "boolean", + "x-order": 8 + }, + "retention": { + "description": "How many artifacts keep. 0 - unlimited.", + "type": "integer", + "format": "int64", + "x-order": 9 + }, + "mode": { + "description": "BackupMode specifies backup mode.", + "type": "string", + "default": "BACKUP_MODE_INVALID", + "enum": [ + "BACKUP_MODE_INVALID", + "SNAPSHOT", + "INCREMENTAL", + "PITR" + ], + "x-order": 10 + }, + "data_model": { + "description": "DataModel is a model used for performing a backup.", + "type": "string", + "default": "DATA_MODEL_INVALID", + "enum": [ + "DATA_MODEL_INVALID", + "PHYSICAL", + "LOGICAL" + ], + "x-order": 11 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "scheduled_backup_id": { + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Backups/Start": { + "post": { + "description": "Could return the Error message in the details containing specific ErrorCode indicating failure reason:\nERROR_CODE_XTRABACKUP_NOT_INSTALLED - xtrabackup is not installed on the service\nERROR_CODE_INVALID_XTRABACKUP - different versions of xtrabackup and xbcloud\nERROR_CODE_INCOMPATIBLE_XTRABACKUP - xtrabackup is not compatible with MySQL for taking a backup", + "tags": [ + "Backups" + ], + "summary": "StartBackup request backup specified service to location.", + "operationId": "StartBackup", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "service_id": { + "description": "Service identifier.", + "type": "string", + "x-order": 0 + }, + "location_id": { + "description": "Machine-readable location ID.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "If empty then name is auto-generated.", + "type": "string", + "x-order": 2 + }, + "description": { + "description": "Human-readable description.", + "type": "string", + "x-order": 3 + }, + "retry_interval": { + "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h.", + "type": "string", + "x-order": 4 + }, + "retries": { + "description": "How many times to retry a failed backup before giving up.", + "type": "integer", + "format": "int64", + "x-order": 5 + }, + "data_model": { + "description": "DataModel is a model used for performing a backup.", + "type": "string", + "default": "DATA_MODEL_INVALID", + "enum": [ + "DATA_MODEL_INVALID", + "PHYSICAL", + "LOGICAL" + ], + "x-order": 6 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "artifact_id": { + "description": "Unique identifier.", + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Locations/Add": { + "post": { + "tags": [ + "Locations" + ], + "summary": "AddLocation adds backup location.", + "operationId": "AddLocation", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Location name", + "x-order": 0 + }, + "description": { + "type": "string", + "x-order": 1 + }, + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", + "type": "object", + "properties": { + "path": { + "type": "string", + "x-order": 0 + } + }, + "x-order": 2 + }, + "s3_config": { + "description": "S3LocationConfig represents S3 bucket configuration.", + "type": "object", + "properties": { + "endpoint": { + "type": "string", + "x-order": 0 + }, + "access_key": { + "type": "string", + "x-order": 1 + }, + "secret_key": { + "type": "string", + "x-order": 2 + }, + "bucket_name": { + "type": "string", + "x-order": 3 + } + }, + "x-order": 3 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "location_id": { + "description": "Machine-readable ID.", + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Locations/Change": { + "post": { + "tags": [ + "Locations" + ], + "summary": "ChangeLocation changes backup location.", + "operationId": "ChangeLocation", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "location_id": { + "description": "Machine-readable ID.", + "type": "string", + "x-order": 0 + }, + "name": { + "type": "string", + "title": "Location name", + "x-order": 1 + }, + "description": { + "type": "string", + "x-order": 2 + }, + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", + "type": "object", + "properties": { + "path": { + "type": "string", + "x-order": 0 + } + }, + "x-order": 3 + }, + "s3_config": { + "description": "S3LocationConfig represents S3 bucket configuration.", + "type": "object", + "properties": { + "endpoint": { + "type": "string", + "x-order": 0 + }, + "access_key": { + "type": "string", + "x-order": 1 + }, + "secret_key": { + "type": "string", + "x-order": 2 + }, + "bucket_name": { + "type": "string", + "x-order": 3 + } + }, + "x-order": 4 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Locations/List": { + "post": { + "tags": [ + "Locations" + ], + "summary": "ListLocations returns a list of all backup locations.", + "operationId": "ListLocations", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "locations": { + "type": "array", + "items": { + "description": "Location represents single Backup Location.", + "type": "object", + "properties": { + "location_id": { + "description": "Machine-readable ID.", + "type": "string", + "x-order": 0 + }, + "name": { + "type": "string", + "title": "Location name", + "x-order": 1 + }, + "description": { + "type": "string", + "title": "Short description", + "x-order": 2 + }, + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", + "type": "object", + "properties": { + "path": { + "type": "string", + "x-order": 0 + } + }, + "x-order": 3 + }, + "s3_config": { + "description": "S3LocationConfig represents S3 bucket configuration.", + "type": "object", + "properties": { + "endpoint": { + "type": "string", + "x-order": 0 + }, + "access_key": { + "type": "string", + "x-order": 1 + }, + "secret_key": { + "type": "string", + "x-order": 2 + }, + "bucket_name": { + "type": "string", + "x-order": 3 + } + }, + "x-order": 4 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Locations/Remove": { + "post": { + "tags": [ + "Locations" + ], + "summary": "RemoveLocation removes existing backup location.", + "operationId": "RemoveLocation", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "location_id": { + "description": "Machine-readable ID.", + "type": "string", + "x-order": 0 + }, + "force": { + "type": "boolean", + "title": "Force mode", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/Locations/TestConfig": { + "post": { + "tags": [ + "Locations" + ], + "summary": "TestLocationConfig tests backup location and credentials.", + "operationId": "TestLocationConfig", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "filesystem_config": { + "description": "FilesystemLocationConfig represents file system location config.", + "type": "object", + "properties": { + "path": { + "type": "string", + "x-order": 0 + } + }, + "x-order": 0 + }, + "s3_config": { + "description": "S3LocationConfig represents S3 bucket configuration.", + "type": "object", + "properties": { + "endpoint": { + "type": "string", + "x-order": 0 + }, + "access_key": { + "type": "string", + "x-order": 1 + }, + "secret_key": { + "type": "string", + "x-order": 2 + }, + "bucket_name": { + "type": "string", + "x-order": 3 + } + }, + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/management/backup/RestoreHistory/List": { + "post": { + "tags": [ + "RestoreHistory" + ], + "summary": "ListRestoreHistory returns a list of all backup restore history items.", + "operationId": "ListRestoreHistory", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "description": "RestoreHistoryItem represents single backup restore item.", + "type": "object", + "properties": { + "restore_id": { + "description": "Machine-readable restore id.", + "type": "string", + "x-order": 0 + }, + "artifact_id": { + "description": "ID of the artifact used for restore.", + "type": "string", + "x-order": 1 + }, + "name": { + "description": "Artifact name used for restore.", + "type": "string", + "x-order": 2 + }, + "vendor": { + "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL.", + "type": "string", + "x-order": 3 + }, + "location_id": { + "description": "Machine-readable location ID.", + "type": "string", + "x-order": 4 + }, + "location_name": { + "description": "Location name.", + "type": "string", + "x-order": 5 + }, + "service_id": { + "description": "Machine-readable service ID.", + "type": "string", + "x-order": 6 + }, + "service_name": { + "description": "Service name.", + "type": "string", + "x-order": 7 + }, + "data_model": { + "description": "DataModel is a model used for performing a backup.", + "type": "string", + "default": "DATA_MODEL_INVALID", + "enum": [ + "DATA_MODEL_INVALID", + "PHYSICAL", + "LOGICAL" + ], + "x-order": 8 + }, + "status": { + "description": "RestoreStatus shows the current status of execution of restore.", + "type": "string", + "default": "RESTORE_STATUS_INVALID", + "enum": [ + "RESTORE_STATUS_INVALID", + "RESTORE_STATUS_IN_PROGRESS", + "RESTORE_STATUS_SUCCESS", + "RESTORE_STATUS_ERROR" + ], + "x-order": 9 + }, + "started_at": { + "description": "Restore start time.", + "type": "string", + "format": "date-time", + "x-order": 10 + }, + "finished_at": { + "description": "Restore finish time.", + "type": "string", + "format": "date-time", + "x-order": 11 + } + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": false + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/readyz": { "get": { "description": "Returns an error when Server components being restarted are not ready yet. Use this API for checking the health of Docker containers and for probing Kubernetes readiness.", @@ -20869,6 +23495,21 @@ }, { "name": "Service" + }, + { + "name": "Artifacts" + }, + { + "name": "Backups" + }, + { + "name": "Locations" + }, + { + "name": "RestoreHistory" + }, + { + "name": "Alerting" } ], "x-readme": { diff --git a/descriptor.bin b/descriptor.bin index 3a0d49cd0363b6c300264054deba722fc0304028..24f860ea2278086019d306f0f10e57f227bafa0d 100644 GIT binary patch delta 98390 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 d5$-qs+A?phhk# zKu{S*Oki0_fM95temq%2Ff^>Jm)RNdlND@O`6#o338+`F;o-Y7Gm~Y%hv@@7(XBm0R##GCDdN?!E&+Vbe*gtcy+PpnGvamnlOr?vU z&y@IPrsD!o*gVT55QWXNOaj5=Jj*0HOP(k37Z@giz?*Le5fFIu?UO%1;EC#6m;|Cv z%x_g#V3-tGGkHLGkZ}&tanu&tGavvH%EBbzlgxz+n;YjA6G?5MJp&RrEf*|G-hB{N z{35H0=ND*;m@TBs0+F-DB8JU2nc&$cH)J-bUH50VwQL{)f}B~{-HPuSyK@Da3_jI*p8weLlSyYyQXFz#8yfFUf;fS;mRHN06?G9dWiYJe z)pApuEEKZ2t=F|9=X%xm!EC>=>uq<_v73VR)@>Gu{Og%nWOGfQIVN+w+3Sjn)iG?Y z#o8n4y5KnT5Q)~*@p6cHh(s&ug5&H%Bw9}w9A_N^Ib)pYTvg^E`Ak22seJ=jBY4Ank<(h$29q)Dkx=;)?Zr zgtEALqRCInl5Oq&}y#LqQxkp!BU3vWee%yP1zXU|M zgbfQ0p};C9NRpY38U62es z>RuNlcYD-{#t5Nq7tvT=Pn?et3K|)5yAujX>EwiB1Qts2P7w;Z7O;aW-iih!1MkdV zOWyOHPBccyd%jyl<6?F56H&Sz7rlAA{KL4roqRwt?rxC}Nt`!A?&p|#=80$#S-`A( z(8!QuPCg(Ra!lkyz=z1TdxL}o@0ubj_e!Z6dApP>!IS^6eY=u}2~U0&ub5Qj;O&yu ziy|Xhiub!W3(1?kKPY*~zFBF|Z}x#8`574;uaMlG2~rQ(8#zG6ls%6eMOe=53U&GEb`Cc8UAd(x`3GB{~VCj z%9)wY47ZJDR{_uei6DGIZGM_vg%d;b^qd%)r{~1bJU#y&klxDicE-1DG`xYslRfsloi$$@NxT_2&L;mH(RO15NDk)iEG87O5}ehfCs z`OZT>Rz31kG&ySzgNfIk9-{3L{BAt-rRt9_MK#${qaazwyckDK$Q2WjGY!qZ#A>g! zM^y9#s=U=LYhjgD%J_@vRM{+?P^^VjXB+F))`M@1b!SFGF|67uiBJryMoE-)Slj9o zIg_K0h#6zuooRq#+(di442p3R@x)79C?CP(#6@b#%Te#B$*6k*W@4%*Yr_U9AGA=N zemP33hZm$r%{}`lU9H`hr!R^|ZKlEKrb24nv@Th1>MUZfV-Konr=p4})9j*7n>5-w zhsL6xhI%CV69SX-U{1bnA}#d3kdu5;AO~|E15Vv@D$3T*U_Vy02@^s!!$;7_4bEVK zk`GrK{Ik@VQ_+OlS@`-*f6?k@*{ud+@XrFtMLoitC%b`~{R+V_O}@XVb4}KOGX{SX z@2iFfh|teZY*d4lX*tiJMURA0N;_m>y2*k44R z&0;QM`a>*Hho!$W{E!a%FR?MwP|^i6TMFx7OJ^|rK6*8pTD#P$pvJylYE@7u`Y**z zDvE_R_*>MH*P=%LRii*38`!)UX zgtV&vqJNVuI|&ath}1gV?2JG$y7huN_SuPFq;=kWyJ>|#y-i*5deqR=<~O0J-!rU@ zB1Ps|i{jiy{U1v)x($U`@*sp#cd%VO{d#o%w00YpPaFN)%iOgkJ#ssB2Su(zNsrtS zPNd}2SJexzM}+cmr4Bz*{OBFFLL+?{*-=?-Gl~#azgk`XMpQ+(m7AIP%U2h>D@k(X z)m+JhTXFKelPe9c=%66PuC03xc=3}o$(^2uxWGGYmB%oYG|8P@bAp~NX_D84HKe0n zyqCkuJ1Y8nuIlSopS=-{99-uaNYMH^|9B*C@;VBLOPR<}@+NnMRiy>wO=je7KLyE} z+~qk)*5oc*IFd1N=sK@bf4HG!O!}yX}bvC`NZ@%k9G?m2!_d=dGx; zsmBY6q*U&)hE1qbD)(5!28z)=6c!h6BUnZH2G#vmG;vX{b)?e9)p~6fa6vODUY+PC zESZ}UTaC>opW!Cd6A>Qml-go!Hhy#UEfz|RPil*`*^EzWi?!KM6Stoo>b9Lz7qV7p ze^I}cJP1DOetTk1n(hYKGbI^Va zDUFze_Pd5+;2;Ax>+9gVIV5$?dZ(v!9#}%=OtL9Rlz~I8+8HF$cu4Z-ngf6=^Vg|M z-;HYKVNIKqohe=I>^fKN3=$64xoT&SaJWtaePmNFC25_nS3iC?s_o>AiQ`a!j(>fg zgT(e+A7o5wT86;k`k=zt`{X#J*yrC{+d<5aZv+G;3g(GRF8M7r?N@}P`a+-D87GB4 zogYoq^lypDCYA_U4Q~t*KeXKB-fxtemZD>bFDs4ld`plVvV@Dd$$!k4KaEwQeOr+B z8j!QO$W6|p0F700Q!w@xYn4cYwo2H~`ZiXHNtn&W58wJ;R9Amiifu7BNwIBge(eN< zL^!AF38Ho=wf4P;j1kTv(>^YO-mJwA$xM`ll*tySc)75oO@Y1*zmC$)Xyi257opu= zkhVM@B$xlLE6)e1M=s5XH+|gVedFdQuCvE4kGv!XF9}kJ-BsztBVOZp1H?&IKW7Z2sh< zG7h3#AoYT+!-%0dcUQ(klyi3l$zA1wv5(rjk_LTOj|3d^@mu|myD5qj>2aCjN@MCj z6(rsx;_qUuo$s#L-M8y&TS<&`^)6NZK{PM(lvE=H)3MQ+@-spBZ>s-;XvrF)?ew;R zwDbKvlTUdg!17E!<&D_?&j!hV^|r3F|7~NFv;V2(`EwP07|mWow4FO4CHDVw`4duN z|38;MAtm3KW*-!>BZz`bMtQ}6OkRryi0naY=*x7h!$Bg>!WD)s?&MiVrHGr^A<(vbe^|ty}unK-}SuR*1Ku+zJ+&_h3dmI(FAqF$I;&g zKfU$7)O7qj+K&(=MysWtL<<*+Vxk=hQEIqoOU989o3&L47UkH~B^L_yE#_lm4T9pY zLN)x;s5D#X-2~!DD1;IA3Oyi3sOC?j>FW6SAS38cBkS`>b@QiDU3R2#5J($6M`GJk zMivUyVw5`dDQB9tl?I~={S6(o0euc`lSl)E47LlJ?LM`QfKavN0C*j-$j#&FEDB#vDx&`MpBVl_={$iCDdF@-h|vsx$68K zCU3b9oe&eY+-m&vpuZe-GyE}OE7TqEUsU1yi_u!)`-{<9VT1cXvg*Y7Mtv4#x0($P zEP7({Dd~lL?v&fsCWNiZzX)(znIN#G`m&-z4;$*z{VjF1JMU6RPCYS6VO5yH(t{;M;#0lyhmXXj+x7j@P)fa2cjc)iy8X-Le-TR#o# zSm~GwZT>W>^ZpQhv#F8QR~|cUyqQL8!WlEDF=KX@j2YC(=8^=PvWZTlfO`86(ah%Q zR=K848f~5kD5f!;MFT$?Az3{w|~z?ddcqFRS&&&pl{>c ziu%TjDh75^k&&S_9u>wSAuH^Tb|M_h%Ur?1SCJkl9^i_y2_)qz(3dYJ+*3WVJ^ook zG2*(C4HeU`m{BX)YO@rhR!%t2W;z>3q6l@_$#AZEVrrb8KMu)RWyLcQj^pC1taw7f zW|hh8$Hm9NW);Pqj!FPfA}q-aTdQ{dKK!0_-j*=bl|tiRhOR9zyV_6;U5jf&jIu;H zo|ACuk}>flb!tppRBHB(X{OWV)su8RlSEib0Duan#q%0UVeCqt(GKG)tg#Hmm@8Ph znlWCBLBMXS z1q>)UZY|T_G)`h!1-G(GE10QW+}pxN6F>mPxNR28jjMZG)}(nguI_E5wKU`Sq_>Cj z?d4?U*lrFHz*0bK`$Ths(S)#V=LF+At-vOCCcYkU_T5$+bqcI{v^f6i=$%AEC=iwwizImLmi~p2WHi#a)Jw3`P+RJeL>zugL6Y-jfI$3P_D%P%DEZ{v#0)q!*1ns}ubPKhsS5cF&JUyz_*d*tFZ1^wEoSS2NX5+T^v zp&HLn`0uSzak`r%xG>|m2uyqn;dIHrI68?qpNvokI&by1`OZ>y=K zWu^_fb*kWlaI$)lPB!k-09hyX|9)y72uRkY;xK)`Jt97yNp$(gg0eiUOP95h$0G37 z1$^p+iW=X#4Rn|C33Yqu7JTdW&@K4Z?V%fd>&Zj+JOR0$At2W?1mt==bPLG!aBV3r zl?cJOUIVRyalK9h4F%(RJ+unO^#ZL1ufRBqR}+|S9QuHu?_`Eht}=*@+t*S!*u?#ZOko#bITsty+e@3o&Q9M5g zKF+OL9Pj^f2%PZ$L*TEM#J#D4Lsdql+W#dgRW+u7w)aLSHsnq(izhooWCvu)UlTkP7tDUR@&d3$LuoGa$VIT;}PTb*}h83%- zwP)e7;O07T*%+#*g_>piv!9 zsBoXU=JNRS4Ff}Rjt>mUIX*BX=lIU#t}mjJZpx$5?&Q~oq7n^%_k35Jd%mmS!+-og DO4%wm delta 94577 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%0D#8yw3ZMcD%3N*V=f%@ zEH$PXa}U0!y=Tn9c%R%rLmd4O<5zoKBMc@o-d3rejgrna{cL57QKg@)j4`V8vz5^o zod-x|+Sfaam$~9Rz#9I5sQdt1FP1!mb3;whqGN-3g-Ys$tpsb7trr0G8e;1OM7@UC zdI5np#MTQ4;zOv{r~)>n*b|25CaK3ii%0D@-0GONC5*twMI>g72_tO9j4@$^_1p!5 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 E2j1PdDF6Tf diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 0a5c9654f0..12a9095551 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -59,7 +59,7 @@ import ( "github.com/percona/pmm/api/managementpb" alertingpb "github.com/percona/pmm/api/managementpb/alerting" azurev1beta1 "github.com/percona/pmm/api/managementpb/azure" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" dbaasv1beta1 "github.com/percona/pmm/api/managementpb/dbaas" iav1beta1 "github.com/percona/pmm/api/managementpb/ia" "github.com/percona/pmm/api/platformpb" @@ -191,7 +191,8 @@ type gRPCServerDeps struct { backupService *backup.Service compatibilityService *backup.CompatibilityService backupRemovalService *backup.RemovalService - minioService *minio.Service + pitrTimerangeService *backup.PITRTimerangeService + minioClient *minio.Client versionCache *versioncache.Service supervisord *supervisord.Service config *config.Config @@ -258,10 +259,10 @@ func runGRPCServer(ctx context.Context, deps *gRPCServerDeps) { iav1beta1.RegisterAlertsServer(gRPCServer, deps.alertsService) alertingpb.RegisterAlertingServer(gRPCServer, deps.templatesService) - backupv1beta1.RegisterBackupsServer(gRPCServer, managementbackup.NewBackupsService(deps.db, deps.backupService, deps.compatibilityService, deps.schedulerService)) - backupv1beta1.RegisterLocationsServer(gRPCServer, managementbackup.NewLocationsService(deps.db, deps.minioService)) - backupv1beta1.RegisterArtifactsServer(gRPCServer, managementbackup.NewArtifactsService(deps.db, deps.backupRemovalService)) - backupv1beta1.RegisterRestoreHistoryServer(gRPCServer, managementbackup.NewRestoreHistoryService(deps.db)) + backuppb.RegisterBackupsServer(gRPCServer, managementbackup.NewBackupsService(deps.db, deps.backupService, deps.compatibilityService, deps.schedulerService)) + backuppb.RegisterLocationsServer(gRPCServer, managementbackup.NewLocationsService(deps.db, deps.minioClient)) + backuppb.RegisterArtifactsServer(gRPCServer, managementbackup.NewArtifactsService(deps.db, deps.backupRemovalService, deps.pitrTimerangeService)) + backuppb.RegisterRestoreHistoryServer(gRPCServer, managementbackup.NewRestoreHistoryService(deps.db)) k8sServer := managementdbaas.NewKubernetesServer(deps.db, deps.dbaasClient, deps.versionServiceClient, deps.grafanaClient) deps.dbaasInitializer.RegisterKubernetesServer(k8sServer) @@ -388,10 +389,10 @@ func runHTTP1Server(ctx context.Context, deps *http1ServerDeps) { iav1beta1.RegisterRulesHandlerFromEndpoint, alertingpb.RegisterAlertingHandlerFromEndpoint, - backupv1beta1.RegisterBackupsHandlerFromEndpoint, - backupv1beta1.RegisterLocationsHandlerFromEndpoint, - backupv1beta1.RegisterArtifactsHandlerFromEndpoint, - backupv1beta1.RegisterRestoreHistoryHandlerFromEndpoint, + backuppb.RegisterBackupsHandlerFromEndpoint, + backuppb.RegisterLocationsHandlerFromEndpoint, + backuppb.RegisterArtifactsHandlerFromEndpoint, + backuppb.RegisterRestoreHistoryHandlerFromEndpoint, dbaasv1beta1.RegisterKubernetesHandlerFromEndpoint, dbaasv1beta1.RegisterDBClustersHandlerFromEndpoint, @@ -733,12 +734,13 @@ func main() { } prom.MustRegister(vmalert) - minioService := minio.New() + minioClient := minio.New() qanClient := getQANClient(ctx, sqlDB, *postgresDBNameF, *qanAPIAddrF) agentsRegistry := agents.NewRegistry(db) - backupRemovalService := backup.NewRemovalService(db, minioService) + backupRemovalService := backup.NewRemovalService(db, minioClient) + pitrTimerangeService := backup.NewPITRTimerangeService(minioClient) backupRetentionService := backup.NewRetentionService(db, backupRemovalService) prom.MustRegister(agentsRegistry) @@ -802,7 +804,7 @@ func main() { versioner := agents.NewVersionerService(agentsRegistry) dbaasClient := dbaas.NewClient(*dbaasControllerAPIAddrF) compatibilityService := backup.NewCompatibilityService(db, versioner) - backupService := backup.NewService(db, jobsService, agentService, compatibilityService) + backupService := backup.NewService(db, jobsService, agentService, compatibilityService, pitrTimerangeService) schedulerService := scheduler.New(db, backupService) versionCache := versioncache.New(db, versioner) emailer := alertmanager.NewEmailer(logrus.WithField("component", "alertmanager-emailer").Logger) @@ -989,7 +991,8 @@ func main() { backupService: backupService, compatibilityService: compatibilityService, backupRemovalService: backupRemovalService, - minioService: minioService, + pitrTimerangeService: pitrTimerangeService, + minioClient: minioClient, versionCache: versionCache, supervisord: supervisord, config: &cfg.Config, diff --git a/managed/models/database.go b/managed/models/database.go index 181670f889..c84ff6a122 100644 --- a/managed/models/database.go +++ b/managed/models/database.go @@ -753,6 +753,14 @@ var databaseSchema = [][]string{ `ALTER TABLE backup_locations DROP COLUMN pmm_server_config`, }, + 70: { + `ALTER TABLE restore_history + ADD COLUMN pitr_timestamp TIMESTAMP`, + }, + 71: { + `ALTER TABLE backup_locations + RENAME COLUMN pmm_client_config TO filesystem_config`, + }, } // ^^^ Avoid default values in schema definition. ^^^ diff --git a/managed/models/location_helpers.go b/managed/models/location_helpers.go index c774e5e11d..c94626dcb8 100644 --- a/managed/models/location_helpers.go +++ b/managed/models/location_helpers.go @@ -59,7 +59,7 @@ func checkUniqueBackupLocationName(q *reform.Querier, name string) error { } } -func checkPMMClientLocationConfig(c *PMMClientLocationConfig) error { +func checkFilesystemLocationConfig(c *FilesystemLocationConfig) error { if c == nil { return status.Error(codes.InvalidArgument, "PMM client location config is empty.") } @@ -194,8 +194,8 @@ func FindBackupLocationsByIDs(q *reform.Querier, ids []string) (map[string]*Back // BackupLocationConfig groups all backup locations configs. type BackupLocationConfig struct { - PMMClientConfig *PMMClientLocationConfig - S3Config *S3LocationConfig + FilesystemConfig *FilesystemLocationConfig + S3Config *S3LocationConfig } // BackupLocationValidationParams contains typed params for backup location validate. @@ -213,9 +213,9 @@ func (c BackupLocationConfig) Validate(params BackupLocationValidationParams) er err = checkS3Config(c.S3Config, params.WithBucketRegion) } - if c.PMMClientConfig != nil { + if c.FilesystemConfig != nil { configCount++ - err = checkPMMClientLocationConfig(c.PMMClientConfig) + err = checkFilesystemLocationConfig(c.FilesystemConfig) } if configCount > 1 { @@ -235,10 +235,10 @@ func (c BackupLocationConfig) FillLocationModel(locationModel *BackupLocation) { case c.S3Config != nil: locationModel.Type = S3BackupLocationType locationModel.S3Config = c.S3Config - locationModel.PMMClientConfig = nil - case c.PMMClientConfig != nil: - locationModel.Type = PMMClientBackupLocationType - locationModel.PMMClientConfig = c.PMMClientConfig + locationModel.FilesystemConfig = nil + case c.FilesystemConfig != nil: + locationModel.Type = FilesystemBackupLocationType + locationModel.FilesystemConfig = c.FilesystemConfig locationModel.S3Config = nil } } diff --git a/managed/models/location_helpers_test.go b/managed/models/location_helpers_test.go index fb1b665f8d..51acb5f189 100644 --- a/managed/models/location_helpers_test.go +++ b/managed/models/location_helpers_test.go @@ -54,7 +54,7 @@ func TestBackupLocations(t *testing.T) { Name: "some name", Description: "some desc", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "/tmp", }, }, @@ -62,10 +62,10 @@ func TestBackupLocations(t *testing.T) { location, err := models.CreateBackupLocation(q, params) require.NoError(t, err) - assert.Equal(t, models.PMMClientBackupLocationType, location.Type) + assert.Equal(t, models.FilesystemBackupLocationType, location.Type) assert.Equal(t, params.Name, location.Name) assert.Equal(t, params.Description, location.Description) - assert.Equal(t, params.PMMClientConfig.Path, location.PMMClientConfig.Path) + assert.Equal(t, params.FilesystemConfig.Path, location.FilesystemConfig.Path) assert.NotEmpty(t, location.ID) }) @@ -118,7 +118,7 @@ func TestBackupLocations(t *testing.T) { Name: "some name", Description: "some desc", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "/tmp", }, S3Config: &models.S3LocationConfig{ @@ -148,7 +148,7 @@ func TestBackupLocations(t *testing.T) { Name: "some name", Description: "some desc", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "/tmp", }, }, @@ -203,7 +203,7 @@ func TestBackupLocations(t *testing.T) { Name: "some name", Description: "some desc", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "/tmp", }, }, @@ -232,7 +232,7 @@ func TestBackupLocations(t *testing.T) { // empty description in request, we expect no change assert.Equal(t, createParams.Description, updatedLoc.Description) assert.Equal(t, models.S3BackupLocationType, updatedLoc.Type) - assert.Nil(t, updatedLoc.PMMClientConfig) + assert.Nil(t, updatedLoc.FilesystemConfig) assert.Equal(t, changeParams.S3Config, updatedLoc.S3Config) findLoc, err := models.FindBackupLocationByID(q, location.ID) @@ -254,7 +254,7 @@ func TestBackupLocations(t *testing.T) { Name: "some name", Description: "some desc", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "/tmp", }, }, @@ -283,7 +283,7 @@ func TestBackupLocations(t *testing.T) { Name: "some name", Description: "some desc", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "/tmp", }, }, @@ -364,7 +364,7 @@ func TestCreateBackupLocationValidation(t *testing.T) { params: models.CreateBackupLocationParams{ Name: "client-1", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "/tmp", }, }, @@ -376,7 +376,7 @@ func TestCreateBackupLocationValidation(t *testing.T) { params: models.CreateBackupLocationParams{ Name: "client-2", BackupLocationConfig: models.BackupLocationConfig{ - PMMClientConfig: &models.PMMClientLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ Path: "", }, }, diff --git a/managed/models/location_model.go b/managed/models/location_model.go index f7e9743de3..ddde641b1b 100644 --- a/managed/models/location_model.go +++ b/managed/models/location_model.go @@ -29,20 +29,20 @@ type BackupLocationType string // BackupLocation types. Same as in agent/runner/jobs/backup_location.go const ( - S3BackupLocationType BackupLocationType = "s3" - PMMClientBackupLocationType BackupLocationType = "pmm-client" + S3BackupLocationType BackupLocationType = "s3" + FilesystemBackupLocationType BackupLocationType = "filesystem" ) // BackupLocation represents destination for backup. // //reform:backup_locations type BackupLocation struct { - ID string `reform:"id,pk"` - Name string `reform:"name"` - Description string `reform:"description"` - Type BackupLocationType `reform:"type"` - S3Config *S3LocationConfig `reform:"s3_config"` - PMMClientConfig *PMMClientLocationConfig `reform:"pmm_client_config"` + ID string `reform:"id,pk"` + Name string `reform:"name"` + Description string `reform:"description"` + Type BackupLocationType `reform:"type"` + S3Config *S3LocationConfig `reform:"s3_config"` + FilesystemConfig *FilesystemLocationConfig `reform:"filesystem_config"` CreatedAt time.Time `reform:"created_at"` UpdatedAt time.Time `reform:"updated_at"` @@ -84,16 +84,16 @@ func (c S3LocationConfig) Value() (driver.Value, error) { return jsonValue(c) } // Scan implements database/sql.Scanner interface. Should be defined on the pointer. func (c *S3LocationConfig) Scan(src interface{}) error { return jsonScan(c, src) } -// PMMClientLocationConfig contains require properties for accessing file system on pmm-client-node. -type PMMClientLocationConfig struct { +// FilesystemLocationConfig contains require properties for accessing file system on pmm-client-node. +type FilesystemLocationConfig struct { Path string `json:"path"` } // Value implements database/sql/driver.Valuer interface. Should be defined on the value. -func (c PMMClientLocationConfig) Value() (driver.Value, error) { return jsonValue(c) } +func (c FilesystemLocationConfig) Value() (driver.Value, error) { return jsonValue(c) } // Scan implements database/sql.Scanner interface. Should be defined on the pointer. -func (c *PMMClientLocationConfig) Scan(src interface{}) error { return jsonScan(c, src) } +func (c *FilesystemLocationConfig) Scan(src interface{}) error { return jsonScan(c, src) } // check interfaces. var ( diff --git a/managed/models/location_model_reform.go b/managed/models/location_model_reform.go index 9286ea78c6..96184e6dc9 100644 --- a/managed/models/location_model_reform.go +++ b/managed/models/location_model_reform.go @@ -33,7 +33,7 @@ func (v *backupLocationTableType) Columns() []string { "description", "type", "s3_config", - "pmm_client_config", + "filesystem_config", "created_at", "updated_at", } @@ -65,7 +65,7 @@ var BackupLocationTable = &backupLocationTableType{ {Name: "Description", Type: "string", Column: "description"}, {Name: "Type", Type: "BackupLocationType", Column: "type"}, {Name: "S3Config", Type: "*S3LocationConfig", Column: "s3_config"}, - {Name: "PMMClientConfig", Type: "*PMMClientLocationConfig", Column: "pmm_client_config"}, + {Name: "FilesystemConfig", Type: "*FilesystemLocationConfig", Column: "filesystem_config"}, {Name: "CreatedAt", Type: "time.Time", Column: "created_at"}, {Name: "UpdatedAt", Type: "time.Time", Column: "updated_at"}, }, @@ -82,7 +82,7 @@ func (s BackupLocation) String() string { res[2] = "Description: " + reform.Inspect(s.Description, true) res[3] = "Type: " + reform.Inspect(s.Type, true) res[4] = "S3Config: " + reform.Inspect(s.S3Config, true) - res[5] = "PMMClientConfig: " + reform.Inspect(s.PMMClientConfig, true) + res[5] = "FilesystemConfig: " + reform.Inspect(s.FilesystemConfig, true) res[6] = "CreatedAt: " + reform.Inspect(s.CreatedAt, true) res[7] = "UpdatedAt: " + reform.Inspect(s.UpdatedAt, true) return strings.Join(res, ", ") @@ -97,7 +97,7 @@ func (s *BackupLocation) Values() []interface{} { s.Description, s.Type, s.S3Config, - s.PMMClientConfig, + s.FilesystemConfig, s.CreatedAt, s.UpdatedAt, } @@ -112,7 +112,7 @@ func (s *BackupLocation) Pointers() []interface{} { &s.Description, &s.Type, &s.S3Config, - &s.PMMClientConfig, + &s.FilesystemConfig, &s.CreatedAt, &s.UpdatedAt, } diff --git a/managed/models/restore_history_helpers.go b/managed/models/restore_history_helpers.go index 81ad66a26d..f7a30cc1ce 100644 --- a/managed/models/restore_history_helpers.go +++ b/managed/models/restore_history_helpers.go @@ -102,9 +102,10 @@ func FindRestoreHistoryItemByID(q *reform.Querier, id string) (*RestoreHistoryIt // CreateRestoreHistoryItemParams are params for creating a new restore history item. type CreateRestoreHistoryItemParams struct { - ArtifactID string - ServiceID string - Status RestoreStatus + ArtifactID string + ServiceID string + PITRTimestamp *time.Time + Status RestoreStatus } // Validate validates params used for creating a restore history item. @@ -136,10 +137,11 @@ func CreateRestoreHistoryItem(q *reform.Querier, params CreateRestoreHistoryItem } row := &RestoreHistoryItem{ - ID: id, - ArtifactID: params.ArtifactID, - ServiceID: params.ServiceID, - Status: params.Status, + ID: id, + ArtifactID: params.ArtifactID, + ServiceID: params.ServiceID, + PITRTimestamp: params.PITRTimestamp, + Status: params.Status, } if err := q.Insert(row); err != nil { return nil, errors.Wrap(err, "failed to insert restore history item") diff --git a/managed/models/restore_history_helpers_test.go b/managed/models/restore_history_helpers_test.go index b13eb67975..3e50495081 100644 --- a/managed/models/restore_history_helpers_test.go +++ b/managed/models/restore_history_helpers_test.go @@ -123,6 +123,7 @@ func TestRestoreHistory(t *testing.T) { require.NoError(t, err) assert.Equal(t, params.ArtifactID, i.ArtifactID) assert.Equal(t, params.ServiceID, i.ServiceID) + assert.Equal(t, params.PITRTimestamp, i.PITRTimestamp) assert.Equal(t, params.Status, i.Status) assert.Less(t, time.Now().UTC().Unix()-i.StartedAt.Unix(), int64(5)) }) @@ -137,16 +138,20 @@ func TestRestoreHistory(t *testing.T) { q := tx.Querier prepareArtifactsAndService(q) + now := time.Now().Round(time.Second) + params := models.CreateRestoreHistoryItemParams{ - ArtifactID: artifactID1, - ServiceID: serviceID1, - Status: models.InProgressRestoreStatus, + ArtifactID: artifactID1, + ServiceID: serviceID1, + PITRTimestamp: &now, + Status: models.InProgressRestoreStatus, } i, err := models.CreateRestoreHistoryItem(q, params) require.NoError(t, err) assert.Equal(t, params.ArtifactID, i.ArtifactID) assert.Equal(t, params.ServiceID, i.ServiceID) + assert.Equal(t, params.PITRTimestamp, i.PITRTimestamp) assert.Equal(t, params.Status, i.Status) assert.Less(t, time.Now().UTC().Unix()-i.StartedAt.Unix(), int64(5)) @@ -156,6 +161,7 @@ func TestRestoreHistory(t *testing.T) { require.NoError(t, err) assert.Equal(t, params.ArtifactID, i.ArtifactID) assert.Equal(t, params.ServiceID, i.ServiceID) + assert.WithinDuration(t, *params.PITRTimestamp, *i.PITRTimestamp, 0) assert.Equal(t, models.ErrorRestoreStatus, i.Status) assert.Less(t, time.Now().UTC().Unix()-i.StartedAt.Unix(), int64(5)) }) diff --git a/managed/models/restore_history_model.go b/managed/models/restore_history_model.go index d93923047c..d294ff144f 100644 --- a/managed/models/restore_history_model.go +++ b/managed/models/restore_history_model.go @@ -50,12 +50,13 @@ func (rs RestoreStatus) Validate() error { // //reform:restore_history type RestoreHistoryItem struct { - ID string `reform:"id,pk"` - ArtifactID string `reform:"artifact_id"` - ServiceID string `reform:"service_id"` - Status RestoreStatus `reform:"status"` - StartedAt time.Time `reform:"started_at"` - FinishedAt *time.Time `reform:"finished_at"` + ID string `reform:"id,pk"` + ArtifactID string `reform:"artifact_id"` + ServiceID string `reform:"service_id"` + PITRTimestamp *time.Time `reform:"pitr_timestamp"` + Status RestoreStatus `reform:"status"` + StartedAt time.Time `reform:"started_at"` + FinishedAt *time.Time `reform:"finished_at"` } // BeforeInsert implements reform.BeforeInserter interface. diff --git a/managed/models/restore_history_model_reform.go b/managed/models/restore_history_model_reform.go index 4390dda843..e9d80ae2f5 100644 --- a/managed/models/restore_history_model_reform.go +++ b/managed/models/restore_history_model_reform.go @@ -31,6 +31,7 @@ func (v *restoreHistoryItemTableType) Columns() []string { "id", "artifact_id", "service_id", + "pitr_timestamp", "status", "started_at", "finished_at", @@ -61,6 +62,7 @@ var RestoreHistoryItemTable = &restoreHistoryItemTableType{ {Name: "ID", Type: "string", Column: "id"}, {Name: "ArtifactID", Type: "string", Column: "artifact_id"}, {Name: "ServiceID", Type: "string", Column: "service_id"}, + {Name: "PITRTimestamp", Type: "*time.Time", Column: "pitr_timestamp"}, {Name: "Status", Type: "RestoreStatus", Column: "status"}, {Name: "StartedAt", Type: "time.Time", Column: "started_at"}, {Name: "FinishedAt", Type: "*time.Time", Column: "finished_at"}, @@ -72,13 +74,14 @@ var RestoreHistoryItemTable = &restoreHistoryItemTableType{ // String returns a string representation of this struct or record. func (s RestoreHistoryItem) String() string { - res := make([]string, 6) + res := make([]string, 7) res[0] = "ID: " + reform.Inspect(s.ID, true) res[1] = "ArtifactID: " + reform.Inspect(s.ArtifactID, true) res[2] = "ServiceID: " + reform.Inspect(s.ServiceID, true) - res[3] = "Status: " + reform.Inspect(s.Status, true) - res[4] = "StartedAt: " + reform.Inspect(s.StartedAt, true) - res[5] = "FinishedAt: " + reform.Inspect(s.FinishedAt, true) + res[3] = "PITRTimestamp: " + reform.Inspect(s.PITRTimestamp, true) + res[4] = "Status: " + reform.Inspect(s.Status, true) + res[5] = "StartedAt: " + reform.Inspect(s.StartedAt, true) + res[6] = "FinishedAt: " + reform.Inspect(s.FinishedAt, true) return strings.Join(res, ", ") } @@ -89,6 +92,7 @@ func (s *RestoreHistoryItem) Values() []interface{} { s.ID, s.ArtifactID, s.ServiceID, + s.PITRTimestamp, s.Status, s.StartedAt, s.FinishedAt, @@ -102,6 +106,7 @@ func (s *RestoreHistoryItem) Pointers() []interface{} { &s.ID, &s.ArtifactID, &s.ServiceID, + &s.PITRTimestamp, &s.Status, &s.StartedAt, &s.FinishedAt, diff --git a/managed/services/agents/jobs.go b/managed/services/agents/jobs.go index b4846385f2..af677e5f7d 100644 --- a/managed/services/agents/jobs.go +++ b/managed/services/agents/jobs.go @@ -24,10 +24,11 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/reform.v1" "github.com/percona/pmm/api/agentpb" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" "github.com/percona/pmm/managed/models" ) @@ -35,10 +36,11 @@ var ( // ErrRetriesExhausted is returned when remaining retries are 0. ErrRetriesExhausted = errors.New("retries exhausted") - pmmAgentMinVersionForMongoLogicalBackupAndRestore = version.Must(version.NewVersion("2.19")) - pmmAgentMinVersionForMySQLBackupAndRestore = version.Must(version.NewVersion("2.23")) - pmmAgentMinVersionForMongoPhysicalBackupAndRestore = version.Must(version.NewVersion("2.31.0-0")) - pmmAgentMinVersionForMongoDBUsePMMClientLocalStorage = version.Must(version.NewVersion("2.32.0-0")) + pmmAgentMinVersionForMongoLogicalBackupAndRestore = version.Must(version.NewVersion("2.19")) + pmmAgentMinVersionForMySQLBackupAndRestore = version.Must(version.NewVersion("2.23")) + pmmAgentMinVersionForMongoPhysicalBackupAndRestore = version.Must(version.NewVersion("2.31.0-0")) + pmmAgentMinVersionForMongoDBUseFilesystemStorage = version.Must(version.NewVersion("2.32.0-0")) + pmmAgentMinVersionForMongoPITRRestore = version.Must(version.NewVersion("2.32.0-0")) ) const ( @@ -131,8 +133,8 @@ func (s *JobsService) RestartJob(ctx context.Context, jobID string) error { if locationModel != nil { locationConfig = &models.BackupLocationConfig{ - PMMClientConfig: locationModel.PMMClientConfig, - S3Config: locationModel.S3Config, + FilesystemConfig: locationModel.FilesystemConfig, + S3Config: locationModel.S3Config, } } @@ -402,14 +404,14 @@ func (s *JobsService) StartMongoDBBackupJob( mongoDBReq.LocationConfig = &agentpb.StartJobRequest_MongoDBBackup_S3Config{ S3Config: convertS3ConfigModel(locationConfig.S3Config), } - case locationConfig.PMMClientConfig != nil: + case locationConfig.FilesystemConfig != nil: if err := PMMAgentSupported(s.r.db.Querier, pmmAgentID, "mongodb backup to client local storage", - pmmAgentMinVersionForMongoDBUsePMMClientLocalStorage); err != nil { + pmmAgentMinVersionForMongoDBUseFilesystemStorage); err != nil { return err } - mongoDBReq.LocationConfig = &agentpb.StartJobRequest_MongoDBBackup_PmmClientConfig{ - PmmClientConfig: &agentpb.PMMClientLocationConfig{Path: locationConfig.PMMClientConfig.Path}, + mongoDBReq.LocationConfig = &agentpb.StartJobRequest_MongoDBBackup_FilesystemConfig{ + FilesystemConfig: &agentpb.FilesystemLocationConfig{Path: locationConfig.FilesystemConfig.Path}, } default: return errors.Errorf("unsupported location config") @@ -495,6 +497,7 @@ func (s *JobsService) StartMongoDBRestoreBackupJob( dbConfig *models.DBConfig, dataModel models.DataModel, locationConfig *models.BackupLocationConfig, + pitrTimestamp time.Time, ) error { var err error switch dataModel { @@ -511,13 +514,23 @@ func (s *JobsService) StartMongoDBRestoreBackupJob( return err } + if pitrTimestamp.Unix() != 0 { + // TODO refactor pmm agent version checking. First detect minimum required version needed for operations and + // then invoke PMMAgentSupported + if err = PMMAgentSupported(s.r.db.Querier, pmmAgentID, + "mongodb pitr restore", pmmAgentMinVersionForMongoPITRRestore); err != nil { + return err + } + } + mongoDBReq := &agentpb.StartJobRequest_MongoDBRestoreBackup{ - Name: name, - User: dbConfig.User, - Password: dbConfig.Password, - Address: dbConfig.Address, - Port: int32(dbConfig.Port), - Socket: dbConfig.Socket, + Name: name, + User: dbConfig.User, + Password: dbConfig.Password, + Address: dbConfig.Address, + Port: int32(dbConfig.Port), + Socket: dbConfig.Socket, + PitrTimestamp: timestamppb.New(pitrTimestamp), } switch { @@ -525,14 +538,14 @@ func (s *JobsService) StartMongoDBRestoreBackupJob( mongoDBReq.LocationConfig = &agentpb.StartJobRequest_MongoDBRestoreBackup_S3Config{ S3Config: convertS3ConfigModel(locationConfig.S3Config), } - case locationConfig.PMMClientConfig != nil: + case locationConfig.FilesystemConfig != nil: if err := PMMAgentSupported(s.r.db.Querier, pmmAgentID, "mongodb restore from client local storage", - pmmAgentMinVersionForMongoDBUsePMMClientLocalStorage); err != nil { + pmmAgentMinVersionForMongoDBUseFilesystemStorage); err != nil { return err } - mongoDBReq.LocationConfig = &agentpb.StartJobRequest_MongoDBRestoreBackup_PmmClientConfig{ - PmmClientConfig: &agentpb.PMMClientLocationConfig{Path: locationConfig.PMMClientConfig.Path}, + mongoDBReq.LocationConfig = &agentpb.StartJobRequest_MongoDBRestoreBackup_FilesystemConfig{ + FilesystemConfig: &agentpb.FilesystemLocationConfig{Path: locationConfig.FilesystemConfig.Path}, } default: return errors.Errorf("unsupported location config") @@ -594,12 +607,12 @@ func convertS3ConfigModel(config *models.S3LocationConfig) *agentpb.S3LocationCo } } -func convertDataModel(model models.DataModel) (backupv1beta1.DataModel, error) { +func convertDataModel(model models.DataModel) (backuppb.DataModel, error) { switch model { case models.PhysicalDataModel: - return backupv1beta1.DataModel_PHYSICAL, nil + return backuppb.DataModel_PHYSICAL, nil case models.LogicalDataModel: - return backupv1beta1.DataModel_LOGICAL, nil + return backuppb.DataModel_LOGICAL, nil default: return 0, errors.Errorf("unknown data model: %s", model) } diff --git a/managed/services/backup/backup_service.go b/managed/services/backup/backup_service.go index 01f90e300c..a875d6c7d8 100644 --- a/managed/services/backup/backup_service.go +++ b/managed/services/backup/backup_service.go @@ -22,6 +22,7 @@ import ( "github.com/AlekSi/pointer" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "gopkg.in/reform.v1" @@ -31,19 +32,23 @@ import ( // Service represents core logic for db backup. type Service struct { + l *logrus.Entry db *reform.DB jobsService jobsService agentService agentService compatibilityService compatibilityService + pitrTimerangeService pitrTimerangeService } // NewService creates new backups logic service. -func NewService(db *reform.DB, jobsService jobsService, agentService agentService, cSvc compatibilityService) *Service { +func NewService(db *reform.DB, jobsService jobsService, agentService agentService, cSvc compatibilityService, pitrSvc pitrTimerangeService) *Service { return &Service{ + l: logrus.WithField("component", "management/backup/backup"), db: db, jobsService: jobsService, agentService: agentService, compatibilityService: cSvc, + pitrTimerangeService: pitrSvc, } } @@ -97,6 +102,11 @@ func (s *Service) PerformBackup(ctx context.Context, params PerformBackupParams) if params.DataModel != models.PhysicalDataModel { return errors.WithMessage(ErrIncompatibleDataModel, "the only supported data model for mySQL is physical") } + + if locationModel.Type != models.S3BackupLocationType { + return errors.WithMessage(ErrIncompatibleLocationType, "the only supported location type for mySQL is s3") + } + if params.Mode != models.Snapshot { return errors.New("the only supported backup mode for mySQL is snapshot") } @@ -165,8 +175,8 @@ func (s *Service) PerformBackup(ctx context.Context, params PerformBackupParams) } locationConfig := &models.BackupLocationConfig{ - PMMClientConfig: locationModel.PMMClientConfig, - S3Config: locationModel.S3Config, + FilesystemConfig: locationModel.FilesystemConfig, + S3Config: locationModel.S3Config, } switch svc.ServiceType { @@ -183,6 +193,12 @@ func (s *Service) PerformBackup(ctx context.Context, params PerformBackupParams) err = status.Errorf(codes.Unknown, "Unknown service: %s", svc.ServiceType) } if err != nil { + if _, e := models.UpdateArtifact(s.db.Querier, artifact.ID, models.UpdateArtifactParams{ + Status: models.BackupStatusPointer(models.ErrorBackupStatus), + }); e != nil { + s.l.WithError(e).Warnf("failed to mark artifact %s as failed", artifact.ID) + } + return "", err } @@ -217,10 +233,15 @@ type prepareRestoreJobParams struct { ServiceType models.ServiceType DBConfig *models.DBConfig DataModel models.DataModel + PITRTimestamp time.Time } // RestoreBackup starts restore backup job. -func (s *Service) RestoreBackup(ctx context.Context, serviceID, artifactID string) (string, error) { +func (s *Service) RestoreBackup(ctx context.Context, serviceID, artifactID string, pitrTimestamp time.Time) (string, error) { + if err := s.checkArtifactModePreconditions(ctx, artifactID, pitrTimestamp); err != nil { + return "", err + } + dbVersion, err := s.compatibilityService.CheckSoftwareCompatibilityForService(ctx, serviceID) if err != nil { return "", err @@ -228,9 +249,9 @@ func (s *Service) RestoreBackup(ctx context.Context, serviceID, artifactID strin var params *prepareRestoreJobParams var jobID, restoreID string - if err := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + if errTx := s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { var err error - params, err = s.prepareRestoreJob(tx.Querier, serviceID, artifactID) + params, err = s.prepareRestoreJob(tx.Querier, serviceID, artifactID, pitrTimestamp) if err != nil { return err } @@ -243,9 +264,10 @@ func (s *Service) RestoreBackup(ctx context.Context, serviceID, artifactID strin } restore, err := models.CreateRestoreHistoryItem(tx.Querier, models.CreateRestoreHistoryItemParams{ - ArtifactID: artifactID, - ServiceID: serviceID, - Status: models.InProgressRestoreStatus, + ArtifactID: artifactID, + ServiceID: serviceID, + PITRTimestamp: &pitrTimestamp, + Status: models.InProgressRestoreStatus, }) if err != nil { return err @@ -296,8 +318,8 @@ func (s *Service) RestoreBackup(ctx context.Context, serviceID, artifactID strin jobID = job.ID return err - }); err != nil { - return "", err + }); errTx != nil { + return "", errTx } if err := s.startRestoreJob(jobID, serviceID, params); err != nil { @@ -356,6 +378,7 @@ func (s *Service) prepareRestoreJob( q *reform.Querier, serviceID string, artifactID string, + pitrTimestamp time.Time, ) (*prepareRestoreJobParams, error) { service, err := models.FindServiceByID(q, serviceID) if err != nil { @@ -367,11 +390,7 @@ func (s *Service) prepareRestoreJob( return nil, err } if artifact.Status != models.SuccessBackupStatus { - return nil, errors.Errorf("artifact %q status is not successful, status: %q", artifactID, artifact.Status) - } - - if artifact.Vendor == string(models.MongoDBServiceType) && artifact.DataModel == models.PhysicalDataModel { - return nil, errors.Wrapf(ErrIncompatibleService, "restore of physical backups is not supported for MongoDB yet") + return nil, errors.Wrapf(ErrArtifactNotReady, "artifact %q in status: %q", artifactID, artifact.Status) } location, err := models.FindBackupLocationByID(q, artifact.LocationID) @@ -400,13 +419,14 @@ func (s *Service) prepareRestoreJob( ServiceType: service.ServiceType, DBConfig: dbConfig, DataModel: artifact.DataModel, + PITRTimestamp: pitrTimestamp, }, nil } func (s *Service) startRestoreJob(jobID, serviceID string, params *prepareRestoreJobParams) error { locationConfig := &models.BackupLocationConfig{ - PMMClientConfig: params.LocationModel.PMMClientConfig, - S3Config: params.LocationModel.S3Config, + FilesystemConfig: params.LocationModel.FilesystemConfig, + S3Config: params.LocationModel.S3Config, } switch params.ServiceType { @@ -428,7 +448,8 @@ func (s *Service) startRestoreJob(jobID, serviceID string, params *prepareRestor params.ArtifactName, params.DBConfig, params.DataModel, - locationConfig); err != nil { + locationConfig, + params.PITRTimestamp); err != nil { return err } case models.PostgreSQLServiceType, @@ -505,3 +526,73 @@ func (s *Service) prepareBackupJob( return res, dbConfig, nil } + +// checkArtifactModePreconditions checks that artifact params and requested restore mode satisfy each other. +func (s *Service) checkArtifactModePreconditions(ctx context.Context, artifactID string, pitrTimestamp time.Time) error { + artifact, err := models.FindArtifactByID(s.db.Querier, artifactID) + if err != nil { + return err + } + + if err := checkArtifactMode(artifact, pitrTimestamp); err != nil { + return err + } + + // Continue checks only if user requested PITR restore. + if pitrTimestamp.Unix() == 0 { + return nil + } + + location, err := models.FindBackupLocationByID(s.db.Querier, artifact.LocationID) + if err != nil { + return err + } + + if location.Type != models.S3BackupLocationType { + return errors.Wrapf(ErrIncompatibleLocationType, "point in time recovery available only for S3 locations") + } + + timeRanges, err := s.pitrTimerangeService.ListPITRTimeranges(ctx, artifact.Name, location) + if err != nil { + return err + } + + for _, tRange := range timeRanges { + if inTimeSpan(time.Unix(int64(tRange.Start), 0), time.Unix(int64(tRange.End), 0), pitrTimestamp) { + return nil + } + } + + return errors.Wrapf(ErrTimestampOutOfRange, "point in time recovery value %s", pitrTimestamp.String()) +} + +// checkArtifactMode crosschecks artifact params and requested restore mode. +func checkArtifactMode(artifact *models.Artifact, pitrTimestamp time.Time) error { + if artifact.Vendor != string(models.MongoDBServiceType) && artifact.Mode == models.PITR { + return errors.Wrapf(ErrIncompatibleService, "restore to point in time is only available for MongoDB") + } + + if artifact.Mode == models.PITR { + if pitrTimestamp.Unix() == 0 { + return errors.Wrapf(ErrIncompatibleArtifactMode, "artifact of type '%s' requires 'time' parameter to be restored to", artifact.Mode) + } + if artifact.DataModel == models.PhysicalDataModel { + return errors.Wrap(ErrIncompatibleArtifactMode, "point in time recovery is only available for Logical data model") + } + } else if pitrTimestamp.Unix() != 0 { + return errors.Wrapf(ErrIncompatibleArtifactMode, "artifact of type '%s' cannot be use to restore to point in time", artifact.Mode) + } + + return nil +} + +// inTimeSpan checks whether given time is in the given range +func inTimeSpan(start, end, check time.Time) bool { + if start.Before(end) { + return !check.Before(start) && !check.After(end) + } + if start.Equal(end) { + return check.Equal(start) + } + return !start.After(check) || !end.Before(check) +} diff --git a/managed/services/backup/backup_service_test.go b/managed/services/backup/backup_service_test.go index 65eccf18c3..f6aed8bdb5 100644 --- a/managed/services/backup/backup_service_test.go +++ b/managed/services/backup/backup_service_test.go @@ -18,6 +18,7 @@ package backup import ( "context" "testing" + "time" "github.com/AlekSi/pointer" "github.com/stretchr/testify/assert" @@ -78,11 +79,11 @@ func TestPerformBackup(t *testing.T) { mockedJobsService := &mockJobsService{} mockedAgentService := &mockAgentService{} mockedCompatibilityService := &mockCompatibilityService{} - backupService := NewService(db, mockedJobsService, mockedAgentService, mockedCompatibilityService) + backupService := NewService(db, mockedJobsService, mockedAgentService, mockedCompatibilityService, nil) - locationRes, err := models.CreateBackupLocation(db.Querier, models.CreateBackupLocationParams{ - Name: "Test location", - Description: "Test description", + s3Location, err := models.CreateBackupLocation(db.Querier, models.CreateBackupLocationParams{ + Name: "Test s3 location", + Description: "Test s3 description", BackupLocationConfig: models.BackupLocationConfig{ S3Config: &models.S3LocationConfig{ Endpoint: "https://s3.us-west-2.amazonaws.com/", @@ -95,6 +96,17 @@ func TestPerformBackup(t *testing.T) { }) require.NoError(t, err) + localLocation, err := models.CreateBackupLocation(db.Querier, models.CreateBackupLocationParams{ + Name: "Test local location", + Description: "Test local description", + BackupLocationConfig: models.BackupLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ + Path: "/opt/data/", + }, + }, + }) + require.NoError(t, err) + t.Run("mysql", func(t *testing.T) { agent := setup(t, db.Querier, models.MySQLServiceType, "test-mysql-backup-service") mockedJobsService.On("StartMySQLBackupJob", mock.Anything, mock.Anything, mock.Anything, @@ -103,25 +115,45 @@ func TestPerformBackup(t *testing.T) { for _, tc := range []struct { name string dbVersion string + locationID string + dataModel models.DataModel expectedError error }{ { name: "successful", dbVersion: "8.0.25", + locationID: s3Location.ID, + dataModel: models.PhysicalDataModel, expectedError: nil, }, { name: "fail", dbVersion: "", + locationID: s3Location.ID, + dataModel: models.PhysicalDataModel, expectedError: ErrXtrabackupNotInstalled, }, + { + name: "unsupported data model", + dbVersion: "8.0.25", + locationID: s3Location.ID, + dataModel: models.LogicalDataModel, + expectedError: ErrIncompatibleDataModel, + }, + { + name: "unsupported location type", + dbVersion: "8.0.25", + locationID: localLocation.ID, + dataModel: models.PhysicalDataModel, + expectedError: ErrIncompatibleLocationType, + }, } { t.Run(tc.name, func(t *testing.T) { mockedCompatibilityService.On("CheckSoftwareCompatibilityForService", ctx, pointer.GetString(agent.ServiceID)). Return(tc.dbVersion, tc.expectedError).Once() artifactID, err := backupService.PerformBackup(ctx, PerformBackupParams{ ServiceID: pointer.GetString(agent.ServiceID), - LocationID: locationRes.ID, + LocationID: s3Location.ID, Name: "test_backup", DataModel: models.PhysicalDataModel, Mode: models.Snapshot, @@ -136,7 +168,7 @@ func TestPerformBackup(t *testing.T) { assert.NoError(t, err) artifact, err := models.FindArtifactByID(db.Querier, artifactID) require.NoError(t, err) - assert.Equal(t, locationRes.ID, artifact.LocationID) + assert.Equal(t, s3Location.ID, artifact.LocationID) assert.Equal(t, *agent.ServiceID, artifact.ServiceID) assert.EqualValues(t, models.MySQLServiceType, artifact.Vendor) }) @@ -151,7 +183,7 @@ func TestPerformBackup(t *testing.T) { Return("", nil).Once() artifactID, err := backupService.PerformBackup(ctx, PerformBackupParams{ ServiceID: pointer.GetString(agent.ServiceID), - LocationID: locationRes.ID, + LocationID: s3Location.ID, Name: "test_backup", DataModel: models.PhysicalDataModel, Mode: models.PITR, @@ -164,7 +196,7 @@ func TestPerformBackup(t *testing.T) { mockedCompatibilityService.On("CheckSoftwareCompatibilityForService", ctx, "").Return("", nil).Once() artifactID, err := backupService.PerformBackup(ctx, PerformBackupParams{ ServiceID: "", - LocationID: locationRes.ID, + LocationID: s3Location.ID, Name: "test_backup", DataModel: models.PhysicalDataModel, Mode: models.PITR, @@ -178,7 +210,7 @@ func TestPerformBackup(t *testing.T) { Return("", nil).Once() artifactID, err := backupService.PerformBackup(ctx, PerformBackupParams{ ServiceID: pointer.GetString(agent.ServiceID), - LocationID: locationRes.ID, + LocationID: s3Location.ID, Name: "test_backup", DataModel: models.PhysicalDataModel, Mode: models.Incremental, @@ -188,7 +220,7 @@ func TestPerformBackup(t *testing.T) { }) }) - mock.AssertExpectationsForObjects(t, mockedJobsService, mockedAgentService, mockedCompatibilityService) + mock.AssertExpectationsForObjects(t, mockedJobsService, mockedCompatibilityService) } func TestRestoreBackup(t *testing.T) { @@ -203,9 +235,9 @@ func TestRestoreBackup(t *testing.T) { mockedJobsService := &mockJobsService{} mockedAgentService := &mockAgentService{} mockedCompatibilityService := &mockCompatibilityService{} - backupService := NewService(db, mockedJobsService, mockedAgentService, mockedCompatibilityService) + backupService := NewService(db, mockedJobsService, mockedAgentService, mockedCompatibilityService, nil) - locationRes, err := models.CreateBackupLocation(db.Querier, models.CreateBackupLocationParams{ + s3Location, err := models.CreateBackupLocation(db.Querier, models.CreateBackupLocationParams{ Name: "Test location", Description: "Test description", BackupLocationConfig: models.BackupLocationConfig{ @@ -220,13 +252,24 @@ func TestRestoreBackup(t *testing.T) { }) require.NoError(t, err) + localLocation, err := models.CreateBackupLocation(db.Querier, models.CreateBackupLocationParams{ + Name: "Test local location", + Description: "Test local description", + BackupLocationConfig: models.BackupLocationConfig{ + FilesystemConfig: &models.FilesystemLocationConfig{ + Path: "/opt/data/", + }, + }, + }) + require.NoError(t, err) + t.Run("mysql", func(t *testing.T) { agent := setup(t, db.Querier, models.MySQLServiceType, "test-mysql-restore-service") artifact, err := models.CreateArtifact(db.Querier, models.CreateArtifactParams{ Name: "mysql-artifact-name", Vendor: string(models.MySQLServiceType), DBVersion: "8.0.25", - LocationID: locationRes.ID, + LocationID: s3Location.ID, ServiceID: *agent.ServiceID, DataModel: models.PhysicalDataModel, Mode: models.Snapshot, @@ -253,11 +296,12 @@ func TestRestoreBackup(t *testing.T) { t.Run(tc.name, func(t *testing.T) { mockedCompatibilityService.On("CheckSoftwareCompatibilityForService", ctx, pointer.GetString(agent.ServiceID)). Return(tc.dbVersion, tc.expectedError).Once() + if tc.expectedError == nil { mockedJobsService.On("StartMySQLRestoreBackupJob", mock.Anything, pointer.GetString(agent.PMMAgentID), pointer.GetString(agent.ServiceID), mock.Anything, artifact.Name, mock.Anything).Return(nil).Once() } - restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID) + restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID, time.Unix(0, 0)) if tc.expectedError != nil { assert.ErrorIs(t, err, tc.expectedError) assert.Empty(t, restoreID) @@ -277,7 +321,8 @@ func TestRestoreBackup(t *testing.T) { mockedCompatibilityService.On("CheckSoftwareCompatibilityForService", ctx, pointer.GetString(agent.ServiceID)). Return("8.0.25", nil).Once() - restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID) + + restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID, time.Unix(0, 0)) require.Errorf(t, err, "artifact %q status is not successful, status: \"pending\"", artifact.ID) assert.Empty(t, restoreID) }) @@ -285,39 +330,313 @@ func TestRestoreBackup(t *testing.T) { t.Run("mongo", func(t *testing.T) { agent := setup(t, db.Querier, models.MongoDBServiceType, "test-mongo-restore-service") - - artifact, err := models.CreateArtifact(db.Querier, models.CreateArtifactParams{ - Name: "mongo-artifact-name", - Vendor: string(models.MongoDBServiceType), - LocationID: locationRes.ID, - ServiceID: *agent.ServiceID, - DataModel: models.PhysicalDataModel, - Mode: models.Snapshot, - Status: models.PendingBackupStatus, - }) - require.NoError(t, err) - t.Run("incomplete backups won't restore", func(t *testing.T) { + artifact, err := models.CreateArtifact(db.Querier, models.CreateArtifactParams{ + Name: "mongo-artifact-name-s3", + Vendor: string(models.MongoDBServiceType), + LocationID: s3Location.ID, + ServiceID: *agent.ServiceID, + DataModel: models.LogicalDataModel, + Mode: models.Snapshot, + Status: models.PendingBackupStatus, + }) + require.NoError(t, err) + mockedCompatibilityService.On("CheckSoftwareCompatibilityForService", ctx, pointer.GetString(agent.ServiceID)). Return("", nil).Once() - restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID) + restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID, time.Unix(0, 0)) require.Errorf(t, err, "artifact %q status is not successful, status: \"pending\"", artifact.ID) assert.Empty(t, restoreID) }) - t.Run("physical backups is not supported", func(t *testing.T) { - mockedCompatibilityService.On("CheckSoftwareCompatibilityForService", ctx, pointer.GetString(agent.ServiceID)). - Return("", nil).Once() - - _, err = models.UpdateArtifact(db.Querier, artifact.ID, models.UpdateArtifactParams{ - Status: models.BackupStatusPointer(models.SuccessBackupStatus), + t.Run("PITR not supported for local storages", func(t *testing.T) { + artifact, err := models.CreateArtifact(db.Querier, models.CreateArtifactParams{ + Name: "mongo-artifact-name-local", + Vendor: string(models.MongoDBServiceType), + LocationID: localLocation.ID, + ServiceID: *agent.ServiceID, + DataModel: models.LogicalDataModel, + Mode: models.Snapshot, + Status: models.PendingBackupStatus, }) - restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID) - require.ErrorIs(t, err, ErrIncompatibleService) + require.NoError(t, err) + + restoreID, err := backupService.RestoreBackup(ctx, pointer.GetString(agent.ServiceID), artifact.ID, time.Now()) + require.Errorf(t, err, "artifact %q status is not successful, status: \"pending\"", artifact.ID) assert.Empty(t, restoreID) }) }) mock.AssertExpectationsForObjects(t, mockedJobsService, mockedAgentService, mockedCompatibilityService) } + +func TestCheckArtifactModePreconditions(t *testing.T) { + ctx := context.Background() + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + + t.Cleanup(func() { + require.NoError(t, sqlDB.Close()) + }) + + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + mockedPitrTimerangeService := &mockPitrTimerangeService{} + backupService := NewService(db, nil, nil, nil, mockedPitrTimerangeService) + + locationRes, err := models.CreateBackupLocation(db.Querier, models.CreateBackupLocationParams{ + Name: "Test location", + Description: "Test description", + BackupLocationConfig: models.BackupLocationConfig{ + S3Config: &models.S3LocationConfig{ + Endpoint: "https://s3.us-west-2.amazonaws.com/", + AccessKey: "access_key", + SecretKey: "secret_key", + BucketName: "example_bucket", + BucketRegion: "us-east-2", + }, + }, + }) + require.NoError(t, err) + + t.Run("mysql", func(t *testing.T) { + agent := setup(t, db.Querier, models.MySQLServiceType, "test-mysql-restore-service") + + for _, tc := range []struct { + name string + pitrValue time.Time + artifactParams models.CreateArtifactParams + err error + }{ + { + name: "success", + pitrValue: time.Unix(0, 0), + artifactParams: models.CreateArtifactParams{ + Name: "mysql-artifact-name-1", + Vendor: string(models.MySQLServiceType), + DBVersion: "8.0.25", + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.PhysicalDataModel, + Mode: models.Snapshot, + Status: models.SuccessBackupStatus, + }, + err: nil, + }, + { + name: "PITR not supported for MySQL", + pitrValue: time.Unix(0, 0), + artifactParams: models.CreateArtifactParams{ + Name: "mysql-artifact-name-2", + Vendor: string(models.MySQLServiceType), + DBVersion: "8.0.25", + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.PhysicalDataModel, + Mode: models.PITR, + Status: models.SuccessBackupStatus, + }, + err: ErrIncompatibleService, + }, + { + name: "snapshot artifact is not compatible with non-empty pitr date", + pitrValue: time.Unix(1, 0), + artifactParams: models.CreateArtifactParams{ + Name: "mysql-artifact-name-3", + Vendor: string(models.MySQLServiceType), + DBVersion: "8.0.25", + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.PhysicalDataModel, + Mode: models.Snapshot, + Status: models.SuccessBackupStatus, + }, + err: ErrIncompatibleArtifactMode, + }, + } { + t.Run(tc.name, func(t *testing.T) { + artifact, err := models.CreateArtifact(db.Querier, tc.artifactParams) + require.NoError(t, err) + + err = backupService.checkArtifactModePreconditions(ctx, artifact.ID, tc.pitrValue) + if tc.err == nil { + require.NoError(t, err) + } else { + assert.ErrorIs(t, err, tc.err) + } + }) + } + }) + + t.Run("mongo", func(t *testing.T) { + agent := setup(t, db.Querier, models.MongoDBServiceType, "test-mongodb-restore-service") + + rangeStart1 := uint32(1) + rangeEnd1 := rangeStart1 + (60 * 60 * 3) // plus 3 hours + + rangeStart2 := uint32(time.Now().Unix()) + rangeEnd2 := rangeStart2 + (60 * 60 * 3) // plus 3 hours + + timelineList := []Timeline{ + {Start: rangeStart1, End: rangeEnd1}, + {Start: rangeStart2, End: rangeEnd2}, + } + + for _, tc := range []struct { + name string + pitrValue time.Time + prepareMock bool + artifactParams models.CreateArtifactParams + err error + }{ + { + name: "success logical restore", + pitrValue: time.Unix(0, 0), + artifactParams: models.CreateArtifactParams{ + Name: "mongo-artifact-name-1", + Vendor: string(models.MongoDBServiceType), + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.LogicalDataModel, + Mode: models.Snapshot, + Status: models.SuccessBackupStatus, + }, + err: nil, + }, + { + name: "physical restore is supported", + pitrValue: time.Unix(0, 0), + artifactParams: models.CreateArtifactParams{ + Name: "mongo-artifact-name-2", + Vendor: string(models.MongoDBServiceType), + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.PhysicalDataModel, + Mode: models.Snapshot, + Status: models.SuccessBackupStatus, + }, + err: nil, + }, + { + name: "snapshot artifact is not compatible with non-empty pitr date", + pitrValue: time.Unix(1, 0), + artifactParams: models.CreateArtifactParams{ + Name: "mongo-artifact-name-3", + Vendor: string(models.MongoDBServiceType), + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.LogicalDataModel, + Mode: models.Snapshot, + Status: models.SuccessBackupStatus, + }, + err: ErrIncompatibleArtifactMode, + }, + { + name: "timestamp not provided for pitr artifact", + pitrValue: time.Unix(0, 0), + artifactParams: models.CreateArtifactParams{ + Name: "mongo-artifact-name-4", + Vendor: string(models.MongoDBServiceType), + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.LogicalDataModel, + Mode: models.PITR, + Status: models.SuccessBackupStatus, + }, + err: ErrIncompatibleArtifactMode, + }, + { + name: "pitr timestamp out of range", + pitrValue: time.Unix(int64(rangeStart2)-1, 0), + prepareMock: true, + artifactParams: models.CreateArtifactParams{ + Name: "mongo-artifact-name-5", + Vendor: string(models.MongoDBServiceType), + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.LogicalDataModel, + Mode: models.PITR, + Status: models.SuccessBackupStatus, + }, + err: ErrTimestampOutOfRange, + }, + { + name: "success pitr timestamp inside the range", + pitrValue: time.Unix(int64(rangeStart2)+1, 0), + prepareMock: true, + artifactParams: models.CreateArtifactParams{ + Name: "mongo-artifact-name-6", + Vendor: string(models.MongoDBServiceType), + LocationID: locationRes.ID, + ServiceID: *agent.ServiceID, + DataModel: models.LogicalDataModel, + Mode: models.PITR, + Status: models.SuccessBackupStatus, + }, + err: nil, + }, + } { + t.Run(tc.name, func(t *testing.T) { + artifact, err := models.CreateArtifact(db.Querier, tc.artifactParams) + require.NoError(t, err) + + if tc.prepareMock { + mockedPitrTimerangeService.On("ListPITRTimeranges", ctx, artifact.Name, locationRes).Return(timelineList, nil).Once() + } + + err = backupService.checkArtifactModePreconditions(ctx, artifact.ID, tc.pitrValue) + if tc.err == nil { + require.NoError(t, err) + } else { + assert.ErrorIs(t, err, tc.err) + } + }) + } + }) + + mock.AssertExpectationsForObjects(t, mockedPitrTimerangeService) +} + +func TestInTimeSpan(t *testing.T) { + now := time.Now() + for _, tc := range []struct { + name string + start time.Time + end time.Time + value time.Time + inRange bool + }{ + { + name: "success start lt end", + start: now.Add(-1 * time.Hour), + end: now.Add(1 * time.Hour), + value: now, + inRange: true, + }, + { + name: "success start eq end", + start: now, + end: now, + value: now, + inRange: true, + }, + { + name: "fail start gt end", + start: now.Add(1 * time.Hour), + end: now.Add(-1 * time.Hour), + value: now, + inRange: false, + }, + { + name: "out of range", + start: now.Add(-1 * time.Hour), + end: now.Add(1 * time.Hour), + value: now.Add(1 * time.Hour).Add(1 * time.Second), + inRange: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + res := inTimeSpan(tc.start, tc.end, tc.value) + assert.Equal(t, tc.inRange, res) + }) + } +} diff --git a/managed/services/backup/compatibility_helpers.go b/managed/services/backup/compatibility_helpers.go index b70f653657..d4c95635b0 100644 --- a/managed/services/backup/compatibility_helpers.go +++ b/managed/services/backup/compatibility_helpers.go @@ -33,21 +33,6 @@ type compatibility struct { } var ( - // ErrIncompatibleService is returned when the service is incompatible for making a backup or restore. - ErrIncompatibleService = errors.New("incompatible service") - // ErrXtrabackupNotInstalled is returned if some xtrabackup component is missing. - ErrXtrabackupNotInstalled = errors.New("xtrabackup is not installed") - // ErrInvalidXtrabackup is returned if xtrabackup components have different version. - ErrInvalidXtrabackup = errors.New("invalid installation of the xtrabackup") - // ErrIncompatibleXtrabackup is returned if xtrabackup is not compatible with the MySQL. - ErrIncompatibleXtrabackup = errors.New("incompatible xtrabackup") - // ErrIncompatibleTargetMySQL is returned if target version of MySQL is not compatible for restoring selected artifact. - ErrIncompatibleTargetMySQL = errors.New("incompatible version of target mysql") - // ErrComparisonImpossible is returned when comparison of versions is impossible for some reasons. - ErrComparisonImpossible = errors.New("cannot compare software versions") - // ErrIncompatibleDataModel is returned if the specified data model (logical or physical) is not compatible with other parameters - ErrIncompatibleDataModel = errors.New("the specified backup model is not compatible with other parameters") - mysqlAndXtrabackupCompatibleVersions []compatibility // Starting from MySQL 8.0.22 if the Percona XtraBackup version is lower than the database version, // processing will be stopped and Percona XtraBackup will not be allowed to continue. diff --git a/managed/services/backup/compatibility_service.go b/managed/services/backup/compatibility_service.go index b9fe7c19d7..3d9b1ee9cc 100644 --- a/managed/services/backup/compatibility_service.go +++ b/managed/services/backup/compatibility_service.go @@ -42,7 +42,7 @@ func NewCompatibilityService(db *reform.DB, v versioner) *CompatibilityService { } } -// checkSoftwareCompatibilityForService contains compatibility checking logic. +// checkCompatibility contains compatibility checking logic. func (s *CompatibilityService) checkCompatibility(serviceModel *models.Service, agentModel *models.Agent) (string, error) { // Only MySQL compatibility checking implemented for now. if serviceModel.ServiceType != models.MySQLServiceType { diff --git a/managed/services/backup/deps.go b/managed/services/backup/deps.go index d26c9852ae..39371bfacc 100644 --- a/managed/services/backup/deps.go +++ b/managed/services/backup/deps.go @@ -21,13 +21,17 @@ import ( "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/services/agents" + "github.com/percona/pmm/managed/services/minio" ) //go:generate ../../../bin/mockery -name=jobsService -case=snake -inpkg -testonly //go:generate ../../../bin/mockery -name=s3 -case=snake -inpkg -testonly //go:generate ../../../bin/mockery -name=agentService -case=snake -inpkg -testonly //go:generate ../../../bin/mockery -name=versioner -case=snake -inpkg -testonly +//go:generate ../../../bin/mockery -name=pitrLocationClient -case=snake -inpkg -testonly //go:generate ../../../bin/mockery -name=compatibilityService -case=snake -inpkg -testonly +//go:generate ../../../bin/mockery -name=pitrLocationClient -case=snake -inpkg -testonly +//go:generate ../../../bin/mockery -name=pitrTimerangeService -case=snake -inpkg -testonly // jobsService is a subset of methods of agents.JobsService used by this package. // We use it instead of real type for testing and to avoid dependency cycle. @@ -67,6 +71,7 @@ type jobsService interface { dbConfig *models.DBConfig, dataModel models.DataModel, locationConfig *models.BackupLocationConfig, + pitrTimestamp time.Time, ) error } @@ -89,10 +94,24 @@ type versioner interface { GetVersions(pmmAgentID string, softwares []agents.Software) ([]agents.Version, error) } -// We use it instead of real type for testing and to avoid dependency cycle type compatibilityService interface { // CheckSoftwareCompatibilityForService checks if all the necessary backup tools are installed, // and they are compatible with the db version. // Returns db version. CheckSoftwareCompatibilityForService(ctx context.Context, serviceID string) (string, error) } + +type pitrLocationClient interface { + // FileStat returns file info. It returns error if file is empty or not exists. + FileStat(ctx context.Context, endpoint, accessKey, secretKey, bucketName, name string) (minio.FileInfo, error) + + // List scans path with prefix and returns all files with given suffix. + // Both prefix and suffix can be omitted. + List(ctx context.Context, endpoint, accessKey, secretKey, bucketName, prefix, suffix string) ([]minio.FileInfo, error) +} + +// pitrTimerangeService provides methods that help us inspect PITR artifacts +type pitrTimerangeService interface { + // ListPITRTimeranges list the available PITR timeranges for the given artifact in the provided location + ListPITRTimeranges(ctx context.Context, artifactName string, location *models.BackupLocation) ([]Timeline, error) +} diff --git a/managed/services/backup/errors.go b/managed/services/backup/errors.go new file mode 100644 index 0000000000..d7647b4ab7 --- /dev/null +++ b/managed/services/backup/errors.go @@ -0,0 +1,45 @@ +// Copyright (C) 2017 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package backup + +import "github.com/pkg/errors" + +var ( + // ErrIncompatibleService is returned when the service is incompatible for making a backup or restore. + ErrIncompatibleService = errors.New("incompatible service") + // ErrXtrabackupNotInstalled is returned if some xtrabackup component is missing. + ErrXtrabackupNotInstalled = errors.New("xtrabackup is not installed") + // ErrInvalidXtrabackup is returned if xtrabackup components have different version. + ErrInvalidXtrabackup = errors.New("invalid installation of the xtrabackup") + // ErrIncompatibleXtrabackup is returned if xtrabackup is not compatible with the MySQL. + ErrIncompatibleXtrabackup = errors.New("incompatible xtrabackup") + // ErrIncompatibleTargetMySQL is returned if target version of MySQL is not compatible for restoring selected artifact. + ErrIncompatibleTargetMySQL = errors.New("incompatible version of target mysql") + // ErrComparisonImpossible is returned when comparison of versions is impossible for some reasons. + ErrComparisonImpossible = errors.New("cannot compare software versions") + // ErrIncompatibleDataModel is returned if the specified data model (logical or physical) is not compatible with other parameters. + ErrIncompatibleDataModel = errors.New("the specified backup model is not compatible with other parameters") + // ErrIncompatibleLocationType is returned if the specified location type (local or s3) is not compatible with other parameters. + ErrIncompatibleLocationType = errors.New("the specified location type is not compatible with other parameters") + // ErrIncompatibleArtifactMode is returned if artifact backup mode is incompatible with other parameters. + ErrIncompatibleArtifactMode = errors.New("artifact backup mode is not compatible with other parameters") + // ErrTimestampOutOfRange is returned if timestamp value is out of allowed range. + ErrTimestampOutOfRange = errors.New("timestamp value is out of range") + // ErrAnotherOperationInProgress is returned if there are other operations in progress that prevent running the requested one. + ErrAnotherOperationInProgress = errors.New("another operation in progress") + // ErrArtifactNotReady is returned when artifact not ready to be restored, i.e. not in success status. + ErrArtifactNotReady = errors.New("artifact not in success status") +) diff --git a/managed/services/backup/mock_jobs_service_test.go b/managed/services/backup/mock_jobs_service_test.go index 11b161b735..f9961b021d 100644 --- a/managed/services/backup/mock_jobs_service_test.go +++ b/managed/services/backup/mock_jobs_service_test.go @@ -29,13 +29,13 @@ func (_m *mockJobsService) StartMongoDBBackupJob(jobID string, pmmAgentID string return r0 } -// StartMongoDBRestoreBackupJob provides a mock function with given fields: jobID, pmmAgentID, timeout, name, dbConfig, dataModel, locationConfig -func (_m *mockJobsService) StartMongoDBRestoreBackupJob(jobID string, pmmAgentID string, timeout time.Duration, name string, dbConfig *models.DBConfig, dataModel models.DataModel, locationConfig *models.BackupLocationConfig) error { - ret := _m.Called(jobID, pmmAgentID, timeout, name, dbConfig, dataModel, locationConfig) +// StartMongoDBRestoreBackupJob provides a mock function with given fields: jobID, pmmAgentID, timeout, name, dbConfig, dataModel, locationConfig, pitrTimestamp +func (_m *mockJobsService) StartMongoDBRestoreBackupJob(jobID string, pmmAgentID string, timeout time.Duration, name string, dbConfig *models.DBConfig, dataModel models.DataModel, locationConfig *models.BackupLocationConfig, pitrTimestamp time.Time) error { + ret := _m.Called(jobID, pmmAgentID, timeout, name, dbConfig, dataModel, locationConfig, pitrTimestamp) var r0 error - if rf, ok := ret.Get(0).(func(string, string, time.Duration, string, *models.DBConfig, models.DataModel, *models.BackupLocationConfig) error); ok { - r0 = rf(jobID, pmmAgentID, timeout, name, dbConfig, dataModel, locationConfig) + if rf, ok := ret.Get(0).(func(string, string, time.Duration, string, *models.DBConfig, models.DataModel, *models.BackupLocationConfig, time.Time) error); ok { + r0 = rf(jobID, pmmAgentID, timeout, name, dbConfig, dataModel, locationConfig, pitrTimestamp) } else { r0 = ret.Error(0) } diff --git a/managed/services/backup/mock_pitr_location_client_test.go b/managed/services/backup/mock_pitr_location_client_test.go new file mode 100644 index 0000000000..82a68a377a --- /dev/null +++ b/managed/services/backup/mock_pitr_location_client_test.go @@ -0,0 +1,60 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package backup + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + minio "github.com/percona/pmm/managed/services/minio" +) + +// mockPitrLocationClient is an autogenerated mock type for the pitrLocationClient type +type mockPitrLocationClient struct { + mock.Mock +} + +// FileStat provides a mock function with given fields: ctx, endpoint, accessKey, secretKey, bucketName, name +func (_m *mockPitrLocationClient) FileStat(ctx context.Context, endpoint string, accessKey string, secretKey string, bucketName string, name string) (minio.FileInfo, error) { + ret := _m.Called(ctx, endpoint, accessKey, secretKey, bucketName, name) + + var r0 minio.FileInfo + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string) minio.FileInfo); ok { + r0 = rf(ctx, endpoint, accessKey, secretKey, bucketName, name) + } else { + r0 = ret.Get(0).(minio.FileInfo) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, string) error); ok { + r1 = rf(ctx, endpoint, accessKey, secretKey, bucketName, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// List provides a mock function with given fields: ctx, endpoint, accessKey, secretKey, bucketName, prefix, suffix +func (_m *mockPitrLocationClient) List(ctx context.Context, endpoint string, accessKey string, secretKey string, bucketName string, prefix string, suffix string) ([]minio.FileInfo, error) { + ret := _m.Called(ctx, endpoint, accessKey, secretKey, bucketName, prefix, suffix) + + var r0 []minio.FileInfo + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, string, string) []minio.FileInfo); ok { + r0 = rf(ctx, endpoint, accessKey, secretKey, bucketName, prefix, suffix) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]minio.FileInfo) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, string, string) error); ok { + r1 = rf(ctx, endpoint, accessKey, secretKey, bucketName, prefix, suffix) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/managed/services/backup/mock_pitr_timerange_service_test.go b/managed/services/backup/mock_pitr_timerange_service_test.go new file mode 100644 index 0000000000..d1558629d0 --- /dev/null +++ b/managed/services/backup/mock_pitr_timerange_service_test.go @@ -0,0 +1,39 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package backup + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + models "github.com/percona/pmm/managed/models" +) + +// mockPitrTimerangeService is an autogenerated mock type for the pitrTimerangeService type +type mockPitrTimerangeService struct { + mock.Mock +} + +// ListPITRTimeranges provides a mock function with given fields: ctx, artifactName, location +func (_m *mockPitrTimerangeService) ListPITRTimeranges(ctx context.Context, artifactName string, location *models.BackupLocation) ([]Timeline, error) { + ret := _m.Called(ctx, artifactName, location) + + var r0 []Timeline + if rf, ok := ret.Get(0).(func(context.Context, string, *models.BackupLocation) []Timeline); ok { + r0 = rf(ctx, artifactName, location) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]Timeline) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, *models.BackupLocation) error); ok { + r1 = rf(ctx, artifactName, location) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/managed/services/backup/pitr_timerange_service.go b/managed/services/backup/pitr_timerange_service.go new file mode 100644 index 0000000000..b05f4c744d --- /dev/null +++ b/managed/services/backup/pitr_timerange_service.go @@ -0,0 +1,357 @@ +// Copyright (C) 2022 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package backup + +import ( + "context" + "path" + "sort" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "go.mongodb.org/mongo-driver/bson/primitive" + + "github.com/percona/pmm/managed/models" +) + +const ( + // pitrFSPrefix is the prefix (folder) for all PITR artifacts in the backup location. + pitrFSPrefix = "pbmPitr" +) + +var errUnsupportedLocation = errors.New("unsupported location config") + +// PITRTimerangeService helps perform file lookups in a backup locationClient location +type PITRTimerangeService struct { + l *logrus.Entry + locationClient pitrLocationClient +} + +// NewPITRTimerangeService creates new backup locationClient service. +func NewPITRTimerangeService(pitrLocationClient pitrLocationClient) *PITRTimerangeService { + return &PITRTimerangeService{ + l: logrus.WithField("component", "services/backup/pitr_storage"), + locationClient: pitrLocationClient, + } +} + +// oplogChunk is index metadata for the oplog chunks +type oplogChunk struct { + RS string `bson:"rs"` + FName string `bson:"fname"` + Compression compressionType `bson:"compression"` + StartTS primitive.Timestamp `bson:"start_ts"` + EndTS primitive.Timestamp `bson:"end_ts"` + size int64 `bson:"-"` +} + +// Timeline is an internal representation of a PITR Timeline +type Timeline struct { + ReplicaSet string `json:"replica_set"` + Start uint32 `json:"start"` + End uint32 `json:"end"` + Size int64 `json:"-"` +} + +type gap struct { + s, e uint32 +} + +type gaps []gap + +func (x gaps) Len() int { return len(x) } +func (x gaps) Less(i, j int) bool { + return x[i].s < x[j].s || (x[i].s == x[j].s && x[i].e < x[j].e) +} +func (x gaps) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +// compressionType is the type of compression used for PITR oplog +type compressionType string + +const ( + compressionTypeNone compressionType = "none" + compressionTypePGZIP compressionType = "pgzip" + compressionTypeSNAPPY compressionType = "snappy" + compressionTypeLZ4 compressionType = "lz4" + compressionTypeS2 compressionType = "s2" + compressionTypeZstandard compressionType = "zstd" +) + +// file return compression alg based on given file extension +func file(ext string) compressionType { + switch ext { + case "gz": + return compressionTypePGZIP + case "lz4": + return compressionTypeLZ4 + case "snappy": + return compressionTypeSNAPPY + case "s2": + return compressionTypeS2 + case "zst": + return compressionTypeZstandard + default: + return compressionTypeNone + } +} + +func (ss *PITRTimerangeService) getPITROplogs(ctx context.Context, location *models.BackupLocation, artifactName string) ([]*oplogChunk, error) { + if location.S3Config == nil { + return nil, errUnsupportedLocation + } + + var err error + var oplogChunks []*oplogChunk + + prefix := path.Join(artifactName, pitrFSPrefix) + pitrFiles, err := ss.locationClient.List(ctx, location.S3Config.Endpoint, location.S3Config.AccessKey, location.S3Config.SecretKey, location.S3Config.BucketName, prefix, "") + if err != nil { + return nil, errors.Wrap(err, "get list of pitr chunks") + } + if len(pitrFiles) == 0 { + return nil, nil + } + + for _, f := range pitrFiles { + if f.IsDeleteMarker { + ss.l.Debugf("skip pitr chunk %s/%s because of file has delete marker", prefix, f.Name) + continue + } + chunk := pitrMetaFromFileName(prefix, f.Name) + if chunk != nil { + chunk.size = f.Size + oplogChunks = append(oplogChunks, chunk) + } + } + + return oplogChunks, nil +} + +func (ss *PITRTimerangeService) ListPITRTimeranges(ctx context.Context, artifactName string, location *models.BackupLocation) ([]Timeline, error) { + var timelines [][]Timeline + + oplogs, err := ss.getPITROplogs(ctx, location, artifactName) + if err != nil { + return nil, errors.Wrap(err, "get slice") + } + if len(oplogs) == 0 { + return nil, nil + } + + t, err := gettimelines(oplogs), nil + if err != nil { + return nil, errors.Wrapf(err, "get PITR timeranges for backup '%s'", artifactName) + } + if len(t) != 0 { + timelines = append(timelines, t) + } + + return mergeTimelines(timelines...), nil +} + +// pitrMetaFromFileName parses given file name and returns PITRChunk metadata +// it returns nil if the file wasn't parse successfully (e.g. wrong format) +// current fromat is 20200715155939-0.20200715160029-1.oplog.snappy +// (https://github.com/percona/percona-backup-mongodb/wiki/PITR:-storage-layout) +// +// !!! should be agreed with pbm/pitr.chunkPath() +func pitrMetaFromFileName(prefix, f string) *oplogChunk { + ppath := strings.Split(f, "/") + if len(ppath) < 2 { + return nil + } + chnk := &oplogChunk{} + chnk.RS = ppath[0] + chnk.FName = path.Join(prefix, f) + + fname := ppath[len(ppath)-1] + fparts := strings.Split(fname, ".") + if len(fparts) < 3 || fparts[2] != "oplog" { + return nil + } + if len(fparts) == 4 { + chnk.Compression = file(fparts[3]) + } else { + chnk.Compression = compressionTypeNone + } + + start := pitrParseTS(fparts[0]) + if start == nil { + return nil + } + end := pitrParseTS(fparts[1]) + if end == nil { + return nil + } + + chnk.StartTS = *start + chnk.EndTS = *end + + return chnk +} + +func pitrParseTS(tstr string) *primitive.Timestamp { + tparts := strings.Split(tstr, "-") + t, err := time.Parse("20060102150405", tparts[0]) + if err != nil { + // just skip this file + return nil + } + ts := primitive.Timestamp{T: uint32(t.Unix())} + if len(tparts) > 1 { + ti, err := strconv.Atoi(tparts[1]) + if err != nil { + // just skip this file + return nil + } + ts.I = uint32(ti) + } + + return &ts +} + +func gettimelines(slices []*oplogChunk) []Timeline { + var tl Timeline + var timelines []Timeline + var prevEnd primitive.Timestamp + for _, s := range slices { + if prevEnd.T != 0 && primitive.CompareTimestamp(prevEnd, s.StartTS) == -1 { + timelines = append(timelines, tl) + tl = Timeline{} + } + if tl.Start == 0 { + tl.Start = s.StartTS.T + } + prevEnd = s.EndTS + tl.End = s.EndTS.T + tl.Size += s.size + tl.ReplicaSet = s.RS + } + + timelines = append(timelines, tl) + return timelines +} + +// mergeTimelines merges overlapping sets on timelines +// it presumes timelines are sorted and don't start from 0 +func mergeTimelines(timelines ...[]Timeline) []Timeline { + // fast paths + if len(timelines) == 0 { + return nil + } + if len(timelines) == 1 { + return timelines[0] + } + + // First, we define the available range. It equals to the beginning of the latest start of the first + // Timeline of any set and to the earliest end of the last Timeline of any set. Then define timelines' gaps + // merge overlapping and apply resulted gap on the available range. + // + // given timelines: + // 1 2 3 4 7 8 10 11 16 17 18 19 20 + // 3 4 5 6 7 8 10 11 12 15 16 17 + // 1 2 3 4 5 6 7 8 10 11 12 16 17 18 + // + // available range: + // 3 4 5 6 7 8 10 11 12 13 15 16 17 + // merged gaps: + // 5 6 12 13 15 18 19 20 + // result: + // 3 4 7 8 10 11 16 17 + // + + // limits of the available range + // `start` is the latest start the timelines range + // `end` - is the earliest end + var start, end uint32 + + // iterating through the timelines 1) define `start` and `end`, + // 2) define gaps and add them into slice. + var g gaps + for _, tln := range timelines { + if len(tln) == 0 { + continue + } + + if tln[0].Start > start { + start = tln[0].Start + } + + if end == 0 || tln[len(tln)-1].End < end { + end = tln[len(tln)-1].End + } + + if len(tln) == 1 { + continue + } + var ls uint32 + for i, t := range tln { + if i == 0 { + ls = t.End + continue + } + g = append(g, gap{ls, t.Start}) + ls = t.End + } + } + sort.Sort(g) + + // if no gaps, just return available range + if len(g) == 0 { + return []Timeline{{Start: start, End: end}} + } + + // merge overlapping gaps + var g2 gaps + var cend uint32 + for _, gp := range g { + if gp.e <= start { + continue + } + if gp.s >= end { + break + } + + if len(g2) != 0 { + cend = g2[len(g2)-1].e + } + + if gp.s > cend { + g2 = append(g2, gp) + continue + } + if gp.e > cend { + g2[len(g2)-1].e = gp.e + } + } + + // split available Timeline with gaps + var ret []Timeline + for _, g := range g2 { + if start < g.s { + ret = append(ret, Timeline{Start: start, End: g.s}) + } + start = g.e + } + if start < end { + ret = append(ret, Timeline{Start: start, End: end}) + } + + return ret +} diff --git a/managed/services/backup/pitr_timerange_service_test.go b/managed/services/backup/pitr_timerange_service_test.go new file mode 100644 index 0000000000..28ab7e1666 --- /dev/null +++ b/managed/services/backup/pitr_timerange_service_test.go @@ -0,0 +1,495 @@ +// Copyright (C) 2022 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package backup + +import ( + "context" + "fmt" + "path" + "strings" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.mongodb.org/mongo-driver/bson/primitive" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/services/minio" +) + +func TestPitrMetaFromFileName(t *testing.T) { + tests := []struct { + name string + filename string + expected *oplogChunk + }{ + { + name: "correctly formatted file name", + filename: "rs0/20220829/20220829115611-1.20220829120544-10.oplog.s2", + expected: &oplogChunk{ + RS: "rs0", + FName: "test_artifact_name/pbmPitr/rs0/20220829/20220829115611-1.20220829120544-10.oplog.s2", + Compression: compressionTypeS2, + StartTS: primitive.Timestamp{T: uint32(1661774171), I: 1}, + EndTS: primitive.Timestamp{T: uint32(1661774744), I: 10}, + }, + }, + { + name: "incomplete file name", + filename: "20220829115611-1.20220829120544-10.oplog.s2", + expected: nil, + }, + { + name: "without end timestamp", + filename: "rs0/20220829/20220829115611-1.oplog.s2", + expected: nil, + }, + { + name: "without specified compression", + filename: "rs0/20220829/20220829115611-1.20220829120544-10.oplog", + expected: &oplogChunk{ + RS: "rs0", + FName: "test_artifact_name/pbmPitr/rs0/20220829/20220829115611-1.20220829120544-10.oplog", + Compression: compressionTypeNone, + StartTS: primitive.Timestamp{T: uint32(1661774171), I: 1}, + EndTS: primitive.Timestamp{T: uint32(1661774744), I: 10}, + }, + }, + } + + prefix := path.Join("test_artifact_name", pitrFSPrefix) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + chunk := pitrMetaFromFileName(prefix, tt.filename) + assert.Equal(t, tt.expected, chunk) + }) + } +} + +func TestPitrParseTs(t *testing.T) { + tests := []struct { + name string + filename string + expected *primitive.Timestamp + }{ + { + name: "with time and index", + filename: "20220829115611-10", + expected: &primitive.Timestamp{T: uint32(1661774171), I: 10}, + }, + { + name: "time without index", + filename: "20220829120544", + expected: &primitive.Timestamp{T: uint32(1661774744), I: 0}, + }, + { + name: "with invalid timestamp", + filename: "2022", + expected: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ts := pitrParseTS(tt.filename) + assert.Equal(t, tt.expected, ts) + }) + } +} + +func TestListPITRTimelines(t *testing.T) { + ctx := context.Background() + location := &models.BackupLocation{ + S3Config: &models.S3LocationConfig{ + Endpoint: "https://s3.us-west-2.amazonaws.com", + AccessKey: "access_key", + SecretKey: "secret_key", + BucketName: "example_bucket", + BucketRegion: "us-east-1", + }, + } + + t.Run("successful", func(t *testing.T) { + mockedStorage := &mockPitrLocationClient{} + listedFiles := []minio.FileInfo{ + { + Name: "rs0/20220829/20220829115611-1.20220829120544-10.oplog.s2", + Size: 1024, + }, + } + + statFile := minio.FileInfo{ + Name: pitrFSPrefix + "rs0/20220829/20220829115611-1.20220829120544-10.oplog.s2", + Size: 1024, + } + mockedStorage.On("List", ctx, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(listedFiles, nil) + mockedStorage.On("FileStat", ctx, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(statFile, nil) + + ss := NewPITRTimerangeService(mockedStorage) + timelines, err := ss.getPITROplogs(ctx, location, "") + assert.NoError(t, err) + assert.Len(t, timelines, 1) + }) + + t.Run("fails on file list error", func(t *testing.T) { + mockedStorage := &mockPitrLocationClient{} + mockedStorage.On("List", ctx, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("listing object error")) + + ss := NewPITRTimerangeService(mockedStorage) + timelines, err := ss.getPITROplogs(ctx, location, "") + assert.Error(t, err) + assert.Nil(t, timelines) + }) + + t.Run("skips artifacts with deletion markers", func(t *testing.T) { + mockedStorage := &mockPitrLocationClient{} + listedFiles := []minio.FileInfo{ + { + Name: "rs0/20220829/20220829115611-1.20220829120544-10.oplog.s2", + Size: 1024, + IsDeleteMarker: true, + }, + } + + mockedStorage.On("List", ctx, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(listedFiles, nil) + + ss := NewPITRTimerangeService(mockedStorage) + timelines, err := ss.getPITROplogs(ctx, location, "") + assert.NoError(t, err) + assert.Len(t, timelines, 0) + }) +} + +func TestPITRMergeTimelines(t *testing.T) { + tests := []struct { + name string + tl [][]Timeline + expect []Timeline + }{ + { + name: "nothing", + tl: [][]Timeline{}, + expect: []Timeline{}, + }, + { + name: "empy set", + tl: [][]Timeline{ + {}, + }, + expect: []Timeline{}, + }, + { + name: "no match", + tl: [][]Timeline{ + { + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 20, End: 42}, + }, + { + {Start: 1, End: 3}, + {Start: 6, End: 14}, + {Start: 50, End: 55}, + }, + { + {Start: 7, End: 10}, + {Start: 12, End: 19}, + {Start: 20, End: 26}, + {Start: 27, End: 60}, + }, + }, + expect: []Timeline{}, + }, + { + name: "no match2", + tl: [][]Timeline{ + { + {Start: 1, End: 5}, + {Start: 8, End: 13}, + }, + { + {Start: 6, End: 7}, + }, + }, + expect: []Timeline{}, + }, + { + name: "no match3", + tl: [][]Timeline{ + { + {Start: 1, End: 5}, + {Start: 8, End: 13}, + }, + { + {Start: 5, End: 8}, + }, + }, + expect: []Timeline{}, + }, + { + name: "some empty", + tl: [][]Timeline{ + {}, + { + {Start: 4, End: 8}, + }, + }, + expect: []Timeline{{Start: 4, End: 8}}, + }, + { + name: "no gaps", + tl: [][]Timeline{ + { + {Start: 1, End: 5}, + }, + { + {Start: 4, End: 8}, + }, + }, + expect: []Timeline{{Start: 4, End: 5}}, + }, + { + name: "no gaps2", + tl: [][]Timeline{ + { + {Start: 4, End: 8}, + }, + { + {Start: 1, End: 5}, + }, + }, + expect: []Timeline{{Start: 4, End: 5}}, + }, + { + name: "no gaps3", + tl: [][]Timeline{ + { + {Start: 1, End: 8}, + }, + { + {Start: 1, End: 5}, + }, + }, + expect: []Timeline{{Start: 1, End: 5}}, + }, + { + name: "overlaps", + tl: [][]Timeline{ + { + {Start: 2, End: 6}, + {Start: 8, End: 12}, + {Start: 13, End: 15}, + }, + { + {Start: 1, End: 4}, + {Start: 9, End: 14}, + }, + { + {Start: 3, End: 7}, + {Start: 8, End: 11}, + {Start: 12, End: 14}, + }, + { + {Start: 2, End: 9}, + {Start: 10, End: 17}, + }, + { + {Start: 1, End: 5}, + {Start: 6, End: 14}, + {Start: 15, End: 19}, + }, + }, + expect: []Timeline{ + {Start: 3, End: 4}, + {Start: 10, End: 11}, + {Start: 13, End: 14}, + }, + }, + { + name: "all match", + tl: [][]Timeline{ + { + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 19, End: 42}, + }, + { + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 19, End: 42}, + }, + { + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 19, End: 42}, + }, + { + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 19, End: 42}, + }, + }, + expect: []Timeline{ + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 19, End: 42}, + }, + }, + { + name: "partly overlap", + tl: [][]Timeline{ + { + {Start: 3, End: 8}, + {Start: 14, End: 19}, + {Start: 21, End: 42}, + }, + { + {Start: 1, End: 3}, + {Start: 4, End: 7}, + {Start: 19, End: 36}, + }, + { + {Start: 5, End: 8}, + {Start: 14, End: 19}, + {Start: 20, End: 42}, + }, + }, + expect: []Timeline{ + {Start: 5, End: 7}, + {Start: 21, End: 36}, + }, + }, + { + name: "partly overlap2", + tl: [][]Timeline{ + { + {Start: 1, End: 4}, + {Start: 7, End: 11}, + {Start: 16, End: 20}, + }, + { + {Start: 3, End: 12}, + {Start: 15, End: 17}, + }, + { + {Start: 1, End: 12}, + {Start: 16, End: 18}, + }, + }, + expect: []Timeline{ + {Start: 3, End: 4}, + {Start: 7, End: 11}, + {Start: 16, End: 17}, + }, + }, + { + name: "redundant chunks", + tl: [][]Timeline{ + { + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 19, End: 40}, + {Start: 42, End: 100500}, + }, + { + {Start: 2, End: 7}, + {Start: 7, End: 8}, + {Start: 8, End: 10}, + {Start: 14, End: 20}, + {Start: 20, End: 30}, + }, + { + {Start: 1, End: 5}, + {Start: 13, End: 19}, + {Start: 20, End: 30}, + }, + }, + expect: []Timeline{ + {Start: 3, End: 5}, + {Start: 14, End: 19}, + {Start: 20, End: 30}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := mergeTimelines(test.tl...) + if len(test.expect) != len(got) { + t.Fatalf("wrong timelines, exepct <%d> %v, got <%d> %v", len(test.expect), printTTL(test.expect...), len(got), printTTL(got...)) + } + for i, gl := range got { + if test.expect[i] != gl { + t.Errorf("wrong timeline %d, exepct %v, got %v", i, printTTL(test.expect[i]), printTTL(gl)) + } + } + }) + } +} + +func BenchmarkMergeTimelines(b *testing.B) { + tl := [][]Timeline{ + { + {Start: 3, End: 8}, + {Start: 14, End: 19}, + {Start: 21, End: 42}, + }, + { + {Start: 1, End: 3}, + {Start: 4, End: 7}, + {Start: 19, End: 36}, + }, + { + {Start: 5, End: 8}, + {Start: 14, End: 19}, + {Start: 20, End: 42}, + }, + { + {Start: 3, End: 6}, + {Start: 14, End: 19}, + {Start: 19, End: 40}, + {Start: 42, End: 100500}, + }, + { + {Start: 2, End: 7}, + {Start: 7, End: 8}, + {Start: 8, End: 10}, + {Start: 14, End: 20}, + {Start: 20, End: 30}, + {Start: 31, End: 40}, + {Start: 41, End: 50}, + {Start: 51, End: 60}, + }, + { + {Start: 1, End: 5}, + {Start: 13, End: 19}, + {Start: 20, End: 30}, + }, + } + for i := 0; i < b.N; i++ { + mergeTimelines(tl...) + } +} + +func printTTL(tlns ...Timeline) string { + ret := make([]string, 0, len(tlns)) + for _, t := range tlns { + ret = append(ret, fmt.Sprintf("[%v - %v]", t.Start, t.End)) + } + + return strings.Join(ret, ", ") +} diff --git a/managed/services/management/backup/artifacts_service.go b/managed/services/management/backup/artifacts_service.go index 5d958ec155..af3112e82a 100644 --- a/managed/services/management/backup/artifacts_service.go +++ b/managed/services/management/backup/artifacts_service.go @@ -18,31 +18,36 @@ package backup import ( "context" + "time" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/reform.v1" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" "github.com/percona/pmm/managed/models" ) // ArtifactsService represents artifacts API. type ArtifactsService struct { - l *logrus.Entry - db *reform.DB - removalSVC removalService + l *logrus.Entry + db *reform.DB + removalSVC removalService + pitrTimerangeSVC pitrTimerangeService - backupv1beta1.UnimplementedArtifactsServer + backuppb.UnimplementedArtifactsServer } // NewArtifactsService creates new artifacts API service. -func NewArtifactsService(db *reform.DB, removalSVC removalService) *ArtifactsService { +func NewArtifactsService(db *reform.DB, removalSVC removalService, storage pitrTimerangeService) *ArtifactsService { return &ArtifactsService{ - l: logrus.WithField("component", "management/backup/artifacts"), - db: db, - removalSVC: removalSVC, + l: logrus.WithField("component", "management/backup/artifacts"), + db: db, + removalSVC: removalSVC, + pitrTimerangeSVC: storage, } } @@ -57,7 +62,7 @@ func (s *ArtifactsService) Enabled() bool { } // ListArtifacts returns a list of all artifacts. -func (s *ArtifactsService) ListArtifacts(context.Context, *backupv1beta1.ListArtifactsRequest) (*backupv1beta1.ListArtifactsResponse, error) { +func (s *ArtifactsService) ListArtifacts(context.Context, *backuppb.ListArtifactsRequest) (*backuppb.ListArtifactsResponse, error) { q := s.db.Querier artifacts, err := models.FindArtifacts(q, models.ArtifactFilters{}) @@ -86,7 +91,7 @@ func (s *ArtifactsService) ListArtifacts(context.Context, *backupv1beta1.ListArt return nil, err } - artifactsResponse := make([]*backupv1beta1.Artifact, 0, len(artifacts)) + artifactsResponse := make([]*backuppb.Artifact, 0, len(artifacts)) for _, b := range artifacts { convertedArtifact, err := convertArtifact(b, services, locations) if err != nil { @@ -94,7 +99,7 @@ func (s *ArtifactsService) ListArtifacts(context.Context, *backupv1beta1.ListArt } artifactsResponse = append(artifactsResponse, convertedArtifact) } - return &backupv1beta1.ListArtifactsResponse{ + return &backuppb.ListArtifactsResponse{ Artifacts: artifactsResponse, }, nil } @@ -102,42 +107,83 @@ func (s *ArtifactsService) ListArtifacts(context.Context, *backupv1beta1.ListArt // DeleteArtifact deletes specified artifact. func (s *ArtifactsService) DeleteArtifact( ctx context.Context, - req *backupv1beta1.DeleteArtifactRequest, -) (*backupv1beta1.DeleteArtifactResponse, error) { + req *backuppb.DeleteArtifactRequest, +) (*backuppb.DeleteArtifactResponse, error) { if err := s.removalSVC.DeleteArtifact(ctx, req.ArtifactId, req.RemoveFiles); err != nil { return nil, err } - return &backupv1beta1.DeleteArtifactResponse{}, nil + return &backuppb.DeleteArtifactResponse{}, nil } -func convertDataModel(model models.DataModel) (backupv1beta1.DataModel, error) { +// ListPitrTimeranges lists available PITR timelines/time-ranges (for MongoDB) +func (s *ArtifactsService) ListPitrTimeranges( + ctx context.Context, + req *backuppb.ListPitrTimerangesRequest, +) (*backuppb.ListPitrTimerangesResponse, error) { + var artifact *models.Artifact + var err error + + artifact, err = models.FindArtifactByID(s.db.Querier, req.ArtifactId) + if err != nil { + if errors.Is(err, models.ErrNotFound) { + return nil, status.Errorf(codes.NotFound, "Artifact with ID %q not found.", req.ArtifactId) + } + return nil, err + } + + if artifact.Mode != models.PITR { + return nil, status.Errorf(codes.FailedPrecondition, "Artifact is not a PITR artifact") + } + + location, err := models.FindBackupLocationByID(s.db.Querier, artifact.LocationID) + if err != nil { + return nil, err + } + + timelines, err := s.pitrTimerangeSVC.ListPITRTimeranges(ctx, artifact.Name, location) + if err != nil { + return nil, err + } + result := make([]*backuppb.PitrTimerange, 0, len(timelines)) + for _, tl := range timelines { + result = append(result, &backuppb.PitrTimerange{ + StartTimestamp: timestamppb.New(time.Unix(int64(tl.Start), 0)), + EndTimestamp: timestamppb.New(time.Unix(int64(tl.End), 0)), + }) + } + return &backuppb.ListPitrTimerangesResponse{ + Timeranges: result, + }, nil +} + +func convertDataModel(model models.DataModel) (backuppb.DataModel, error) { switch model { case models.PhysicalDataModel: - return backupv1beta1.DataModel_PHYSICAL, nil + return backuppb.DataModel_PHYSICAL, nil case models.LogicalDataModel: - return backupv1beta1.DataModel_LOGICAL, nil + return backuppb.DataModel_LOGICAL, nil default: return 0, errors.Errorf("unknown data model: %s", model) } } -func convertBackupStatus(status models.BackupStatus) (backupv1beta1.BackupStatus, error) { +func convertBackupStatus(status models.BackupStatus) (backuppb.BackupStatus, error) { switch status { case models.PendingBackupStatus: - return backupv1beta1.BackupStatus_BACKUP_STATUS_PENDING, nil + return backuppb.BackupStatus_BACKUP_STATUS_PENDING, nil case models.InProgressBackupStatus: - return backupv1beta1.BackupStatus_BACKUP_STATUS_IN_PROGRESS, nil + return backuppb.BackupStatus_BACKUP_STATUS_IN_PROGRESS, nil case models.PausedBackupStatus: - return backupv1beta1.BackupStatus_BACKUP_STATUS_PAUSED, nil + return backuppb.BackupStatus_BACKUP_STATUS_PAUSED, nil case models.SuccessBackupStatus: - return backupv1beta1.BackupStatus_BACKUP_STATUS_SUCCESS, nil + return backuppb.BackupStatus_BACKUP_STATUS_SUCCESS, nil case models.ErrorBackupStatus: - return backupv1beta1.BackupStatus_BACKUP_STATUS_ERROR, nil + return backuppb.BackupStatus_BACKUP_STATUS_ERROR, nil case models.DeletingBackupStatus: - return backupv1beta1.BackupStatus_BACKUP_STATUS_DELETING, nil + return backuppb.BackupStatus_BACKUP_STATUS_DELETING, nil case models.FailedToDeleteBackupStatus: - return backupv1beta1.BackupStatus_BACKUP_STATUS_FAILED_TO_DELETE, nil + return backuppb.BackupStatus_BACKUP_STATUS_FAILED_TO_DELETE, nil default: return 0, errors.Errorf("invalid status '%s'", status) } @@ -147,7 +193,7 @@ func convertArtifact( a *models.Artifact, services map[string]*models.Service, locationModels map[string]*models.BackupLocation, -) (*backupv1beta1.Artifact, error) { +) (*backuppb.Artifact, error) { createdAt := timestamppb.New(a.CreatedAt) if err := createdAt.CheckValid(); err != nil { return nil, errors.Wrap(err, "failed to convert timestamp") @@ -179,7 +225,7 @@ func convertArtifact( return nil, errors.Wrapf(err, "artifact id '%s'", a.ID) } - return &backupv1beta1.Artifact{ + return &backuppb.Artifact{ ArtifactId: a.ID, Name: a.Name, Vendor: a.Vendor, @@ -196,5 +242,5 @@ func convertArtifact( // Check interfaces. var ( - _ backupv1beta1.ArtifactsServer = (*ArtifactsService)(nil) + _ backuppb.ArtifactsServer = (*ArtifactsService)(nil) ) diff --git a/managed/services/management/backup/artifacts_service_test.go b/managed/services/management/backup/artifacts_service_test.go new file mode 100644 index 0000000000..94f57e78b9 --- /dev/null +++ b/managed/services/management/backup/artifacts_service_test.go @@ -0,0 +1,127 @@ +// Copyright (C) 2022 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package backup + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/brianvoe/gofakeit/v6" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/dialects/postgresql" + + backuppb "github.com/percona/pmm/api/managementpb/backup" + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/services/backup" + "github.com/percona/pmm/managed/utils/testdb" + "github.com/percona/pmm/managed/utils/tests" +) + +func TestListPitrTimelines(t *testing.T) { + ctx := context.Background() + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + + mockedPitrStorageSvc := &mockPitrTimerangeService{} + + timelines := []backup.Timeline{ + { + ReplicaSet: "rs0", + Start: uint32(time.Now().Unix()), + End: uint32(time.Now().Unix()), + }, + } + + mockedPitrStorageSvc.On("ListPITRTimeranges", ctx, mock.Anything, mock.Anything).Return(timelines, nil) + artifactsService := NewArtifactsService(db, nil, mockedPitrStorageSvc) + var locationID string + + params := models.CreateBackupLocationParams{ + Name: gofakeit.Name(), + Description: "", + } + params.S3Config = &models.S3LocationConfig{ + Endpoint: "https://awsS3.us-west-2.amazonaws.com/", + AccessKey: "access_key", + SecretKey: "secret_key", + BucketName: "example_bucket", + BucketRegion: "us-east-1", + } + loc, err := models.CreateBackupLocation(db.Querier, params) + require.NoError(t, err) + require.NotEmpty(t, loc.ID) + + locationID = loc.ID + + t.Run("successfully lists PITR time ranges", func(t *testing.T) { + artifact, err := models.CreateArtifact(db.Querier, models.CreateArtifactParams{ + Name: "test_artifact", + Vendor: "test_vendor", + LocationID: locationID, + ServiceID: "test_service", + Mode: models.PITR, + DataModel: models.LogicalDataModel, + Status: models.PendingBackupStatus, + }) + assert.NoError(t, err) + assert.NotEmpty(t, artifact.ID) + + response, err := artifactsService.ListPitrTimeranges(ctx, &backuppb.ListPitrTimerangesRequest{ + ArtifactId: artifact.ID, + }) + require.NoError(t, err) + require.NotNil(t, response) + assert.Len(t, response.Timeranges, 1) + }) + + t.Run("fails for invalid artifact ID", func(t *testing.T) { + unknownID := "artifact_id/" + uuid.New().String() + response, err := artifactsService.ListPitrTimeranges(ctx, &backuppb.ListPitrTimerangesRequest{ + ArtifactId: unknownID, + }) + tests.AssertGRPCError(t, status.New(codes.NotFound, fmt.Sprintf("Artifact with ID %q not found.", unknownID)), err) + assert.Nil(t, response) + }) + + t.Run("fails for non-PITR artifact", func(t *testing.T) { + artifact, err := models.CreateArtifact(db.Querier, models.CreateArtifactParams{ + Name: "test_non_pitr_artifact", + Vendor: "test_vendor", + LocationID: locationID, + ServiceID: "test_service", + Mode: models.Snapshot, + DataModel: models.LogicalDataModel, + Status: models.PendingBackupStatus, + }) + assert.NoError(t, err) + assert.NotEmpty(t, artifact.ID) + + response, err := artifactsService.ListPitrTimeranges(ctx, &backuppb.ListPitrTimerangesRequest{ + ArtifactId: artifact.ID, + }) + tests.AssertGRPCError(t, status.New(codes.FailedPrecondition, "Artifact is not a PITR artifact"), err) + assert.Nil(t, response) + }) + mock.AssertExpectationsForObjects(t, mockedPitrStorageSvc) +} diff --git a/managed/services/management/backup/backups_service.go b/managed/services/management/backup/backups_service.go index 855f96ba52..e32c963dc3 100644 --- a/managed/services/management/backup/backups_service.go +++ b/managed/services/management/backup/backups_service.go @@ -27,10 +27,11 @@ import ( "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" "gopkg.in/reform.v1" "github.com/percona/pmm/api/inventorypb" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/services" "github.com/percona/pmm/managed/services/agents" @@ -46,7 +47,7 @@ type BackupsService struct { scheduleService scheduleService l *logrus.Entry - backupv1beta1.UnimplementedBackupsServer + backuppb.UnimplementedBackupsServer } const ( @@ -70,41 +71,8 @@ func NewBackupsService( } } -func convertBackupError(restoreError error) error { - if restoreError == nil { - return nil - } - - var code backupv1beta1.ErrorCode - switch { - case errors.Is(restoreError, backup.ErrIncompatibleService): - return status.Error(codes.FailedPrecondition, restoreError.Error()) - case errors.Is(restoreError, backup.ErrXtrabackupNotInstalled): - code = backupv1beta1.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED - case errors.Is(restoreError, backup.ErrInvalidXtrabackup): - code = backupv1beta1.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP - case errors.Is(restoreError, backup.ErrIncompatibleXtrabackup): - code = backupv1beta1.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP - - case errors.Is(restoreError, agents.ErrIncompatibleAgentVersion): - return status.Error(codes.FailedPrecondition, restoreError.Error()) - - default: - return restoreError - } - - st, err := status.New(codes.FailedPrecondition, restoreError.Error()).WithDetails(&backupv1beta1.Error{ - Code: code, - }) - if err != nil { - return fmt.Errorf("failed to construct status error: %w, restore error: %s", err, restoreError) - } - - return st.Err() -} - // StartBackup starts on-demand backup. -func (s *BackupsService) StartBackup(ctx context.Context, req *backupv1beta1.StartBackupRequest) (*backupv1beta1.StartBackupResponse, error) { +func (s *BackupsService) StartBackup(ctx context.Context, req *backuppb.StartBackupRequest) (*backuppb.StartBackupResponse, error) { if req.Retries > maxRetriesAttempts { return nil, status.Errorf(codes.InvalidArgument, "Exceeded max retries %d.", maxRetriesAttempts) } @@ -141,63 +109,43 @@ func (s *BackupsService) StartBackup(ctx context.Context, req *backupv1beta1.Sta return nil, convertBackupError(err) } - return &backupv1beta1.StartBackupResponse{ + return &backuppb.StartBackupResponse{ ArtifactId: artifactID, }, nil } -func convertRestoreBackupError(restoreError error) error { - if restoreError == nil { - return nil +// RestoreBackup starts restore backup job. +func (s *BackupsService) RestoreBackup( + ctx context.Context, + req *backuppb.RestoreBackupRequest, +) (*backuppb.RestoreBackupResponse, error) { + // Disable all related scheduled backups before restoring + tasks, err := models.FindScheduledTasks(s.db.Querier, models.ScheduledTasksFilter{ServiceID: req.ServiceId}) + if err != nil { + return nil, err } - var code backupv1beta1.ErrorCode - switch { - case errors.Is(restoreError, backup.ErrIncompatibleService): - return status.Error(codes.FailedPrecondition, restoreError.Error()) - case errors.Is(restoreError, backup.ErrXtrabackupNotInstalled): - code = backupv1beta1.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED - case errors.Is(restoreError, backup.ErrInvalidXtrabackup): - code = backupv1beta1.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP - case errors.Is(restoreError, backup.ErrIncompatibleXtrabackup): - code = backupv1beta1.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP - case errors.Is(restoreError, backup.ErrIncompatibleTargetMySQL): - code = backupv1beta1.ErrorCode_ERROR_CODE_INCOMPATIBLE_TARGET_MYSQL - - case errors.Is(restoreError, agents.ErrIncompatibleAgentVersion): - return status.Error(codes.FailedPrecondition, restoreError.Error()) - - default: - return restoreError + for _, t := range tasks { + if _, err := s.ChangeScheduledBackup(ctx, &backuppb.ChangeScheduledBackupRequest{ + ScheduledBackupId: t.ID, + Enabled: &wrapperspb.BoolValue{Value: false}, + }); err != nil { + return nil, err + } } - st, err := status.New(codes.FailedPrecondition, restoreError.Error()).WithDetails(&backupv1beta1.Error{ - Code: code, - }) - if err != nil { - return fmt.Errorf("failed to construct status error: %w, restore error: %s", err, restoreError) - } - - return st.Err() -} - -// RestoreBackup starts restore backup job. -func (s *BackupsService) RestoreBackup( - ctx context.Context, - req *backupv1beta1.RestoreBackupRequest, -) (*backupv1beta1.RestoreBackupResponse, error) { - id, err := s.backupService.RestoreBackup(ctx, req.ServiceId, req.ArtifactId) + id, err := s.backupService.RestoreBackup(ctx, req.ServiceId, req.ArtifactId, req.PitrTimestamp.AsTime()) if err != nil { return nil, convertRestoreBackupError(err) } - return &backupv1beta1.RestoreBackupResponse{ + return &backuppb.RestoreBackupResponse{ RestoreId: id, }, nil } // ScheduleBackup add new backup task to scheduler. -func (s *BackupsService) ScheduleBackup(ctx context.Context, req *backupv1beta1.ScheduleBackupRequest) (*backupv1beta1.ScheduleBackupResponse, error) { +func (s *BackupsService) ScheduleBackup(ctx context.Context, req *backuppb.ScheduleBackupRequest) (*backuppb.ScheduleBackupResponse, error) { var id string if req.Retries > maxRetriesAttempts { @@ -281,11 +229,11 @@ func (s *BackupsService) ScheduleBackup(ctx context.Context, req *backupv1beta1. if errTx != nil { return nil, errTx } - return &backupv1beta1.ScheduleBackupResponse{ScheduledBackupId: id}, nil + return &backuppb.ScheduleBackupResponse{ScheduledBackupId: id}, nil } // ListScheduledBackups lists all tasks related to backup. -func (s *BackupsService) ListScheduledBackups(ctx context.Context, req *backupv1beta1.ListScheduledBackupsRequest) (*backupv1beta1.ListScheduledBackupsResponse, error) { +func (s *BackupsService) ListScheduledBackups(ctx context.Context, req *backuppb.ListScheduledBackupsRequest) (*backuppb.ListScheduledBackupsResponse, error) { tasks, err := models.FindScheduledTasks(s.db.Querier, models.ScheduledTasksFilter{ Types: []models.ScheduledTaskType{ models.ScheduledMySQLBackupTask, @@ -324,7 +272,7 @@ func (s *BackupsService) ListScheduledBackups(ctx context.Context, req *backupv1 return nil, err } - scheduledBackups := make([]*backupv1beta1.ScheduledBackup, 0, len(tasks)) + scheduledBackups := make([]*backuppb.ScheduledBackup, 0, len(tasks)) for _, task := range tasks { scheduledBackup, err := convertTaskToScheduledBackup(task, svcs, locations) if err != nil { @@ -334,13 +282,13 @@ func (s *BackupsService) ListScheduledBackups(ctx context.Context, req *backupv1 scheduledBackups = append(scheduledBackups, scheduledBackup) } - return &backupv1beta1.ListScheduledBackupsResponse{ + return &backuppb.ListScheduledBackupsResponse{ ScheduledBackups: scheduledBackups, }, nil } // ChangeScheduledBackup changes existing scheduled backup task. -func (s *BackupsService) ChangeScheduledBackup(ctx context.Context, req *backupv1beta1.ChangeScheduledBackupRequest) (*backupv1beta1.ChangeScheduledBackupResponse, error) { +func (s *BackupsService) ChangeScheduledBackup(ctx context.Context, req *backuppb.ChangeScheduledBackupRequest) (*backuppb.ChangeScheduledBackupResponse, error) { var disablePITR bool var serviceID string @@ -427,11 +375,11 @@ func (s *BackupsService) ChangeScheduledBackup(ctx context.Context, req *backupv } } - return &backupv1beta1.ChangeScheduledBackupResponse{}, nil + return &backuppb.ChangeScheduledBackupResponse{}, nil } // RemoveScheduledBackup stops and removes existing scheduled backup task. -func (s *BackupsService) RemoveScheduledBackup(ctx context.Context, req *backupv1beta1.RemoveScheduledBackupRequest) (*backupv1beta1.RemoveScheduledBackupResponse, error) { +func (s *BackupsService) RemoveScheduledBackup(ctx context.Context, req *backuppb.RemoveScheduledBackupRequest) (*backuppb.RemoveScheduledBackupResponse, error) { task, err := models.FindScheduledTaskByID(s.db.Querier, req.ScheduledBackupId) if err != nil { return nil, err @@ -477,11 +425,11 @@ func (s *BackupsService) RemoveScheduledBackup(ctx context.Context, req *backupv } } - return &backupv1beta1.RemoveScheduledBackupResponse{}, nil + return &backuppb.RemoveScheduledBackupResponse{}, nil } // GetLogs returns logs for artifact. -func (s *BackupsService) GetLogs(ctx context.Context, req *backupv1beta1.GetLogsRequest) (*backupv1beta1.GetLogsResponse, error) { +func (s *BackupsService) GetLogs(ctx context.Context, req *backuppb.GetLogsRequest) (*backuppb.GetLogsResponse, error) { jobs, err := models.FindJobs(s.db.Querier, models.JobsFilter{ ArtifactID: req.ArtifactId, Types: []models.JobType{ @@ -512,15 +460,15 @@ func (s *BackupsService) GetLogs(ctx context.Context, req *backupv1beta1.GetLogs return nil, err } - res := &backupv1beta1.GetLogsResponse{ - Logs: make([]*backupv1beta1.LogChunk, 0, len(jobLogs)), + res := &backuppb.GetLogsResponse{ + Logs: make([]*backuppb.LogChunk, 0, len(jobLogs)), } for _, log := range jobLogs { if log.LastChunk { res.End = true break } - res.Logs = append(res.Logs, &backupv1beta1.LogChunk{ + res.Logs = append(res.Logs, &backuppb.LogChunk{ ChunkId: uint32(log.ChunkID), Data: log.Data, }) @@ -532,8 +480,8 @@ func (s *BackupsService) GetLogs(ctx context.Context, req *backupv1beta1.GetLogs // ListArtifactCompatibleServices lists compatible service for restoring given artifact. func (s *BackupsService) ListArtifactCompatibleServices( ctx context.Context, - req *backupv1beta1.ListArtifactCompatibleServicesRequest, -) (*backupv1beta1.ListArtifactCompatibleServicesResponse, error) { + req *backuppb.ListArtifactCompatibleServicesRequest, +) (*backuppb.ListArtifactCompatibleServicesResponse, error) { compatibleServices, err := s.compatibilityService.FindArtifactCompatibleServices(ctx, req.ArtifactId) switch { case err == nil: @@ -543,7 +491,7 @@ func (s *BackupsService) ListArtifactCompatibleServices( return nil, err } - res := &backupv1beta1.ListArtifactCompatibleServicesResponse{} + res := &backuppb.ListArtifactCompatibleServicesResponse{} for _, service := range compatibleServices { apiService, err := services.ToAPIService(service) if err != nil { @@ -571,8 +519,8 @@ func (s *BackupsService) ListArtifactCompatibleServices( func convertTaskToScheduledBackup(task *models.ScheduledTask, services map[string]*models.Service, locationModels map[string]*models.BackupLocation, -) (*backupv1beta1.ScheduledBackup, error) { - scheduledBackup := &backupv1beta1.ScheduledBackup{ +) (*backuppb.ScheduledBackup, error) { + scheduledBackup := &backuppb.ScheduledBackup{ ScheduledBackupId: task.ID, CronExpression: task.CronExpression, Enabled: !task.Disabled, @@ -627,46 +575,123 @@ func convertTaskToScheduledBackup(task *models.ScheduledTask, return scheduledBackup, nil } -func convertBackupModeToModel(mode backupv1beta1.BackupMode) (models.BackupMode, error) { +func convertBackupModeToModel(mode backuppb.BackupMode) (models.BackupMode, error) { switch mode { - case backupv1beta1.BackupMode_SNAPSHOT: + case backuppb.BackupMode_SNAPSHOT: return models.Snapshot, nil - case backupv1beta1.BackupMode_INCREMENTAL: + case backuppb.BackupMode_INCREMENTAL: return models.Incremental, nil - case backupv1beta1.BackupMode_PITR: + case backuppb.BackupMode_PITR: return models.PITR, nil - case backupv1beta1.BackupMode_BACKUP_MODE_INVALID: + case backuppb.BackupMode_BACKUP_MODE_INVALID: return "", status.Errorf(codes.InvalidArgument, "invalid backup mode: %s", mode.String()) default: return "", status.Errorf(codes.InvalidArgument, "Unknown backup mode: %s", mode.String()) } } -func convertModelToBackupMode(mode models.BackupMode) (backupv1beta1.BackupMode, error) { +func convertModelToBackupMode(mode models.BackupMode) (backuppb.BackupMode, error) { switch mode { case models.Snapshot: - return backupv1beta1.BackupMode_SNAPSHOT, nil + return backuppb.BackupMode_SNAPSHOT, nil case models.Incremental: - return backupv1beta1.BackupMode_INCREMENTAL, nil + return backuppb.BackupMode_INCREMENTAL, nil case models.PITR: - return backupv1beta1.BackupMode_PITR, nil + return backuppb.BackupMode_PITR, nil default: return 0, errors.Errorf("unknown backup mode: %s", mode) } } -func convertModelToBackupModel(dataModel backupv1beta1.DataModel) (models.DataModel, error) { +func convertModelToBackupModel(dataModel backuppb.DataModel) (models.DataModel, error) { switch dataModel { - case backupv1beta1.DataModel_LOGICAL: + case backuppb.DataModel_LOGICAL: return models.LogicalDataModel, nil - case backupv1beta1.DataModel_PHYSICAL: + case backuppb.DataModel_PHYSICAL: return models.PhysicalDataModel, nil default: return "", errors.Errorf("unknown backup mode: %s", dataModel) } } +func convertBackupError(restoreError error) error { + if restoreError == nil { + return nil + } + + var code backuppb.ErrorCode + switch { + case errors.Is(restoreError, backup.ErrIncompatibleService): + return status.Error(codes.FailedPrecondition, restoreError.Error()) + case errors.Is(restoreError, backup.ErrXtrabackupNotInstalled): + code = backuppb.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED + case errors.Is(restoreError, backup.ErrInvalidXtrabackup): + code = backuppb.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP + case errors.Is(restoreError, backup.ErrIncompatibleXtrabackup): + code = backuppb.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP + + case errors.Is(restoreError, agents.ErrIncompatibleAgentVersion): + return status.Error(codes.FailedPrecondition, restoreError.Error()) + + default: + return restoreError + } + + st, err := status.New(codes.FailedPrecondition, restoreError.Error()).WithDetails(&backuppb.Error{ + Code: code, + }) + if err != nil { + return fmt.Errorf("failed to construct status error: %w, restore error: %s", err, restoreError) + } + + return st.Err() +} + +func convertRestoreBackupError(restoreError error) error { + if restoreError == nil { + return nil + } + + var code backuppb.ErrorCode + switch { + case errors.Is(restoreError, backup.ErrIncompatibleService): + return status.Error(codes.FailedPrecondition, restoreError.Error()) + case errors.Is(restoreError, backup.ErrXtrabackupNotInstalled): + code = backuppb.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED + case errors.Is(restoreError, backup.ErrInvalidXtrabackup): + code = backuppb.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP + case errors.Is(restoreError, backup.ErrIncompatibleXtrabackup): + code = backuppb.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP + case errors.Is(restoreError, backup.ErrIncompatibleTargetMySQL): + code = backuppb.ErrorCode_ERROR_CODE_INCOMPATIBLE_TARGET_MYSQL + case errors.Is(restoreError, backup.ErrTimestampOutOfRange): + return status.Error(codes.OutOfRange, restoreError.Error()) + case errors.Is(restoreError, backup.ErrIncompatibleArtifactMode): + return status.Error(codes.FailedPrecondition, restoreError.Error()) + case errors.Is(restoreError, agents.ErrIncompatibleAgentVersion): + return status.Error(codes.FailedPrecondition, restoreError.Error()) + case errors.Is(restoreError, models.ErrNotFound): + return status.Error(codes.NotFound, restoreError.Error()) + case errors.Is(restoreError, backup.ErrAnotherOperationInProgress): + return status.Error(codes.FailedPrecondition, restoreError.Error()) + case errors.Is(restoreError, backup.ErrArtifactNotReady): + return status.Error(codes.FailedPrecondition, restoreError.Error()) + + default: + return restoreError + } + + st, err := status.New(codes.FailedPrecondition, restoreError.Error()).WithDetails(&backuppb.Error{ + Code: code, + }) + if err != nil { + return fmt.Errorf("failed to construct status error: %w, restore error: %s", err, restoreError) + } + + return st.Err() +} + // Check interfaces. var ( - _ backupv1beta1.BackupsServer = (*BackupsService)(nil) + _ backuppb.BackupsServer = (*BackupsService)(nil) ) diff --git a/managed/services/management/backup/backups_service_test.go b/managed/services/management/backup/backups_service_test.go index 02be92f065..d2c037a203 100644 --- a/managed/services/management/backup/backups_service_test.go +++ b/managed/services/management/backup/backups_service_test.go @@ -33,7 +33,7 @@ import ( "gopkg.in/reform.v1" "gopkg.in/reform.v1/dialects/postgresql" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/services/backup" "github.com/percona/pmm/managed/services/scheduler" @@ -87,22 +87,22 @@ func TestStartBackup(t *testing.T) { for _, tc := range []struct { testName string backupError error - code backupv1beta1.ErrorCode + code backuppb.ErrorCode }{ { testName: "xtrabackup not installed", backupError: backup.ErrXtrabackupNotInstalled, - code: backupv1beta1.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED, + code: backuppb.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED, }, { testName: "invalid xtrabackup", backupError: backup.ErrInvalidXtrabackup, - code: backupv1beta1.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP, + code: backuppb.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP, }, { testName: "incompatible xtrabackup", backupError: backup.ErrIncompatibleXtrabackup, - code: backupv1beta1.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP, + code: backuppb.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP, }, } { t.Run(tc.testName, func(t *testing.T) { @@ -110,7 +110,7 @@ func TestStartBackup(t *testing.T) { backupService.On("PerformBackup", mock.Anything, mock.Anything). Return("", backupError).Once() ctx := context.Background() - resp, err := backupSvc.StartBackup(ctx, &backupv1beta1.StartBackupRequest{ + resp, err := backupSvc.StartBackup(ctx, &backuppb.StartBackupRequest{ ServiceId: *agent.ServiceID, LocationId: "locationID", Name: "name", @@ -124,7 +124,7 @@ func TestStartBackup(t *testing.T) { assert.Equal(t, codes.FailedPrecondition, st.Code()) assert.Equal(t, backupError.Error(), st.Message()) require.Len(t, st.Details(), 1) - detailedError, ok := st.Details()[0].(*backupv1beta1.Error) + detailedError, ok := st.Details()[0].(*backuppb.Error) require.True(t, ok) assert.Equal(t, tc.code, detailedError.Code) }) @@ -156,14 +156,14 @@ func TestStartBackup(t *testing.T) { backupService := &mockBackupService{} backupSvc := NewBackupsService(db, backupService, nil, nil) backupService.On("PerformBackup", mock.Anything, mock.Anything).Return("", nil) - _, err := backupSvc.StartBackup(ctx, &backupv1beta1.StartBackupRequest{ + _, err := backupSvc.StartBackup(ctx, &backuppb.StartBackupRequest{ ServiceId: *agent.ServiceID, LocationId: locationRes.ID, Name: "name", Description: "description", RetryInterval: nil, Retries: 0, - DataModel: backupv1beta1.DataModel_PHYSICAL, + DataModel: backuppb.DataModel_PHYSICAL, }) require.NoError(t, err) }) @@ -171,41 +171,43 @@ func TestStartBackup(t *testing.T) { } func TestRestoreBackupErrors(t *testing.T) { + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) backupService := &mockBackupService{} - backupSvc := NewBackupsService(nil, backupService, nil, nil) + backupSvc := NewBackupsService(db, backupService, nil, nil) for _, tc := range []struct { testName string backupError error - code backupv1beta1.ErrorCode + code backuppb.ErrorCode }{ { testName: "xtrabackup not installed", backupError: backup.ErrXtrabackupNotInstalled, - code: backupv1beta1.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED, + code: backuppb.ErrorCode_ERROR_CODE_XTRABACKUP_NOT_INSTALLED, }, { testName: "invalid xtrabackup", backupError: backup.ErrInvalidXtrabackup, - code: backupv1beta1.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP, + code: backuppb.ErrorCode_ERROR_CODE_INVALID_XTRABACKUP, }, { testName: "incompatible xtrabackup", backupError: backup.ErrIncompatibleXtrabackup, - code: backupv1beta1.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP, + code: backuppb.ErrorCode_ERROR_CODE_INCOMPATIBLE_XTRABACKUP, }, { testName: "target MySQL is not compatible", backupError: backup.ErrIncompatibleTargetMySQL, - code: backupv1beta1.ErrorCode_ERROR_CODE_INCOMPATIBLE_TARGET_MYSQL, + code: backuppb.ErrorCode_ERROR_CODE_INCOMPATIBLE_TARGET_MYSQL, }, } { t.Run(tc.testName, func(t *testing.T) { backupError := fmt.Errorf("error: %w", tc.backupError) - backupService.On("RestoreBackup", mock.Anything, "serviceID1", "artifactID1"). + backupService.On("RestoreBackup", mock.Anything, "serviceID1", "artifactID1", mock.Anything). Return("", backupError).Once() ctx := context.Background() - resp, err := backupSvc.RestoreBackup(ctx, &backupv1beta1.RestoreBackupRequest{ + resp, err := backupSvc.RestoreBackup(ctx, &backuppb.RestoreBackupRequest{ ServiceId: "serviceID1", ArtifactId: "artifactID1", }) @@ -215,7 +217,7 @@ func TestRestoreBackupErrors(t *testing.T) { assert.Equal(t, codes.FailedPrecondition, st.Code()) assert.Equal(t, backupError.Error(), st.Message()) require.Len(t, st.Details(), 1) - detailedError, ok := st.Details()[0].(*backupv1beta1.Error) + detailedError, ok := st.Details()[0].(*backuppb.Error) require.True(t, ok) assert.Equal(t, tc.code, detailedError.Code) }) @@ -252,7 +254,7 @@ func TestScheduledBackups(t *testing.T) { agent := setup(t, db.Querier, models.MySQLServiceType, t.Name()) t.Run("schedule/change", func(t *testing.T) { - req := &backupv1beta1.ScheduleBackupRequest{ + req := &backuppb.ScheduleBackupRequest{ ServiceId: pointer.GetString(agent.ServiceID), LocationId: locationRes.ID, CronExpression: "1 * * * *", @@ -260,7 +262,7 @@ func TestScheduledBackups(t *testing.T) { Name: t.Name(), Description: t.Name(), Enabled: true, - Mode: backupv1beta1.BackupMode_SNAPSHOT, + Mode: backuppb.BackupMode_SNAPSHOT, Retries: maxRetriesAttempts - 1, RetryInterval: durationpb.New(maxRetryInterval), } @@ -281,7 +283,7 @@ func TestScheduledBackups(t *testing.T) { assert.Equal(t, req.Retries, data.Retries) assert.Equal(t, req.RetryInterval.AsDuration(), data.RetryInterval) - changeReq := &backupv1beta1.ChangeScheduledBackupRequest{ + changeReq := &backuppb.ChangeScheduledBackupRequest{ ScheduledBackupId: task.ID, Enabled: wrapperspb.Bool(false), CronExpression: wrapperspb.String("2 * * * *"), @@ -306,7 +308,7 @@ func TestScheduledBackups(t *testing.T) { }) t.Run("list", func(t *testing.T) { - res, err := backupSvc.ListScheduledBackups(ctx, &backupv1beta1.ListScheduledBackupsRequest{}) + res, err := backupSvc.ListScheduledBackups(ctx, &backuppb.ListScheduledBackupsRequest{}) assert.NoError(t, err) assert.Len(t, res.ScheduledBackups, 1) @@ -333,7 +335,7 @@ func TestScheduledBackups(t *testing.T) { }) require.NoError(t, err) - _, err = backupSvc.RemoveScheduledBackup(ctx, &backupv1beta1.RemoveScheduledBackupRequest{ + _, err = backupSvc.RemoveScheduledBackup(ctx, &backuppb.RemoveScheduledBackupRequest{ ScheduledBackupId: task.ID, }) assert.NoError(t, err) @@ -360,15 +362,15 @@ func TestScheduledBackups(t *testing.T) { backupSvc := NewBackupsService(db, nil, nil, schedulerService) schedulerService.On("Add", mock.Anything, mock.Anything).Return("", nil) - _, err := backupSvc.ScheduleBackup(ctx, &backupv1beta1.ScheduleBackupRequest{ + _, err := backupSvc.ScheduleBackup(ctx, &backuppb.ScheduleBackupRequest{ ServiceId: *agent.ServiceID, LocationId: locationRes.ID, Name: "name", Description: "description", RetryInterval: durationpb.New(maxRetryInterval), Retries: maxRetriesAttempts, - DataModel: backupv1beta1.DataModel_PHYSICAL, - Mode: backupv1beta1.BackupMode_PITR, + DataModel: backuppb.DataModel_PHYSICAL, + Mode: backuppb.BackupMode_PITR, }) require.Error(t, err) tests.AssertGRPCErrorRE(t, codes.InvalidArgument, "PITR is only supported for logical backups", err) @@ -379,15 +381,15 @@ func TestScheduledBackups(t *testing.T) { schedulerService := &mockScheduleService{} backupSvc := NewBackupsService(db, nil, nil, schedulerService) schedulerService.On("Add", mock.Anything, mock.Anything).Return(&models.ScheduledTask{}, nil) - _, err := backupSvc.ScheduleBackup(ctx, &backupv1beta1.ScheduleBackupRequest{ + _, err := backupSvc.ScheduleBackup(ctx, &backuppb.ScheduleBackupRequest{ ServiceId: *agent.ServiceID, LocationId: locationRes.ID, Name: "name", Description: "description", RetryInterval: durationpb.New(maxRetryInterval), Retries: maxRetriesAttempts, - DataModel: backupv1beta1.DataModel_PHYSICAL, - Mode: backupv1beta1.BackupMode_SNAPSHOT, + DataModel: backuppb.DataModel_PHYSICAL, + Mode: backuppb.BackupMode_SNAPSHOT, }) require.NoError(t, err) }) @@ -453,7 +455,7 @@ func TestGetLogs(t *testing.T) { }, } for _, tc := range testCases { - logs, err := backupSvc.GetLogs(ctx, &backupv1beta1.GetLogsRequest{ + logs, err := backupSvc.GetLogs(ctx, &backuppb.GetLogsRequest{ ArtifactId: "artifact", Offset: tc.offset, Limit: tc.limit, diff --git a/managed/services/management/backup/deps.go b/managed/services/management/backup/deps.go index d917077217..4b43efd318 100644 --- a/managed/services/management/backup/deps.go +++ b/managed/services/management/backup/deps.go @@ -17,6 +17,7 @@ package backup import ( "context" + "time" "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/services/backup" @@ -27,6 +28,7 @@ import ( //go:generate ../../../../bin/mockery -name=backupService -case=snake -inpkg -testonly //go:generate ../../../../bin/mockery -name=scheduleService -case=snake -inpkg -testonly //go:generate ../../../../bin/mockery -name=removalService -case=snake -inpkg -testonly +//go:generate ../../../../bin/mockery -name=pitrTimerangeService -case=snake -inpkg -testonly type awsS3 interface { GetBucketLocation(ctx context.Context, host string, accessKey, secretKey, name string) (string, error) @@ -36,7 +38,7 @@ type awsS3 interface { type backupService interface { PerformBackup(ctx context.Context, params backup.PerformBackupParams) (string, error) - RestoreBackup(ctx context.Context, serviceID, artifactID string) (string, error) + RestoreBackup(ctx context.Context, serviceID, artifactID string, pitrTimestamp time.Time) (string, error) SwitchMongoPITR(ctx context.Context, serviceID string, enabled bool) error } @@ -56,3 +58,9 @@ type scheduleService interface { type removalService interface { DeleteArtifact(ctx context.Context, artifactID string, removeFiles bool) error } + +// pitrTimerangeService provides methods that help us inspect PITR artifacts +type pitrTimerangeService interface { + // ListPITRTimeranges returns the available PITR timeranges for the given artifact in the provided location + ListPITRTimeranges(ctx context.Context, artifactName string, location *models.BackupLocation) ([]backup.Timeline, error) +} diff --git a/managed/services/management/backup/locations_service.go b/managed/services/management/backup/locations_service.go index 8808c6e361..fbe8e7ad77 100644 --- a/managed/services/management/backup/locations_service.go +++ b/managed/services/management/backup/locations_service.go @@ -25,7 +25,7 @@ import ( "google.golang.org/grpc/status" "gopkg.in/reform.v1" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" "github.com/percona/pmm/managed/models" ) @@ -35,7 +35,7 @@ type LocationsService struct { s3 awsS3 l *logrus.Entry - backupv1beta1.UnimplementedLocationsServer + backuppb.UnimplementedLocationsServer } // NewLocationsService creates new backup locations API service. @@ -58,12 +58,12 @@ func (s *LocationsService) Enabled() bool { } // ListLocations returns list of all available backup locations. -func (s *LocationsService) ListLocations(ctx context.Context, req *backupv1beta1.ListLocationsRequest) (*backupv1beta1.ListLocationsResponse, error) { +func (s *LocationsService) ListLocations(ctx context.Context, req *backuppb.ListLocationsRequest) (*backuppb.ListLocationsResponse, error) { locations, err := models.FindBackupLocations(s.db.Querier) if err != nil { return nil, err } - res := make([]*backupv1beta1.Location, len(locations)) + res := make([]*backuppb.Location, len(locations)) for i, location := range locations { loc, err := convertLocation(location) if err != nil { @@ -71,13 +71,13 @@ func (s *LocationsService) ListLocations(ctx context.Context, req *backupv1beta1 } res[i] = loc } - return &backupv1beta1.ListLocationsResponse{ + return &backuppb.ListLocationsResponse{ Locations: res, }, nil } // AddLocation adds new backup location. -func (s *LocationsService) AddLocation(ctx context.Context, req *backupv1beta1.AddLocationRequest) (*backupv1beta1.AddLocationResponse, error) { +func (s *LocationsService) AddLocation(ctx context.Context, req *backuppb.AddLocationRequest) (*backuppb.AddLocationResponse, error) { params := models.CreateBackupLocationParams{ Name: req.Name, Description: req.Description, @@ -92,9 +92,9 @@ func (s *LocationsService) AddLocation(ctx context.Context, req *backupv1beta1.A } } - if req.PmmClientConfig != nil { - params.PMMClientConfig = &models.PMMClientLocationConfig{ - Path: req.PmmClientConfig.Path, + if req.FilesystemConfig != nil { + params.FilesystemConfig = &models.FilesystemLocationConfig{ + Path: req.FilesystemConfig.Path, } } @@ -127,13 +127,13 @@ func (s *LocationsService) AddLocation(ctx context.Context, req *backupv1beta1.A return nil, err } - return &backupv1beta1.AddLocationResponse{ + return &backuppb.AddLocationResponse{ LocationId: locationModel.ID, }, nil } // ChangeLocation changes existing backup location. -func (s *LocationsService) ChangeLocation(ctx context.Context, req *backupv1beta1.ChangeLocationRequest) (*backupv1beta1.ChangeLocationResponse, error) { +func (s *LocationsService) ChangeLocation(ctx context.Context, req *backuppb.ChangeLocationRequest) (*backuppb.ChangeLocationResponse, error) { params := models.ChangeBackupLocationParams{ Name: req.Name, Description: req.Description, @@ -148,9 +148,9 @@ func (s *LocationsService) ChangeLocation(ctx context.Context, req *backupv1beta } } - if req.PmmClientConfig != nil { - params.PMMClientConfig = &models.PMMClientLocationConfig{ - Path: req.PmmClientConfig.Path, + if req.FilesystemConfig != nil { + params.FilesystemConfig = &models.FilesystemLocationConfig{ + Path: req.FilesystemConfig.Path, } } if err := params.Validate(models.BackupLocationValidationParams{ @@ -180,14 +180,14 @@ func (s *LocationsService) ChangeLocation(ctx context.Context, req *backupv1beta return nil, err } - return &backupv1beta1.ChangeLocationResponse{}, nil + return &backuppb.ChangeLocationResponse{}, nil } // TestLocationConfig tests backup location and credentials. func (s *LocationsService) TestLocationConfig( ctx context.Context, - req *backupv1beta1.TestLocationConfigRequest, -) (*backupv1beta1.TestLocationConfigResponse, error) { + req *backuppb.TestLocationConfigRequest, +) (*backuppb.TestLocationConfigResponse, error) { var locationConfig models.BackupLocationConfig if req.S3Config != nil { @@ -199,9 +199,9 @@ func (s *LocationsService) TestLocationConfig( } } - if req.PmmClientConfig != nil { - locationConfig.PMMClientConfig = &models.PMMClientLocationConfig{ - Path: req.PmmClientConfig.Path, + if req.FilesystemConfig != nil { + locationConfig.FilesystemConfig = &models.FilesystemLocationConfig{ + Path: req.FilesystemConfig.Path, } } @@ -218,11 +218,11 @@ func (s *LocationsService) TestLocationConfig( } } - return &backupv1beta1.TestLocationConfigResponse{}, nil + return &backuppb.TestLocationConfigResponse{}, nil } // RemoveLocation removes backup location. -func (s *LocationsService) RemoveLocation(ctx context.Context, req *backupv1beta1.RemoveLocationRequest) (*backupv1beta1.RemoveLocationResponse, error) { +func (s *LocationsService) RemoveLocation(ctx context.Context, req *backuppb.RemoveLocationRequest) (*backuppb.RemoveLocationResponse, error) { mode := models.RemoveRestrict if req.Force { mode = models.RemoveCascade @@ -235,27 +235,27 @@ func (s *LocationsService) RemoveLocation(ctx context.Context, req *backupv1beta return nil, err } - return &backupv1beta1.RemoveLocationResponse{}, nil + return &backuppb.RemoveLocationResponse{}, nil } -func convertLocation(locationModel *models.BackupLocation) (*backupv1beta1.Location, error) { - loc := &backupv1beta1.Location{ +func convertLocation(locationModel *models.BackupLocation) (*backuppb.Location, error) { + loc := &backuppb.Location{ LocationId: locationModel.ID, Name: locationModel.Name, Description: locationModel.Description, } switch locationModel.Type { - case models.PMMClientBackupLocationType: - config := locationModel.PMMClientConfig - loc.Config = &backupv1beta1.Location_PmmClientConfig{ - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + case models.FilesystemBackupLocationType: + config := locationModel.FilesystemConfig + loc.Config = &backuppb.Location_FilesystemConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: config.Path, }, } case models.S3BackupLocationType: config := locationModel.S3Config - loc.Config = &backupv1beta1.Location_S3Config{ - S3Config: &backupv1beta1.S3LocationConfig{ + loc.Config = &backuppb.Location_S3Config{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: config.Endpoint, AccessKey: config.AccessKey, SecretKey: config.SecretKey, @@ -299,5 +299,5 @@ func (s *LocationsService) checkBucket(ctx context.Context, c *models.S3Location // Check interfaces. var ( - _ backupv1beta1.LocationsServer = (*LocationsService)(nil) + _ backuppb.LocationsServer = (*LocationsService)(nil) ) diff --git a/managed/services/management/backup/locations_service_test.go b/managed/services/management/backup/locations_service_test.go index f51622c539..3da986e337 100644 --- a/managed/services/management/backup/locations_service_test.go +++ b/managed/services/management/backup/locations_service_test.go @@ -29,7 +29,7 @@ import ( "gopkg.in/reform.v1" "gopkg.in/reform.v1/dialects/postgresql" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/utils/testdb" "github.com/percona/pmm/managed/utils/tests" @@ -45,9 +45,9 @@ func TestCreateBackupLocation(t *testing.T) { mock.Anything).Return("us-east-2", nil) svc := NewLocationsService(db, mockedS3) t.Run("add server config", func(t *testing.T) { - loc, err := svc.AddLocation(ctx, &backupv1beta1.AddLocationRequest{ + loc, err := svc.AddLocation(ctx, &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, }) @@ -57,9 +57,9 @@ func TestCreateBackupLocation(t *testing.T) { }) t.Run("add client config", func(t *testing.T) { - loc, err := svc.AddLocation(ctx, &backupv1beta1.AddLocationRequest{ + loc, err := svc.AddLocation(ctx, &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, }) @@ -69,9 +69,9 @@ func TestCreateBackupLocation(t *testing.T) { }) t.Run("add awsS3", func(t *testing.T) { - loc, err := svc.AddLocation(ctx, &backupv1beta1.AddLocationRequest{ + loc, err := svc.AddLocation(ctx, &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - S3Config: &backupv1beta1.S3LocationConfig{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://awsS3.us-west-2.amazonaws.com/", AccessKey: "access_key", SecretKey: "secret_key", @@ -84,12 +84,12 @@ func TestCreateBackupLocation(t *testing.T) { }) t.Run("multiple configs", func(t *testing.T) { - _, err := svc.AddLocation(ctx, &backupv1beta1.AddLocationRequest{ + _, err := svc.AddLocation(ctx, &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, - S3Config: &backupv1beta1.S3LocationConfig{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://awsS3.us-west-2.amazonaws.com/", AccessKey: "access_key", SecretKey: "secret_key", @@ -110,17 +110,17 @@ func TestListBackupLocations(t *testing.T) { mock.Anything).Return("us-east-2", nil) svc := NewLocationsService(db, mockedS3) - req1 := &backupv1beta1.AddLocationRequest{ + req1 := &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, } res1, err := svc.AddLocation(ctx, req1) require.Nil(t, err) - req2 := &backupv1beta1.AddLocationRequest{ + req2 := &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - S3Config: &backupv1beta1.S3LocationConfig{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://awsS3.us-west-2.amazonaws.com/", AccessKey: "access_key", SecretKey: "secret_key", @@ -131,10 +131,10 @@ func TestListBackupLocations(t *testing.T) { require.Nil(t, err) t.Run("list", func(t *testing.T) { - res, err := svc.ListLocations(ctx, &backupv1beta1.ListLocationsRequest{}) + res, err := svc.ListLocations(ctx, &backuppb.ListLocationsRequest{}) require.Nil(t, err) - checkLocation := func(id string, req *backupv1beta1.AddLocationRequest) func() bool { + checkLocation := func(id string, req *backuppb.AddLocationRequest) func() bool { return func() bool { for _, loc := range res.Locations { if loc.LocationId == id { @@ -142,7 +142,7 @@ func TestListBackupLocations(t *testing.T) { return false } if req.S3Config != nil { - cfg := loc.Config.(*backupv1beta1.Location_S3Config) + cfg := loc.Config.(*backuppb.Location_S3Config) if req.S3Config.Endpoint != cfg.S3Config.Endpoint || req.S3Config.AccessKey != cfg.S3Config.AccessKey || req.S3Config.SecretKey != cfg.S3Config.SecretKey || @@ -151,9 +151,9 @@ func TestListBackupLocations(t *testing.T) { } } - if req.PmmClientConfig != nil { - cfg := loc.Config.(*backupv1beta1.Location_PmmClientConfig) - if req.PmmClientConfig.Path != cfg.PmmClientConfig.Path { + if req.FilesystemConfig != nil { + cfg := loc.Config.(*backuppb.Location_FilesystemConfig) + if req.FilesystemConfig.Path != cfg.FilesystemConfig.Path { return false } } @@ -181,20 +181,20 @@ func TestChangeBackupLocation(t *testing.T) { mock.Anything).Return("us-east-2", nil) svc := NewLocationsService(db, mockedS3) t.Run("update existing config", func(t *testing.T) { - loc, err := svc.AddLocation(ctx, &backupv1beta1.AddLocationRequest{ + loc, err := svc.AddLocation(ctx, &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, }) require.NoError(t, err) require.NotEmpty(t, loc.LocationId) - updateReq := &backupv1beta1.ChangeLocationRequest{ + updateReq := &backuppb.ChangeLocationRequest{ LocationId: loc.LocationId, Name: gofakeit.Name(), Description: gofakeit.Quote(), - S3Config: &backupv1beta1.S3LocationConfig{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://example.com", AccessKey: "access_key", SecretKey: "secret_key", @@ -208,7 +208,7 @@ func TestChangeBackupLocation(t *testing.T) { require.NoError(t, err) assert.Equal(t, updateReq.Name, updatedLocation.Name) assert.Equal(t, updateReq.Description, updatedLocation.Description) - assert.Nil(t, updatedLocation.PMMClientConfig) + assert.Nil(t, updatedLocation.FilesystemConfig) require.NotNil(t, updatedLocation.S3Config) assert.Equal(t, updateReq.S3Config.Endpoint, updatedLocation.S3Config.Endpoint) assert.Equal(t, updateReq.S3Config.AccessKey, updatedLocation.S3Config.AccessKey) @@ -217,9 +217,9 @@ func TestChangeBackupLocation(t *testing.T) { }) t.Run("update only name", func(t *testing.T) { - addReq := &backupv1beta1.AddLocationRequest{ + addReq := &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, } @@ -227,7 +227,7 @@ func TestChangeBackupLocation(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, loc.LocationId) - updateReq := &backupv1beta1.ChangeLocationRequest{ + updateReq := &backuppb.ChangeLocationRequest{ LocationId: loc.LocationId, Name: gofakeit.Name(), } @@ -237,32 +237,32 @@ func TestChangeBackupLocation(t *testing.T) { updatedLocation, err := models.FindBackupLocationByID(db.Querier, loc.LocationId) require.NoError(t, err) assert.Equal(t, updateReq.Name, updatedLocation.Name) - require.NotNil(t, updatedLocation.PMMClientConfig) - assert.Equal(t, addReq.PmmClientConfig.Path, updatedLocation.PMMClientConfig.Path) + require.NotNil(t, updatedLocation.FilesystemConfig) + assert.Equal(t, addReq.FilesystemConfig.Path, updatedLocation.FilesystemConfig.Path) }) t.Run("update to existing name", func(t *testing.T) { name := gofakeit.Name() - _, err := svc.AddLocation(ctx, &backupv1beta1.AddLocationRequest{ + _, err := svc.AddLocation(ctx, &backuppb.AddLocationRequest{ Name: name, - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, }) require.NoError(t, err) - loc2, err := svc.AddLocation(ctx, &backupv1beta1.AddLocationRequest{ + loc2, err := svc.AddLocation(ctx, &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, }) require.NoError(t, err) - updateReq := &backupv1beta1.ChangeLocationRequest{ + updateReq := &backuppb.ChangeLocationRequest{ LocationId: loc2.LocationId, Name: name, - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, } @@ -278,9 +278,9 @@ func TestRemoveBackupLocation(t *testing.T) { mockedS3 := &mockAwsS3{} svc := NewLocationsService(db, mockedS3) - req := &backupv1beta1.AddLocationRequest{ + req := &backuppb.AddLocationRequest{ Name: gofakeit.Name(), - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "/tmp", }, } @@ -293,7 +293,7 @@ func TestRemoveBackupLocation(t *testing.T) { res3, err := svc.AddLocation(ctx, req) require.NoError(t, err) - foundLocation := func(id string, locations []*backupv1beta1.Location) bool { + foundLocation := func(id string, locations []*backuppb.Location) bool { for _, loc := range locations { if loc.LocationId == id { return true @@ -302,17 +302,17 @@ func TestRemoveBackupLocation(t *testing.T) { return false } - _, err = svc.RemoveLocation(ctx, &backupv1beta1.RemoveLocationRequest{ + _, err = svc.RemoveLocation(ctx, &backuppb.RemoveLocationRequest{ LocationId: res1.LocationId, }) assert.NoError(t, err) - _, err = svc.RemoveLocation(ctx, &backupv1beta1.RemoveLocationRequest{ + _, err = svc.RemoveLocation(ctx, &backuppb.RemoveLocationRequest{ LocationId: res3.LocationId, }) assert.NoError(t, err) - res, err := svc.ListLocations(ctx, &backupv1beta1.ListLocationsRequest{}) + res, err := svc.ListLocations(ctx, &backuppb.ListLocationsRequest{}) require.NoError(t, err) assert.False(t, foundLocation(res1.LocationId, res.Locations)) @@ -320,7 +320,7 @@ func TestRemoveBackupLocation(t *testing.T) { assert.True(t, foundLocation(res2.LocationId, res.Locations)) // Try to remove non-existing location - _, err = svc.RemoveLocation(ctx, &backupv1beta1.RemoveLocationRequest{ + _, err = svc.RemoveLocation(ctx, &backuppb.RemoveLocationRequest{ LocationId: "non-existing", }) assert.EqualError(t, err, `rpc error: code = NotFound desc = Backup location with ID "non-existing" not found.`) @@ -339,13 +339,13 @@ func TestVerifyBackupLocationValidation(t *testing.T) { tableTests := []struct { name string - req *backupv1beta1.TestLocationConfigRequest + req *backuppb.TestLocationConfigRequest errorMsg string }{ { name: "client config - missing path", - req: &backupv1beta1.TestLocationConfigRequest{ - PmmClientConfig: &backupv1beta1.PMMClientLocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + FilesystemConfig: &backuppb.FilesystemLocationConfig{ Path: "", }, }, @@ -353,13 +353,13 @@ func TestVerifyBackupLocationValidation(t *testing.T) { }, { name: "awsS3 config - missing config", - req: &backupv1beta1.TestLocationConfigRequest{}, + req: &backuppb.TestLocationConfigRequest{}, errorMsg: "rpc error: code = InvalidArgument desc = Missing location config.", }, { name: "awsS3 config - missing endpoint", - req: &backupv1beta1.TestLocationConfigRequest{ - S3Config: &backupv1beta1.S3LocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "", AccessKey: "access_key", SecretKey: "secret_key", @@ -370,8 +370,8 @@ func TestVerifyBackupLocationValidation(t *testing.T) { }, { name: "awsS3 config - missing access key", - req: &backupv1beta1.TestLocationConfigRequest{ - S3Config: &backupv1beta1.S3LocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://awsS3.us-west-2.amazonaws.com/", AccessKey: "", SecretKey: "secret_key", @@ -382,8 +382,8 @@ func TestVerifyBackupLocationValidation(t *testing.T) { }, { name: "awsS3 config - missing secret key", - req: &backupv1beta1.TestLocationConfigRequest{ - S3Config: &backupv1beta1.S3LocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://awsS3.us-west-2.amazonaws.com/", AccessKey: "secret_key", SecretKey: "", @@ -394,8 +394,8 @@ func TestVerifyBackupLocationValidation(t *testing.T) { }, { name: "awsS3 config - missing bucket name", - req: &backupv1beta1.TestLocationConfigRequest{ - S3Config: &backupv1beta1.S3LocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://awsS3.us-west-2.amazonaws.com/", AccessKey: "secret_key", SecretKey: "example_key", @@ -406,8 +406,8 @@ func TestVerifyBackupLocationValidation(t *testing.T) { }, { name: "awsS3 config - invalid endpoint", - req: &backupv1beta1.TestLocationConfigRequest{ - S3Config: &backupv1beta1.S3LocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "#invalidendpoint", AccessKey: "secret_key", SecretKey: "example_key", @@ -418,8 +418,8 @@ func TestVerifyBackupLocationValidation(t *testing.T) { }, { name: "awsS3 config - invalid endpoint, path is not allowed", - req: &backupv1beta1.TestLocationConfigRequest{ - S3Config: &backupv1beta1.S3LocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "https://awsS3.us-west-2.amazonaws.com/path", AccessKey: "secret_key", SecretKey: "example_key", @@ -430,8 +430,8 @@ func TestVerifyBackupLocationValidation(t *testing.T) { }, { name: "awsS3 config - invalid scheme", - req: &backupv1beta1.TestLocationConfigRequest{ - S3Config: &backupv1beta1.S3LocationConfig{ + req: &backuppb.TestLocationConfigRequest{ + S3Config: &backuppb.S3LocationConfig{ Endpoint: "tcp://awsS3.us-west-2.amazonaws.com", AccessKey: "secret_key", SecretKey: "example_key", diff --git a/managed/services/management/backup/mock_backup_service_test.go b/managed/services/management/backup/mock_backup_service_test.go index efa518e749..a7df318ba1 100644 --- a/managed/services/management/backup/mock_backup_service_test.go +++ b/managed/services/management/backup/mock_backup_service_test.go @@ -4,6 +4,7 @@ package backup import ( context "context" + time "time" mock "github.com/stretchr/testify/mock" @@ -36,20 +37,20 @@ func (_m *mockBackupService) PerformBackup(ctx context.Context, params backup.Pe return r0, r1 } -// RestoreBackup provides a mock function with given fields: ctx, serviceID, artifactID -func (_m *mockBackupService) RestoreBackup(ctx context.Context, serviceID string, artifactID string) (string, error) { - ret := _m.Called(ctx, serviceID, artifactID) +// RestoreBackup provides a mock function with given fields: ctx, serviceID, artifactID, pitrTimestamp +func (_m *mockBackupService) RestoreBackup(ctx context.Context, serviceID string, artifactID string, pitrTimestamp time.Time) (string, error) { + ret := _m.Called(ctx, serviceID, artifactID, pitrTimestamp) var r0 string - if rf, ok := ret.Get(0).(func(context.Context, string, string) string); ok { - r0 = rf(ctx, serviceID, artifactID) + if rf, ok := ret.Get(0).(func(context.Context, string, string, time.Time) string); ok { + r0 = rf(ctx, serviceID, artifactID, pitrTimestamp) } else { r0 = ret.Get(0).(string) } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, serviceID, artifactID) + if rf, ok := ret.Get(1).(func(context.Context, string, string, time.Time) error); ok { + r1 = rf(ctx, serviceID, artifactID, pitrTimestamp) } else { r1 = ret.Error(1) } diff --git a/managed/services/management/backup/mock_pitr_timerange_service_test.go b/managed/services/management/backup/mock_pitr_timerange_service_test.go new file mode 100644 index 0000000000..43f7faa583 --- /dev/null +++ b/managed/services/management/backup/mock_pitr_timerange_service_test.go @@ -0,0 +1,40 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package backup + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + models "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/services/backup" +) + +// mockPitrTimerangeService is an autogenerated mock type for the pitrTimerangeService type +type mockPitrTimerangeService struct { + mock.Mock +} + +// ListPITRTimeranges provides a mock function with given fields: ctx, artifactName, location +func (_m *mockPitrTimerangeService) ListPITRTimeranges(ctx context.Context, artifactName string, location *models.BackupLocation) ([]backup.Timeline, error) { + ret := _m.Called(ctx, artifactName, location) + + var r0 []backup.Timeline + if rf, ok := ret.Get(0).(func(context.Context, string, *models.BackupLocation) []backup.Timeline); ok { + r0 = rf(ctx, artifactName, location) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]backup.Timeline) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, *models.BackupLocation) error); ok { + r1 = rf(ctx, artifactName, location) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/managed/services/management/backup/restore_history_service.go b/managed/services/management/backup/restore_history_service.go index 64d9ed616e..75d3a93c97 100644 --- a/managed/services/management/backup/restore_history_service.go +++ b/managed/services/management/backup/restore_history_service.go @@ -24,7 +24,7 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/reform.v1" - backupv1beta1 "github.com/percona/pmm/api/managementpb/backup" + backuppb "github.com/percona/pmm/api/managementpb/backup" "github.com/percona/pmm/managed/models" ) @@ -33,7 +33,7 @@ type RestoreHistoryService struct { l *logrus.Entry db *reform.DB - backupv1beta1.UnimplementedRestoreHistoryServer + backuppb.UnimplementedRestoreHistoryServer } // NewRestoreHistoryService creates new restore history API service. @@ -57,8 +57,8 @@ func (s *RestoreHistoryService) Enabled() bool { // ListRestoreHistory returns a list of restore history. func (s *RestoreHistoryService) ListRestoreHistory( context.Context, - *backupv1beta1.ListRestoreHistoryRequest, -) (*backupv1beta1.ListRestoreHistoryResponse, error) { + *backuppb.ListRestoreHistoryRequest, +) (*backuppb.ListRestoreHistoryResponse, error) { var items []*models.RestoreHistoryItem var services map[string]*models.Service var artifacts map[string]*models.Artifact @@ -104,7 +104,7 @@ func (s *RestoreHistoryService) ListRestoreHistory( return nil, err } - artifactsResponse := make([]*backupv1beta1.RestoreHistoryItem, 0, len(artifacts)) + artifactsResponse := make([]*backuppb.RestoreHistoryItem, 0, len(artifacts)) for _, i := range items { convertedArtifact, err := convertRestoreHistoryItem(i, services, artifacts, locationModels) if err != nil { @@ -113,20 +113,20 @@ func (s *RestoreHistoryService) ListRestoreHistory( artifactsResponse = append(artifactsResponse, convertedArtifact) } - return &backupv1beta1.ListRestoreHistoryResponse{ + return &backuppb.ListRestoreHistoryResponse{ Items: artifactsResponse, }, nil } -func convertRestoreStatus(status models.RestoreStatus) (*backupv1beta1.RestoreStatus, error) { - var s backupv1beta1.RestoreStatus +func convertRestoreStatus(status models.RestoreStatus) (*backuppb.RestoreStatus, error) { + var s backuppb.RestoreStatus switch status { case models.InProgressRestoreStatus: - s = backupv1beta1.RestoreStatus_RESTORE_STATUS_IN_PROGRESS + s = backuppb.RestoreStatus_RESTORE_STATUS_IN_PROGRESS case models.SuccessRestoreStatus: - s = backupv1beta1.RestoreStatus_RESTORE_STATUS_SUCCESS + s = backuppb.RestoreStatus_RESTORE_STATUS_SUCCESS case models.ErrorRestoreStatus: - s = backupv1beta1.RestoreStatus_RESTORE_STATUS_ERROR + s = backuppb.RestoreStatus_RESTORE_STATUS_ERROR default: return nil, errors.Errorf("invalid status '%s'", status) } @@ -140,7 +140,7 @@ func convertRestoreHistoryItem( services map[string]*models.Service, artifacts map[string]*models.Artifact, locations map[string]*models.BackupLocation, -) (*backupv1beta1.RestoreHistoryItem, error) { +) (*backuppb.RestoreHistoryItem, error) { startedAt := timestamppb.New(i.StartedAt) if err := startedAt.CheckValid(); err != nil { return nil, errors.Wrap(err, "failed to convert startedAt timestamp") @@ -183,7 +183,7 @@ func convertRestoreHistoryItem( return nil, errors.Wrapf(err, "restore history item id '%s'", i.ID) } - return &backupv1beta1.RestoreHistoryItem{ + return &backuppb.RestoreHistoryItem{ RestoreId: i.ID, ArtifactId: i.ArtifactID, Name: artifact.Name, @@ -201,5 +201,5 @@ func convertRestoreHistoryItem( // Check interfaces. var ( - _ backupv1beta1.RestoreHistoryServer = (*RestoreHistoryService)(nil) + _ backuppb.RestoreHistoryServer = (*RestoreHistoryService)(nil) ) diff --git a/managed/services/minio/client.go b/managed/services/minio/client.go new file mode 100644 index 0000000000..a508132c4a --- /dev/null +++ b/managed/services/minio/client.go @@ -0,0 +1,211 @@ +// Copyright (C) 2017 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Package minio provides implementation for Minio operations. +package minio + +import ( + "context" + "strings" + + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" + + "github.com/percona/pmm/managed/models" +) + +// Client is a wrapper around minio.Client. +type Client struct { + l *logrus.Entry +} + +// New creates a new minio client. +func New() *Client { + return &Client{ + l: logrus.WithField("component", "minio-client"), + } +} + +// FileInfo contains information about a single file in the bucket. +type FileInfo struct { + // Name is the absolute object name (with path included) + Name string + // Size is the size of the object + Size int64 + // IsDeleteMarker specifies if the object is marked for deletion + IsDeleteMarker bool +} + +// BucketExists return true if bucket can be accessed with provided credentials and exists. +func (c *Client) BucketExists(ctx context.Context, endpoint, accessKey, secretKey, bucketName string) (bool, error) { + mc, err := createMinioClient(endpoint, accessKey, secretKey) + if err != nil { + return false, err + } + return mc.BucketExists(ctx, bucketName) +} + +// GetBucketLocation retrieves bucket location by specified bucket name. +func (c *Client) GetBucketLocation(ctx context.Context, endpoint, accessKey, secretKey, bucketName string) (string, error) { + mc, err := createMinioClient(endpoint, accessKey, secretKey) + if err != nil { + return "", err + } + return mc.GetBucketLocation(ctx, bucketName) +} + +// RemoveRecursive removes objects recursively from storage with given prefix. +func (c *Client) RemoveRecursive(ctx context.Context, endpoint, accessKey, secretKey, bucketName, prefix string) (rerr error) { + mc, err := createMinioClient(endpoint, accessKey, secretKey) + if err != nil { + return err + } + + objectsCh := make(chan minio.ObjectInfo) + var g errgroup.Group + g.Go(func() error { + defer close(objectsCh) + + options := minio.ListObjectsOptions{ //nolint:exhaustruct + Prefix: prefix, + Recursive: true, + } + for object := range mc.ListObjects(ctx, bucketName, options) { + if object.Err != nil { + return errors.WithStack(object.Err) + } + + objectsCh <- object + } + + return nil + }) + + defer func() { + err := g.Wait() + if err == nil { + return + } + + if rerr != nil { + rerr = errors.Wrapf(rerr, "listing objects error: %s", err.Error()) + } else { + rerr = errors.WithStack(err) + } + }() + + var errorsEncountered bool + for rErr := range mc.RemoveObjects(ctx, bucketName, objectsCh, minio.RemoveObjectsOptions{}) { //nolint:exhaustruct + errorsEncountered = true + c.l.WithError(rErr.Err).Debugf("failed to remove object %q", rErr.ObjectName) + } + + if errorsEncountered { + return errors.Errorf("errors encountered while removing objects from bucket %q", bucketName) + } + + return nil +} + +// List is a wrapper over the minio API to list all objects in the bucket. +// It scans path with prefix and returns all files with given suffix. +// Both prefix and suffix can be omitted. +func (c *Client) List(ctx context.Context, endpoint, accessKey, secretKey, bucketName, prefix, suffix string) ([]FileInfo, error) { + var files []FileInfo + if prefix != "" && !strings.HasSuffix(prefix, "/") { + prefix += "/" + } + mc, err := createMinioClient(endpoint, accessKey, secretKey) + if err != nil { + return nil, err + } + + options := minio.ListObjectsOptions{ + Prefix: prefix, + Recursive: true, + } + + for object := range mc.ListObjects(ctx, bucketName, options) { + if object.Err != nil { + return nil, errors.WithStack(object.Err) + } + filename := object.Key + filename = strings.TrimPrefix(filename, options.Prefix) + if len(filename) == 0 { + continue + } + if filename[0] == '/' { + filename = filename[1:] + } + + if strings.HasSuffix(filename, suffix) { + files = append(files, FileInfo{ + Name: filename, + Size: object.Size, + IsDeleteMarker: object.IsDeleteMarker, + }) + } + } + + return files, nil +} + +// FileStat returns file info. It returns error if file is empty or not exists. +func (c *Client) FileStat(ctx context.Context, endpoint, accessKey, secretKey, bucketName, name string) (FileInfo, error) { + var file FileInfo + mc, err := createMinioClient(endpoint, accessKey, secretKey) + if err != nil { + return file, err + } + + stat, err := mc.StatObject(ctx, bucketName, name, minio.StatObjectOptions{}) //nolint:exhaustruct + if err != nil { + return file, err + } + + if stat.IsDeleteMarker { + return file, errors.New("file has delete marker") + } + + file.Name = name + file.Size = stat.Size + file.IsDeleteMarker = stat.IsDeleteMarker + + if file.Size == 0 { + return file, errors.New("file is empty") + } + + return file, nil +} + +func createMinioClient(endpoint, accessKey, secretKey string) (*minio.Client, error) { + url, err := models.ParseEndpoint(endpoint) + if err != nil { + return nil, err + } + + secure := true + if url.Scheme == "http" { + secure = false + } + + return minio.New(url.Host, &minio.Options{ + Secure: secure, + Creds: credentials.NewStaticV4(accessKey, secretKey, ""), + }) +} diff --git a/managed/services/minio/service.go b/managed/services/minio/service.go deleted file mode 100644 index 05bd772133..0000000000 --- a/managed/services/minio/service.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (C) 2017 Percona LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -// Package minio provides implementation for Minio operations. -package minio - -import ( - "context" - - "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "golang.org/x/sync/errgroup" - - "github.com/percona/pmm/managed/models" -) - -// Service is wrapper around minio client. -type Service struct { - l *logrus.Entry -} - -// New creates new minio service. -func New() *Service { - return &Service{ - l: logrus.WithField("component", "minio-client"), - } -} - -// BucketExists return true if bucket can be accessed with provided credentials and exists. -func (s *Service) BucketExists(ctx context.Context, endpoint, accessKey, secretKey, name string) (bool, error) { - minioClient, err := newClient(endpoint, accessKey, secretKey) - if err != nil { - return false, err - } - return minioClient.BucketExists(ctx, name) -} - -// GetBucketLocation retrieves bucket location by specified bucket name. -func (s *Service) GetBucketLocation(ctx context.Context, endpoint, accessKey, secretKey, name string) (string, error) { - minioClient, err := newClient(endpoint, accessKey, secretKey) - if err != nil { - return "", err - } - return minioClient.GetBucketLocation(ctx, name) -} - -// RemoveRecursive removes objects recursively from storage with given prefix. -func (s *Service) RemoveRecursive(ctx context.Context, endpoint, accessKey, secretKey, bucketName, prefix string) (rerr error) { - minioClient, err := newClient(endpoint, accessKey, secretKey) - if err != nil { - return err - } - - objectsCh := make(chan minio.ObjectInfo) - var g errgroup.Group - g.Go(func() error { - defer close(objectsCh) - - options := minio.ListObjectsOptions{ - Prefix: prefix, - Recursive: true, - } - for object := range minioClient.ListObjects(ctx, bucketName, options) { - if object.Err != nil { - return errors.WithStack(object.Err) - } - - objectsCh <- object - } - - return nil - }) - - defer func() { - err := g.Wait() - if err == nil { - return - } - - if rerr != nil { - rerr = errors.Wrapf(rerr, "listing objects error: %s", err.Error()) - } else { - rerr = errors.WithStack(err) - } - }() - - var errorsEncountered bool - for rErr := range minioClient.RemoveObjects(ctx, bucketName, objectsCh, minio.RemoveObjectsOptions{}) { - errorsEncountered = true - s.l.WithError(rErr.Err).Debugf("failed to remove object %q", rErr.ObjectName) - } - - if errorsEncountered { - return errors.Errorf("errors encountered while removing objects from bucket %q", bucketName) - } - - return nil -} - -func newClient(endpoint, accessKey, secretKey string) (*minio.Client, error) { - url, err := models.ParseEndpoint(endpoint) - if err != nil { - return nil, err - } - - secure := true - if url.Scheme == "http" { - secure = false - } - - return minio.New(url.Host, &minio.Options{ - Secure: secure, - Creds: credentials.NewStaticV4(accessKey, secretKey, ""), - }) -}