From d5089e621f679c511ca4738fdd67a606465f3adc Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 30 Jun 2026 11:47:01 +0800 Subject: [PATCH 01/45] fix contest of nodeAgentCheck when restorer is called concurrently Signed-off-by: Lyndon-Li --- pkg/podvolume/restorer.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/podvolume/restorer.go b/pkg/podvolume/restorer.go index bac22298e..cd6533ac5 100644 --- a/pkg/podvolume/restorer.go +++ b/pkg/podvolume/restorer.go @@ -63,10 +63,9 @@ type restorer struct { kubeClient kubernetes.Interface crClient ctrlclient.Client - resultsLock sync.Mutex - results map[string]chan *velerov1api.PodVolumeRestore - nodeAgentCheck chan error - log logrus.FieldLogger + resultsLock sync.Mutex + results map[string]chan *velerov1api.PodVolumeRestore + log logrus.FieldLogger } func newRestorer( @@ -153,7 +152,7 @@ func (r *restorer) RestorePodVolumes(data RestoreData, tracker *volume.RestoreVo r.results[resultsKey(data.Pod.Namespace, data.Pod.Name)] = resultsChan r.resultsLock.Unlock() - r.nodeAgentCheck = make(chan error) + nodeAgentCheck := make(chan error) var ( errs []error @@ -217,7 +216,7 @@ func (r *restorer) RestorePodVolumes(data RestoreData, tracker *volume.RestoreVo err = nodeagent.IsRunningInNode(checkCtx, data.Restore.Namespace, nodeName, r.crClient) if err != nil { r.log.WithField("node", nodeName).WithError(err).Error("node-agent pod is not running in node, abort the restore") - r.nodeAgentCheck <- errors.Wrapf(err, "node-agent pod is not running in node %s", nodeName) + nodeAgentCheck <- errors.Wrapf(err, "node-agent pod is not running in node %s", nodeName) } } }() @@ -235,7 +234,7 @@ ForEachVolume: errs = append(errs, errors.Errorf("pod volume restore canceled: %s", res.Status.Message)) } tracker.TrackPodVolume(res) - case err := <-r.nodeAgentCheck: + case err := <-nodeAgentCheck: errs = append(errs, err) break ForEachVolume } From 0f86521735cb98ee5f8cd71ffee6cd14a9ac7caa Mon Sep 17 00:00:00 2001 From: chlins Date: Wed, 29 Jul 2026 13:43:52 +0800 Subject: [PATCH 02/45] Verify extracted item paths stay inside the backup directory archive.GetItemFilePath/GetVersionedItemFilePath joined the group resource, namespace and name into a path without checking the result against rootDir. Those components can come from backup contents - the additional items a RestoreItemAction returns are built from annotations on a backed up object - so a component containing ".." resolved to an arbitrary file on the Velero pod, which was then Stat'd, unmarshalled and restored as a Kubernetes object. Both helpers now return an error when the joined path escapes rootDir, and all callers handle it. rootDir is empty when building an entry path inside the backup tarball, so "." is used as the containment base for that relative form. Signed-off-by: chlins --- changelogs/unreleased/10102-chlins | 1 + internal/delete/delete_item_action_handler.go | 5 +- pkg/archive/filesystem.go | 32 ++++++- pkg/archive/filesystem_test.go | 89 +++++++++++++++++-- pkg/backup/item_backupper.go | 22 +++-- pkg/restore/restore.go | 50 ++++++++--- 6 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 changelogs/unreleased/10102-chlins diff --git a/changelogs/unreleased/10102-chlins b/changelogs/unreleased/10102-chlins new file mode 100644 index 000000000..70b4b5c44 --- /dev/null +++ b/changelogs/unreleased/10102-chlins @@ -0,0 +1 @@ +Verify extracted item paths stay inside the backup directory diff --git a/internal/delete/delete_item_action_handler.go b/internal/delete/delete_item_action_handler.go index 2a16044ee..89a638331 100644 --- a/internal/delete/delete_item_action_handler.go +++ b/internal/delete/delete_item_action_handler.go @@ -114,7 +114,10 @@ func InvokeDeleteActions(ctx *Context) error { // Process individual items from the backup for _, item := range items { - itemPath := archive.GetItemFilePath(dir, resource, namespace, item) + itemPath, err := archive.GetItemFilePath(dir, resource, namespace, item) + if err != nil { + return errors.Wrapf(err, "could not build item path: %v", item) + } // obj is the Unstructured item from the backup obj, err := archive.Unmarshal(ctx.Filesystem, itemPath) diff --git a/pkg/archive/filesystem.go b/pkg/archive/filesystem.go index 73b0d1dcf..310ab64dc 100644 --- a/pkg/archive/filesystem.go +++ b/pkg/archive/filesystem.go @@ -19,7 +19,9 @@ package archive import ( "encoding/json" "path/filepath" + "strings" + "github.com/cockroachdb/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" @@ -27,13 +29,37 @@ import ( ) // GetItemFilePath returns an item's file path once extracted from a Velero backup archive. -func GetItemFilePath(rootDir, groupResource, namespace, name string) string { +func GetItemFilePath(rootDir, groupResource, namespace, name string) (string, error) { return GetVersionedItemFilePath(rootDir, groupResource, namespace, name, "") } // GetVersionedItemFilePath returns an item's file path once extracted from a Velero backup archive, with version included. -func GetVersionedItemFilePath(rootDir, groupResource, namespace, name, versionPath string) string { - return filepath.Join(rootDir, velerov1api.ResourcesDir, groupResource, versionPath, GetScopeDir(namespace), namespace, name+".json") +// +// The namespace and name components can originate from backup contents - for example the +// additional items a RestoreItemAction returns are built from annotations on a backed up +// object - so the joined path is verified to stay within rootDir. Without that check a +// component containing ".." escapes the extracted backup directory and addresses an +// arbitrary file on the Velero pod's filesystem. +func GetVersionedItemFilePath(rootDir, groupResource, namespace, name, versionPath string) (string, error) { + path := filepath.Join(rootDir, velerov1api.ResourcesDir, groupResource, versionPath, GetScopeDir(namespace), namespace, name+".json") + + // rootDir is empty when building the path of an entry inside the backup tarball rather + // than of an extracted file on disk; "." is the containment base for that relative form. + base := rootDir + if base == "" { + base = "." + } + + rel, err := filepath.Rel(base, path) + if err != nil { + return "", errors.Wrapf(err, "error resolving item path for %q/%q", namespace, name) + } + + if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { + return "", errors.Errorf("invalid item path for %q/%q: escapes the backup directory", namespace, name) + } + + return path, nil } // GetScopeDir returns NamespaceScopedDir if namespace is present, or ClusterScopedDir if empty diff --git a/pkg/archive/filesystem_test.go b/pkg/archive/filesystem_test.go index bf7f16c76..c6225ff85 100644 --- a/pkg/archive/filesystem_test.go +++ b/pkg/archive/filesystem_test.go @@ -27,31 +27,104 @@ import ( ) func TestGetItemFilePath(t *testing.T) { - res := GetItemFilePath("root", "resource", "", "item") + res, err := GetItemFilePath("root", "resource", "", "item") + require.NoError(t, err) assert.Equal(t, "root/resources/resource/cluster/item.json", res) - res = GetItemFilePath("root", "resource", "namespace", "item") + res, err = GetItemFilePath("root", "resource", "namespace", "item") + require.NoError(t, err) assert.Equal(t, "root/resources/resource/namespaces/namespace/item.json", res) - res = GetItemFilePath("", "resource", "", "item") + res, err = GetItemFilePath("", "resource", "", "item") + require.NoError(t, err) assert.Equal(t, "resources/resource/cluster/item.json", res) - res = GetVersionedItemFilePath("root", "resource", "", "item", "") + res, err = GetVersionedItemFilePath("root", "resource", "", "item", "") + require.NoError(t, err) assert.Equal(t, "root/resources/resource/cluster/item.json", res) - res = GetVersionedItemFilePath("root", "resource", "namespace", "item", "") + res, err = GetVersionedItemFilePath("root", "resource", "namespace", "item", "") + require.NoError(t, err) assert.Equal(t, "root/resources/resource/namespaces/namespace/item.json", res) - res = GetVersionedItemFilePath("root", "resource", "namespace", "item", "v1") + res, err = GetVersionedItemFilePath("root", "resource", "namespace", "item", "v1") + require.NoError(t, err) assert.Equal(t, "root/resources/resource/v1/namespaces/namespace/item.json", res) - res = GetVersionedItemFilePath("root", "resource", "", "item", "v1") + res, err = GetVersionedItemFilePath("root", "resource", "", "item", "v1") + require.NoError(t, err) assert.Equal(t, "root/resources/resource/v1/cluster/item.json", res) - res = GetVersionedItemFilePath("", "resource", "", "item", "") + res, err = GetVersionedItemFilePath("", "resource", "", "item", "") + require.NoError(t, err) assert.Equal(t, "resources/resource/cluster/item.json", res) } +// TestGetItemFilePathRejectsPathTraversal verifies that a name or namespace containing +// ".." cannot address a file outside the extracted backup directory. These components can +// come from backup contents, for example the additional items a RestoreItemAction builds +// from annotations on a backed up object. +func TestGetItemFilePathRejectsPathTraversal(t *testing.T) { + tests := []struct { + name string + rootDir string + groupResource string + namespace string + itemName string + }{ + { + name: "traversal in name escapes root", + rootDir: "/tmp/restore-dir", + groupResource: "secrets", + namespace: "x", + itemName: "../../../../../../root/.docker/config", + }, + { + name: "traversal in namespace escapes root", + rootDir: "/tmp/restore-dir", + groupResource: "secrets", + namespace: "../../../../../../etc", + itemName: "passwd", + }, + { + name: "traversal in group resource escapes root", + rootDir: "/tmp/restore-dir", + groupResource: "../../../../../../etc", + namespace: "", + itemName: "passwd", + }, + { + name: "traversal escapes archive-relative root", + rootDir: "", + groupResource: "secrets", + namespace: "x", + itemName: "../../../../../../escape", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + res, err := GetItemFilePath(tc.rootDir, tc.groupResource, tc.namespace, tc.itemName) + require.Error(t, err) + assert.Contains(t, err.Error(), "escapes the backup directory") + assert.Empty(t, res) + + res, err = GetVersionedItemFilePath(tc.rootDir, tc.groupResource, tc.namespace, tc.itemName, "v1") + require.Error(t, err) + assert.Contains(t, err.Error(), "escapes the backup directory") + assert.Empty(t, res) + }) + } +} + +// TestGetItemFilePathAllowsInnerDotDot verifies the containment check does not reject a +// path whose ".." segments resolve back inside the root directory. +func TestGetItemFilePathAllowsInnerDotDot(t *testing.T) { + res, err := GetItemFilePath("root", "resource", "namespaces/..", "item") + require.NoError(t, err) + assert.Equal(t, "root/resources/resource/namespaces/item.json", res) +} + func TestGetScopeDir(t *testing.T) { res := GetScopeDir("") assert.Equal(t, velerov1api.ClusterScopedDir, res) diff --git a/pkg/backup/item_backupper.go b/pkg/backup/item_backupper.go index f43888252..c180092a5 100644 --- a/pkg/backup/item_backupper.go +++ b/pkg/backup/item_backupper.go @@ -351,16 +351,28 @@ func (ib *itemBackupper) backupItemInternal(logger logrus.FieldLogger, obj runti if versionPath == preferredGVR.Version { // backing up preferred version backup without API Group version - for backward compatibility log.Debugf("Resource %s/%s, version= %s, preferredVersion=%s", groupResource.String(), name, versionPath, preferredGVR.Version) - itemFiles = append(itemFiles, getFileForArchive(namespace, name, groupResource.String(), "", itemBytes)) + fileForArchive, err := getFileForArchive(namespace, name, groupResource.String(), "", itemBytes) + if err != nil { + return false, itemFiles, err + } + itemFiles = append(itemFiles, fileForArchive) versionPath = versionPath + velerov1api.PreferredVersionDir } - itemFiles = append(itemFiles, getFileForArchive(namespace, name, groupResource.String(), versionPath, itemBytes)) + fileForArchive, err := getFileForArchive(namespace, name, groupResource.String(), versionPath, itemBytes) + if err != nil { + return false, itemFiles, err + } + itemFiles = append(itemFiles, fileForArchive) return true, itemFiles, nil } -func getFileForArchive(namespace, name, groupResource, versionPath string, itemBytes []byte) FileForArchive { - filePath := archive.GetVersionedItemFilePath("", groupResource, namespace, name, versionPath) +func getFileForArchive(namespace, name, groupResource, versionPath string, itemBytes []byte) (FileForArchive, error) { + filePath, err := archive.GetVersionedItemFilePath("", groupResource, namespace, name, versionPath) + if err != nil { + return FileForArchive{}, err + } + hdr := &tar.Header{ Name: filePath, Size: int64(len(itemBytes)), @@ -368,7 +380,7 @@ func getFileForArchive(namespace, name, groupResource, versionPath string, itemB Mode: 0755, ModTime: time.Now(), } - return FileForArchive{FilePath: filePath, Header: hdr, FileBytes: itemBytes} + return FileForArchive{FilePath: filePath, Header: hdr, FileBytes: itemBytes}, nil } // backupPodVolumes triggers pod volume backups of the specified pod volumes, and returns a list of PodVolumeBackups diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index e7a284fb1..336add4de 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -1011,11 +1011,13 @@ func (ctx *restoreContext) processSelectedResource( if namespace != "" && !existingNamespaces.Has(targetNS) { logger := ctx.log.WithField("namespace", namespace) - ns := getNamespace( - logger, - archive.GetItemFilePath(ctx.restoreDir, "namespaces", "", namespace), - targetNS, - ) + nsPath, err := archive.GetItemFilePath(ctx.restoreDir, "namespaces", "", namespace) + if err != nil { + errs.AddVeleroError(err) + continue + } + + ns := getNamespace(logger, nsPath, targetNS) _, nsCreated, err := kube.EnsureNamespaceExistsAndIsReady( ns, ctx.namespaceClient, @@ -1440,7 +1442,13 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso // If the namespace scoped resource should be restored, ensure that the // namespace into which the resource is being restored into exists. // This is the *remapped* namespace that we are ensuring exists. - nsToEnsure := getNamespace(restoreLogger, archive.GetItemFilePath(ctx.restoreDir, "namespaces", "", obj.GetNamespace()), namespace) + nsPath, err := archive.GetItemFilePath(ctx.restoreDir, "namespaces", "", obj.GetNamespace()) + if err != nil { + errs.AddVeleroError(err) + return warnings, errs, itemExists + } + + nsToEnsure := getNamespace(restoreLogger, nsPath, namespace) _, nsCreated, err := kube.EnsureNamespaceExistsAndIsReady(nsToEnsure, ctx.namespaceClient, ctx.resourceTerminatingTimeout, ctx.resourceDeletionStatusTracker) if err != nil { errs.AddVeleroError(err) @@ -1693,7 +1701,17 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso var filteredAdditionalItems []velero.ResourceIdentifier for _, additionalItem := range executeOutput.AdditionalItems { - itemPath := archive.GetItemFilePath(ctx.restoreDir, additionalItem.GroupResource.String(), additionalItem.Namespace, additionalItem.Name) + itemPath, err := archive.GetItemFilePath(ctx.restoreDir, additionalItem.GroupResource.String(), additionalItem.Namespace, additionalItem.Name) + if err != nil { + restoreLogger.WithError(err).WithFields(logrus.Fields{ + "additionalResource": additionalItem.GroupResource.String(), + "additionalResourceNamespace": additionalItem.Namespace, + "additionalResourceName": additionalItem.Name, + }).Warn("unable to restore additional item") + warnings.Add(additionalItem.Namespace, err) + + continue + } if _, err := ctx.fileSystem.Stat(itemPath); err != nil { restoreLogger.WithError(err).WithFields(logrus.Fields{ @@ -2671,9 +2689,9 @@ func (ctx *restoreContext) getSelectedRestoreableItems(resource string, original // Peek-and-map logic for unresolvable kinds if rf == nil && len(items) > 0 { - peekPath := archive.GetItemFilePath(ctx.restoreDir, resourceForPath, originalNamespace, items[0]) - // Ignore unmarshal errors during peek; the main restore loop will catch and report them - if obj, err := archive.Unmarshal(ctx.fileSystem, peekPath); err == nil { + peekPath, pathErr := archive.GetItemFilePath(ctx.restoreDir, resourceForPath, originalNamespace, items[0]) + // Ignore path and unmarshal errors during peek; the main restore loop will catch and report them + if obj, err := archive.Unmarshal(ctx.fileSystem, peekPath); pathErr == nil && err == nil { actualKind := obj.GroupVersionKind().Kind for _, filter := range nsFilter.resourceFilterMap { for _, k := range filter.originalKinds { @@ -2714,9 +2732,9 @@ func (ctx *restoreContext) getSelectedRestoreableItems(resource string, original // Note: Unlike the namespaced path, this fallback is always reachable // because the main restore loop does not have a fast-path skip for // unlisted cluster-scoped resources. - peekPath := archive.GetItemFilePath(ctx.restoreDir, resourceForPath, originalNamespace, items[0]) - // Ignore unmarshal errors during peek; the main restore loop will catch and report them - if obj, err := archive.Unmarshal(ctx.fileSystem, peekPath); err == nil { + peekPath, pathErr := archive.GetItemFilePath(ctx.restoreDir, resourceForPath, originalNamespace, items[0]) + // Ignore path and unmarshal errors during peek; the main restore loop will catch and report them + if obj, err := archive.Unmarshal(ctx.fileSystem, peekPath); pathErr == nil && err == nil { actualKind := obj.GroupVersionKind().Kind for _, filter := range ctx.clusterScopedFilterMap { for _, k := range filter.originalKinds { @@ -2742,7 +2760,11 @@ func (ctx *restoreContext) getSelectedRestoreableItems(resource string, original } for _, item := range items { - itemPath := archive.GetItemFilePath(ctx.restoreDir, resourceForPath, originalNamespace, item) + itemPath, err := archive.GetItemFilePath(ctx.restoreDir, resourceForPath, originalNamespace, item) + if err != nil { + errs.Add(targetNamespace, err) + continue + } obj, err := archive.Unmarshal(ctx.fileSystem, itemPath) if err != nil { From 4220c7abe8ac9c6e424811ef3b38a7ee14b0986d Mon Sep 17 00:00:00 2001 From: chlins Date: Thu, 30 Jul 2026 16:37:18 +0800 Subject: [PATCH 03/45] Cancel hook exec stream on timeout and bound hook timeouts Hook timeouts come from pod annotations via time.ParseDuration, which accepts negative and arbitrarily large values, and the exec stream was never cancelled. Signed-off-by: chlins --- changelogs/unreleased/10125-chlins | 1 + pkg/podexec/pod_command_executor.go | 39 +++-- pkg/podexec/pod_command_executor_test.go | 18 +++ .../pod_command_executor_timeout_test.go | 136 ++++++++++++++++++ 4 files changed, 182 insertions(+), 12 deletions(-) create mode 100644 changelogs/unreleased/10125-chlins create mode 100644 pkg/podexec/pod_command_executor_timeout_test.go diff --git a/changelogs/unreleased/10125-chlins b/changelogs/unreleased/10125-chlins new file mode 100644 index 000000000..1a1b00371 --- /dev/null +++ b/changelogs/unreleased/10125-chlins @@ -0,0 +1 @@ +Cancel hook exec stream on timeout and bound hook timeouts diff --git a/pkg/podexec/pod_command_executor.go b/pkg/podexec/pod_command_executor.go index 4ba4d4dc9..71894a489 100644 --- a/pkg/podexec/pod_command_executor.go +++ b/pkg/podexec/pod_command_executor.go @@ -36,6 +36,10 @@ import ( const defaultTimeout = 30 * time.Second +// maxHookTimeout bounds a user-supplied hook timeout, which can come from a pod +// annotation, so a single hook cannot hold up a backup for an unbounded time. +const maxHookTimeout = 4 * time.Hour + // PodCommandExecutor is capable of executing a command in a container in a pod. type PodCommandExecutor interface { // ExecutePodCommand executes a command in a container in a pod. If the command takes longer than @@ -112,9 +116,15 @@ func (e *defaultPodCommandExecutor) ExecutePodCommand(log logrus.FieldLogger, it localHook.OnError = api.HookErrorModeFail } - if localHook.Timeout.Duration == 0 { + // A non-positive timeout is not a valid bound. Timeouts sourced from pod annotations are + // parsed with time.ParseDuration, which accepts negative values, and a negative duration + // would otherwise leave the hook without any timeout at all. + if localHook.Timeout.Duration <= 0 { localHook.Timeout.Duration = defaultTimeout } + if localHook.Timeout.Duration > maxHookTimeout { + localHook.Timeout.Duration = maxHookTimeout + } hookLog := log.WithFields( logrus.Fields{ @@ -158,23 +168,28 @@ func (e *defaultPodCommandExecutor) ExecutePodCommand(log logrus.FieldLogger, it Stderr: &stderr, } - errCh := make(chan error) + // The timeout drives the context so the exec stream is actually cancelled, rather than + // being left running on the API server after this function has returned. + ctx, cancel := context.WithTimeout(context.Background(), localHook.Timeout.Duration) + defer cancel() + + // Buffered so the goroutine below can always send its result and exit, even when this + // function has already returned on the timeout path. + errCh := make(chan error, 1) go func() { - err = executor.StreamWithContext(context.Background(), streamOptions) - errCh <- err + errCh <- executor.StreamWithContext(ctx, streamOptions) }() - var timeoutCh <-chan time.Time - if localHook.Timeout.Duration > 0 { - timer := time.NewTimer(localHook.Timeout.Duration) - defer timer.Stop() - timeoutCh = timer.C - } - select { case err = <-errCh: - case <-timeoutCh: + // On a timeout the stream returns because the context expired, so both this case + // and ctx.Done() are ready and the select picks one at random. Report the timeout + // either way instead of surfacing the context error only some of the time. + if errors.Is(ctx.Err(), context.DeadlineExceeded) { + return errors.Errorf("timed out after %v", localHook.Timeout.Duration) + } + case <-ctx.Done(): return errors.Errorf("timed out after %v", localHook.Timeout.Duration) } diff --git a/pkg/podexec/pod_command_executor_test.go b/pkg/podexec/pod_command_executor_test.go index 13b00877a..de32fc605 100644 --- a/pkg/podexec/pod_command_executor_test.go +++ b/pkg/podexec/pod_command_executor_test.go @@ -177,6 +177,24 @@ func TestExecutePodCommand(t *testing.T) { hookError: errors.New("hook error"), expectedError: "hook error", }, + { + // Timeouts from pod annotations go through time.ParseDuration, which accepts + // negative values. Without clamping, the hook would run with no timeout at all. + name: "negative timeout falls back to the default", + command: []string{"some", "command"}, + expectedContainerName: "foo", + expectedErrorMode: v1.HookErrorModeFail, + timeout: -1 * time.Second, + expectedTimeout: 30 * time.Second, + }, + { + name: "timeout above the maximum is capped", + command: []string{"some", "command"}, + expectedContainerName: "foo", + expectedErrorMode: v1.HookErrorModeFail, + timeout: 100000 * time.Hour, + expectedTimeout: maxHookTimeout, + }, } for _, test := range tests { diff --git a/pkg/podexec/pod_command_executor_timeout_test.go b/pkg/podexec/pod_command_executor_timeout_test.go new file mode 100644 index 000000000..88cb3ed92 --- /dev/null +++ b/pkg/podexec/pod_command_executor_timeout_test.go @@ -0,0 +1,136 @@ +package podexec + +import ( + "context" + "net/url" + "runtime" + "testing" + "time" + + "github.com/stretchr/testify/mock" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/remotecommand" + + v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + velerotest "github.com/vmware-tanzu/velero/pkg/test" +) + +const timeoutTestPodJSON = `{ + "metadata": {"namespace": "ns", "name": "pod-1"}, + "spec": {"containers": [{"name": "container-1"}]} +}` + +// contextAwareExecutor returns once its context is cancelled, like the SPDY executor does. +type contextAwareExecutor struct { + cancelled chan struct{} + cancelledOnce bool +} + +func (e *contextAwareExecutor) Stream(options remotecommand.StreamOptions) error { return nil } + +func (e *contextAwareExecutor) StreamWithContext(ctx context.Context, options remotecommand.StreamOptions) error { + <-ctx.Done() + if !e.cancelledOnce { + e.cancelledOnce = true + close(e.cancelled) + } + return ctx.Err() +} + +func newTimeoutTestExecutor(t *testing.T, exec remotecommand.Executor) (*defaultPodCommandExecutor, map[string]any) { + t.Helper() + + clientConfig := &rest.Config{} + poster := &mockPoster{} + podCommandExecutor := NewPodCommandExecutor(clientConfig, poster).(*defaultPodCommandExecutor) + + factory := &mockStreamExecutorFactory{} + podCommandExecutor.streamExecutorFactory = factory + + baseURL, _ := url.Parse("https://some.server") + contentConfig := rest.ClientContentConfig{GroupVersion: schema.GroupVersion{Group: "", Version: "v1"}} + poster.On("Post").Return(rest.NewRequestWithClient(baseURL, "/api/v1", contentConfig, nil)) + factory.On("NewSPDYExecutor", clientConfig, "POST", mock.Anything).Return(exec, nil) + + pod, err := velerotest.GetAsMap(timeoutTestPodJSON) + if err != nil { + t.Fatal(err) + } + + return podCommandExecutor, pod +} + +func timeoutTestHook(timeout time.Duration) *v1.ExecHook { + return &v1.ExecHook{ + Container: "container-1", + Command: []string{"sh", "-c", "sleep 60"}, + Timeout: metav1.Duration{Duration: timeout}, + } +} + +// A hook that times out must have its exec stream cancelled, otherwise the command keeps +// running on the API server after ExecutePodCommand has returned. +func TestExecutePodCommandCancelsStreamOnTimeout(t *testing.T) { + exec := &contextAwareExecutor{cancelled: make(chan struct{})} + podCommandExecutor, pod := newTimeoutTestExecutor(t, exec) + + err := podCommandExecutor.ExecutePodCommand(velerotest.NewLogger(), pod, "ns", "pod-1", "hookName", timeoutTestHook(100*time.Millisecond)) + if err == nil { + t.Fatal("expected a timeout error") + } + + select { + case <-exec.cancelled: + case <-time.After(2 * time.Second): + t.Fatal("stream was not cancelled after the hook timed out") + } +} + +// When the stream returns because the context expired, both select cases are ready and one +// is picked at random, so the reported error must not depend on which one wins. +func TestExecutePodCommandTimeoutErrorIsDeterministic(t *testing.T) { + const rounds = 50 + + messages := map[string]int{} + for range rounds { + exec := &contextAwareExecutor{cancelled: make(chan struct{})} + podCommandExecutor, pod := newTimeoutTestExecutor(t, exec) + + err := podCommandExecutor.ExecutePodCommand(velerotest.NewLogger(), pod, "ns", "pod-1", "hookName", timeoutTestHook(time.Millisecond)) + if err == nil { + t.Fatal("expected a timeout error") + } + messages[err.Error()]++ + } + + if len(messages) != 1 { + t.Fatalf("expected one error message, got %d: %v", len(messages), messages) + } +} + +func TestExecutePodCommandDoesNotLeakOnTimeout(t *testing.T) { + const rounds = 10 + + runtime.GC() + time.Sleep(200 * time.Millisecond) + before := runtime.NumGoroutine() + + for range rounds { + exec := &contextAwareExecutor{cancelled: make(chan struct{})} + podCommandExecutor, pod := newTimeoutTestExecutor(t, exec) + + if err := podCommandExecutor.ExecutePodCommand(velerotest.NewLogger(), pod, "ns", "pod-1", "hookName", timeoutTestHook(50*time.Millisecond)); err == nil { + t.Fatal("expected a timeout error") + } + } + + time.Sleep(time.Second) + runtime.GC() + time.Sleep(200 * time.Millisecond) + + if leaked := runtime.NumGoroutine() - before; leaked >= rounds { + t.Fatalf("%d goroutines leaked over %d timed out hooks", leaked, rounds) + } +} From 8ec4b224968693eba686cffb305781a802051f34 Mon Sep 17 00:00:00 2001 From: Jay2006sawant Date: Mon, 3 Aug 2026 09:44:00 +0530 Subject: [PATCH 04/45] fix: return errors correctly in block restore validation and BatchForget Signed-off-by: Jay2006sawant --- .../fix-error-handling-Jay2006sawant | 9 ++++ pkg/repository/provider/unified_repo.go | 2 +- pkg/repository/provider/unified_repo_test.go | 35 ++++++++++++++ pkg/uploader/block/uploader.go | 6 +-- pkg/uploader/block/uploader_test.go | 48 +++++++++++++++++++ 5 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/fix-error-handling-Jay2006sawant diff --git a/changelogs/unreleased/fix-error-handling-Jay2006sawant b/changelogs/unreleased/fix-error-handling-Jay2006sawant new file mode 100644 index 000000000..82a05f6c3 --- /dev/null +++ b/changelogs/unreleased/fix-error-handling-Jay2006sawant @@ -0,0 +1,9 @@ +fix: return errors correctly in block restore validation and BatchForget + +Block uploader Restore used errors.Wrapf with a stale nil err after +successful getSourceSize, causing size validation failures to return +(0, nil). flushZeroBlocks had the same pattern on short writes. + +BatchForget dropped delete errors when flush also failed. + +Signed-off-by: Jay2006sawant diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index bfe1a2bd9..664750c77 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -384,7 +384,7 @@ func (urp *unifiedRepoProvider) BatchForget(ctx context.Context, snapshotIDs []s err = bkRepo.Flush(ctx) if err != nil { - return []error{errors.Wrap(err, "error to flush repo")} + errs = append(errs, errors.Wrap(err, "error to flush repo")) } log.Debug("Forget snapshot complete") diff --git a/pkg/repository/provider/unified_repo_test.go b/pkg/repository/provider/unified_repo_test.go index e0e0a8b8f..2cd9bf576 100644 --- a/pkg/repository/provider/unified_repo_test.go +++ b/pkg/repository/provider/unified_repo_test.go @@ -1062,6 +1062,41 @@ func TestBatchForget(t *testing.T) { }, expectedErr: []string{"error to flush repo: fake-error-4"}, }, + { + name: "delete and flush fail", + getter: new(credmock.SecretStore), + credStoreReturn: "fake-password", + funcTable: localFuncTable{ + getStorageVariables: func(*velerov1api.BackupStorageLocation, string, string, map[string]string, velerocredentials.CredentialGetter) (map[string]string, error) { + return map[string]string{}, nil + }, + getStorageCredentials: func(*velerov1api.BackupStorageLocation, velerocredentials.FileStore) (map[string]string, error) { + return map[string]string{}, nil + }, + }, + repoService: new(reposervicenmocks.BackupRepoService), + backupRepo: new(reposervicenmocks.BackupRepo), + retFuncOpen: []any{ + func(context.Context, udmrepo.RepoOptions) udmrepo.BackupRepo { + return backupRepo + }, + + func(context.Context, udmrepo.RepoOptions) error { + return nil + }, + }, + retFuncDelete: func(context.Context, udmrepo.ID) error { + return errors.New("fake-delete-error") + }, + retFuncFlush: func(context.Context) error { + return errors.New("fake-flush-error") + }, + snapshots: []string{"snapshot-1"}, + expectedErr: []string{ + "error to delete manifest snapshot-1: fake-delete-error", + "error to flush repo: fake-flush-error", + }, + }, } for _, tc := range testCases { diff --git a/pkg/uploader/block/uploader.go b/pkg/uploader/block/uploader.go index 1d74bd462..824c0ae9f 100644 --- a/pkg/uploader/block/uploader.go +++ b/pkg/uploader/block/uploader.go @@ -169,11 +169,11 @@ func (blkup *blockUploader) Restore(snapshot udmrepo.Snapshot, dest destInfo, bi } if sourceSize > meta.SubObjects[0].Size { - return 0, errors.Wrapf(err, "unexpected size (%v vs. %v) for bdev object %s", meta.SubObjects[0].Size, sourceSize, meta.SubObjects[0].Name) + return 0, errors.Errorf("unexpected size (%v vs. %v) for bdev object %s", meta.SubObjects[0].Size, sourceSize, meta.SubObjects[0].Name) } if sourceSize > dest.size { - return 0, errors.Wrapf(err, "dest dev(%s) size is too small (%v vs. %v)", dest.path, dest.size, sourceSize) + return 0, errors.Errorf("dest dev(%s) size is too small (%v vs. %v)", dest.path, dest.size, sourceSize) } reader, err := blkup.repoWriter.OpenObject(blkup.ctx, meta.SubObjects[0].ID) @@ -616,7 +616,7 @@ func flushZeroBlocks(dest *os.File, start int64, length int64, zeroBlock []byte, } if writeSize != n { - return errors.Wrapf(err, "short write zero buffer at %v, length %v", start+written, writeSize) + return errors.Errorf("short write zero buffer at %v, length %v", start+written, writeSize) } written += int64(writeSize) diff --git a/pkg/uploader/block/uploader_test.go b/pkg/uploader/block/uploader_test.go index 1765eb045..3b8930476 100644 --- a/pkg/uploader/block/uploader_test.go +++ b/pkg/uploader/block/uploader_test.go @@ -689,4 +689,52 @@ func TestBlockUploaderRestore(t *testing.T) { require.NoError(t, err) assert.Equal(t, int64(1048576), written) }) + + t.Run("source size tag larger than object size", func(t *testing.T) { + ctx := context.Background() + repoWriter := udmrepomocks.NewBackupRepo(t) + blkup := NewUploader(ctx, repoWriter, nil, logrus.New()) + + meta := &udmrepo.Metadata{ + SubObjects: []udmrepo.ObjectMetadata{ + {ID: "data-id", Name: "bdev", Size: 1048576}, + }, + } + repoWriter.On("ReadMetadata", mock.Anything, udmrepo.ID("root-id")).Return(meta, nil) + + snap := udmrepo.Snapshot{ + RootObject: udmrepo.ObjectMetadata{ID: "root-id"}, + Tags: map[string]string{bdevSourceSizeTag: "2097152"}, + } + dest := destInfo{size: 4194304, path: "/dev/target"} + iterMock := cbtmocks.NewIterator(t) + + _, err := blkup.Restore(snap, dest, iterMock, nil) + require.Error(t, err) + assert.Contains(t, err.Error(), "unexpected size (1048576 vs. 2097152) for bdev object bdev") + }) + + t.Run("destination smaller than source size", func(t *testing.T) { + ctx := context.Background() + repoWriter := udmrepomocks.NewBackupRepo(t) + blkup := NewUploader(ctx, repoWriter, nil, logrus.New()) + + meta := &udmrepo.Metadata{ + SubObjects: []udmrepo.ObjectMetadata{ + {ID: "data-id", Name: "bdev", Size: 1048576}, + }, + } + repoWriter.On("ReadMetadata", mock.Anything, udmrepo.ID("root-id")).Return(meta, nil) + + snap := udmrepo.Snapshot{ + RootObject: udmrepo.ObjectMetadata{ID: "root-id"}, + Tags: map[string]string{bdevSourceSizeTag: "1048576"}, + } + dest := destInfo{size: 512, path: "/dev/small"} + iterMock := cbtmocks.NewIterator(t) + + _, err := blkup.Restore(snap, dest, iterMock, nil) + require.Error(t, err) + assert.Contains(t, err.Error(), "dest dev(/dev/small) size is too small") + }) } From 2649b2554c05ba4dc35d8a9facf5943b7d1e45e3 Mon Sep 17 00:00:00 2001 From: chlins Date: Mon, 3 Aug 2026 13:28:31 +0800 Subject: [PATCH 05/45] Fix hook timeout review feedback Signed-off-by: chlins --- pkg/podexec/pod_command_executor.go | 22 ++++-- pkg/podexec/pod_command_executor_test.go | 57 +++++++++++++++ .../pod_command_executor_timeout_test.go | 73 +++++++++++++++---- 3 files changed, 130 insertions(+), 22 deletions(-) diff --git a/pkg/podexec/pod_command_executor.go b/pkg/podexec/pod_command_executor.go index 71894a489..997795c35 100644 --- a/pkg/podexec/pod_command_executor.go +++ b/pkg/podexec/pod_command_executor.go @@ -168,7 +168,7 @@ func (e *defaultPodCommandExecutor) ExecutePodCommand(log logrus.FieldLogger, it Stderr: &stderr, } - // The timeout drives the context so the exec stream is actually cancelled, rather than + // The timeout drives the context so the exec stream is actually canceled, rather than // being left running on the API server after this function has returned. ctx, cancel := context.WithTimeout(context.Background(), localHook.Timeout.Duration) defer cancel() @@ -178,17 +178,15 @@ func (e *defaultPodCommandExecutor) ExecutePodCommand(log logrus.FieldLogger, it errCh := make(chan error, 1) go func() { - errCh <- executor.StreamWithContext(ctx, streamOptions) + streamErr := executor.StreamWithContext(ctx, streamOptions) + // Inspect the local context as soon as the stream returns. Otherwise a stream error + // completed before the deadline could be misclassified if this goroutine sends its + // result before the caller is scheduled to receive it. + errCh <- normalizeExecHookError(streamErr, ctx.Err(), localHook.Timeout.Duration) }() select { case err = <-errCh: - // On a timeout the stream returns because the context expired, so both this case - // and ctx.Done() are ready and the select picks one at random. Report the timeout - // either way instead of surfacing the context error only some of the time. - if errors.Is(ctx.Err(), context.DeadlineExceeded) { - return errors.Errorf("timed out after %v", localHook.Timeout.Duration) - } case <-ctx.Done(): return errors.Errorf("timed out after %v", localHook.Timeout.Duration) } @@ -199,6 +197,14 @@ func (e *defaultPodCommandExecutor) ExecutePodCommand(log logrus.FieldLogger, it return err } +func normalizeExecHookError(streamErr, contextErr error, timeout time.Duration) error { + if errors.Is(contextErr, context.DeadlineExceeded) { + return errors.Errorf("timed out after %v", timeout) + } + + return streamErr +} + func ensureContainerExists(pod *corev1api.Pod, container string) error { existsAsMainContainer := slices.ContainsFunc(pod.Spec.Containers, func(c corev1api.Container) bool { return c.Name == container diff --git a/pkg/podexec/pod_command_executor_test.go b/pkg/podexec/pod_command_executor_test.go index de32fc605..e30911a20 100644 --- a/pkg/podexec/pod_command_executor_test.go +++ b/pkg/podexec/pod_command_executor_test.go @@ -177,6 +177,15 @@ func TestExecutePodCommand(t *testing.T) { hookError: errors.New("hook error"), expectedError: "hook error", }, + { + name: "stream deadline exceeded before local timeout", + command: []string{"some", "command"}, + expectedContainerName: "foo", + expectedErrorMode: v1.HookErrorModeFail, + expectedTimeout: defaultTimeout, + hookError: context.DeadlineExceeded, + expectedError: context.DeadlineExceeded.Error(), + }, { // Timeouts from pod annotations go through time.ParseDuration, which accepts // negative values. Without clamping, the hook would run with no timeout at all. @@ -264,6 +273,54 @@ func TestExecutePodCommand(t *testing.T) { } } +func TestNormalizeExecHookError(t *testing.T) { + hookErr := errors.New("hook error") + tests := []struct { + name string + streamErr error + contextErr error + expectedError string + preserveStreamErr bool + }{ + { + name: "local context deadline exceeded", + streamErr: context.DeadlineExceeded, + contextErr: context.DeadlineExceeded, + expectedError: "timed out after 30s", + }, + { + name: "stream deadline exceeded before local timeout", + streamErr: context.DeadlineExceeded, + expectedError: context.DeadlineExceeded.Error(), + preserveStreamErr: true, + }, + { + name: "ordinary hook error", + streamErr: hookErr, + expectedError: hookErr.Error(), + preserveStreamErr: true, + }, + { + name: "no errors", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := normalizeExecHookError(test.streamErr, test.contextErr, defaultTimeout) + if test.expectedError == "" { + require.NoError(t, err) + return + } + + require.EqualError(t, err, test.expectedError) + if test.preserveStreamErr && err != test.streamErr { + t.Fatalf("expected stream error to be returned unchanged") + } + }) + } +} + func TestEnsureContainerExists(t *testing.T) { pod := &corev1api.Pod{ Spec: corev1api.PodSpec{ diff --git a/pkg/podexec/pod_command_executor_timeout_test.go b/pkg/podexec/pod_command_executor_timeout_test.go index 88cb3ed92..a79389481 100644 --- a/pkg/podexec/pod_command_executor_timeout_test.go +++ b/pkg/podexec/pod_command_executor_timeout_test.go @@ -1,9 +1,26 @@ +/* +Copyright 2026 the Velero contributors. + +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 podexec import ( "context" "net/url" "runtime" + "sync" "testing" "time" @@ -22,23 +39,38 @@ const timeoutTestPodJSON = `{ "spec": {"containers": [{"name": "container-1"}]} }` -// contextAwareExecutor returns once its context is cancelled, like the SPDY executor does. +// contextAwareExecutor returns once its context is canceled, like the SPDY executor does. type contextAwareExecutor struct { - cancelled chan struct{} - cancelledOnce bool + canceled chan struct{} + canceledOnce bool } func (e *contextAwareExecutor) Stream(options remotecommand.StreamOptions) error { return nil } func (e *contextAwareExecutor) StreamWithContext(ctx context.Context, options remotecommand.StreamOptions) error { <-ctx.Done() - if !e.cancelledOnce { - e.cancelledOnce = true - close(e.cancelled) + if !e.canceledOnce { + e.canceledOnce = true + close(e.canceled) } return ctx.Err() } +// contextIgnoringExecutor lets the outer timeout path return before the stream does. +// Once released, the stream goroutine can only exit if its result channel is buffered. +type contextIgnoringExecutor struct { + release <-chan struct{} + returned *sync.WaitGroup +} + +func (e *contextIgnoringExecutor) Stream(options remotecommand.StreamOptions) error { return nil } + +func (e *contextIgnoringExecutor) StreamWithContext(ctx context.Context, options remotecommand.StreamOptions) error { + defer e.returned.Done() + <-e.release + return nil +} + func newTimeoutTestExecutor(t *testing.T, exec remotecommand.Executor) (*defaultPodCommandExecutor, map[string]any) { t.Helper() @@ -70,10 +102,10 @@ func timeoutTestHook(timeout time.Duration) *v1.ExecHook { } } -// A hook that times out must have its exec stream cancelled, otherwise the command keeps +// A hook that times out must have its exec stream canceled, otherwise the command keeps // running on the API server after ExecutePodCommand has returned. func TestExecutePodCommandCancelsStreamOnTimeout(t *testing.T) { - exec := &contextAwareExecutor{cancelled: make(chan struct{})} + exec := &contextAwareExecutor{canceled: make(chan struct{})} podCommandExecutor, pod := newTimeoutTestExecutor(t, exec) err := podCommandExecutor.ExecutePodCommand(velerotest.NewLogger(), pod, "ns", "pod-1", "hookName", timeoutTestHook(100*time.Millisecond)) @@ -82,26 +114,32 @@ func TestExecutePodCommandCancelsStreamOnTimeout(t *testing.T) { } select { - case <-exec.cancelled: + case <-exec.canceled: case <-time.After(2 * time.Second): - t.Fatal("stream was not cancelled after the hook timed out") + t.Fatal("stream was not canceled after the hook timed out") } } // When the stream returns because the context expired, both select cases are ready and one // is picked at random, so the reported error must not depend on which one wins. func TestExecutePodCommandTimeoutErrorIsDeterministic(t *testing.T) { - const rounds = 50 + const ( + rounds = 50 + expectedError = "timed out after 1ms" + ) messages := map[string]int{} for range rounds { - exec := &contextAwareExecutor{cancelled: make(chan struct{})} + exec := &contextAwareExecutor{canceled: make(chan struct{})} podCommandExecutor, pod := newTimeoutTestExecutor(t, exec) err := podCommandExecutor.ExecutePodCommand(velerotest.NewLogger(), pod, "ns", "pod-1", "hookName", timeoutTestHook(time.Millisecond)) if err == nil { t.Fatal("expected a timeout error") } + if err.Error() != expectedError { + t.Fatalf("expected %q, got %q", expectedError, err) + } messages[err.Error()]++ } @@ -117,8 +155,11 @@ func TestExecutePodCommandDoesNotLeakOnTimeout(t *testing.T) { time.Sleep(200 * time.Millisecond) before := runtime.NumGoroutine() + release := make(chan struct{}) + returned := &sync.WaitGroup{} for range rounds { - exec := &contextAwareExecutor{cancelled: make(chan struct{})} + returned.Add(1) + exec := &contextIgnoringExecutor{release: release, returned: returned} podCommandExecutor, pod := newTimeoutTestExecutor(t, exec) if err := podCommandExecutor.ExecutePodCommand(velerotest.NewLogger(), pod, "ns", "pod-1", "hookName", timeoutTestHook(50*time.Millisecond)); err == nil { @@ -126,7 +167,11 @@ func TestExecutePodCommandDoesNotLeakOnTimeout(t *testing.T) { } } - time.Sleep(time.Second) + // Every ExecutePodCommand call has already taken the timeout path. Releasing the + // streams now forces their goroutines to send into an errCh with no receiver. + close(release) + returned.Wait() + time.Sleep(200 * time.Millisecond) runtime.GC() time.Sleep(200 * time.Millisecond) From 46f5adb7a37f9096835c65b27b1814dc67422f7b Mon Sep 17 00:00:00 2001 From: Jay2006sawant Date: Mon, 3 Aug 2026 11:26:00 +0530 Subject: [PATCH 06/45] fix(provider): return immediately when BatchForget flush fails Signed-off-by: Jay2006sawant --- pkg/repository/provider/unified_repo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index 664750c77..b30e4618b 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -384,7 +384,7 @@ func (urp *unifiedRepoProvider) BatchForget(ctx context.Context, snapshotIDs []s err = bkRepo.Flush(ctx) if err != nil { - errs = append(errs, errors.Wrap(err, "error to flush repo")) + return append(errs, errors.Wrap(err, "error to flush repo")) } log.Debug("Forget snapshot complete") From b2dea8d169f55413bc5553d13b677271fa55d27b Mon Sep 17 00:00:00 2001 From: Jay2006sawant Date: Tue, 4 Aug 2026 14:49:08 +0530 Subject: [PATCH 07/45] chore: add one-line changelog for PR 10138 Signed-off-by: Jay2006sawant --- changelogs/unreleased/10138-Jay2006sawant | 1 + changelogs/unreleased/fix-error-handling-Jay2006sawant | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) create mode 100644 changelogs/unreleased/10138-Jay2006sawant delete mode 100644 changelogs/unreleased/fix-error-handling-Jay2006sawant diff --git a/changelogs/unreleased/10138-Jay2006sawant b/changelogs/unreleased/10138-Jay2006sawant new file mode 100644 index 000000000..cc5339217 --- /dev/null +++ b/changelogs/unreleased/10138-Jay2006sawant @@ -0,0 +1 @@ +Fix block uploader restore validation and BatchForget error handling diff --git a/changelogs/unreleased/fix-error-handling-Jay2006sawant b/changelogs/unreleased/fix-error-handling-Jay2006sawant deleted file mode 100644 index 82a05f6c3..000000000 --- a/changelogs/unreleased/fix-error-handling-Jay2006sawant +++ /dev/null @@ -1,9 +0,0 @@ -fix: return errors correctly in block restore validation and BatchForget - -Block uploader Restore used errors.Wrapf with a stale nil err after -successful getSourceSize, causing size validation failures to return -(0, nil). flushZeroBlocks had the same pattern on short writes. - -BatchForget dropped delete errors when flush also failed. - -Signed-off-by: Jay2006sawant From 5a615ad580af17706332a5494fb5664cd2f11d11 Mon Sep 17 00:00:00 2001 From: chlins Date: Tue, 4 Aug 2026 17:19:25 +0800 Subject: [PATCH 08/45] Verify build tool downloads Pin architecture-specific SHA-256 checksums for kubebuilder, protoc, and GoReleaser before installation. Signed-off-by: chlins --- .../unreleased/RS-MIRRORS_GITHUB_VELERO-22 | 1 + hack/build-image/Dockerfile | 81 +++++++------ hack/verify-build-image-tool-checksums.sh | 111 ++++++++++++++++++ 3 files changed, 160 insertions(+), 33 deletions(-) create mode 100644 changelogs/unreleased/RS-MIRRORS_GITHUB_VELERO-22 create mode 100755 hack/verify-build-image-tool-checksums.sh diff --git a/changelogs/unreleased/RS-MIRRORS_GITHUB_VELERO-22 b/changelogs/unreleased/RS-MIRRORS_GITHUB_VELERO-22 new file mode 100644 index 000000000..b17917098 --- /dev/null +++ b/changelogs/unreleased/RS-MIRRORS_GITHUB_VELERO-22 @@ -0,0 +1 @@ +Verify downloaded build tools against architecture-specific SHA-256 checksums before installation. diff --git a/hack/build-image/Dockerfile b/hack/build-image/Dockerfile index 4f34ba470..8978855b2 100644 --- a/hack/build-image/Dockerfile +++ b/hack/build-image/Dockerfile @@ -29,8 +29,18 @@ RUN go install sigs.k8s.io/controller-runtime/tools/setup-envtest@v0.0.0-2026030 ENVTEST_ASSETS_DIR=$(setup-envtest use 1.33.0 --bin-dir /usr/local/kubebuilder/bin -p path) && \ cp -r ${ENVTEST_ASSETS_DIR}/* /usr/local/kubebuilder/bin/ -RUN wget --quiet https://github.com/kubernetes-sigs/kubebuilder/releases/download/v3.2.0/kubebuilder_linux_$(go env GOARCH) && \ - mv kubebuilder_linux_$(go env GOARCH) /usr/local/kubebuilder/bin/kubebuilder && \ +RUN set -eux; \ + ARCH="$(go env GOARCH)"; \ + case "$ARCH" in \ + amd64) KUBEBUILDER_SHA256="102bb0f586dcb50951aded67856483a2ee114057c56475b3cda6051a12832a72" ;; \ + arm64) KUBEBUILDER_SHA256="0a340ea925c801aa71344becdefce96eda6fa0bc92352b9c7bcb36a4f8c56314" ;; \ + ppc64le) KUBEBUILDER_SHA256="74473d094908caad852a77088f64bb64eb4c79497f6695eb5e9e8bc4bacd9409" ;; \ + *) echo "Unsupported kubebuilder architecture: $ARCH" >&2; exit 1 ;; \ + esac; \ + FILE="kubebuilder_linux_$ARCH"; \ + wget --quiet "https://github.com/kubernetes-sigs/kubebuilder/releases/download/v3.2.0/$FILE"; \ + echo "$KUBEBUILDER_SHA256 $FILE" | sha256sum -c -; \ + mv "$FILE" /usr/local/kubebuilder/bin/kubebuilder; \ chmod +x /usr/local/kubebuilder/bin/kubebuilder # get controller-tools @@ -52,26 +62,27 @@ RUN apt-get update && apt-get install -y unzip # cpu = "ppcle_64" # snippet from: https://github.com/protocolbuffers/protobuf/blob/d445953603e66eb8992a39b4e10fcafec8501f24/protobuf_release.bzl#L18-L24 # cpu names: https://github.com/bazelbuild/platforms/blob/main/cpu/BUILD -RUN ARCH=$(go env GOARCH) && \ - if [ "$ARCH" = "s390x" ] ; then \ - ARCH="s390_64"; \ - elif [ "$ARCH" = "arm64" ] ; then \ - ARCH="aarch_64"; \ - elif [ "$ARCH" = "ppc64le" ] ; then \ - ARCH="ppcle_64"; \ - elif [ "$ARCH" = "ppc64" ] ; then \ - ARCH="ppcle_64"; \ - else \ - ARCH=$(uname -m); \ - fi && echo "ARCH=$ARCH" && \ - wget --quiet https://github.com/protocolbuffers/protobuf/releases/download/v25.2/protoc-25.2-linux-$ARCH.zip && \ - unzip protoc-25.2-linux-$ARCH.zip; \ - rm *.zip && \ - mv bin/protoc /usr/bin/protoc && \ - mv include/google /usr/include && \ - chmod a+x /usr/include/google && \ - chmod a+x /usr/include/google/protobuf && \ - chmod a+r -R /usr/include/google && \ +RUN set -eux; \ + GOARCH="$(go env GOARCH)"; \ + case "$GOARCH" in \ + amd64) ARCH="x86_64"; PROTOC_SHA256="78ab9c3288919bdaa6cfcec6127a04813cf8a0ce406afa625e48e816abee2878" ;; \ + 386) ARCH="x86_32"; PROTOC_SHA256="cc1c6e31a9b333c3e6d026aac5fdc1f7d70c6cd8851631505188ca9826acee5a" ;; \ + arm64) ARCH="aarch_64"; PROTOC_SHA256="07683afc764e4efa3fa969d5f049fbc2bdfc6b4e7786a0b233413ac0d8753f6b" ;; \ + ppc64|ppc64le) ARCH="ppcle_64"; PROTOC_SHA256="cea283337101ed08ff6c76a98461b1d871bac21f41dc1dabdfddaa5d99df9339" ;; \ + s390x) ARCH="s390_64"; PROTOC_SHA256="8a13ec6518585f7664d58f929417c9e6d0c4aeedf3bcdd854aeafceb5ef0a389" ;; \ + *) echo "Unsupported protoc architecture: $GOARCH" >&2; exit 1 ;; \ + esac; \ + echo "ARCH=$ARCH"; \ + FILE="protoc-25.2-linux-$ARCH.zip"; \ + wget --quiet "https://github.com/protocolbuffers/protobuf/releases/download/v25.2/$FILE"; \ + echo "$PROTOC_SHA256 $FILE" | sha256sum -c -; \ + unzip "$FILE"; \ + rm "$FILE"; \ + mv bin/protoc /usr/bin/protoc; \ + mv include/google /usr/include; \ + chmod a+x /usr/include/google; \ + chmod a+x /usr/include/google/protobuf; \ + chmod a+r -R /usr/include/google; \ chmod +x /usr/bin/protoc RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@${PROTOC_GEN_GO_VERSION} \ && go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0 @@ -84,17 +95,21 @@ RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@${PROTOC_GEN_GO_VERS # {{- else if eq .Arch "386" }}i386 # {{- else }}{{ .Arch }}{{ end }} # {{- if .Arm }}v{{ .Arm }}{{ end -}} -RUN ARCH=$(go env GOARCH) && \ - if [ "$ARCH" = "amd64" ] ; then \ - ARCH="x86_64"; \ - elif [ "$ARCH" = "386" ] ; then \ - ARCH="i386"; \ - elif [ "$ARCH" = "ppc64le" ] ; then \ - ARCH="ppc64"; \ - fi && \ - wget --quiet "https://github.com/goreleaser/goreleaser/releases/download/v1.26.2/goreleaser_Linux_$ARCH.tar.gz" && \ - tar xvf goreleaser_Linux_$ARCH.tar.gz; \ - mv goreleaser /usr/bin/goreleaser && \ +RUN set -eux; \ + GOARCH="$(go env GOARCH)"; \ + case "$GOARCH" in \ + amd64) ARCH="x86_64"; GORELEASER_SHA256="cfbdf12e3ea20e4c3a209d07311f43c2e0baf20d5cce09bcdc232567e0f34307" ;; \ + 386) ARCH="i386"; GORELEASER_SHA256="21c236575cccd29588182b570b4ffe83ad8fb96cd3b13b2af79feafd8ae37b1b" ;; \ + arm64) ARCH="arm64"; GORELEASER_SHA256="2b984e2932b24be0d638c7dab7357a59d86eb79ca7fee1afd31be5ebb1847cbb" ;; \ + arm) ARCH="armv7"; GORELEASER_SHA256="6db2899885be19f123b36192a42dcfb3bb2b3e1009fec7277517969e96d8a7c6" ;; \ + ppc64|ppc64le) ARCH="ppc64"; GORELEASER_SHA256="76d060ebb8d48e76fde45983f87040fe3ac0ca37c5ace4648a956959b81bfdf0" ;; \ + *) echo "Unsupported goreleaser architecture: $GOARCH" >&2; exit 1 ;; \ + esac; \ + FILE="goreleaser_Linux_$ARCH.tar.gz"; \ + wget --quiet "https://github.com/goreleaser/goreleaser/releases/download/v1.26.2/$FILE"; \ + echo "$GORELEASER_SHA256 $FILE" | sha256sum -c -; \ + tar xvf "$FILE"; \ + mv goreleaser /usr/bin/goreleaser; \ chmod +x /usr/bin/goreleaser # get golangci-lint diff --git a/hack/verify-build-image-tool-checksums.sh b/hack/verify-build-image-tool-checksums.sh new file mode 100755 index 000000000..a11f258ab --- /dev/null +++ b/hack/verify-build-image-tool-checksums.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +# Copyright 2026 the Velero contributors. +# +# 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. + +set -euo pipefail + +ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +DOCKERFILE="${ROOT_DIR}/hack/build-image/Dockerfile" + +verify_block() { + local tool=$1 + local start=$2 + local end=$3 + local hash_variable=$4 + local install_pattern=$5 + shift 5 + local expected_arches=("$@") + local block + + block=$(awk -v start="${start}" -v end="${end}" ' + $0 ~ start { printing = 1 } + printing { print } + printing && $0 ~ end { exit } + ' "${DOCKERFILE}") + + if [[ -z "${block}" ]]; then + echo "Unable to find ${tool} install block" >&2 + return 1 + fi + + local actual_arches + actual_arches=$(printf '%s\n' "${block}" | + sed -nE "s/^[[:space:]]*([[:alnum:]_|]+)\).*${hash_variable}=\"([[:xdigit:]]+)\".*/\1 \2/p") + + local expected_arch + for expected_arch in "${expected_arches[@]}"; do + if ! printf '%s\n' "${actual_arches}" | awk -v arch="${expected_arch}" ' + $1 == arch && length($2) == 64 && $2 ~ /^[0-9a-f]+$/ { found = 1 } + END { exit !found } + '; then + echo "${tool} is missing a lowercase 64-hex SHA-256 for ${expected_arch}" >&2 + return 1 + fi + done + + local actual_count + actual_count=$(printf '%s\n' "${actual_arches}" | sed '/^$/d' | wc -l | tr -d ' ') + if [[ "${actual_count}" -ne "${#expected_arches[@]}" ]]; then + echo "${tool} architecture mapping changed; update this verification gate" >&2 + printf '%s\n' "${actual_arches}" >&2 + return 1 + fi + + if ! printf '%s\n' "${block}" | grep -Eq '^ \*\).*Unsupported .+ architecture:.+exit 1'; then + echo "${tool} does not fail closed for unknown architectures" >&2 + return 1 + fi + + local download_line checksum_line install_line + download_line=$(printf '%s\n' "${block}" | grep -n 'wget --quiet' | head -1 | cut -d: -f1) + checksum_line=$(printf '%s\n' "${block}" | grep -n "echo \"\$${hash_variable} \$FILE\" | sha256sum -c -" | head -1 | cut -d: -f1) + install_line=$(printf '%s\n' "${block}" | grep -nE "${install_pattern}" | head -1 | cut -d: -f1) + + if [[ -z "${download_line}" || -z "${checksum_line}" || -z "${install_line}" || + "${download_line}" -ge "${checksum_line}" || "${checksum_line}" -ge "${install_line}" ]]; then + echo "${tool} must download, verify, then install/extract in that order" >&2 + return 1 + fi + + if ! printf '%s\n' "${block}" | grep -q '^RUN set -eux;'; then + echo "${tool} install block must use strict shell error handling" >&2 + return 1 + fi +} + +verify_block \ + kubebuilder \ + '^RUN set -eux;.*$' \ + '^# get controller-tools$' \ + KUBEBUILDER_SHA256 \ + 'mv "\$FILE"' \ + amd64 arm64 ppc64le + +verify_block \ + protoc \ + '^# cpu names:' \ + '^RUN go install google.golang.org/protobuf' \ + PROTOC_SHA256 \ + 'unzip "\$FILE"' \ + amd64 386 arm64 'ppc64|ppc64le' s390x + +verify_block \ + goreleaser \ + '^# goreleaser name template' \ + '^# get golangci-lint$' \ + GORELEASER_SHA256 \ + 'tar xvf "\$FILE"' \ + amd64 386 arm64 arm 'ppc64|ppc64le' + +echo "Verified pinned build-tool checksums and fail-closed install ordering" From 66b637e398b886a764a7c249c28660baac59f8f8 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Thu, 6 Aug 2026 09:36:28 +0000 Subject: [PATCH 09/45] update protocol buffer code Signed-off-by: Lyndon-Li --- pkg/plugin/generated/BackupItemAction.pb.go | 201 ++---- pkg/plugin/generated/DeleteItemAction.pb.go | 160 ++--- pkg/plugin/generated/ObjectStore.pb.go | 603 +++++------------- pkg/plugin/generated/PluginLister.pb.go | 112 +--- pkg/plugin/generated/RestoreItemAction.pb.go | 219 ++----- pkg/plugin/generated/Shared.pb.go | 299 +++------ pkg/plugin/generated/VolumeSnapshotter.pb.go | 590 +++++------------ .../v2/BackupItemAction.pb.go | 344 +++------- .../itemblockaction/v1/ItemBlockAction.pb.go | 199 ++---- .../v2/RestoreItemAction.pb.go | 453 ++++--------- 10 files changed, 894 insertions(+), 2286 deletions(-) diff --git a/pkg/plugin/generated/BackupItemAction.pb.go b/pkg/plugin/generated/BackupItemAction.pb.go index 5d3d3cb7e..f9f363d1e 100644 --- a/pkg/plugin/generated/BackupItemAction.pb.go +++ b/pkg/plugin/generated/BackupItemAction.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: BackupItemAction.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,22 +22,19 @@ const ( ) type ExecuteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` - Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ExecuteRequest) Reset() { *x = ExecuteRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_BackupItemAction_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_BackupItemAction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExecuteRequest) String() string { @@ -47,7 +45,7 @@ func (*ExecuteRequest) ProtoMessage() {} func (x *ExecuteRequest) ProtoReflect() protoreflect.Message { mi := &file_BackupItemAction_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -84,21 +82,18 @@ func (x *ExecuteRequest) GetBackup() []byte { } type ExecuteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Item []byte `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` - AdditionalItems []*ResourceIdentifier `protobuf:"bytes,2,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Item []byte `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + AdditionalItems []*ResourceIdentifier `protobuf:"bytes,2,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExecuteResponse) Reset() { *x = ExecuteResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_BackupItemAction_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_BackupItemAction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExecuteResponse) String() string { @@ -109,7 +104,7 @@ func (*ExecuteResponse) ProtoMessage() {} func (x *ExecuteResponse) ProtoReflect() protoreflect.Message { mi := &file_BackupItemAction_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -139,20 +134,17 @@ func (x *ExecuteResponse) GetAdditionalItems() []*ResourceIdentifier { } type BackupItemActionAppliesToRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BackupItemActionAppliesToRequest) Reset() { *x = BackupItemActionAppliesToRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_BackupItemAction_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_BackupItemAction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BackupItemActionAppliesToRequest) String() string { @@ -163,7 +155,7 @@ func (*BackupItemActionAppliesToRequest) ProtoMessage() {} func (x *BackupItemActionAppliesToRequest) ProtoReflect() protoreflect.Message { mi := &file_BackupItemAction_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -186,20 +178,17 @@ func (x *BackupItemActionAppliesToRequest) GetPlugin() string { } type BackupItemActionAppliesToResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ResourceSelector *ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ResourceSelector *ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *BackupItemActionAppliesToResponse) Reset() { *x = BackupItemActionAppliesToResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_BackupItemAction_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_BackupItemAction_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BackupItemActionAppliesToResponse) String() string { @@ -210,7 +199,7 @@ func (*BackupItemActionAppliesToResponse) ProtoMessage() {} func (x *BackupItemActionAppliesToResponse) ProtoReflect() protoreflect.Message { mi := &file_BackupItemAction_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -234,65 +223,38 @@ func (x *BackupItemActionAppliesToResponse) GetResourceSelector() *ResourceSelec var File_BackupItemAction_proto protoreflect.FileDescriptor -var file_BackupItemAction_proto_rawDesc = []byte{ - 0x0a, 0x16, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x1a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x54, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, - 0x16, 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x6e, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x47, - 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x0a, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x22, 0x6c, 0x0a, 0x21, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, - 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, - 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x32, 0xbc, 0x01, 0x0a, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x73, 0x54, 0x6f, 0x12, 0x2b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, - 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2c, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, - 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x67, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, - 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, - 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, 0x75, 0x2f, 0x76, 0x65, 0x6c, 0x65, - 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x67, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_BackupItemAction_proto_rawDesc = "" + + "\n" + + "\x16BackupItemAction.proto\x12\tgenerated\x1a\fShared.proto\"T\n" + + "\x0eExecuteRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x12\n" + + "\x04item\x18\x02 \x01(\fR\x04item\x12\x16\n" + + "\x06backup\x18\x03 \x01(\fR\x06backup\"n\n" + + "\x0fExecuteResponse\x12\x12\n" + + "\x04item\x18\x01 \x01(\fR\x04item\x12G\n" + + "\x0fadditionalItems\x18\x02 \x03(\v2\x1d.generated.ResourceIdentifierR\x0fadditionalItems\":\n" + + " BackupItemActionAppliesToRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\"l\n" + + "!BackupItemActionAppliesToResponse\x12G\n" + + "\x10ResourceSelector\x18\x01 \x01(\v2\x1b.generated.ResourceSelectorR\x10ResourceSelector2\xbc\x01\n" + + "\x10BackupItemAction\x12f\n" + + "\tAppliesTo\x12+.generated.BackupItemActionAppliesToRequest\x1a,.generated.BackupItemActionAppliesToResponse\x12@\n" + + "\aExecute\x12\x19.generated.ExecuteRequest\x1a\x1a.generated.ExecuteResponseB5Z3github.com/vmware-tanzu/velero/pkg/plugin/generatedb\x06proto3" var ( file_BackupItemAction_proto_rawDescOnce sync.Once - file_BackupItemAction_proto_rawDescData = file_BackupItemAction_proto_rawDesc + file_BackupItemAction_proto_rawDescData []byte ) func file_BackupItemAction_proto_rawDescGZIP() []byte { file_BackupItemAction_proto_rawDescOnce.Do(func() { - file_BackupItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(file_BackupItemAction_proto_rawDescData) + file_BackupItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_BackupItemAction_proto_rawDesc), len(file_BackupItemAction_proto_rawDesc))) }) return file_BackupItemAction_proto_rawDescData } var file_BackupItemAction_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_BackupItemAction_proto_goTypes = []interface{}{ +var file_BackupItemAction_proto_goTypes = []any{ (*ExecuteRequest)(nil), // 0: generated.ExecuteRequest (*ExecuteResponse)(nil), // 1: generated.ExecuteResponse (*BackupItemActionAppliesToRequest)(nil), // 2: generated.BackupItemActionAppliesToRequest @@ -320,61 +282,11 @@ func file_BackupItemAction_proto_init() { return } file_Shared_proto_init() - if !protoimpl.UnsafeEnabled { - file_BackupItemAction_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecuteRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_BackupItemAction_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecuteResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_BackupItemAction_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupItemActionAppliesToRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_BackupItemAction_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupItemActionAppliesToResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_BackupItemAction_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_BackupItemAction_proto_rawDesc), len(file_BackupItemAction_proto_rawDesc)), NumEnums: 0, NumMessages: 4, NumExtensions: 0, @@ -385,7 +297,6 @@ func file_BackupItemAction_proto_init() { MessageInfos: file_BackupItemAction_proto_msgTypes, }.Build() File_BackupItemAction_proto = out.File - file_BackupItemAction_proto_rawDesc = nil file_BackupItemAction_proto_goTypes = nil file_BackupItemAction_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/DeleteItemAction.pb.go b/pkg/plugin/generated/DeleteItemAction.pb.go index 871b63889..3935cf216 100644 --- a/pkg/plugin/generated/DeleteItemAction.pb.go +++ b/pkg/plugin/generated/DeleteItemAction.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: DeleteItemAction.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,22 +22,19 @@ const ( ) type DeleteItemActionExecuteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` - Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteItemActionExecuteRequest) Reset() { *x = DeleteItemActionExecuteRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_DeleteItemAction_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_DeleteItemAction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeleteItemActionExecuteRequest) String() string { @@ -47,7 +45,7 @@ func (*DeleteItemActionExecuteRequest) ProtoMessage() {} func (x *DeleteItemActionExecuteRequest) ProtoReflect() protoreflect.Message { mi := &file_DeleteItemAction_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -84,20 +82,17 @@ func (x *DeleteItemActionExecuteRequest) GetBackup() []byte { } type DeleteItemActionAppliesToRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteItemActionAppliesToRequest) Reset() { *x = DeleteItemActionAppliesToRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_DeleteItemAction_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_DeleteItemAction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeleteItemActionAppliesToRequest) String() string { @@ -108,7 +103,7 @@ func (*DeleteItemActionAppliesToRequest) ProtoMessage() {} func (x *DeleteItemActionAppliesToRequest) ProtoReflect() protoreflect.Message { mi := &file_DeleteItemAction_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -131,20 +126,17 @@ func (x *DeleteItemActionAppliesToRequest) GetPlugin() string { } type DeleteItemActionAppliesToResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ResourceSelector *ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ResourceSelector *ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteItemActionAppliesToResponse) Reset() { *x = DeleteItemActionAppliesToResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_DeleteItemAction_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_DeleteItemAction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeleteItemActionAppliesToResponse) String() string { @@ -155,7 +147,7 @@ func (*DeleteItemActionAppliesToResponse) ProtoMessage() {} func (x *DeleteItemActionAppliesToResponse) ProtoReflect() protoreflect.Message { mi := &file_DeleteItemAction_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -179,60 +171,35 @@ func (x *DeleteItemActionAppliesToResponse) GetResourceSelector() *ResourceSelec var File_DeleteItemAction_proto protoreflect.FileDescriptor -var file_DeleteItemAction_proto_rawDesc = []byte{ - 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x1a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x64, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, - 0x16, 0x0a, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x3a, 0x0a, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x22, 0x6c, 0x0a, 0x21, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, - 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, - 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x32, 0xc2, 0x01, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x66, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x73, 0x54, 0x6f, 0x12, 0x2b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2c, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, - 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x29, 0x2e, 0x67, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, - 0x75, 0x2f, 0x76, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_DeleteItemAction_proto_rawDesc = "" + + "\n" + + "\x16DeleteItemAction.proto\x12\tgenerated\x1a\fShared.proto\"d\n" + + "\x1eDeleteItemActionExecuteRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x12\n" + + "\x04item\x18\x02 \x01(\fR\x04item\x12\x16\n" + + "\x06backup\x18\x03 \x01(\fR\x06backup\":\n" + + " DeleteItemActionAppliesToRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\"l\n" + + "!DeleteItemActionAppliesToResponse\x12G\n" + + "\x10ResourceSelector\x18\x01 \x01(\v2\x1b.generated.ResourceSelectorR\x10ResourceSelector2\xc2\x01\n" + + "\x10DeleteItemAction\x12f\n" + + "\tAppliesTo\x12+.generated.DeleteItemActionAppliesToRequest\x1a,.generated.DeleteItemActionAppliesToResponse\x12F\n" + + "\aExecute\x12).generated.DeleteItemActionExecuteRequest\x1a\x10.generated.EmptyB5Z3github.com/vmware-tanzu/velero/pkg/plugin/generatedb\x06proto3" var ( file_DeleteItemAction_proto_rawDescOnce sync.Once - file_DeleteItemAction_proto_rawDescData = file_DeleteItemAction_proto_rawDesc + file_DeleteItemAction_proto_rawDescData []byte ) func file_DeleteItemAction_proto_rawDescGZIP() []byte { file_DeleteItemAction_proto_rawDescOnce.Do(func() { - file_DeleteItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(file_DeleteItemAction_proto_rawDescData) + file_DeleteItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_DeleteItemAction_proto_rawDesc), len(file_DeleteItemAction_proto_rawDesc))) }) return file_DeleteItemAction_proto_rawDescData } var file_DeleteItemAction_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_DeleteItemAction_proto_goTypes = []interface{}{ +var file_DeleteItemAction_proto_goTypes = []any{ (*DeleteItemActionExecuteRequest)(nil), // 0: generated.DeleteItemActionExecuteRequest (*DeleteItemActionAppliesToRequest)(nil), // 1: generated.DeleteItemActionAppliesToRequest (*DeleteItemActionAppliesToResponse)(nil), // 2: generated.DeleteItemActionAppliesToResponse @@ -258,49 +225,11 @@ func file_DeleteItemAction_proto_init() { return } file_Shared_proto_init() - if !protoimpl.UnsafeEnabled { - file_DeleteItemAction_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteItemActionExecuteRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_DeleteItemAction_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteItemActionAppliesToRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_DeleteItemAction_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteItemActionAppliesToResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_DeleteItemAction_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_DeleteItemAction_proto_rawDesc), len(file_DeleteItemAction_proto_rawDesc)), NumEnums: 0, NumMessages: 3, NumExtensions: 0, @@ -311,7 +240,6 @@ func file_DeleteItemAction_proto_init() { MessageInfos: file_DeleteItemAction_proto_msgTypes, }.Build() File_DeleteItemAction_proto = out.File - file_DeleteItemAction_proto_rawDesc = nil file_DeleteItemAction_proto_goTypes = nil file_DeleteItemAction_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/ObjectStore.pb.go b/pkg/plugin/generated/ObjectStore.pb.go index 563849355..c960f159c 100644 --- a/pkg/plugin/generated/ObjectStore.pb.go +++ b/pkg/plugin/generated/ObjectStore.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: ObjectStore.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,23 +22,20 @@ const ( ) type PutObjectRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` - Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` - Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PutObjectRequest) Reset() { *x = PutObjectRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PutObjectRequest) String() string { @@ -48,7 +46,7 @@ func (*PutObjectRequest) ProtoMessage() {} func (x *PutObjectRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -92,22 +90,19 @@ func (x *PutObjectRequest) GetBody() []byte { } type ObjectExistsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` - Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ObjectExistsRequest) Reset() { *x = ObjectExistsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ObjectExistsRequest) String() string { @@ -118,7 +113,7 @@ func (*ObjectExistsRequest) ProtoMessage() {} func (x *ObjectExistsRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -155,20 +150,17 @@ func (x *ObjectExistsRequest) GetKey() string { } type ObjectExistsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Exists bool `protobuf:"varint,1,opt,name=exists,proto3" json:"exists,omitempty"` unknownFields protoimpl.UnknownFields - - Exists bool `protobuf:"varint,1,opt,name=exists,proto3" json:"exists,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ObjectExistsResponse) Reset() { *x = ObjectExistsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ObjectExistsResponse) String() string { @@ -179,7 +171,7 @@ func (*ObjectExistsResponse) ProtoMessage() {} func (x *ObjectExistsResponse) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -202,22 +194,19 @@ func (x *ObjectExistsResponse) GetExists() bool { } type GetObjectRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` - Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetObjectRequest) Reset() { *x = GetObjectRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetObjectRequest) String() string { @@ -228,7 +217,7 @@ func (*GetObjectRequest) ProtoMessage() {} func (x *GetObjectRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -265,20 +254,17 @@ func (x *GetObjectRequest) GetKey() string { } type Bytes struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields - - Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Bytes) Reset() { *x = Bytes{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Bytes) String() string { @@ -289,7 +275,7 @@ func (*Bytes) ProtoMessage() {} func (x *Bytes) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -312,23 +298,20 @@ func (x *Bytes) GetData() []byte { } type ListCommonPrefixesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + Delimiter string `protobuf:"bytes,3,opt,name=delimiter,proto3" json:"delimiter,omitempty"` + Prefix string `protobuf:"bytes,4,opt,name=prefix,proto3" json:"prefix,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` - Delimiter string `protobuf:"bytes,3,opt,name=delimiter,proto3" json:"delimiter,omitempty"` - Prefix string `protobuf:"bytes,4,opt,name=prefix,proto3" json:"prefix,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListCommonPrefixesRequest) Reset() { *x = ListCommonPrefixesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListCommonPrefixesRequest) String() string { @@ -339,7 +322,7 @@ func (*ListCommonPrefixesRequest) ProtoMessage() {} func (x *ListCommonPrefixesRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -383,20 +366,17 @@ func (x *ListCommonPrefixesRequest) GetPrefix() string { } type ListCommonPrefixesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Prefixes []string `protobuf:"bytes,1,rep,name=prefixes,proto3" json:"prefixes,omitempty"` unknownFields protoimpl.UnknownFields - - Prefixes []string `protobuf:"bytes,1,rep,name=prefixes,proto3" json:"prefixes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListCommonPrefixesResponse) Reset() { *x = ListCommonPrefixesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListCommonPrefixesResponse) String() string { @@ -407,7 +387,7 @@ func (*ListCommonPrefixesResponse) ProtoMessage() {} func (x *ListCommonPrefixesResponse) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -430,22 +410,19 @@ func (x *ListCommonPrefixesResponse) GetPrefixes() []string { } type ListObjectsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + Prefix string `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` - Prefix string `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListObjectsRequest) Reset() { *x = ListObjectsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListObjectsRequest) String() string { @@ -456,7 +433,7 @@ func (*ListObjectsRequest) ProtoMessage() {} func (x *ListObjectsRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -493,20 +470,17 @@ func (x *ListObjectsRequest) GetPrefix() string { } type ListObjectsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` unknownFields protoimpl.UnknownFields - - Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListObjectsResponse) Reset() { *x = ListObjectsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListObjectsResponse) String() string { @@ -517,7 +491,7 @@ func (*ListObjectsResponse) ProtoMessage() {} func (x *ListObjectsResponse) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -540,22 +514,19 @@ func (x *ListObjectsResponse) GetKeys() []string { } type DeleteObjectRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` - Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteObjectRequest) Reset() { *x = DeleteObjectRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeleteObjectRequest) String() string { @@ -566,7 +537,7 @@ func (*DeleteObjectRequest) ProtoMessage() {} func (x *DeleteObjectRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -603,23 +574,20 @@ func (x *DeleteObjectRequest) GetKey() string { } type CreateSignedURLRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + Ttl int64 `protobuf:"varint,4,opt,name=ttl,proto3" json:"ttl,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` - Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` - Ttl int64 `protobuf:"varint,4,opt,name=ttl,proto3" json:"ttl,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateSignedURLRequest) Reset() { *x = CreateSignedURLRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateSignedURLRequest) String() string { @@ -630,7 +598,7 @@ func (*CreateSignedURLRequest) ProtoMessage() {} func (x *CreateSignedURLRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -674,20 +642,17 @@ func (x *CreateSignedURLRequest) GetTtl() int64 { } type CreateSignedURLResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` unknownFields protoimpl.UnknownFields - - Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateSignedURLResponse) Reset() { *x = CreateSignedURLResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateSignedURLResponse) String() string { @@ -698,7 +663,7 @@ func (*CreateSignedURLResponse) ProtoMessage() {} func (x *CreateSignedURLResponse) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -721,21 +686,18 @@ func (x *CreateSignedURLResponse) GetUrl() string { } type ObjectStoreInitRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Config map[string]string `protobuf:"bytes,2,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Config map[string]string `protobuf:"bytes,2,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + sizeCache protoimpl.SizeCache } func (x *ObjectStoreInitRequest) Reset() { *x = ObjectStoreInitRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_ObjectStore_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_ObjectStore_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ObjectStoreInitRequest) String() string { @@ -746,7 +708,7 @@ func (*ObjectStoreInitRequest) ProtoMessage() {} func (x *ObjectStoreInitRequest) ProtoReflect() protoreflect.Message { mi := &file_ObjectStore_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -777,138 +739,80 @@ func (x *ObjectStoreInitRequest) GetConfig() map[string]string { var File_ObjectStore_proto protoreflect.FileDescriptor -var file_ObjectStore_proto_rawDesc = []byte{ - 0x0a, 0x11, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x1a, 0x0c, - 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x68, 0x0a, 0x10, - 0x50, 0x75, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x57, 0x0a, 0x13, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, - 0x2e, 0x0a, 0x14, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, - 0x54, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, - 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, - 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x1b, 0x0a, 0x05, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x12, - 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x22, 0x81, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x12, 0x16, - 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x38, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, - 0x22, 0x5c, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x29, - 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x57, 0x0a, 0x13, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x22, 0x6c, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, - 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x10, - 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, - 0x22, 0x2b, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, - 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, - 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xb2, 0x01, - 0x0a, 0x16, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x69, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x12, 0x45, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x32, 0xe4, 0x04, 0x0a, 0x0b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, - 0x72, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x21, 0x2e, 0x67, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, - 0x72, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x3c, 0x0a, 0x09, 0x50, 0x75, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1b, 0x2e, 0x67, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x50, 0x75, 0x74, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x4f, 0x0a, - 0x0c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x1e, 0x2e, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, - 0x0a, 0x09, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1b, 0x2e, 0x67, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x30, 0x01, 0x12, 0x61, 0x0a, 0x12, - 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, - 0x65, 0x73, 0x12, 0x24, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, - 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x4c, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1d, - 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, - 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1e, 0x2e, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x58, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x55, - 0x52, 0x4c, 0x12, 0x21, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x55, 0x52, 0x4c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x55, 0x52, - 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, - 0x61, 0x6e, 0x7a, 0x75, 0x2f, 0x76, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, - 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_ObjectStore_proto_rawDesc = "" + + "\n" + + "\x11ObjectStore.proto\x12\tgenerated\x1a\fShared.proto\"h\n" + + "\x10PutObjectRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x16\n" + + "\x06bucket\x18\x02 \x01(\tR\x06bucket\x12\x10\n" + + "\x03key\x18\x03 \x01(\tR\x03key\x12\x12\n" + + "\x04body\x18\x04 \x01(\fR\x04body\"W\n" + + "\x13ObjectExistsRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x16\n" + + "\x06bucket\x18\x02 \x01(\tR\x06bucket\x12\x10\n" + + "\x03key\x18\x03 \x01(\tR\x03key\".\n" + + "\x14ObjectExistsResponse\x12\x16\n" + + "\x06exists\x18\x01 \x01(\bR\x06exists\"T\n" + + "\x10GetObjectRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x16\n" + + "\x06bucket\x18\x02 \x01(\tR\x06bucket\x12\x10\n" + + "\x03key\x18\x03 \x01(\tR\x03key\"\x1b\n" + + "\x05Bytes\x12\x12\n" + + "\x04data\x18\x01 \x01(\fR\x04data\"\x81\x01\n" + + "\x19ListCommonPrefixesRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x16\n" + + "\x06bucket\x18\x02 \x01(\tR\x06bucket\x12\x1c\n" + + "\tdelimiter\x18\x03 \x01(\tR\tdelimiter\x12\x16\n" + + "\x06prefix\x18\x04 \x01(\tR\x06prefix\"8\n" + + "\x1aListCommonPrefixesResponse\x12\x1a\n" + + "\bprefixes\x18\x01 \x03(\tR\bprefixes\"\\\n" + + "\x12ListObjectsRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x16\n" + + "\x06bucket\x18\x02 \x01(\tR\x06bucket\x12\x16\n" + + "\x06prefix\x18\x03 \x01(\tR\x06prefix\")\n" + + "\x13ListObjectsResponse\x12\x12\n" + + "\x04keys\x18\x01 \x03(\tR\x04keys\"W\n" + + "\x13DeleteObjectRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x16\n" + + "\x06bucket\x18\x02 \x01(\tR\x06bucket\x12\x10\n" + + "\x03key\x18\x03 \x01(\tR\x03key\"l\n" + + "\x16CreateSignedURLRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x16\n" + + "\x06bucket\x18\x02 \x01(\tR\x06bucket\x12\x10\n" + + "\x03key\x18\x03 \x01(\tR\x03key\x12\x10\n" + + "\x03ttl\x18\x04 \x01(\x03R\x03ttl\"+\n" + + "\x17CreateSignedURLResponse\x12\x10\n" + + "\x03url\x18\x01 \x01(\tR\x03url\"\xb2\x01\n" + + "\x16ObjectStoreInitRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12E\n" + + "\x06config\x18\x02 \x03(\v2-.generated.ObjectStoreInitRequest.ConfigEntryR\x06config\x1a9\n" + + "\vConfigEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x012\xe4\x04\n" + + "\vObjectStore\x12;\n" + + "\x04Init\x12!.generated.ObjectStoreInitRequest\x1a\x10.generated.Empty\x12<\n" + + "\tPutObject\x12\x1b.generated.PutObjectRequest\x1a\x10.generated.Empty(\x01\x12O\n" + + "\fObjectExists\x12\x1e.generated.ObjectExistsRequest\x1a\x1f.generated.ObjectExistsResponse\x12<\n" + + "\tGetObject\x12\x1b.generated.GetObjectRequest\x1a\x10.generated.Bytes0\x01\x12a\n" + + "\x12ListCommonPrefixes\x12$.generated.ListCommonPrefixesRequest\x1a%.generated.ListCommonPrefixesResponse\x12L\n" + + "\vListObjects\x12\x1d.generated.ListObjectsRequest\x1a\x1e.generated.ListObjectsResponse\x12@\n" + + "\fDeleteObject\x12\x1e.generated.DeleteObjectRequest\x1a\x10.generated.Empty\x12X\n" + + "\x0fCreateSignedURL\x12!.generated.CreateSignedURLRequest\x1a\".generated.CreateSignedURLResponseB5Z3github.com/vmware-tanzu/velero/pkg/plugin/generatedb\x06proto3" var ( file_ObjectStore_proto_rawDescOnce sync.Once - file_ObjectStore_proto_rawDescData = file_ObjectStore_proto_rawDesc + file_ObjectStore_proto_rawDescData []byte ) func file_ObjectStore_proto_rawDescGZIP() []byte { file_ObjectStore_proto_rawDescOnce.Do(func() { - file_ObjectStore_proto_rawDescData = protoimpl.X.CompressGZIP(file_ObjectStore_proto_rawDescData) + file_ObjectStore_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ObjectStore_proto_rawDesc), len(file_ObjectStore_proto_rawDesc))) }) return file_ObjectStore_proto_rawDescData } var file_ObjectStore_proto_msgTypes = make([]protoimpl.MessageInfo, 14) -var file_ObjectStore_proto_goTypes = []interface{}{ +var file_ObjectStore_proto_goTypes = []any{ (*PutObjectRequest)(nil), // 0: generated.PutObjectRequest (*ObjectExistsRequest)(nil), // 1: generated.ObjectExistsRequest (*ObjectExistsResponse)(nil), // 2: generated.ObjectExistsResponse @@ -956,169 +860,11 @@ func file_ObjectStore_proto_init() { return } file_Shared_proto_init() - if !protoimpl.UnsafeEnabled { - file_ObjectStore_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PutObjectRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ObjectExistsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ObjectExistsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetObjectRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Bytes); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListCommonPrefixesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListCommonPrefixesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListObjectsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListObjectsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteObjectRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateSignedURLRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateSignedURLResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_ObjectStore_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ObjectStoreInitRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_ObjectStore_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_ObjectStore_proto_rawDesc), len(file_ObjectStore_proto_rawDesc)), NumEnums: 0, NumMessages: 14, NumExtensions: 0, @@ -1129,7 +875,6 @@ func file_ObjectStore_proto_init() { MessageInfos: file_ObjectStore_proto_msgTypes, }.Build() File_ObjectStore_proto = out.File - file_ObjectStore_proto_rawDesc = nil file_ObjectStore_proto_goTypes = nil file_ObjectStore_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/PluginLister.pb.go b/pkg/plugin/generated/PluginLister.pb.go index 590265750..239e57266 100644 --- a/pkg/plugin/generated/PluginLister.pb.go +++ b/pkg/plugin/generated/PluginLister.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: PluginLister.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,22 +22,19 @@ const ( ) type PluginIdentifier struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` + Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` unknownFields protoimpl.UnknownFields - - Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` - Kind string `protobuf:"bytes,2,opt,name=kind,proto3" json:"kind,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PluginIdentifier) Reset() { *x = PluginIdentifier{} - if protoimpl.UnsafeEnabled { - mi := &file_PluginLister_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_PluginLister_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PluginIdentifier) String() string { @@ -47,7 +45,7 @@ func (*PluginIdentifier) ProtoMessage() {} func (x *PluginIdentifier) ProtoReflect() protoreflect.Message { mi := &file_PluginLister_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -84,20 +82,17 @@ func (x *PluginIdentifier) GetName() string { } type ListPluginsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugins []*PluginIdentifier `protobuf:"bytes,1,rep,name=plugins,proto3" json:"plugins,omitempty"` unknownFields protoimpl.UnknownFields - - Plugins []*PluginIdentifier `protobuf:"bytes,1,rep,name=plugins,proto3" json:"plugins,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListPluginsResponse) Reset() { *x = ListPluginsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_PluginLister_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_PluginLister_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListPluginsResponse) String() string { @@ -108,7 +103,7 @@ func (*ListPluginsResponse) ProtoMessage() {} func (x *ListPluginsResponse) ProtoReflect() protoreflect.Message { mi := &file_PluginLister_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -132,46 +127,32 @@ func (x *ListPluginsResponse) GetPlugins() []*PluginIdentifier { var File_PluginLister_proto protoreflect.FileDescriptor -var file_PluginLister_proto_rawDesc = []byte{ - 0x0a, 0x12, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x1a, - 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x54, 0x0a, - 0x10, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6b, - 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0x4c, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x07, 0x70, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x73, 0x32, 0x4f, 0x0a, 0x0c, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x12, 0x3f, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, - 0x12, 0x10, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x1a, 0x1e, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, 0x75, 0x2f, 0x76, 0x65, - 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} +const file_PluginLister_proto_rawDesc = "" + + "\n" + + "\x12PluginLister.proto\x12\tgenerated\x1a\fShared.proto\"T\n" + + "\x10PluginIdentifier\x12\x18\n" + + "\acommand\x18\x01 \x01(\tR\acommand\x12\x12\n" + + "\x04kind\x18\x02 \x01(\tR\x04kind\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\"L\n" + + "\x13ListPluginsResponse\x125\n" + + "\aplugins\x18\x01 \x03(\v2\x1b.generated.PluginIdentifierR\aplugins2O\n" + + "\fPluginLister\x12?\n" + + "\vListPlugins\x12\x10.generated.Empty\x1a\x1e.generated.ListPluginsResponseB5Z3github.com/vmware-tanzu/velero/pkg/plugin/generatedb\x06proto3" var ( file_PluginLister_proto_rawDescOnce sync.Once - file_PluginLister_proto_rawDescData = file_PluginLister_proto_rawDesc + file_PluginLister_proto_rawDescData []byte ) func file_PluginLister_proto_rawDescGZIP() []byte { file_PluginLister_proto_rawDescOnce.Do(func() { - file_PluginLister_proto_rawDescData = protoimpl.X.CompressGZIP(file_PluginLister_proto_rawDescData) + file_PluginLister_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_PluginLister_proto_rawDesc), len(file_PluginLister_proto_rawDesc))) }) return file_PluginLister_proto_rawDescData } var file_PluginLister_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_PluginLister_proto_goTypes = []interface{}{ +var file_PluginLister_proto_goTypes = []any{ (*PluginIdentifier)(nil), // 0: generated.PluginIdentifier (*ListPluginsResponse)(nil), // 1: generated.ListPluginsResponse (*Empty)(nil), // 2: generated.Empty @@ -193,37 +174,11 @@ func file_PluginLister_proto_init() { return } file_Shared_proto_init() - if !protoimpl.UnsafeEnabled { - file_PluginLister_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PluginIdentifier); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_PluginLister_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListPluginsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_PluginLister_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_PluginLister_proto_rawDesc), len(file_PluginLister_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -234,7 +189,6 @@ func file_PluginLister_proto_init() { MessageInfos: file_PluginLister_proto_msgTypes, }.Build() File_PluginLister_proto = out.File - file_PluginLister_proto_rawDesc = nil file_PluginLister_proto_goTypes = nil file_PluginLister_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/RestoreItemAction.pb.go b/pkg/plugin/generated/RestoreItemAction.pb.go index 9489af476..f0d6dd3b7 100644 --- a/pkg/plugin/generated/RestoreItemAction.pb.go +++ b/pkg/plugin/generated/RestoreItemAction.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: RestoreItemAction.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,23 +22,20 @@ const ( ) type RestoreItemActionExecuteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` - Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` - ItemFromBackup []byte `protobuf:"bytes,4,opt,name=itemFromBackup,proto3" json:"itemFromBackup,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` + ItemFromBackup []byte `protobuf:"bytes,4,opt,name=itemFromBackup,proto3" json:"itemFromBackup,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionExecuteRequest) Reset() { *x = RestoreItemActionExecuteRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_RestoreItemAction_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_RestoreItemAction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionExecuteRequest) String() string { @@ -48,7 +46,7 @@ func (*RestoreItemActionExecuteRequest) ProtoMessage() {} func (x *RestoreItemActionExecuteRequest) ProtoReflect() protoreflect.Message { mi := &file_RestoreItemAction_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -92,22 +90,19 @@ func (x *RestoreItemActionExecuteRequest) GetItemFromBackup() []byte { } type RestoreItemActionExecuteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Item []byte `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` - AdditionalItems []*ResourceIdentifier `protobuf:"bytes,2,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` - SkipRestore bool `protobuf:"varint,3,opt,name=skipRestore,proto3" json:"skipRestore,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Item []byte `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + AdditionalItems []*ResourceIdentifier `protobuf:"bytes,2,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` + SkipRestore bool `protobuf:"varint,3,opt,name=skipRestore,proto3" json:"skipRestore,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionExecuteResponse) Reset() { *x = RestoreItemActionExecuteResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_RestoreItemAction_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_RestoreItemAction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionExecuteResponse) String() string { @@ -118,7 +113,7 @@ func (*RestoreItemActionExecuteResponse) ProtoMessage() {} func (x *RestoreItemActionExecuteResponse) ProtoReflect() protoreflect.Message { mi := &file_RestoreItemAction_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -155,20 +150,17 @@ func (x *RestoreItemActionExecuteResponse) GetSkipRestore() bool { } type RestoreItemActionAppliesToRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionAppliesToRequest) Reset() { *x = RestoreItemActionAppliesToRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_RestoreItemAction_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_RestoreItemAction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionAppliesToRequest) String() string { @@ -179,7 +171,7 @@ func (*RestoreItemActionAppliesToRequest) ProtoMessage() {} func (x *RestoreItemActionAppliesToRequest) ProtoReflect() protoreflect.Message { mi := &file_RestoreItemAction_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -202,20 +194,17 @@ func (x *RestoreItemActionAppliesToRequest) GetPlugin() string { } type RestoreItemActionAppliesToResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ResourceSelector *ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ResourceSelector *ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionAppliesToResponse) Reset() { *x = RestoreItemActionAppliesToResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_RestoreItemAction_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_RestoreItemAction_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionAppliesToResponse) String() string { @@ -226,7 +215,7 @@ func (*RestoreItemActionAppliesToResponse) ProtoMessage() {} func (x *RestoreItemActionAppliesToResponse) ProtoReflect() protoreflect.Message { mi := &file_RestoreItemAction_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -250,75 +239,40 @@ func (x *RestoreItemActionAppliesToResponse) GetResourceSelector() *ResourceSele var File_RestoreItemAction_proto protoreflect.FileDescriptor -var file_RestoreItemAction_proto_rawDesc = []byte{ - 0x0a, 0x17, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x1a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x8f, 0x01, 0x0a, 0x1f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, - 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, - 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x26, 0x0a, 0x0e, - 0x69, 0x74, 0x65, 0x6d, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x69, 0x74, 0x65, 0x6d, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x22, 0xa1, 0x01, 0x0a, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x47, 0x0a, - 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, - 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x6b, 0x69, - 0x70, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x3b, 0x0a, 0x21, 0x52, 0x65, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x6d, 0x0a, 0x22, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x10, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x52, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x32, 0xe1, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x68, 0x0a, 0x09, 0x41, 0x70, - 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x12, 0x2c, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, - 0x2a, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x67, 0x65, - 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, - 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, - 0x6e, 0x7a, 0x75, 0x2f, 0x76, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_RestoreItemAction_proto_rawDesc = "" + + "\n" + + "\x17RestoreItemAction.proto\x12\tgenerated\x1a\fShared.proto\"\x8f\x01\n" + + "\x1fRestoreItemActionExecuteRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x12\n" + + "\x04item\x18\x02 \x01(\fR\x04item\x12\x18\n" + + "\arestore\x18\x03 \x01(\fR\arestore\x12&\n" + + "\x0eitemFromBackup\x18\x04 \x01(\fR\x0eitemFromBackup\"\xa1\x01\n" + + " RestoreItemActionExecuteResponse\x12\x12\n" + + "\x04item\x18\x01 \x01(\fR\x04item\x12G\n" + + "\x0fadditionalItems\x18\x02 \x03(\v2\x1d.generated.ResourceIdentifierR\x0fadditionalItems\x12 \n" + + "\vskipRestore\x18\x03 \x01(\bR\vskipRestore\";\n" + + "!RestoreItemActionAppliesToRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\"m\n" + + "\"RestoreItemActionAppliesToResponse\x12G\n" + + "\x10ResourceSelector\x18\x01 \x01(\v2\x1b.generated.ResourceSelectorR\x10ResourceSelector2\xe1\x01\n" + + "\x11RestoreItemAction\x12h\n" + + "\tAppliesTo\x12,.generated.RestoreItemActionAppliesToRequest\x1a-.generated.RestoreItemActionAppliesToResponse\x12b\n" + + "\aExecute\x12*.generated.RestoreItemActionExecuteRequest\x1a+.generated.RestoreItemActionExecuteResponseB5Z3github.com/vmware-tanzu/velero/pkg/plugin/generatedb\x06proto3" var ( file_RestoreItemAction_proto_rawDescOnce sync.Once - file_RestoreItemAction_proto_rawDescData = file_RestoreItemAction_proto_rawDesc + file_RestoreItemAction_proto_rawDescData []byte ) func file_RestoreItemAction_proto_rawDescGZIP() []byte { file_RestoreItemAction_proto_rawDescOnce.Do(func() { - file_RestoreItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(file_RestoreItemAction_proto_rawDescData) + file_RestoreItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_RestoreItemAction_proto_rawDesc), len(file_RestoreItemAction_proto_rawDesc))) }) return file_RestoreItemAction_proto_rawDescData } var file_RestoreItemAction_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_RestoreItemAction_proto_goTypes = []interface{}{ +var file_RestoreItemAction_proto_goTypes = []any{ (*RestoreItemActionExecuteRequest)(nil), // 0: generated.RestoreItemActionExecuteRequest (*RestoreItemActionExecuteResponse)(nil), // 1: generated.RestoreItemActionExecuteResponse (*RestoreItemActionAppliesToRequest)(nil), // 2: generated.RestoreItemActionAppliesToRequest @@ -346,61 +300,11 @@ func file_RestoreItemAction_proto_init() { return } file_Shared_proto_init() - if !protoimpl.UnsafeEnabled { - file_RestoreItemAction_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionExecuteRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_RestoreItemAction_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionExecuteResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_RestoreItemAction_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionAppliesToRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_RestoreItemAction_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionAppliesToResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_RestoreItemAction_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_RestoreItemAction_proto_rawDesc), len(file_RestoreItemAction_proto_rawDesc)), NumEnums: 0, NumMessages: 4, NumExtensions: 0, @@ -411,7 +315,6 @@ func file_RestoreItemAction_proto_init() { MessageInfos: file_RestoreItemAction_proto_msgTypes, }.Build() File_RestoreItemAction_proto = out.File - file_RestoreItemAction_proto_rawDesc = nil file_RestoreItemAction_proto_goTypes = nil file_RestoreItemAction_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/Shared.pb.go b/pkg/plugin/generated/Shared.pb.go index 07af30089..7c458579b 100644 --- a/pkg/plugin/generated/Shared.pb.go +++ b/pkg/plugin/generated/Shared.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: Shared.proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,18 +23,16 @@ const ( ) type Empty struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Empty) Reset() { *x = Empty{} - if protoimpl.UnsafeEnabled { - mi := &file_Shared_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Shared_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Empty) String() string { @@ -44,7 +43,7 @@ func (*Empty) ProtoMessage() {} func (x *Empty) ProtoReflect() protoreflect.Message { mi := &file_Shared_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -60,20 +59,17 @@ func (*Empty) Descriptor() ([]byte, []int) { } type Stack struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Frames []*StackFrame `protobuf:"bytes,1,rep,name=frames,proto3" json:"frames,omitempty"` unknownFields protoimpl.UnknownFields - - Frames []*StackFrame `protobuf:"bytes,1,rep,name=frames,proto3" json:"frames,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Stack) Reset() { *x = Stack{} - if protoimpl.UnsafeEnabled { - mi := &file_Shared_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Shared_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Stack) String() string { @@ -84,7 +80,7 @@ func (*Stack) ProtoMessage() {} func (x *Stack) ProtoReflect() protoreflect.Message { mi := &file_Shared_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -107,22 +103,19 @@ func (x *Stack) GetFrames() []*StackFrame { } type StackFrame struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` + Line int32 `protobuf:"varint,2,opt,name=line,proto3" json:"line,omitempty"` + Function string `protobuf:"bytes,3,opt,name=function,proto3" json:"function,omitempty"` unknownFields protoimpl.UnknownFields - - File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` - Line int32 `protobuf:"varint,2,opt,name=line,proto3" json:"line,omitempty"` - Function string `protobuf:"bytes,3,opt,name=function,proto3" json:"function,omitempty"` + sizeCache protoimpl.SizeCache } func (x *StackFrame) Reset() { *x = StackFrame{} - if protoimpl.UnsafeEnabled { - mi := &file_Shared_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Shared_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StackFrame) String() string { @@ -133,7 +126,7 @@ func (*StackFrame) ProtoMessage() {} func (x *StackFrame) ProtoReflect() protoreflect.Message { mi := &file_Shared_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -170,23 +163,20 @@ func (x *StackFrame) GetFunction() string { } type ResourceIdentifier struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Group string `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` + Resource string `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` unknownFields protoimpl.UnknownFields - - Group string `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` - Resource string `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` - Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` - Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ResourceIdentifier) Reset() { *x = ResourceIdentifier{} - if protoimpl.UnsafeEnabled { - mi := &file_Shared_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Shared_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResourceIdentifier) String() string { @@ -197,7 +187,7 @@ func (*ResourceIdentifier) ProtoMessage() {} func (x *ResourceIdentifier) ProtoReflect() protoreflect.Message { mi := &file_Shared_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -241,24 +231,21 @@ func (x *ResourceIdentifier) GetName() string { } type ResourceSelector struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - IncludedNamespaces []string `protobuf:"bytes,1,rep,name=includedNamespaces,proto3" json:"includedNamespaces,omitempty"` - ExcludedNamespaces []string `protobuf:"bytes,2,rep,name=excludedNamespaces,proto3" json:"excludedNamespaces,omitempty"` - IncludedResources []string `protobuf:"bytes,3,rep,name=includedResources,proto3" json:"includedResources,omitempty"` - ExcludedResources []string `protobuf:"bytes,4,rep,name=excludedResources,proto3" json:"excludedResources,omitempty"` - Selector string `protobuf:"bytes,5,opt,name=selector,proto3" json:"selector,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + IncludedNamespaces []string `protobuf:"bytes,1,rep,name=includedNamespaces,proto3" json:"includedNamespaces,omitempty"` + ExcludedNamespaces []string `protobuf:"bytes,2,rep,name=excludedNamespaces,proto3" json:"excludedNamespaces,omitempty"` + IncludedResources []string `protobuf:"bytes,3,rep,name=includedResources,proto3" json:"includedResources,omitempty"` + ExcludedResources []string `protobuf:"bytes,4,rep,name=excludedResources,proto3" json:"excludedResources,omitempty"` + Selector string `protobuf:"bytes,5,opt,name=selector,proto3" json:"selector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ResourceSelector) Reset() { *x = ResourceSelector{} - if protoimpl.UnsafeEnabled { - mi := &file_Shared_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Shared_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ResourceSelector) String() string { @@ -269,7 +256,7 @@ func (*ResourceSelector) ProtoMessage() {} func (x *ResourceSelector) ProtoReflect() protoreflect.Message { mi := &file_Shared_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -320,10 +307,7 @@ func (x *ResourceSelector) GetSelector() string { } type OperationProgress struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Completed bool `protobuf:"varint,1,opt,name=completed,proto3" json:"completed,omitempty"` Err string `protobuf:"bytes,2,opt,name=err,proto3" json:"err,omitempty"` NCompleted int64 `protobuf:"varint,3,opt,name=nCompleted,proto3" json:"nCompleted,omitempty"` @@ -332,15 +316,15 @@ type OperationProgress struct { Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` Started *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=started,proto3" json:"started,omitempty"` Updated *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=updated,proto3" json:"updated,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *OperationProgress) Reset() { *x = OperationProgress{} - if protoimpl.UnsafeEnabled { - mi := &file_Shared_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_Shared_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *OperationProgress) String() string { @@ -351,7 +335,7 @@ func (*OperationProgress) ProtoMessage() {} func (x *OperationProgress) ProtoReflect() protoreflect.Message { mi := &file_Shared_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -424,82 +408,54 @@ func (x *OperationProgress) GetUpdated() *timestamppb.Timestamp { var File_Shared_proto protoreflect.FileDescriptor -var file_Shared_proto_rawDesc = []byte{ - 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 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, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x36, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x12, 0x2d, 0x0a, 0x06, - 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x46, 0x72, - 0x61, 0x6d, 0x65, 0x52, 0x06, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x50, 0x0a, 0x0a, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6c, 0x69, 0x6e, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x78, 0x0a, - 0x12, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x2e, 0x0a, 0x12, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, - 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x65, 0x78, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x22, 0xb1, 0x02, 0x0a, 0x11, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6e, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, - 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x54, - 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x54, 0x6f, 0x74, - 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, - 0x6e, 0x69, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x07, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 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, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x08, 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, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, - 0x6e, 0x7a, 0x75, 0x2f, 0x76, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_Shared_proto_rawDesc = "" + + "\n" + + "\fShared.proto\x12\tgenerated\x1a\x1fgoogle/protobuf/timestamp.proto\"\a\n" + + "\x05Empty\"6\n" + + "\x05Stack\x12-\n" + + "\x06frames\x18\x01 \x03(\v2\x15.generated.StackFrameR\x06frames\"P\n" + + "\n" + + "StackFrame\x12\x12\n" + + "\x04file\x18\x01 \x01(\tR\x04file\x12\x12\n" + + "\x04line\x18\x02 \x01(\x05R\x04line\x12\x1a\n" + + "\bfunction\x18\x03 \x01(\tR\bfunction\"x\n" + + "\x12ResourceIdentifier\x12\x14\n" + + "\x05group\x18\x01 \x01(\tR\x05group\x12\x1a\n" + + "\bresource\x18\x02 \x01(\tR\bresource\x12\x1c\n" + + "\tnamespace\x18\x03 \x01(\tR\tnamespace\x12\x12\n" + + "\x04name\x18\x04 \x01(\tR\x04name\"\xea\x01\n" + + "\x10ResourceSelector\x12.\n" + + "\x12includedNamespaces\x18\x01 \x03(\tR\x12includedNamespaces\x12.\n" + + "\x12excludedNamespaces\x18\x02 \x03(\tR\x12excludedNamespaces\x12,\n" + + "\x11includedResources\x18\x03 \x03(\tR\x11includedResources\x12,\n" + + "\x11excludedResources\x18\x04 \x03(\tR\x11excludedResources\x12\x1a\n" + + "\bselector\x18\x05 \x01(\tR\bselector\"\xb1\x02\n" + + "\x11OperationProgress\x12\x1c\n" + + "\tcompleted\x18\x01 \x01(\bR\tcompleted\x12\x10\n" + + "\x03err\x18\x02 \x01(\tR\x03err\x12\x1e\n" + + "\n" + + "nCompleted\x18\x03 \x01(\x03R\n" + + "nCompleted\x12\x16\n" + + "\x06nTotal\x18\x04 \x01(\x03R\x06nTotal\x12&\n" + + "\x0eoperationUnits\x18\x05 \x01(\tR\x0eoperationUnits\x12 \n" + + "\vdescription\x18\x06 \x01(\tR\vdescription\x124\n" + + "\astarted\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\astarted\x124\n" + + "\aupdated\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\aupdatedB5Z3github.com/vmware-tanzu/velero/pkg/plugin/generatedb\x06proto3" var ( file_Shared_proto_rawDescOnce sync.Once - file_Shared_proto_rawDescData = file_Shared_proto_rawDesc + file_Shared_proto_rawDescData []byte ) func file_Shared_proto_rawDescGZIP() []byte { file_Shared_proto_rawDescOnce.Do(func() { - file_Shared_proto_rawDescData = protoimpl.X.CompressGZIP(file_Shared_proto_rawDescData) + file_Shared_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_Shared_proto_rawDesc), len(file_Shared_proto_rawDesc))) }) return file_Shared_proto_rawDescData } var file_Shared_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_Shared_proto_goTypes = []interface{}{ +var file_Shared_proto_goTypes = []any{ (*Empty)(nil), // 0: generated.Empty (*Stack)(nil), // 1: generated.Stack (*StackFrame)(nil), // 2: generated.StackFrame @@ -524,85 +480,11 @@ func file_Shared_proto_init() { if File_Shared_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_Shared_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Empty); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Shared_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Stack); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Shared_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StackFrame); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Shared_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResourceIdentifier); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Shared_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResourceSelector); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_Shared_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OperationProgress); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_Shared_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_Shared_proto_rawDesc), len(file_Shared_proto_rawDesc)), NumEnums: 0, NumMessages: 6, NumExtensions: 0, @@ -613,7 +495,6 @@ func file_Shared_proto_init() { MessageInfos: file_Shared_proto_msgTypes, }.Build() File_Shared_proto = out.File - file_Shared_proto_rawDesc = nil file_Shared_proto_goTypes = nil file_Shared_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/VolumeSnapshotter.pb.go b/pkg/plugin/generated/VolumeSnapshotter.pb.go index 673ad9739..2b5f9a86e 100644 --- a/pkg/plugin/generated/VolumeSnapshotter.pb.go +++ b/pkg/plugin/generated/VolumeSnapshotter.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: VolumeSnapshotter.proto @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,24 +22,21 @@ const ( ) type CreateVolumeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + SnapshotID string `protobuf:"bytes,2,opt,name=snapshotID,proto3" json:"snapshotID,omitempty"` + VolumeType string `protobuf:"bytes,3,opt,name=volumeType,proto3" json:"volumeType,omitempty"` + VolumeAZ string `protobuf:"bytes,4,opt,name=volumeAZ,proto3" json:"volumeAZ,omitempty"` + Iops int64 `protobuf:"varint,5,opt,name=iops,proto3" json:"iops,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - SnapshotID string `protobuf:"bytes,2,opt,name=snapshotID,proto3" json:"snapshotID,omitempty"` - VolumeType string `protobuf:"bytes,3,opt,name=volumeType,proto3" json:"volumeType,omitempty"` - VolumeAZ string `protobuf:"bytes,4,opt,name=volumeAZ,proto3" json:"volumeAZ,omitempty"` - Iops int64 `protobuf:"varint,5,opt,name=iops,proto3" json:"iops,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateVolumeRequest) Reset() { *x = CreateVolumeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateVolumeRequest) String() string { @@ -49,7 +47,7 @@ func (*CreateVolumeRequest) ProtoMessage() {} func (x *CreateVolumeRequest) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -100,20 +98,17 @@ func (x *CreateVolumeRequest) GetIops() int64 { } type CreateVolumeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + VolumeID string `protobuf:"bytes,1,opt,name=volumeID,proto3" json:"volumeID,omitempty"` unknownFields protoimpl.UnknownFields - - VolumeID string `protobuf:"bytes,1,opt,name=volumeID,proto3" json:"volumeID,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateVolumeResponse) Reset() { *x = CreateVolumeResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateVolumeResponse) String() string { @@ -124,7 +119,7 @@ func (*CreateVolumeResponse) ProtoMessage() {} func (x *CreateVolumeResponse) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -147,22 +142,19 @@ func (x *CreateVolumeResponse) GetVolumeID() string { } type GetVolumeInfoRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + VolumeID string `protobuf:"bytes,2,opt,name=volumeID,proto3" json:"volumeID,omitempty"` + VolumeAZ string `protobuf:"bytes,3,opt,name=volumeAZ,proto3" json:"volumeAZ,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - VolumeID string `protobuf:"bytes,2,opt,name=volumeID,proto3" json:"volumeID,omitempty"` - VolumeAZ string `protobuf:"bytes,3,opt,name=volumeAZ,proto3" json:"volumeAZ,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetVolumeInfoRequest) Reset() { *x = GetVolumeInfoRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetVolumeInfoRequest) String() string { @@ -173,7 +165,7 @@ func (*GetVolumeInfoRequest) ProtoMessage() {} func (x *GetVolumeInfoRequest) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -210,21 +202,18 @@ func (x *GetVolumeInfoRequest) GetVolumeAZ() string { } type GetVolumeInfoResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + VolumeType string `protobuf:"bytes,1,opt,name=volumeType,proto3" json:"volumeType,omitempty"` + Iops int64 `protobuf:"varint,2,opt,name=iops,proto3" json:"iops,omitempty"` unknownFields protoimpl.UnknownFields - - VolumeType string `protobuf:"bytes,1,opt,name=volumeType,proto3" json:"volumeType,omitempty"` - Iops int64 `protobuf:"varint,2,opt,name=iops,proto3" json:"iops,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetVolumeInfoResponse) Reset() { *x = GetVolumeInfoResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetVolumeInfoResponse) String() string { @@ -235,7 +224,7 @@ func (*GetVolumeInfoResponse) ProtoMessage() {} func (x *GetVolumeInfoResponse) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -265,23 +254,20 @@ func (x *GetVolumeInfoResponse) GetIops() int64 { } type CreateSnapshotRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + VolumeID string `protobuf:"bytes,2,opt,name=volumeID,proto3" json:"volumeID,omitempty"` + VolumeAZ string `protobuf:"bytes,3,opt,name=volumeAZ,proto3" json:"volumeAZ,omitempty"` + Tags map[string]string `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - VolumeID string `protobuf:"bytes,2,opt,name=volumeID,proto3" json:"volumeID,omitempty"` - VolumeAZ string `protobuf:"bytes,3,opt,name=volumeAZ,proto3" json:"volumeAZ,omitempty"` - Tags map[string]string `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + sizeCache protoimpl.SizeCache } func (x *CreateSnapshotRequest) Reset() { *x = CreateSnapshotRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateSnapshotRequest) String() string { @@ -292,7 +278,7 @@ func (*CreateSnapshotRequest) ProtoMessage() {} func (x *CreateSnapshotRequest) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -336,20 +322,17 @@ func (x *CreateSnapshotRequest) GetTags() map[string]string { } type CreateSnapshotResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SnapshotID string `protobuf:"bytes,1,opt,name=snapshotID,proto3" json:"snapshotID,omitempty"` unknownFields protoimpl.UnknownFields - - SnapshotID string `protobuf:"bytes,1,opt,name=snapshotID,proto3" json:"snapshotID,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateSnapshotResponse) Reset() { *x = CreateSnapshotResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateSnapshotResponse) String() string { @@ -360,7 +343,7 @@ func (*CreateSnapshotResponse) ProtoMessage() {} func (x *CreateSnapshotResponse) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -383,21 +366,18 @@ func (x *CreateSnapshotResponse) GetSnapshotID() string { } type DeleteSnapshotRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + SnapshotID string `protobuf:"bytes,2,opt,name=snapshotID,proto3" json:"snapshotID,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - SnapshotID string `protobuf:"bytes,2,opt,name=snapshotID,proto3" json:"snapshotID,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteSnapshotRequest) Reset() { *x = DeleteSnapshotRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeleteSnapshotRequest) String() string { @@ -408,7 +388,7 @@ func (*DeleteSnapshotRequest) ProtoMessage() {} func (x *DeleteSnapshotRequest) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -438,21 +418,18 @@ func (x *DeleteSnapshotRequest) GetSnapshotID() string { } type GetVolumeIDRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - PersistentVolume []byte `protobuf:"bytes,2,opt,name=persistentVolume,proto3" json:"persistentVolume,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + PersistentVolume []byte `protobuf:"bytes,2,opt,name=persistentVolume,proto3" json:"persistentVolume,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *GetVolumeIDRequest) Reset() { *x = GetVolumeIDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetVolumeIDRequest) String() string { @@ -463,7 +440,7 @@ func (*GetVolumeIDRequest) ProtoMessage() {} func (x *GetVolumeIDRequest) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -493,20 +470,17 @@ func (x *GetVolumeIDRequest) GetPersistentVolume() []byte { } type GetVolumeIDResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + VolumeID string `protobuf:"bytes,1,opt,name=volumeID,proto3" json:"volumeID,omitempty"` unknownFields protoimpl.UnknownFields - - VolumeID string `protobuf:"bytes,1,opt,name=volumeID,proto3" json:"volumeID,omitempty"` + sizeCache protoimpl.SizeCache } func (x *GetVolumeIDResponse) Reset() { *x = GetVolumeIDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *GetVolumeIDResponse) String() string { @@ -517,7 +491,7 @@ func (*GetVolumeIDResponse) ProtoMessage() {} func (x *GetVolumeIDResponse) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -540,22 +514,19 @@ func (x *GetVolumeIDResponse) GetVolumeID() string { } type SetVolumeIDRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - PersistentVolume []byte `protobuf:"bytes,2,opt,name=persistentVolume,proto3" json:"persistentVolume,omitempty"` - VolumeID string `protobuf:"bytes,3,opt,name=volumeID,proto3" json:"volumeID,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + PersistentVolume []byte `protobuf:"bytes,2,opt,name=persistentVolume,proto3" json:"persistentVolume,omitempty"` + VolumeID string `protobuf:"bytes,3,opt,name=volumeID,proto3" json:"volumeID,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SetVolumeIDRequest) Reset() { *x = SetVolumeIDRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetVolumeIDRequest) String() string { @@ -566,7 +537,7 @@ func (*SetVolumeIDRequest) ProtoMessage() {} func (x *SetVolumeIDRequest) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -603,20 +574,17 @@ func (x *SetVolumeIDRequest) GetVolumeID() string { } type SetVolumeIDResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PersistentVolume []byte `protobuf:"bytes,1,opt,name=persistentVolume,proto3" json:"persistentVolume,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + PersistentVolume []byte `protobuf:"bytes,1,opt,name=persistentVolume,proto3" json:"persistentVolume,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SetVolumeIDResponse) Reset() { *x = SetVolumeIDResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *SetVolumeIDResponse) String() string { @@ -627,7 +595,7 @@ func (*SetVolumeIDResponse) ProtoMessage() {} func (x *SetVolumeIDResponse) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -650,21 +618,18 @@ func (x *SetVolumeIDResponse) GetPersistentVolume() []byte { } type VolumeSnapshotterInitRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Config map[string]string `protobuf:"bytes,2,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Config map[string]string `protobuf:"bytes,2,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + sizeCache protoimpl.SizeCache } func (x *VolumeSnapshotterInitRequest) Reset() { *x = VolumeSnapshotterInitRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_VolumeSnapshotter_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_VolumeSnapshotter_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *VolumeSnapshotterInitRequest) String() string { @@ -675,7 +640,7 @@ func (*VolumeSnapshotterInitRequest) ProtoMessage() {} func (x *VolumeSnapshotterInitRequest) ProtoReflect() protoreflect.Message { mi := &file_VolumeSnapshotter_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -706,147 +671,87 @@ func (x *VolumeSnapshotterInitRequest) GetConfig() map[string]string { var File_VolumeSnapshotter_proto protoreflect.FileDescriptor -var file_VolumeSnapshotter_proto_rawDesc = []byte{ - 0x0a, 0x17, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x1a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x49, 0x44, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x41, 0x5a, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x41, 0x5a, 0x12, 0x12, - 0x0a, 0x04, 0x69, 0x6f, 0x70, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x69, 0x6f, - 0x70, 0x73, 0x22, 0x32, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, - 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x22, 0x66, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x41, 0x5a, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x41, 0x5a, 0x22, 0x4b, - 0x0a, 0x15, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6f, 0x70, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x69, 0x6f, 0x70, 0x73, 0x22, 0xe0, 0x01, 0x0a, 0x15, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x41, 0x5a, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x41, 0x5a, 0x12, 0x3e, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x38, - 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x49, 0x44, 0x22, 0x4f, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x49, 0x44, 0x22, 0x58, 0x0a, 0x12, 0x47, 0x65, 0x74, - 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x70, 0x65, 0x72, 0x73, 0x69, - 0x73, 0x74, 0x65, 0x6e, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x10, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x22, 0x31, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x22, 0x74, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, - 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, - 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x22, 0x41, 0x0a, 0x13, - 0x53, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, - 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, - 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x22, - 0xbe, 0x01, 0x0a, 0x1c, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, - 0x6f, 0x74, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x4b, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x32, 0xc0, 0x04, 0x0a, 0x11, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x27, - 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x56, 0x6f, 0x6c, 0x75, 0x6d, - 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x69, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5b, 0x0a, 0x18, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1e, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x0e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x20, 0x2e, 0x67, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, - 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x44, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, - 0x68, 0x6f, 0x74, 0x12, 0x20, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x56, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, - 0x6d, 0x65, 0x49, 0x44, 0x12, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, - 0x2e, 0x53, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, - 0x53, 0x65, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, 0x75, 0x2f, 0x76, - 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, -} +const file_VolumeSnapshotter_proto_rawDesc = "" + + "\n" + + "\x17VolumeSnapshotter.proto\x12\tgenerated\x1a\fShared.proto\"\x9d\x01\n" + + "\x13CreateVolumeRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x1e\n" + + "\n" + + "snapshotID\x18\x02 \x01(\tR\n" + + "snapshotID\x12\x1e\n" + + "\n" + + "volumeType\x18\x03 \x01(\tR\n" + + "volumeType\x12\x1a\n" + + "\bvolumeAZ\x18\x04 \x01(\tR\bvolumeAZ\x12\x12\n" + + "\x04iops\x18\x05 \x01(\x03R\x04iops\"2\n" + + "\x14CreateVolumeResponse\x12\x1a\n" + + "\bvolumeID\x18\x01 \x01(\tR\bvolumeID\"f\n" + + "\x14GetVolumeInfoRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x1a\n" + + "\bvolumeID\x18\x02 \x01(\tR\bvolumeID\x12\x1a\n" + + "\bvolumeAZ\x18\x03 \x01(\tR\bvolumeAZ\"K\n" + + "\x15GetVolumeInfoResponse\x12\x1e\n" + + "\n" + + "volumeType\x18\x01 \x01(\tR\n" + + "volumeType\x12\x12\n" + + "\x04iops\x18\x02 \x01(\x03R\x04iops\"\xe0\x01\n" + + "\x15CreateSnapshotRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x1a\n" + + "\bvolumeID\x18\x02 \x01(\tR\bvolumeID\x12\x1a\n" + + "\bvolumeAZ\x18\x03 \x01(\tR\bvolumeAZ\x12>\n" + + "\x04tags\x18\x04 \x03(\v2*.generated.CreateSnapshotRequest.TagsEntryR\x04tags\x1a7\n" + + "\tTagsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"8\n" + + "\x16CreateSnapshotResponse\x12\x1e\n" + + "\n" + + "snapshotID\x18\x01 \x01(\tR\n" + + "snapshotID\"O\n" + + "\x15DeleteSnapshotRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x1e\n" + + "\n" + + "snapshotID\x18\x02 \x01(\tR\n" + + "snapshotID\"X\n" + + "\x12GetVolumeIDRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12*\n" + + "\x10persistentVolume\x18\x02 \x01(\fR\x10persistentVolume\"1\n" + + "\x13GetVolumeIDResponse\x12\x1a\n" + + "\bvolumeID\x18\x01 \x01(\tR\bvolumeID\"t\n" + + "\x12SetVolumeIDRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12*\n" + + "\x10persistentVolume\x18\x02 \x01(\fR\x10persistentVolume\x12\x1a\n" + + "\bvolumeID\x18\x03 \x01(\tR\bvolumeID\"A\n" + + "\x13SetVolumeIDResponse\x12*\n" + + "\x10persistentVolume\x18\x01 \x01(\fR\x10persistentVolume\"\xbe\x01\n" + + "\x1cVolumeSnapshotterInitRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12K\n" + + "\x06config\x18\x02 \x03(\v23.generated.VolumeSnapshotterInitRequest.ConfigEntryR\x06config\x1a9\n" + + "\vConfigEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x012\xc0\x04\n" + + "\x11VolumeSnapshotter\x12A\n" + + "\x04Init\x12'.generated.VolumeSnapshotterInitRequest\x1a\x10.generated.Empty\x12[\n" + + "\x18CreateVolumeFromSnapshot\x12\x1e.generated.CreateVolumeRequest\x1a\x1f.generated.CreateVolumeResponse\x12R\n" + + "\rGetVolumeInfo\x12\x1f.generated.GetVolumeInfoRequest\x1a .generated.GetVolumeInfoResponse\x12U\n" + + "\x0eCreateSnapshot\x12 .generated.CreateSnapshotRequest\x1a!.generated.CreateSnapshotResponse\x12D\n" + + "\x0eDeleteSnapshot\x12 .generated.DeleteSnapshotRequest\x1a\x10.generated.Empty\x12L\n" + + "\vGetVolumeID\x12\x1d.generated.GetVolumeIDRequest\x1a\x1e.generated.GetVolumeIDResponse\x12L\n" + + "\vSetVolumeID\x12\x1d.generated.SetVolumeIDRequest\x1a\x1e.generated.SetVolumeIDResponseB5Z3github.com/vmware-tanzu/velero/pkg/plugin/generatedb\x06proto3" var ( file_VolumeSnapshotter_proto_rawDescOnce sync.Once - file_VolumeSnapshotter_proto_rawDescData = file_VolumeSnapshotter_proto_rawDesc + file_VolumeSnapshotter_proto_rawDescData []byte ) func file_VolumeSnapshotter_proto_rawDescGZIP() []byte { file_VolumeSnapshotter_proto_rawDescOnce.Do(func() { - file_VolumeSnapshotter_proto_rawDescData = protoimpl.X.CompressGZIP(file_VolumeSnapshotter_proto_rawDescData) + file_VolumeSnapshotter_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_VolumeSnapshotter_proto_rawDesc), len(file_VolumeSnapshotter_proto_rawDesc))) }) return file_VolumeSnapshotter_proto_rawDescData } var file_VolumeSnapshotter_proto_msgTypes = make([]protoimpl.MessageInfo, 14) -var file_VolumeSnapshotter_proto_goTypes = []interface{}{ +var file_VolumeSnapshotter_proto_goTypes = []any{ (*CreateVolumeRequest)(nil), // 0: generated.CreateVolumeRequest (*CreateVolumeResponse)(nil), // 1: generated.CreateVolumeResponse (*GetVolumeInfoRequest)(nil), // 2: generated.GetVolumeInfoRequest @@ -893,157 +798,11 @@ func file_VolumeSnapshotter_proto_init() { return } file_Shared_proto_init() - if !protoimpl.UnsafeEnabled { - file_VolumeSnapshotter_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateVolumeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateVolumeResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVolumeInfoRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVolumeInfoResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateSnapshotRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateSnapshotResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteSnapshotRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVolumeIDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetVolumeIDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SetVolumeIDRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SetVolumeIDResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_VolumeSnapshotter_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VolumeSnapshotterInitRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_VolumeSnapshotter_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_VolumeSnapshotter_proto_rawDesc), len(file_VolumeSnapshotter_proto_rawDesc)), NumEnums: 0, NumMessages: 14, NumExtensions: 0, @@ -1054,7 +813,6 @@ func file_VolumeSnapshotter_proto_init() { MessageInfos: file_VolumeSnapshotter_proto_msgTypes, }.Build() File_VolumeSnapshotter_proto = out.File - file_VolumeSnapshotter_proto_rawDesc = nil file_VolumeSnapshotter_proto_goTypes = nil file_VolumeSnapshotter_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/backupitemaction/v2/BackupItemAction.pb.go b/pkg/plugin/generated/backupitemaction/v2/BackupItemAction.pb.go index 5eb2c852b..097dfc721 100644 --- a/pkg/plugin/generated/backupitemaction/v2/BackupItemAction.pb.go +++ b/pkg/plugin/generated/backupitemaction/v2/BackupItemAction.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: backupitemaction/v2/BackupItemAction.proto @@ -13,6 +13,7 @@ import ( emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -23,22 +24,19 @@ const ( ) type ExecuteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` - Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ExecuteRequest) Reset() { *x = ExecuteRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExecuteRequest) String() string { @@ -49,7 +47,7 @@ func (*ExecuteRequest) ProtoMessage() {} func (x *ExecuteRequest) ProtoReflect() protoreflect.Message { mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -86,23 +84,20 @@ func (x *ExecuteRequest) GetBackup() []byte { } type ExecuteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Item []byte `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` AdditionalItems []*generated.ResourceIdentifier `protobuf:"bytes,2,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` OperationID string `protobuf:"bytes,3,opt,name=operationID,proto3" json:"operationID,omitempty"` PostOperationItems []*generated.ResourceIdentifier `protobuf:"bytes,4,rep,name=postOperationItems,proto3" json:"postOperationItems,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExecuteResponse) Reset() { *x = ExecuteResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ExecuteResponse) String() string { @@ -113,7 +108,7 @@ func (*ExecuteResponse) ProtoMessage() {} func (x *ExecuteResponse) ProtoReflect() protoreflect.Message { mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -157,20 +152,17 @@ func (x *ExecuteResponse) GetPostOperationItems() []*generated.ResourceIdentifie } type BackupItemActionAppliesToRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BackupItemActionAppliesToRequest) Reset() { *x = BackupItemActionAppliesToRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BackupItemActionAppliesToRequest) String() string { @@ -181,7 +173,7 @@ func (*BackupItemActionAppliesToRequest) ProtoMessage() {} func (x *BackupItemActionAppliesToRequest) ProtoReflect() protoreflect.Message { mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -204,20 +196,17 @@ func (x *BackupItemActionAppliesToRequest) GetPlugin() string { } type BackupItemActionAppliesToResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` ResourceSelector *generated.ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *BackupItemActionAppliesToResponse) Reset() { *x = BackupItemActionAppliesToResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BackupItemActionAppliesToResponse) String() string { @@ -228,7 +217,7 @@ func (*BackupItemActionAppliesToResponse) ProtoMessage() {} func (x *BackupItemActionAppliesToResponse) ProtoReflect() protoreflect.Message { mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -251,22 +240,19 @@ func (x *BackupItemActionAppliesToResponse) GetResourceSelector() *generated.Res } type BackupItemActionProgressRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` + Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` - Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BackupItemActionProgressRequest) Reset() { *x = BackupItemActionProgressRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BackupItemActionProgressRequest) String() string { @@ -277,7 +263,7 @@ func (*BackupItemActionProgressRequest) ProtoMessage() {} func (x *BackupItemActionProgressRequest) ProtoReflect() protoreflect.Message { mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -314,20 +300,17 @@ func (x *BackupItemActionProgressRequest) GetBackup() []byte { } type BackupItemActionProgressResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Progress *generated.OperationProgress `protobuf:"bytes,1,opt,name=progress,proto3" json:"progress,omitempty"` unknownFields protoimpl.UnknownFields - - Progress *generated.OperationProgress `protobuf:"bytes,1,opt,name=progress,proto3" json:"progress,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BackupItemActionProgressResponse) Reset() { *x = BackupItemActionProgressResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BackupItemActionProgressResponse) String() string { @@ -338,7 +321,7 @@ func (*BackupItemActionProgressResponse) ProtoMessage() {} func (x *BackupItemActionProgressResponse) ProtoReflect() protoreflect.Message { mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -361,22 +344,19 @@ func (x *BackupItemActionProgressResponse) GetProgress() *generated.OperationPro } type BackupItemActionCancelRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` + Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` - Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` + sizeCache protoimpl.SizeCache } func (x *BackupItemActionCancelRequest) Reset() { *x = BackupItemActionCancelRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *BackupItemActionCancelRequest) String() string { @@ -387,7 +367,7 @@ func (*BackupItemActionCancelRequest) ProtoMessage() {} func (x *BackupItemActionCancelRequest) ProtoReflect() protoreflect.Message { mi := &file_backupitemaction_v2_BackupItemAction_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -425,105 +405,52 @@ func (x *BackupItemActionCancelRequest) GetBackup() []byte { var File_backupitemaction_v2_BackupItemAction_proto protoreflect.FileDescriptor -var file_backupitemaction_v2_BackupItemAction_proto_rawDesc = []byte{ - 0x0a, 0x2a, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x2f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x76, 0x32, - 0x1a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x54, 0x0a, 0x0e, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x22, 0xdf, 0x01, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x47, 0x0a, 0x0f, 0x61, 0x64, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, - 0x6d, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x4d, 0x0a, 0x12, 0x70, 0x6f, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, - 0x12, 0x70, 0x6f, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, - 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x0a, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, - 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, - 0x6c, 0x0a, 0x21, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x10, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x73, 0x0a, - 0x1f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x62, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x22, 0x5c, 0x0a, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, - 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, - 0x22, 0x71, 0x0a, 0x1d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x32, 0xbc, 0x02, 0x0a, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, - 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x58, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x73, 0x54, 0x6f, 0x12, 0x24, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x76, 0x32, - 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x12, 0x2e, - 0x76, 0x32, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x13, 0x2e, 0x76, 0x32, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x23, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x49, 0x74, - 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, - 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x21, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x42, 0x49, 0x5a, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, 0x75, 0x2f, 0x76, 0x65, - 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x69, 0x74, 0x65, 0x6d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_backupitemaction_v2_BackupItemAction_proto_rawDesc = "" + + "\n" + + "*backupitemaction/v2/BackupItemAction.proto\x12\x02v2\x1a\fShared.proto\x1a\x1bgoogle/protobuf/empty.proto\"T\n" + + "\x0eExecuteRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x12\n" + + "\x04item\x18\x02 \x01(\fR\x04item\x12\x16\n" + + "\x06backup\x18\x03 \x01(\fR\x06backup\"\xdf\x01\n" + + "\x0fExecuteResponse\x12\x12\n" + + "\x04item\x18\x01 \x01(\fR\x04item\x12G\n" + + "\x0fadditionalItems\x18\x02 \x03(\v2\x1d.generated.ResourceIdentifierR\x0fadditionalItems\x12 \n" + + "\voperationID\x18\x03 \x01(\tR\voperationID\x12M\n" + + "\x12postOperationItems\x18\x04 \x03(\v2\x1d.generated.ResourceIdentifierR\x12postOperationItems\":\n" + + " BackupItemActionAppliesToRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\"l\n" + + "!BackupItemActionAppliesToResponse\x12G\n" + + "\x10ResourceSelector\x18\x01 \x01(\v2\x1b.generated.ResourceSelectorR\x10ResourceSelector\"s\n" + + "\x1fBackupItemActionProgressRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12 \n" + + "\voperationID\x18\x02 \x01(\tR\voperationID\x12\x16\n" + + "\x06backup\x18\x03 \x01(\fR\x06backup\"\\\n" + + " BackupItemActionProgressResponse\x128\n" + + "\bprogress\x18\x01 \x01(\v2\x1c.generated.OperationProgressR\bprogress\"q\n" + + "\x1dBackupItemActionCancelRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12 \n" + + "\voperationID\x18\x02 \x01(\tR\voperationID\x12\x16\n" + + "\x06backup\x18\x03 \x01(\fR\x06backup2\xbc\x02\n" + + "\x10BackupItemAction\x12X\n" + + "\tAppliesTo\x12$.v2.BackupItemActionAppliesToRequest\x1a%.v2.BackupItemActionAppliesToResponse\x122\n" + + "\aExecute\x12\x12.v2.ExecuteRequest\x1a\x13.v2.ExecuteResponse\x12U\n" + + "\bProgress\x12#.v2.BackupItemActionProgressRequest\x1a$.v2.BackupItemActionProgressResponse\x12C\n" + + "\x06Cancel\x12!.v2.BackupItemActionCancelRequest\x1a\x16.google.protobuf.EmptyBIZGgithub.com/vmware-tanzu/velero/pkg/plugin/generated/backupitemaction/v2b\x06proto3" var ( file_backupitemaction_v2_BackupItemAction_proto_rawDescOnce sync.Once - file_backupitemaction_v2_BackupItemAction_proto_rawDescData = file_backupitemaction_v2_BackupItemAction_proto_rawDesc + file_backupitemaction_v2_BackupItemAction_proto_rawDescData []byte ) func file_backupitemaction_v2_BackupItemAction_proto_rawDescGZIP() []byte { file_backupitemaction_v2_BackupItemAction_proto_rawDescOnce.Do(func() { - file_backupitemaction_v2_BackupItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(file_backupitemaction_v2_BackupItemAction_proto_rawDescData) + file_backupitemaction_v2_BackupItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_backupitemaction_v2_BackupItemAction_proto_rawDesc), len(file_backupitemaction_v2_BackupItemAction_proto_rawDesc))) }) return file_backupitemaction_v2_BackupItemAction_proto_rawDescData } var file_backupitemaction_v2_BackupItemAction_proto_msgTypes = make([]protoimpl.MessageInfo, 7) -var file_backupitemaction_v2_BackupItemAction_proto_goTypes = []interface{}{ +var file_backupitemaction_v2_BackupItemAction_proto_goTypes = []any{ (*ExecuteRequest)(nil), // 0: v2.ExecuteRequest (*ExecuteResponse)(nil), // 1: v2.ExecuteResponse (*BackupItemActionAppliesToRequest)(nil), // 2: v2.BackupItemActionAppliesToRequest @@ -561,97 +488,11 @@ func file_backupitemaction_v2_BackupItemAction_proto_init() { if File_backupitemaction_v2_BackupItemAction_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_backupitemaction_v2_BackupItemAction_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecuteRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_backupitemaction_v2_BackupItemAction_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecuteResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_backupitemaction_v2_BackupItemAction_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupItemActionAppliesToRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_backupitemaction_v2_BackupItemAction_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupItemActionAppliesToResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_backupitemaction_v2_BackupItemAction_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupItemActionProgressRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_backupitemaction_v2_BackupItemAction_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupItemActionProgressResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_backupitemaction_v2_BackupItemAction_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BackupItemActionCancelRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_backupitemaction_v2_BackupItemAction_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_backupitemaction_v2_BackupItemAction_proto_rawDesc), len(file_backupitemaction_v2_BackupItemAction_proto_rawDesc)), NumEnums: 0, NumMessages: 7, NumExtensions: 0, @@ -662,7 +503,6 @@ func file_backupitemaction_v2_BackupItemAction_proto_init() { MessageInfos: file_backupitemaction_v2_BackupItemAction_proto_msgTypes, }.Build() File_backupitemaction_v2_BackupItemAction_proto = out.File - file_backupitemaction_v2_BackupItemAction_proto_rawDesc = nil file_backupitemaction_v2_BackupItemAction_proto_goTypes = nil file_backupitemaction_v2_BackupItemAction_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/itemblockaction/v1/ItemBlockAction.pb.go b/pkg/plugin/generated/itemblockaction/v1/ItemBlockAction.pb.go index cec604477..6d73eb826 100644 --- a/pkg/plugin/generated/itemblockaction/v1/ItemBlockAction.pb.go +++ b/pkg/plugin/generated/itemblockaction/v1/ItemBlockAction.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: itemblockaction/v1/ItemBlockAction.proto @@ -12,6 +12,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,20 +23,17 @@ const ( ) type ItemBlockActionAppliesToRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ItemBlockActionAppliesToRequest) Reset() { *x = ItemBlockActionAppliesToRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ItemBlockActionAppliesToRequest) String() string { @@ -46,7 +44,7 @@ func (*ItemBlockActionAppliesToRequest) ProtoMessage() {} func (x *ItemBlockActionAppliesToRequest) ProtoReflect() protoreflect.Message { mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -69,20 +67,17 @@ func (x *ItemBlockActionAppliesToRequest) GetPlugin() string { } type ItemBlockActionAppliesToResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` ResourceSelector *generated.ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ItemBlockActionAppliesToResponse) Reset() { *x = ItemBlockActionAppliesToResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ItemBlockActionAppliesToResponse) String() string { @@ -93,7 +88,7 @@ func (*ItemBlockActionAppliesToResponse) ProtoMessage() {} func (x *ItemBlockActionAppliesToResponse) ProtoReflect() protoreflect.Message { mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -116,22 +111,19 @@ func (x *ItemBlockActionAppliesToResponse) GetResourceSelector() *generated.Reso } type ItemBlockActionGetRelatedItemsRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` - Backup []byte `protobuf:"bytes,3,opt,name=backup,proto3" json:"backup,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ItemBlockActionGetRelatedItemsRequest) Reset() { *x = ItemBlockActionGetRelatedItemsRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ItemBlockActionGetRelatedItemsRequest) String() string { @@ -142,7 +134,7 @@ func (*ItemBlockActionGetRelatedItemsRequest) ProtoMessage() {} func (x *ItemBlockActionGetRelatedItemsRequest) ProtoReflect() protoreflect.Message { mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -179,20 +171,17 @@ func (x *ItemBlockActionGetRelatedItemsRequest) GetBackup() []byte { } type ItemBlockActionGetRelatedItemsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + RelatedItems []*generated.ResourceIdentifier `protobuf:"bytes,1,rep,name=relatedItems,proto3" json:"relatedItems,omitempty"` unknownFields protoimpl.UnknownFields - - RelatedItems []*generated.ResourceIdentifier `protobuf:"bytes,1,rep,name=relatedItems,proto3" json:"relatedItems,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ItemBlockActionGetRelatedItemsResponse) Reset() { *x = ItemBlockActionGetRelatedItemsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ItemBlockActionGetRelatedItemsResponse) String() string { @@ -203,7 +192,7 @@ func (*ItemBlockActionGetRelatedItemsResponse) ProtoMessage() {} func (x *ItemBlockActionGetRelatedItemsResponse) ProtoReflect() protoreflect.Message { mi := &file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -227,70 +216,37 @@ func (x *ItemBlockActionGetRelatedItemsResponse) GetRelatedItems() []*generated. var File_itemblockaction_v1_ItemBlockAction_proto protoreflect.FileDescriptor -var file_itemblockaction_v1_ItemBlockAction_proto_rawDesc = []byte{ - 0x0a, 0x28, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x76, 0x31, 0x1a, 0x0c, - 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x39, 0x0a, 0x1f, - 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x6b, 0x0a, 0x20, 0x49, 0x74, 0x65, 0x6d, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, - 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x10, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x52, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x22, 0x6b, 0x0a, 0x25, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, - 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x22, 0x6b, 0x0a, 0x26, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x49, 0x74, - 0x65, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x52, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x32, 0xd3, - 0x01, 0x0a, 0x0f, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x12, - 0x23, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, - 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0f, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x29, 0x2e, - 0x76, 0x31, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x49, 0x74, 0x65, 0x6d, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x74, - 0x65, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x65, 0x74, - 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, 0x75, 0x2f, - 0x76, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x69, 0x74, 0x65, 0x6d, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_itemblockaction_v1_ItemBlockAction_proto_rawDesc = "" + + "\n" + + "(itemblockaction/v1/ItemBlockAction.proto\x12\x02v1\x1a\fShared.proto\"9\n" + + "\x1fItemBlockActionAppliesToRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\"k\n" + + " ItemBlockActionAppliesToResponse\x12G\n" + + "\x10ResourceSelector\x18\x01 \x01(\v2\x1b.generated.ResourceSelectorR\x10ResourceSelector\"k\n" + + "%ItemBlockActionGetRelatedItemsRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x12\n" + + "\x04item\x18\x02 \x01(\fR\x04item\x12\x16\n" + + "\x06backup\x18\x03 \x01(\fR\x06backup\"k\n" + + "&ItemBlockActionGetRelatedItemsResponse\x12A\n" + + "\frelatedItems\x18\x01 \x03(\v2\x1d.generated.ResourceIdentifierR\frelatedItems2\xd3\x01\n" + + "\x0fItemBlockAction\x12V\n" + + "\tAppliesTo\x12#.v1.ItemBlockActionAppliesToRequest\x1a$.v1.ItemBlockActionAppliesToResponse\x12h\n" + + "\x0fGetRelatedItems\x12).v1.ItemBlockActionGetRelatedItemsRequest\x1a*.v1.ItemBlockActionGetRelatedItemsResponseBHZFgithub.com/vmware-tanzu/velero/pkg/plugin/generated/itemblockaction/v1b\x06proto3" var ( file_itemblockaction_v1_ItemBlockAction_proto_rawDescOnce sync.Once - file_itemblockaction_v1_ItemBlockAction_proto_rawDescData = file_itemblockaction_v1_ItemBlockAction_proto_rawDesc + file_itemblockaction_v1_ItemBlockAction_proto_rawDescData []byte ) func file_itemblockaction_v1_ItemBlockAction_proto_rawDescGZIP() []byte { file_itemblockaction_v1_ItemBlockAction_proto_rawDescOnce.Do(func() { - file_itemblockaction_v1_ItemBlockAction_proto_rawDescData = protoimpl.X.CompressGZIP(file_itemblockaction_v1_ItemBlockAction_proto_rawDescData) + file_itemblockaction_v1_ItemBlockAction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_itemblockaction_v1_ItemBlockAction_proto_rawDesc), len(file_itemblockaction_v1_ItemBlockAction_proto_rawDesc))) }) return file_itemblockaction_v1_ItemBlockAction_proto_rawDescData } var file_itemblockaction_v1_ItemBlockAction_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_itemblockaction_v1_ItemBlockAction_proto_goTypes = []interface{}{ +var file_itemblockaction_v1_ItemBlockAction_proto_goTypes = []any{ (*ItemBlockActionAppliesToRequest)(nil), // 0: v1.ItemBlockActionAppliesToRequest (*ItemBlockActionAppliesToResponse)(nil), // 1: v1.ItemBlockActionAppliesToResponse (*ItemBlockActionGetRelatedItemsRequest)(nil), // 2: v1.ItemBlockActionGetRelatedItemsRequest @@ -317,61 +273,11 @@ func file_itemblockaction_v1_ItemBlockAction_proto_init() { if File_itemblockaction_v1_ItemBlockAction_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ItemBlockActionAppliesToRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ItemBlockActionAppliesToResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ItemBlockActionGetRelatedItemsRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_itemblockaction_v1_ItemBlockAction_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ItemBlockActionGetRelatedItemsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_itemblockaction_v1_ItemBlockAction_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_itemblockaction_v1_ItemBlockAction_proto_rawDesc), len(file_itemblockaction_v1_ItemBlockAction_proto_rawDesc)), NumEnums: 0, NumMessages: 4, NumExtensions: 0, @@ -382,7 +288,6 @@ func file_itemblockaction_v1_ItemBlockAction_proto_init() { MessageInfos: file_itemblockaction_v1_ItemBlockAction_proto_msgTypes, }.Build() File_itemblockaction_v1_ItemBlockAction_proto = out.File - file_itemblockaction_v1_ItemBlockAction_proto_rawDesc = nil file_itemblockaction_v1_ItemBlockAction_proto_goTypes = nil file_itemblockaction_v1_ItemBlockAction_proto_depIdxs = nil } diff --git a/pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go b/pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go index a7bbc421e..48444045d 100644 --- a/pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go +++ b/pkg/plugin/generated/restoreitemaction/v2/RestoreItemAction.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.36.11-devel // protoc v4.25.2 // source: restoreitemaction/v2/RestoreItemAction.proto @@ -14,6 +14,7 @@ import ( emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -24,23 +25,20 @@ const ( ) type RestoreItemActionExecuteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` - Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` - ItemFromBackup []byte `protobuf:"bytes,4,opt,name=itemFromBackup,proto3" json:"itemFromBackup,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Item []byte `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` + ItemFromBackup []byte `protobuf:"bytes,4,opt,name=itemFromBackup,proto3" json:"itemFromBackup,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionExecuteRequest) Reset() { *x = RestoreItemActionExecuteRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionExecuteRequest) String() string { @@ -51,7 +49,7 @@ func (*RestoreItemActionExecuteRequest) ProtoMessage() {} func (x *RestoreItemActionExecuteRequest) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -95,25 +93,22 @@ func (x *RestoreItemActionExecuteRequest) GetItemFromBackup() []byte { } type RestoreItemActionExecuteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Item []byte `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` AdditionalItems []*generated.ResourceIdentifier `protobuf:"bytes,2,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` SkipRestore bool `protobuf:"varint,3,opt,name=skipRestore,proto3" json:"skipRestore,omitempty"` OperationID string `protobuf:"bytes,4,opt,name=operationID,proto3" json:"operationID,omitempty"` WaitForAdditionalItems bool `protobuf:"varint,5,opt,name=waitForAdditionalItems,proto3" json:"waitForAdditionalItems,omitempty"` AdditionalItemsReadyTimeout *durationpb.Duration `protobuf:"bytes,6,opt,name=additionalItemsReadyTimeout,proto3" json:"additionalItemsReadyTimeout,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionExecuteResponse) Reset() { *x = RestoreItemActionExecuteResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionExecuteResponse) String() string { @@ -124,7 +119,7 @@ func (*RestoreItemActionExecuteResponse) ProtoMessage() {} func (x *RestoreItemActionExecuteResponse) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -182,20 +177,17 @@ func (x *RestoreItemActionExecuteResponse) GetAdditionalItemsReadyTimeout() *dur } type RestoreItemActionAppliesToRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionAppliesToRequest) Reset() { *x = RestoreItemActionAppliesToRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionAppliesToRequest) String() string { @@ -206,7 +198,7 @@ func (*RestoreItemActionAppliesToRequest) ProtoMessage() {} func (x *RestoreItemActionAppliesToRequest) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -229,20 +221,17 @@ func (x *RestoreItemActionAppliesToRequest) GetPlugin() string { } type RestoreItemActionAppliesToResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` ResourceSelector *generated.ResourceSelector `protobuf:"bytes,1,opt,name=ResourceSelector,proto3" json:"ResourceSelector,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionAppliesToResponse) Reset() { *x = RestoreItemActionAppliesToResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionAppliesToResponse) String() string { @@ -253,7 +242,7 @@ func (*RestoreItemActionAppliesToResponse) ProtoMessage() {} func (x *RestoreItemActionAppliesToResponse) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -276,22 +265,19 @@ func (x *RestoreItemActionAppliesToResponse) GetResourceSelector() *generated.Re } type RestoreItemActionProgressRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` + Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` - Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionProgressRequest) Reset() { *x = RestoreItemActionProgressRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionProgressRequest) String() string { @@ -302,7 +288,7 @@ func (*RestoreItemActionProgressRequest) ProtoMessage() {} func (x *RestoreItemActionProgressRequest) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -339,20 +325,17 @@ func (x *RestoreItemActionProgressRequest) GetRestore() []byte { } type RestoreItemActionProgressResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Progress *generated.OperationProgress `protobuf:"bytes,1,opt,name=progress,proto3" json:"progress,omitempty"` unknownFields protoimpl.UnknownFields - - Progress *generated.OperationProgress `protobuf:"bytes,1,opt,name=progress,proto3" json:"progress,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionProgressResponse) Reset() { *x = RestoreItemActionProgressResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionProgressResponse) String() string { @@ -363,7 +346,7 @@ func (*RestoreItemActionProgressResponse) ProtoMessage() {} func (x *RestoreItemActionProgressResponse) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -386,22 +369,19 @@ func (x *RestoreItemActionProgressResponse) GetProgress() *generated.OperationPr } type RestoreItemActionCancelRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` + Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` unknownFields protoimpl.UnknownFields - - Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` - OperationID string `protobuf:"bytes,2,opt,name=operationID,proto3" json:"operationID,omitempty"` - Restore []byte `protobuf:"bytes,3,opt,name=restore,proto3" json:"restore,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionCancelRequest) Reset() { *x = RestoreItemActionCancelRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionCancelRequest) String() string { @@ -412,7 +392,7 @@ func (*RestoreItemActionCancelRequest) ProtoMessage() {} func (x *RestoreItemActionCancelRequest) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -449,22 +429,19 @@ func (x *RestoreItemActionCancelRequest) GetRestore() []byte { } type RestoreItemActionItemsReadyRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` Plugin string `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` Restore []byte `protobuf:"bytes,2,opt,name=restore,proto3" json:"restore,omitempty"` AdditionalItems []*generated.ResourceIdentifier `protobuf:"bytes,3,rep,name=additionalItems,proto3" json:"additionalItems,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionItemsReadyRequest) Reset() { *x = RestoreItemActionItemsReadyRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionItemsReadyRequest) String() string { @@ -475,7 +452,7 @@ func (*RestoreItemActionItemsReadyRequest) ProtoMessage() {} func (x *RestoreItemActionItemsReadyRequest) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -512,20 +489,17 @@ func (x *RestoreItemActionItemsReadyRequest) GetAdditionalItems() []*generated.R } type RestoreItemActionItemsReadyResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Ready bool `protobuf:"varint,1,opt,name=ready,proto3" json:"ready,omitempty"` unknownFields protoimpl.UnknownFields - - Ready bool `protobuf:"varint,1,opt,name=ready,proto3" json:"ready,omitempty"` + sizeCache protoimpl.SizeCache } func (x *RestoreItemActionItemsReadyResponse) Reset() { *x = RestoreItemActionItemsReadyResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *RestoreItemActionItemsReadyResponse) String() string { @@ -536,7 +510,7 @@ func (*RestoreItemActionItemsReadyResponse) ProtoMessage() {} func (x *RestoreItemActionItemsReadyResponse) ProtoReflect() protoreflect.Message { mi := &file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -560,142 +534,62 @@ func (x *RestoreItemActionItemsReadyResponse) GetReady() bool { var File_restoreitemaction_v2_RestoreItemAction_proto protoreflect.FileDescriptor -var file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc = []byte{ - 0x0a, 0x2c, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x2f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, - 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, - 0x76, 0x32, 0x1a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 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, 0x22, 0x8f, 0x01, - 0x0a, 0x1f, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x18, 0x0a, - 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, - 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x74, 0x65, 0x6d, 0x46, - 0x72, 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0e, 0x69, 0x74, 0x65, 0x6d, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, - 0xd8, 0x02, 0x0a, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x47, 0x0a, 0x0f, 0x61, 0x64, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, - 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x65, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x36, 0x0a, 0x16, 0x77, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, - 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x77, 0x61, 0x69, 0x74, 0x46, 0x6f, 0x72, 0x41, 0x64, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x5b, 0x0a, - 0x1b, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, - 0x52, 0x65, 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x06, 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, 0x1b, 0x61, - 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, - 0x61, 0x64, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x3b, 0x0a, 0x21, 0x52, 0x65, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x22, 0x6d, 0x0a, 0x22, 0x52, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, - 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x52, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x76, 0x0a, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x5d, - 0x0a, 0x21, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x74, 0x0a, - 0x1e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x22, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, - 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, - 0x61, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x47, 0x0a, 0x0f, - 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, - 0x49, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3b, 0x0a, 0x23, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, - 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x72, 0x65, 0x61, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, - 0x64, 0x79, 0x32, 0xd0, 0x03, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, - 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x73, 0x54, 0x6f, 0x12, 0x25, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x76, - 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x07, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, - 0x23, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x08, 0x50, 0x72, - 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x76, - 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x22, 0x2e, - 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x6a, 0x0a, 0x17, 0x41, 0x72, 0x65, - 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, - 0x65, 0x61, 0x64, 0x79, 0x12, 0x26, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, - 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x76, - 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x61, 0x6e, 0x7a, 0x75, - 0x2f, 0x76, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x72, 0x65, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, - 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc = "" + + "\n" + + ",restoreitemaction/v2/RestoreItemAction.proto\x12\x02v2\x1a\fShared.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1egoogle/protobuf/duration.proto\"\x8f\x01\n" + + "\x1fRestoreItemActionExecuteRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x12\n" + + "\x04item\x18\x02 \x01(\fR\x04item\x12\x18\n" + + "\arestore\x18\x03 \x01(\fR\arestore\x12&\n" + + "\x0eitemFromBackup\x18\x04 \x01(\fR\x0eitemFromBackup\"\xd8\x02\n" + + " RestoreItemActionExecuteResponse\x12\x12\n" + + "\x04item\x18\x01 \x01(\fR\x04item\x12G\n" + + "\x0fadditionalItems\x18\x02 \x03(\v2\x1d.generated.ResourceIdentifierR\x0fadditionalItems\x12 \n" + + "\vskipRestore\x18\x03 \x01(\bR\vskipRestore\x12 \n" + + "\voperationID\x18\x04 \x01(\tR\voperationID\x126\n" + + "\x16waitForAdditionalItems\x18\x05 \x01(\bR\x16waitForAdditionalItems\x12[\n" + + "\x1badditionalItemsReadyTimeout\x18\x06 \x01(\v2\x19.google.protobuf.DurationR\x1badditionalItemsReadyTimeout\";\n" + + "!RestoreItemActionAppliesToRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\"m\n" + + "\"RestoreItemActionAppliesToResponse\x12G\n" + + "\x10ResourceSelector\x18\x01 \x01(\v2\x1b.generated.ResourceSelectorR\x10ResourceSelector\"v\n" + + " RestoreItemActionProgressRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12 \n" + + "\voperationID\x18\x02 \x01(\tR\voperationID\x12\x18\n" + + "\arestore\x18\x03 \x01(\fR\arestore\"]\n" + + "!RestoreItemActionProgressResponse\x128\n" + + "\bprogress\x18\x01 \x01(\v2\x1c.generated.OperationProgressR\bprogress\"t\n" + + "\x1eRestoreItemActionCancelRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12 \n" + + "\voperationID\x18\x02 \x01(\tR\voperationID\x12\x18\n" + + "\arestore\x18\x03 \x01(\fR\arestore\"\x9f\x01\n" + + "\"RestoreItemActionItemsReadyRequest\x12\x16\n" + + "\x06plugin\x18\x01 \x01(\tR\x06plugin\x12\x18\n" + + "\arestore\x18\x02 \x01(\fR\arestore\x12G\n" + + "\x0fadditionalItems\x18\x03 \x03(\v2\x1d.generated.ResourceIdentifierR\x0fadditionalItems\";\n" + + "#RestoreItemActionItemsReadyResponse\x12\x14\n" + + "\x05ready\x18\x01 \x01(\bR\x05ready2\xd0\x03\n" + + "\x11RestoreItemAction\x12Z\n" + + "\tAppliesTo\x12%.v2.RestoreItemActionAppliesToRequest\x1a&.v2.RestoreItemActionAppliesToResponse\x12T\n" + + "\aExecute\x12#.v2.RestoreItemActionExecuteRequest\x1a$.v2.RestoreItemActionExecuteResponse\x12W\n" + + "\bProgress\x12$.v2.RestoreItemActionProgressRequest\x1a%.v2.RestoreItemActionProgressResponse\x12D\n" + + "\x06Cancel\x12\".v2.RestoreItemActionCancelRequest\x1a\x16.google.protobuf.Empty\x12j\n" + + "\x17AreAdditionalItemsReady\x12&.v2.RestoreItemActionItemsReadyRequest\x1a'.v2.RestoreItemActionItemsReadyResponseBJZHgithub.com/vmware-tanzu/velero/pkg/plugin/generated/restoreitemaction/v2b\x06proto3" var ( file_restoreitemaction_v2_RestoreItemAction_proto_rawDescOnce sync.Once - file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData = file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc + file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData []byte ) func file_restoreitemaction_v2_RestoreItemAction_proto_rawDescGZIP() []byte { file_restoreitemaction_v2_RestoreItemAction_proto_rawDescOnce.Do(func() { - file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData) + file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc), len(file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc))) }) return file_restoreitemaction_v2_RestoreItemAction_proto_rawDescData } var file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes = make([]protoimpl.MessageInfo, 9) -var file_restoreitemaction_v2_RestoreItemAction_proto_goTypes = []interface{}{ +var file_restoreitemaction_v2_RestoreItemAction_proto_goTypes = []any{ (*RestoreItemActionExecuteRequest)(nil), // 0: v2.RestoreItemActionExecuteRequest (*RestoreItemActionExecuteResponse)(nil), // 1: v2.RestoreItemActionExecuteResponse (*RestoreItemActionAppliesToRequest)(nil), // 2: v2.RestoreItemActionAppliesToRequest @@ -739,121 +633,11 @@ func file_restoreitemaction_v2_RestoreItemAction_proto_init() { if File_restoreitemaction_v2_RestoreItemAction_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionExecuteRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionExecuteResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionAppliesToRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionAppliesToResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionProgressRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionProgressResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionCancelRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionItemsReadyRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RestoreItemActionItemsReadyResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc), len(file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc)), NumEnums: 0, NumMessages: 9, NumExtensions: 0, @@ -864,7 +648,6 @@ func file_restoreitemaction_v2_RestoreItemAction_proto_init() { MessageInfos: file_restoreitemaction_v2_RestoreItemAction_proto_msgTypes, }.Build() File_restoreitemaction_v2_RestoreItemAction_proto = out.File - file_restoreitemaction_v2_RestoreItemAction_proto_rawDesc = nil file_restoreitemaction_v2_RestoreItemAction_proto_goTypes = nil file_restoreitemaction_v2_RestoreItemAction_proto_depIdxs = nil } From 22ae12575ca4a5ae412d5f2a7f9698ea6e96cae2 Mon Sep 17 00:00:00 2001 From: PragatiVerma111 Date: Sun, 9 Aug 2026 20:45:29 +0530 Subject: [PATCH 10/45] =?UTF-8?q?Fix=20excluded=20namespace=20objects=20le?= =?UTF-8?q?aking=20into=20backup=20with=20cross-namespa=E2=80=A6=20(#10159?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix excluded namespace objects leaking into backup with cross-namespace listing Signed-off-by: Pragati * Add changelog for PR 10159 Signed-off-by: Pragati --------- Signed-off-by: Pragati Co-authored-by: Pragati --- changelogs/unreleased/10159-Pragati5-DEBUG | 1 + pkg/backup/backup_test.go | 23 ++++++++++++++++++++++ pkg/backup/item_collector.go | 3 ++- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/10159-Pragati5-DEBUG diff --git a/changelogs/unreleased/10159-Pragati5-DEBUG b/changelogs/unreleased/10159-Pragati5-DEBUG new file mode 100644 index 000000000..e8f33122d --- /dev/null +++ b/changelogs/unreleased/10159-Pragati5-DEBUG @@ -0,0 +1 @@ +Fix excluded namespace objects leaking into backups when using cross-namespace listing diff --git a/pkg/backup/backup_test.go b/pkg/backup/backup_test.go index 3baae0131..b116d5376 100644 --- a/pkg/backup/backup_test.go +++ b/pkg/backup/backup_test.go @@ -5429,6 +5429,29 @@ func TestBackupNamespaces(t *testing.T) { "resources/namespaces/v1-preferredversion/cluster/ns-3.json", }, }, + { + name: "Wildcard star with excluded namespaces test", + backup: defaultBackup().IncludedNamespaces("*").ExcludedNamespaces("ns-2").Result(), + apiResources: []*test.APIResource{ + test.Namespaces( + builder.ForNamespace("ns-1").Phase(corev1api.NamespaceActive).Result(), + builder.ForNamespace("ns-2").Phase(corev1api.NamespaceActive).Result(), + builder.ForNamespace("ns-3").Phase(corev1api.NamespaceActive).Result(), + ), + test.Deployments( + builder.ForDeployment("ns-1", "deploy-1").Result(), + builder.ForDeployment("ns-2", "deploy-2").Result(), + ), + }, + want: []string{ + "resources/namespaces/cluster/ns-1.json", + "resources/namespaces/v1-preferredversion/cluster/ns-1.json", + "resources/namespaces/cluster/ns-3.json", + "resources/namespaces/v1-preferredversion/cluster/ns-3.json", + "resources/deployments.apps/namespaces/ns-1/deploy-1.json", + "resources/deployments.apps/v1-preferredversion/namespaces/ns-1/deploy-1.json", + }, + }, { name: "Empty namespace test", backup: defaultBackup().IncludedNamespaces("invalid*").Result(), diff --git a/pkg/backup/item_collector.go b/pkg/backup/item_collector.go index f4c712921..3aade5fad 100644 --- a/pkg/backup/item_collector.go +++ b/pkg/backup/item_collector.go @@ -508,7 +508,8 @@ func (r *itemCollector) getResourceItems( kind: resource.Kind, }) - if item.GetNamespace() != "" { + if item.GetNamespace() != "" && + r.backupRequest.NamespaceIncludesExcludes.ShouldInclude(item.GetNamespace()) { log.Debugf("Track namespace %s in nsTracker", item.GetNamespace()) r.nsTracker.track(item.GetNamespace()) } From cc4161b7edd3cd4c92cfb38bf11a5848a7a61d63 Mon Sep 17 00:00:00 2001 From: PragatiVerma111 Date: Sun, 9 Aug 2026 21:31:32 +0530 Subject: [PATCH 11/45] ci: add backport/cherry-pick GitHub Action for release branches (#10158) * ci: add backport/cherry-pick GitHub Action for release branches Signed-off-by: Pragati * ci: add unreleased changelog for backport Action Signed-off-by: Pragati * ci: pin backport-action to commit SHA for write-permission safety Signed-off-by: Pragati * ci: address review nits on backport workflow Move permissions to the job (least privilege), document the backport-action bot user id guard, and fix a garbled comment. Signed-off-by: Pragati --------- Signed-off-by: Pragati Co-authored-by: Pragati --- .github/workflows/backport.yml | 78 ++++++++++++++++++++++ changelogs/unreleased/10158-Pragati5-DEBUG | 1 + 2 files changed, 79 insertions(+) create mode 100644 .github/workflows/backport.yml create mode 100644 changelogs/unreleased/10158-Pragati5-DEBUG diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000..d0e13129e --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,78 @@ +name: Backport merged pull request + +# Automates cherry-picking merged PRs onto release branches. +# - Label a merged PR with e.g. `backport release-1.17` to backport on merge. +# - Or comment `/backport release-1.17` or `/cherrypick release-1.17` on a merged PR. +# See: https://github.com/velero-io/velero/issues/9603 + +on: + pull_request_target: + types: [closed] + issue_comment: + types: [created] + +permissions: {} + +jobs: + backport: + name: Backport pull request + # Exclude comments from the backport-action bot (user id 97796249) to prevent + # recursive triggers. The bot does not post /backport commands, so startsWith + # already blocks recursion; the id check is defense in depth. + if: > + github.repository == 'velero-io/velero' && + ( + ( + github.event_name == 'pull_request_target' && + github.event.pull_request.merged && + contains(toJSON(github.event.pull_request.labels.*.name), '"backport ') + ) || ( + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.comment.user.id != 97796249 && + contains( + fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), + github.event.comment.author_association + ) && + ( + startsWith(github.event.comment.body, '/backport') || + startsWith(github.event.comment.body, '/cherrypick') + ) + ) + ) + runs-on: ubuntu-latest + permissions: + contents: write # push backport branches and comment + pull-requests: write # open backport PRs + steps: + - name: Parse target branches from comment + id: parse + if: github.event_name == 'issue_comment' + env: + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + # First line only; strip /backport or /cherrypick prefix. + # Remaining text is a space-delimited list of target branches + # (may be empty, falls back to labels). + line=$(printf '%s' "$COMMENT_BODY" | head -n1 | tr -d '\r') + branches=$(printf '%s' "$line" | sed -E 's|^/(backport|cherrypick)[[:space:]]*||') + echo "branches=${branches}" >> "$GITHUB_OUTPUT" + + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Create backport pull requests + # Pin to commit SHA: workflow has contents/pull-requests write. + uses: korthout/backport-action@2e830a1d0b8269505846ddd407a70876913ad1f8 # v4.6.0 + with: + # Labels like `backport release-1.17` select the target branch. + label_pattern: '^backport ([^ ]+)$' + # Prefer draft PRs with conflict markers over failing the job silently. + experimental: | + { + "conflict_resolution": "draft_commit_conflicts" + } + # Empty when triggered by merge labels; set when `/backport` or `/cherrypick` includes branches. + target_branches: ${{ steps.parse.outputs.branches }} + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/changelogs/unreleased/10158-Pragati5-DEBUG b/changelogs/unreleased/10158-Pragati5-DEBUG new file mode 100644 index 000000000..060fa5c38 --- /dev/null +++ b/changelogs/unreleased/10158-Pragati5-DEBUG @@ -0,0 +1 @@ +Add GitHub Action to automate backport/cherry-pick onto release branches From c9d4501d3699537cf24aa1c5a90da26994ca2357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wenkai=20Yin=28=E5=B0=B9=E6=96=87=E5=BC=80=29?= Date: Mon, 10 Aug 2026 14:20:59 +0800 Subject: [PATCH 12/45] Design for supporting volume data in-place restore (#10014) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Design for supporting volume data in-place restore Design for supporting volume data in-place restore Signed-off-by: Wenkai Yin(尹文开) * Update the in-place restore design according the comments from internal and community Update the in-place restore design according the comments from internal and community Signed-off-by: Wenkai Yin(尹文开) * Add namespace-mapping section to clarify how to handle the namespace mapping Signed-off-by: Wenkai Yin(尹文开) --------- Signed-off-by: Wenkai Yin(尹文开) --- .../volume-data-inplace-restore.md | 370 ++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 design/volume-data-inplace-restore/volume-data-inplace-restore.md diff --git a/design/volume-data-inplace-restore/volume-data-inplace-restore.md b/design/volume-data-inplace-restore/volume-data-inplace-restore.md new file mode 100644 index 000000000..664f5a654 --- /dev/null +++ b/design/volume-data-inplace-restore/volume-data-inplace-restore.md @@ -0,0 +1,370 @@ +# Volume Data In-place Full/Incremental Restore + +## Table of Contents + +- [Background](#background) +- [Goals](#goals) +- [Non-Goals](#non-goals) +- [Overview](#overview) +- [Detailed Design](#detailed-design) + - [CRD Changes](#crd-changes) + - [CLI](#cli) + - [Workload Management](#workload-management) + - [Handling Cross-Zone Scheduling (WaitForFirstConsumer)](#handling-cross-zone-scheduling-waitforfirstconsumer) + - [Namespace Mapping](#namespace-mapping) + - [Pre-flight Checks](#pre-flight-checks) + - [1. PVC is Not Actively Used by a Running Pod](#1-pvc-is-not-actively-used-by-a-running-pod) + - [2. PVC is Bound to the Original PV](#2-pvc-is-bound-to-the-original-pv) + - [3. Volume Size Validation](#3-volume-size-validation) + - [Error Handling](#error-handling) + - [Restore Workflow Update](#restore-workflow-update) + - [In-place Incremental Restore for CSI Snapshot with Block Data Move for Block Volumes](#in-place-incremental-restore-for-csi-snapshot-with-block-data-move-for-block-volumes) + - [In-place Full Restore for CSI Snapshot with Block Data Move for Block Volumes](#in-place-full-restore-for-csi-snapshot-with-block-data-move-for-block-volumes) + - [In-place Incremental Restore for CSI Snapshot with File System Data Move for File System Volumes](#in-place-incremental-restore-for-csi-snapshot-with-file-system-data-move-for-file-system-volumes) + - [In-place Full Restore for CSI Snapshot with File System Data Move for File System Volumes](#in-place-full-restore-for-csi-snapshot-with-file-system-data-move-for-file-system-volumes) + - [In-place Incremental Restore for CSI Snapshot with Block Data Move for File System Volumes](#in-place-incremental-restore-for-csi-snapshot-with-block-data-move-for-file-system-volumes) + - [In-place Full Restore for CSI Snapshot with Block Data Move for File System Volumes](#in-place-full-restore-for-csi-snapshot-with-block-data-move-for-file-system-volumes) + - [In-place Incremental Restore for File System Backup for File System Volumes](#in-place-incremental-restore-for-file-system-backup-for-file-system-volumes) + - [In-place Full Restore for File System Backup for File System Volumes](#in-place-full-restore-for-file-system-backup-for-file-system-volumes) +- [Installation](#installation) +- [Upgrade](#upgrade) + +## Background + +Currently, Velero only supports restoring volume data to a newly provisioned PVC. If the target PVC already exists in the cluster, Velero skips the data restoration entirely and leaves the existing volume untouched. + +This design introduces the "in-place restore" capability, allowing Velero to restore volume data directly into an existing, bound PVC. When performing an in-place restore, users can choose to either overwrite the volume entirely (in-place full restore) or only restore the modified data to optimize performance (in-place incremental restore). + +To ensure data consistency and allow Velero to safely recreate the PVC during the process, users must manually delete any pods consuming the target volume before initiating an in-place restore. + +## Goals + +- Enable Velero to restore volume data directly into an existing, bound PVC without requiring the user to manually delete the PVC and PV. +- Support both Full (overwrite all) and Incremental (overwrite only changed data) in-place restores. +- Support in-place restores for Windows workloads. +- Ensure data consistency and correct Kubernetes scheduling constraints (e.g., handling `WaitForFirstConsumer` and zonal topologies) are respected during and after the restore. + +## Non-Goals + +- Automating the deletion of workloads before the restore. It remains the user's responsibility to ensure the volume is not actively consumed and the Pods are completely removed before triggering the restore to prevent data corruption and allow PVC recreation. +- In-place restore for CSI snapshot without data move. +- In-place restore for Native Snapshots (cloud provider snapshots without CSI). +- Fine-grained, per-volume control over in-place restores. The newly introduced in-place restore policies apply globally to all volumes within a single restore operation. Allowing users to specify different restore strategies for individual volumes is deferred to a future enhancement. + +## Overview + +This design focuses exclusively on volume data restoration. To support this, we are introducing a new field, `ExistingVolumeDataPolicy`, to the `Restore` spec. This feature operates independently of Kubernetes resource restoration, which remains controlled by the existing `ExistingResourcePolicy` field. + +Depending on how unchanged data is handled during the restoration process, in-place volume data restores are categorized into two types: + +- **In-place full restore**: Overwrites the volume with the backup data, regardless of whether the existing data has changed. +- **In-place incremental restore**: Optimizes the process by restoring only the data that has changed since the backup, leaving unmodified data intact. This is achieved by leveraging Changed Block Tracking (CBT) for block data and file metadata comparisons for file system data. + +Support for in-place full and incremental restores varies depending on the underlying backup method, as detailed in the following table: + +| Backup Method | In-place Full Restore | In-place Incremental Restore | +| --------------------------------------- | --------------------- | ---------------------------- | +| CSI Snapshot with Block Data Move | Yes | Yes | +| CSI Snapshot with File System Data Move | Yes | Yes | +| CSI Snapshot without Data Move | No | No | +| File System Backup | Yes | Yes | +| Native Snapshot | No | No | + +Additionally, a new boolean field `DeleteExtraFiles` is added to the `UploaderConfig` within the `Restore` spec. When performing a file system restore (either via PodVolumeBackup or CSI File System Data Move), this flag controls whether files present in the target volume but absent in the backup should be deleted. Setting this to `true` ensures the target volume's file system exactly mirrors the backup state. Note that this setting is ignored for block data mover restores, as block-level operations inherently overwrite the entire file system structure. + +Because Velero must create a temporary restore Pod in the Velero namespace to mount the volume and restore the data, it cannot directly use the existing PVC, which resides in the workload namespace. Velero must delete the existing PVC, recreate a temporary restore PVC in the Velero namespace, and bind it to the existing PV. The core strategy for implementing an in-place restore involves the following sequence: + +```mermaid +flowchart TD + subgraph PVC CSI RIA + A[Patch existing PV's reclaim policy to Retain] --> B[Delete existing PVC] + end + subgraph Exposer + B --> C[Create temporary restore PVC in Velero namespace
and bind it to existing PV] + C --> D[Create temporary restore Pod
that mounts temporary restore PVC] + end + subgraph Block/File System Uploader + D --> E[Restore data directly into the volume] + end + subgraph Exposer Post-Restore + E --> F[Delete temporary restore Pod and PVC] + end + F --> G[Target workload Pod mounts target PVC
once it is recreated] +``` + +When restoring a file system volume using the block data mover, the PV must temporarily have its `volumeMode` set to `Block` so the restore Pod can mount it as a raw block device. Because the `volumeMode` field in a PV spec is immutable, reusing the existing PV directly is not possible. Instead, Velero must delete the existing PV and create a temporary one. The sequence for this scenario is as follows: + +```mermaid +flowchart TD + subgraph PVC CSI RIA + A[Patch existing PV's reclaim policy to Retain] --> B[Delete existing PVC] + end + subgraph Exposer + B --> C[Delete existing PV] + C --> D[Create temporary restore PV with volumeMode: Block
using same volume handle] + D --> E[Create temporary restore PVC in Velero namespace
with volumeMode: Block and bind to temporary PV] + E --> F[Create temporary restore Pod
that mounts temporary restore PVC] + end + subgraph Block Uploader + F --> G[Restore data directly into the volume] + end + subgraph Exposer Post-Restore + G --> H[Delete temporary restore Pod, PVC, and PV] + H --> I[Recreate original PV with volumeMode: Filesystem] + end + I --> J[Recreate original PVC in workload namespace
and allow it to bind to recreated PV] +``` + + +## Detailed Design + +### CRD Changes + +To support the new in-place restore policies and incremental data transfer, several Custom Resource Definitions (CRDs) will be updated. + +**Restore CRD** +A new field `existingVolumeDataPolicy` is added to the `Restore` spec to allow users to define how existing volume data should be handled. Additionally, a new field `deleteExtraFiles` is added to the `uploaderConfig` to control file deletion during file system restores. + +```yaml +spec: + existingVolumeDataPolicy: "" # Valid values: "", none, full, incremental + uploaderConfig: + deleteExtraFiles: false +``` + +- `existingVolumeDataPolicy`: + - `""` (default) or `none`: Do not restore volume data if the target PVC already exists. + - `full`: Perform an in-place full restore, overwriting all existing data on the volume. + - `incremental`: Perform an in-place incremental restore, only overwriting data that has changed since the backup. +- `uploaderConfig.deleteExtraFiles`: A boolean flag that controls whether files present in the target volume but absent from the backup should be deleted. **Note:** This setting is *only* applicable to File System restores (PodVolumeBackup or CSI File System Data Move) and has no effect on Block Data Move restores. Furthermore, it is ignored for non-in-place restores (where `existingVolumeDataPolicy` is not set to `full` or `incremental`). + +If the target PVC does not exist, Velero will fall back to its default behavior and provision a new PVC for the restore, regardless of whether `existingVolumeDataPolicy` is set to `full` or `incremental`. Furthermore, if `existingVolumeDataPolicy` is set to `incremental` but the underlying storage does not support incremental restores, Velero will automatically fall back to a `full` restore. + +The following table summarizes the expected behavior for different combinations of `existingResourcePolicy` and `existingVolumeDataPolicy` when the target PVC already exists: + +| `existingResourcePolicy` | `existingVolumeDataPolicy` | PVC Resource Action | Volume Data Restore | +| ------------------------ | -------------------------- | ------------------- | ------------------- | +| `none` | `none` | Untouched | Untouched | +| `none` | `full` | Untouched | Full | +| `none` | `incremental` | Untouched | Incremental | +| `update` | `none` | Patched | Untouched | +| `update` | `full` | Patched | Full | +| `update` | `incremental` | Patched | Incremental | + +**DataDownload CRD** +To support incremental restores, the `DataDownload` spec is extended with a new `restoreType` string flag (valid values are `full` and `incremental`) to instruct the data mover to perform an incremental restore. It also introduces a new `csiSnapshot` field, which captures the metadata of a snapshot taken from the existing PVC, acting as the baseline for Changed Block Tracking (CBT) delta calculations during an in-place incremental block restore. Additionally, the `deleteExtraFiles` configuration is passed to the underlying data mover via the existing `dataMoverConfig` map. + +```yaml +spec: + restoreType: "incremental" + csiSnapshot: + volumeSnapshot: "" + storageClass: "" + snapshotClass: "" + driver: "" +``` + +- `restoreType`: A string flag indicating whether the data mover should perform a `full` or `incremental` restore. +- `csiSnapshot`: + - `volumeSnapshot`: the name of the volume snapshot + - `storageClass`: the name of the storage class of the PVC that the volume snapshot is created from + - `snapshotClass`: the name of the snapshot class that the volume snapshot is created with + - `driver`: the driver used by the VolumeSnapshotContent + +**PodVolumeRestore CRD** +A new `restoreType` string flag (valid values are `full` and `incremental`) is added to the `PodVolumeRestore` spec to instruct the file system data mover (e.g., Kopia) to perform an incremental restore. Additionally, the `deleteExtraFiles` configuration is passed to the underlying uploader via the existing `uploaderSettings` map. + +```yaml +spec: + restoreType: "incremental" +``` + +- `restoreType`: A string flag indicating whether the data mover should perform a `full` or `incremental` restore. + +### CLI + +New flags will be added to the `velero restore create` command to support the new policy: + +- `--existing-volume-data-policy`: Accepts the values `none`, `full`, or `incremental`, mapping to `existingVolumeDataPolicy`. +- `--delete-extra-files`: A boolean flag mapping to `uploaderConfig.deleteExtraFiles`. + +### Workload Management + +To ensure data consistency and allow for necessary configuration changes, users must delete any Pods actively using the target volume before initiating an in-place restore. This is required for three primary reasons: + +1. **Preventing Data Corruption:** It is critical to prevent the active workload Pods and the temporary restore Pods from writing to the volume simultaneously, which would lead to data corruption. +2. **PVC Recreation:** Velero creates a temporary restore Pod in the Velero namespace to mount the volume and restore the data. Since it cannot directly use the existing PVC located in the workload namespace, Velero must delete the existing PVC, create a temporary restore PVC in the Velero namespace, and bind it to the existing PV. However, Kubernetes' `pvc-protection` finalizer prevents the deletion of any PVC actively used by a running Pod. Consequently, simply pausing the workload is insufficient; the Pods must be completely removed to allow the PVC deletion to proceed. +3. **ReadWriteOncePod Access Mode:** If the volume is configured with the `ReadWriteOncePod` access mode, Kubernetes strictly enforces that the volume can only be mounted by a single Pod at a time. The existing workload Pod must be completely deleted to release the volume, allowing Velero's temporary restore Pod to successfully mount it and perform the data transfer. + +Users must manage the lifecycle of their workloads before starting the restore. This applies to various workload types: + +- **Standard Controllers (Deployments, StatefulSets, Jobs, CronJobs):** The required action depends on the restore method: + - **For CSI Snapshot Restores:** Users can scale these controllers down to zero replicas to terminate the underlying Pods. + - **For File System Restores (PodVolumeRestore):** Users must completely delete the controllers. Simply scaling down to zero is insufficient because file system restores rely on an init container injected into the restored target Pod to process the data transfer. If the controller is only scaled down, it will immediately terminate the Pod restored by Velero to maintain its zero-replica count. Although the controller may subsequently spawn a new Pod, that new Pod will lack the required restore init container, causing the restore to fail. +- **DaemonSets:** Since Kubernetes lacks a mechanism to scale DaemonSets to zero, users must either delete the DaemonSet entirely or use node selectors/cordoning to evict the Pods. +- **Operator-Managed Pods:** Custom controllers (like ArgoCD) may have fast reconciliation loops that aggressively recreate Pods. These operators must be paused or suspended, and their managed Pods deleted. +- **Out-of-Cluster Clients:** External consumers accessing the storage directly (e.g., via NFS or storage APIs) are invisible to Kubernetes and must be manually disconnected to ensure no external writes occur during the restore. + +**Note:** Automating the deletion of these workloads is explicitly out of scope for this feature. It remains the user's responsibility to ensure the volume is not actively consumed and the Pods are removed before triggering the restore. + +### Handling Cross-Zone Scheduling (WaitForFirstConsumer) + +When performing an in-place restore, Velero deletes the existing target PVC and recreates it. For StorageClasses using the `WaitForFirstConsumer` volume binding mode, this recreation resets the scheduling lifecycle. Even though Velero adds a selector to the PVC spec to ensure it binds exclusively to the original PV, a scheduling issue can still occur. If the target PVC loses its node affinity, the Kubernetes Scheduler might schedule the recreated business Pod to a different availability zone. Because the original PV is physically constrained to its original zone, the Pod will fail to mount the volume and remain stuck in the `ContainerCreating` state with an attachment error. + +**Solution**: +During the PVC Restore Item Action (RIA), Velero must extract the `volume.kubernetes.io/selected-node` annotation from the original PVC. When Velero recreates the target PVC, it must inject this annotation back into the PVC spec. +By preserving the `selected-node` annotation, the Kubernetes Scheduler is forced to schedule the recreated business Pod to the original node/zone, ensuring it successfully mounts the restored PV. + +### Namespace Mapping +When namespace mapping is configured, in-place restores work normally in most scenarios. However, in-place incremental restores using CSI snapshots with a block data mover are not natively supported across different namespaces. Velero cannot use Changed Block Tracking (CBT) to calculate data deltas when the target volume is in a different namespace, as the volumes may belong to different lineages. + +Despite this, users can achieve a fast cross-namespace "clone and restore" workflow. For example, to quickly clone a large production workload into a test namespace ((e.g., for debugging, testing, or auditing)), a standard full restore would be too slow. Instead, users can manually take a CSI snapshot of the source PVC and provision a new PVC in the destination namespace from that snapshot. + +When a Velero restore is triggered against this new PVC, Velero detects the snapshot and uses CBT to write only the blocks that changed since the backup. This effectively "rolls back" the clone to the backup's state, drastically reducing data transfer and speeding up the restore. + +The key requirements for this approach are: +1. **Manual Cloning:** Users must manually snapshot the source PVC and clone it to the destination namespace before the restore. *(Note: Users must manually recreate the `VolumeSnapshotContent` and `VolumeSnapshot` in the destination namespace, or use `CrossNamespaceVolumeDataSource` if supported).* +2. **Workload Management:** Ensure no Pods are mounting the destination PVC during the restore to prevent data corruption. +3. **Snapshot Detection:** Velero inspects the destination PVC's `dataSource`. If it is a `VolumeSnapshot`, Velero uses its `SnapshotHandle` along with the backup's handle to calculate CBT. +4. **One-Shot Operation:** This is a one-time process. To restore a different backup later, users must clean up the destination namespace and repeat the workflow. +5. **Snapshot Cleanup:** Users must manually delete the temporary snapshot after the restore completes. + +### Pre-flight Checks + +Before initiating an in-place restore for a volume, Velero performs the following pre-flight checks to ensure the operation is safe and valid: + +#### 1. PVC is Not Actively Used by a Running Pod +Velero verifies that the target PVC is not currently mounted or consumed by any running Pods in the cluster. If the PVC is in use, Velero will skip the in-place restore for that volume and log an error. This enforces the prerequisite that users must completely delete consuming workloads prior to the restore, which prevents data corruption and avoids deadlocks caused by the Kubernetes `pvc-protection` finalizer during PVC recreation. + +#### 2. PVC is Bound to the Original PV +Velero checks whether the existing PVC in the cluster is still bound to the same PersistentVolume (PV) it was bound to at the time of the backup. If the PVC is bound to a different PV, performing an in-place restore (especially an incremental one that relies on Changed Block Tracking) may be unsafe or result in unpredictable behavior. If this check fails, Velero will log an error and skip the in-place restore for that volume. + + +#### 3. Volume Size Validation + +For in-place restores, the target volume must be large enough to accommodate the backed-up data. While the data path performs size checks during the actual restoration (only for block data mover), Velero will fail early to prevent unnecessary operations (such as taking a temporary snapshot). + +Before initiating an in-place restore, Velero compares the existing PV's size (`pv.spec.capacity.storage`) against the backup's data size (retrieved from the backup volume info). If the target PV is smaller than the backup data size, Velero will log an error and skip the volume data restoration. + +### Error Handling + +It is highly recommended that users create a backup (e.g., a CSI snapshot backup without data movement, if possible) before initiating an in-place restore. This ensures that the original state can be recovered in the event of a restore failure. + +If an in-place restore fails, Velero will intentionally leave certain temporary resources intact, such as the temporary PVC bound to the existing PV. Velero does not automatically clean up these resources because doing so could inadvertently trigger the deletion of the underlying storage volume. In such failure scenarios, users must manually clean up these temporary resources and, if necessary, use their pre-restore backup to recover the system's state. + +### Restore Workflow Update + +This section outlines the step-by-step control path and data path workflows for in-place restores. The exact sequence of operations depends on the backup method (CSI snapshot vs. file system backup), the chosen data mover (block vs. file system), and the target volume mode (block vs. file system). The following subsections detail the mechanisms for each supported scenario. + +#### In-place Incremental Restore for CSI Snapshot with Block Data Move for Block Volumes + +**Control Path** + +PVC RIA: +- Preserve the `volume.kubernetes.io/selected-node` annotation to ensure correct scheduling during target PVC recreation. + +PVC CSI RIA: +- Create a snapshot of the existing `PVC` to serve as the baseline for CBT delta calculations. +- Patch the existing PV's reclaim policy to `Retain`. +- Delete the existing PVC. +- Create a `DataDownload` resource referencing this snapshot and the existing `PV`, with `restoreType` set to `incremental`. + +Restore Exposer: +- Create a temporary restore PVC and bind it to the existing PV. +- Create a temporary restore Pod that mounts the temporary restore PVC. + +**Data Path** + +Block Uploader: +- The block uploader leverages Changed Block Tracking (CBT) to calculate the delta between the volume's current state and the backup snapshot. By skipping unchanged blocks and exclusively overwriting the modified ones, it significantly reduces I/O operations and accelerates the overall restore process. If the underlying storage system lacks CBT support, Velero will automatically fall back to performing an in-place full restore. + +#### In-place Full Restore for CSI Snapshot with Block Data Move for Block Volumes + +The workflow is identical to the **In-place Incremental Restore for CSI Snapshot with Block Data Move for Block Volumes**, with the following exceptions: +- No baseline snapshot is taken. +- The uploader does not use CBT to calculate deltas; instead, it overwrites all data on the volume. + +#### In-place Incremental Restore for CSI Snapshot with File System Data Move for File System Volumes + +**Control Path** + +The control path workflow is identical to the **In-place Incremental Restore for CSI Snapshot with Block Data Move for Block Volumes**, with the following exceptions: +- No baseline snapshot is taken. + +**Data Path** + +Kopia Uploader: +- Set the `incremental` flag to `true` when initiating the restore with the Kopia uploader. +- Pass the `deleteExtraFiles` configuration to the Kopia uploader based on the user's settings. +- Kopia evaluates file metadata (e.g., modification times and sizes) to identify changed files. It skips downloading and overwriting files that are identical to the backup, only restoring those that are modified, missing, or corrupted. + +#### In-place Full Restore for CSI Snapshot with File System Data Move for File System Volumes + +The workflow is identical to the **In-place Incremental Restore for CSI Snapshot with File System Data Move for File System Volumes**, with the following exceptions: +- The `restoreType` flag set to `full`. +- The Kopia uploader does not evaluate file metadata to skip unchanged files; instead, it overwrites all data on the target volume. + +#### In-place Incremental Restore for CSI Snapshot with Block Data Move for File System Volumes + +**Control Path** + +PVC RIA: +- Preserve the `volume.kubernetes.io/selected-node` annotation to ensure correct scheduling during target PVC recreation. + +PVC CSI RIA: +- Create a snapshot of the existing `PVC` to serve as the baseline for CBT delta calculations. +- Patch the existing `PV` to set its `persistentVolumeReclaimPolicy` to `Retain`. +- Delete the existing `PVC`. +- Create a `DataDownload` resource referencing the snapshot and the existing `PV`, with `restoreType` set to `incremental`. + +Restore Exposer: +- Delete the existing `PV`. +- Create a temporary restore `PV` with `volumeMode` set to `Block`, using the same volume handle as the original `PV`. +- Reset the bind information of the temporary restore `PV` to ensure it only binds to the temporary restore `PVC`. +- Create a temporary restore `PVC` with `volumeMode` set to `Block`. +- Create a temporary restore Pod that mounts the temporary restore `PVC`. + +**Data Path** + +Block Uploader: +- The block uploader leverages Changed Block Tracking (CBT) to calculate the delta between the volume's current state and the backup snapshot. By skipping unchanged blocks and exclusively overwriting the modified ones, it significantly reduces I/O operations and accelerates the overall restore process. If the underlying storage system lacks CBT support, Velero will automatically fall back to performing an in-place full restore. + +**Control Path (Post-Restore)** + +Restore Exposer: +- Delete the temporary restore Pod, `PVC`, and `PV`. +- Recreate the original `PV` with its `volumeMode` set back to `Filesystem`. +- Proceed with the standard process to allow the target `PVC` to bind to the recreated `PV`. + +#### In-place Full Restore for CSI Snapshot with Block Data Move for File System Volumes + +The workflow is identical to the **In-place Incremental Restore for CSI Snapshot with Block Data Move for File System Volumes**, with the following exceptions: +- No baseline snapshot is taken. +- The uploader does not use CBT to calculate deltas; instead, it overwrites all data on the volume. + +#### In-place Incremental Restore for File System Backup for File System Volumes + +**Control Path** + +- Create a `PodVolumeRestore` resource with `restoreType` set to `incremental`. + +**Data Path** + +Kopia Uploader: +- Set the `incremental` flag to `true` when initiating the restore with the Kopia uploader. +- Pass the `deleteExtraFiles` configuration to the Kopia uploader based on the user's settings. +- Similar to the CSI File System Data Move, Kopia evaluates file metadata to skip unchanged files and only restores those that are modified or missing. + +#### In-place Full Restore for File System Backup for File System Volumes + +The workflow is identical to the **In-place Incremental Restore for File System Backup for File System Volumes**, with the following exceptions: +- The `restoreType` flag is set to `full`. +- The Kopia uploader does not evaluate file metadata to skip unchanged files; instead, it overwrites all data on the target volume. + +## Installation + +No change to Installation. + +## Upgrade + +No impacts to Upgrade. The new fields in the CRDs are all optional fields and have backwards compatible values. \ No newline at end of file From fb86290def985b2c27285e2faf5dc19347b98e0d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 09:44:01 -0700 Subject: [PATCH 13/45] Merge pull request #10208 from velero-io/copilot/edit-autoassign-workflow Re-request maintainer review when only one CODEOWNERS approval exists --- .github/workflows/auto_assign_prs.yml | 68 ++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto_assign_prs.yml b/.github/workflows/auto_assign_prs.yml index 8966b235e..b51fde199 100644 --- a/.github/workflows/auto_assign_prs.yml +++ b/.github/workflows/auto_assign_prs.yml @@ -6,6 +6,10 @@ name: "Auto Assign Author" on: pull_request_target: types: [opened, reopened, ready_for_review] + # Watch for submitted reviews so we can re-request a second CODEOWNERS + # review once only one maintainer has approved. + pull_request_review: + types: [submitted] permissions: contents: read @@ -14,10 +18,72 @@ permissions: jobs: # Automatically assigns reviewers and owner add-reviews: - if: github.repository == 'velero-io/velero' + if: github.repository == 'velero-io/velero' && github.event_name == 'pull_request_target' runs-on: ubuntu-latest steps: - name: Set the author of a PR as the assignee uses: kentaro-m/auto-assign-action@v2.0.0 with: configuration-path: ".github/auto-assignees.yml" + + # `.github/CODEOWNERS` automatically requests review from the + # velero-io/maintainer team, but that request is cleared as soon as a + # single member of the team submits a review. Since we require a minimum + # of 2 reviewers (see `number_of_reviewers` in auto-assignees.yml), this + # re-requests a review from the maintainer team whenever a PR still has + # fewer than the required number of approvals, so a second CODEOWNERS + # reviewer gets pinged. + re-request-review: + if: github.repository == 'velero-io/velero' && github.event_name == 'pull_request_review' && github.event.review.state == 'approved' + runs-on: ubuntu-latest + steps: + - name: Re-request review from maintainers if more approvals are needed + uses: actions/github-script@v7 + with: + script: | + const requiredApprovals = 2; + const maintainerTeam = 'maintainer'; + const { owner, repo } = context.repo; + const pull_number = context.payload.pull_request.number; + + const { data: reviews } = await github.rest.pulls.listReviews({ + owner, + repo, + pull_number, + }); + + // Count distinct users whose most recent review is an approval. + // The Reviews API does not guarantee chronological order, so + // sort by submission time before folding into the map. + const sortedReviews = [...reviews].sort( + (a, b) => new Date(a.submitted_at) - new Date(b.submitted_at) + ); + const latestReviewByUser = new Map(); + for (const review of sortedReviews) { + latestReviewByUser.set(review.user.login, review.state); + } + const approvedReviewers = [...latestReviewByUser.entries()].filter( + ([, state]) => state === 'APPROVED' + ); + + if (approvedReviewers.length >= requiredApprovals) { + console.log( + `PR already has ${approvedReviewers.length} approvals, no need to re-request review.` + ); + return; + } + + console.log( + `PR has ${approvedReviewers.length}/${requiredApprovals} approvals, re-requesting review from @${owner}/${maintainerTeam}.` + ); + + try { + await github.rest.pulls.requestReviewers({ + owner, + repo, + pull_number, + team_reviewers: [maintainerTeam], + }); + } catch (error) { + core.warning(`Failed to re-request review from maintainers: ${error.message}`); + } From ced051b72f3abb467fa57eb2b85a0e7aedcf4936 Mon Sep 17 00:00:00 2001 From: Tiger Kaovilai Date: Mon, 10 Aug 2026 15:36:14 -0400 Subject: [PATCH 14/45] Fix restore-wait init container ignoring pod-level securityContext (#10047) restore-wait's securityContext fallback chain checked the fs-restore ConfigMap, then the first container's SecurityContext, then hardcoded runAsUser 1000. It never consulted pod.Spec.SecurityContext, so pods that set identity only at the pod level got a helper running as uid 1000 regardless of the workload's actual uid. On volumes where restored content is owner-only-visible to a non-1000 uid, the helper's stat on the done-file returns EACCES forever and the pod deadlocks at Init:0/1. Add pod-level spec.securityContext.runAsUser/runAsGroup as a fallback between the container-level check and the hardcoded default, since the workload's own identity is the one that can read what it restored. Defer to the pod's own RunAsNonRoot setting when runAsUser is 0, since the hardcoded RunAsNonRoot: true would otherwise contradict a root uid. Also add a test case covering both container-level and pod-level SecurityContext set together, confirming container-level still wins. Fixes #10046 Signed-off-by: Tiger Kaovilai --- changelogs/unreleased/10047-kaovilai | 1 + .../actions/pod_volume_restore_action.go | 19 ++ .../actions/pod_volume_restore_action_test.go | 205 ++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 changelogs/unreleased/10047-kaovilai diff --git a/changelogs/unreleased/10047-kaovilai b/changelogs/unreleased/10047-kaovilai new file mode 100644 index 000000000..6d96bdede --- /dev/null +++ b/changelogs/unreleased/10047-kaovilai @@ -0,0 +1 @@ +Fix restore-wait init container ignoring pod-level securityContext, falling back to hardcoded runAsUser 1000 instead of the workload's own uid/gid, causing fs-backup restores to deadlock at Init:0/1 on owner-restricted volumes diff --git a/pkg/restore/actions/pod_volume_restore_action.go b/pkg/restore/actions/pod_volume_restore_action.go index 5f2b3db3e..cbfcbfb35 100644 --- a/pkg/restore/actions/pod_volume_restore_action.go +++ b/pkg/restore/actions/pod_volume_restore_action.go @@ -198,6 +198,25 @@ func (a *PodVolumeRestoreAction) Execute(input *velero.RestoreItemActionExecuteI securityContext = *pod.Spec.Containers[0].SecurityContext.DeepCopy() securityContextSet = true } + // if no configmap or container-level securityContext is set, fall back to the pod-level + // spec.securityContext runAsUser/runAsGroup: the workload's own identity is the one that + // wrote the restored files, so it's the one that can read them back + if !securityContextSet && pod.Spec.SecurityContext != nil && + (pod.Spec.SecurityContext.RunAsUser != nil || pod.Spec.SecurityContext.RunAsGroup != nil) { + securityContext = defaultSecurityCtx() + if pod.Spec.SecurityContext.RunAsUser != nil { + securityContext.RunAsUser = pod.Spec.SecurityContext.RunAsUser + // defaultSecurityCtx() hardcodes RunAsNonRoot: true, which contradicts a pod-level + // RunAsUser of 0 (root); defer to the pod's own RunAsNonRoot setting in that case + if *pod.Spec.SecurityContext.RunAsUser == 0 { + securityContext.RunAsNonRoot = pod.Spec.SecurityContext.RunAsNonRoot + } + } + if pod.Spec.SecurityContext.RunAsGroup != nil { + securityContext.RunAsGroup = pod.Spec.SecurityContext.RunAsGroup + } + securityContextSet = true + } if !securityContextSet { securityContext = defaultSecurityCtx() } diff --git a/pkg/restore/actions/pod_volume_restore_action_test.go b/pkg/restore/actions/pod_volume_restore_action_test.go index bc9662ab7..614a5d1be 100644 --- a/pkg/restore/actions/pod_volume_restore_action_test.go +++ b/pkg/restore/actions/pod_volume_restore_action_test.go @@ -156,6 +156,155 @@ func TestPodVolumeRestoreActionExecute(t *testing.T) { defaultRestoreHelperImage := "velero/velero:v1.0" + podLevelUID := int64(999) + podLevelGID := int64(999) + podLevelSecurityContext := corev1api.SecurityContext{ + AllowPrivilegeEscalation: boolptr.False(), + Capabilities: &corev1api.Capabilities{ + Drop: []corev1api.Capability{"ALL"}, + }, + SeccompProfile: &corev1api.SeccompProfile{ + Type: corev1api.SeccompProfileTypeRuntimeDefault, + }, + RunAsUser: &podLevelUID, + RunAsGroup: &podLevelGID, + RunAsNonRoot: boolptr.True(), + } + + podWithPodLevelSecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + Result() + podWithPodLevelSecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsUser: &podLevelUID, RunAsGroup: &podLevelGID} + + wantPodWithPodLevelSecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + InitContainers( + newRestoreInitContainerBuilder(defaultRestoreHelperImage, ""). + Resources(&resourceReqs). + SecurityContext(&podLevelSecurityContext). + VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()). + Command([]string{"/velero-restore-helper"}).Result()). + Result() + wantPodWithPodLevelSecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsUser: &podLevelUID, RunAsGroup: &podLevelGID} + + podLevelRootUID := int64(0) + podLevelRootSecurityContext := corev1api.SecurityContext{ + AllowPrivilegeEscalation: boolptr.False(), + Capabilities: &corev1api.Capabilities{ + Drop: []corev1api.Capability{"ALL"}, + }, + SeccompProfile: &corev1api.SeccompProfile{ + Type: corev1api.SeccompProfileTypeRuntimeDefault, + }, + RunAsUser: &podLevelRootUID, + } + + podWithPodLevelRootSecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + Result() + podWithPodLevelRootSecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsUser: &podLevelRootUID} + + wantPodWithPodLevelRootSecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + InitContainers( + newRestoreInitContainerBuilder(defaultRestoreHelperImage, ""). + Resources(&resourceReqs). + SecurityContext(&podLevelRootSecurityContext). + VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()). + Command([]string{"/velero-restore-helper"}).Result()). + Result() + wantPodWithPodLevelRootSecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsUser: &podLevelRootUID} + + podLevelGroupOnlyGID := int64(777) + podLevelGroupOnlySecurityContext := corev1api.SecurityContext{ + AllowPrivilegeEscalation: boolptr.False(), + Capabilities: &corev1api.Capabilities{ + Drop: []corev1api.Capability{"ALL"}, + }, + SeccompProfile: &corev1api.SeccompProfile{ + Type: corev1api.SeccompProfileTypeRuntimeDefault, + }, + RunAsUser: &id, + RunAsGroup: &podLevelGroupOnlyGID, + RunAsNonRoot: boolptr.True(), + } + + podWithPodLevelGroupOnlySecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + Result() + podWithPodLevelGroupOnlySecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsGroup: &podLevelGroupOnlyGID} + + wantPodWithPodLevelGroupOnlySecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + InitContainers( + newRestoreInitContainerBuilder(defaultRestoreHelperImage, ""). + Resources(&resourceReqs). + SecurityContext(&podLevelGroupOnlySecurityContext). + VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()). + Command([]string{"/velero-restore-helper"}).Result()). + Result() + wantPodWithPodLevelGroupOnlySecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsGroup: &podLevelGroupOnlyGID} + + bothLevelsPodUID := int64(500) + bothLevelsContainerUID := int64(999) + bothLevelsContainerSecurityContext := corev1api.SecurityContext{ + AllowPrivilegeEscalation: boolptr.False(), + Capabilities: &corev1api.Capabilities{ + Drop: []corev1api.Capability{"ALL"}, + }, + SeccompProfile: &corev1api.SeccompProfile{ + Type: corev1api.SeccompProfileTypeRuntimeDefault, + }, + RunAsUser: &bothLevelsContainerUID, + RunAsNonRoot: boolptr.True(), + } + + podWithBothLevelsSecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + Containers( + builder.ForContainer("app-container", "app-image"). + SecurityContext(&bothLevelsContainerSecurityContext).Result()). + Result() + podWithBothLevelsSecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsUser: &bothLevelsPodUID} + + wantPodWithBothLevelsSecurityContext := builder.ForPod("ns-1", "my-pod"). + ObjectMeta(builder.WithAnnotations("snapshot.velero.io/myvol", "")). + Volumes( + builder.ForVolume("myvol").PersistentVolumeClaimSource("pvc-1").Result(), + ). + Containers( + builder.ForContainer("app-container", "app-image"). + SecurityContext(&bothLevelsContainerSecurityContext).Result()). + InitContainers( + newRestoreInitContainerBuilder(defaultRestoreHelperImage, ""). + Resources(&resourceReqs). + SecurityContext(&bothLevelsContainerSecurityContext). + VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()). + Command([]string{"/velero-restore-helper"}).Result()). + Result() + wantPodWithBothLevelsSecurityContext.Spec.SecurityContext = &corev1api.PodSecurityContext{RunAsUser: &bothLevelsPodUID} + tests := []struct { name string pod *corev1api.Pod @@ -350,6 +499,62 @@ func TestPodVolumeRestoreActionExecute(t *testing.T) { VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()). Command([]string{"/velero-restore-helper"}).Result()).Result(), }, + { + name: "Restoring pod with pod-level securityContext (no container-level SecurityContext) uses pod-level runAsUser/runAsGroup for the restore initContainer", + pod: podWithPodLevelSecurityContext, + podVolumeBackups: []runtime.Object{ + builder.ForPodVolumeBackup(veleroNs, "pvb-1"). + PodName("my-pod"). + PodNamespace("ns-1"). + Volume("myvol"). + ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, backupName)). + SnapshotID("foo"). + Result(), + }, + want: wantPodWithPodLevelSecurityContext, + }, + { + name: "Restoring pod with pod-level securityContext.runAsUser=0 does not force RunAsNonRoot on the restore initContainer", + pod: podWithPodLevelRootSecurityContext, + podVolumeBackups: []runtime.Object{ + builder.ForPodVolumeBackup(veleroNs, "pvb-1"). + PodName("my-pod"). + PodNamespace("ns-1"). + Volume("myvol"). + ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, backupName)). + SnapshotID("foo"). + Result(), + }, + want: wantPodWithPodLevelRootSecurityContext, + }, + { + name: "Restoring pod with pod-level securityContext.runAsGroup only (no runAsUser) still applies the group to the restore initContainer", + pod: podWithPodLevelGroupOnlySecurityContext, + podVolumeBackups: []runtime.Object{ + builder.ForPodVolumeBackup(veleroNs, "pvb-1"). + PodName("my-pod"). + PodNamespace("ns-1"). + Volume("myvol"). + ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, backupName)). + SnapshotID("foo"). + Result(), + }, + want: wantPodWithPodLevelGroupOnlySecurityContext, + }, + { + name: "Restoring pod with both container-level and pod-level SecurityContext set uses the container-level SecurityContext for the restore initContainer (container-level takes priority)", + pod: podWithBothLevelsSecurityContext, + podVolumeBackups: []runtime.Object{ + builder.ForPodVolumeBackup(veleroNs, "pvb-1"). + PodName("my-pod"). + PodNamespace("ns-1"). + Volume("myvol"). + ObjectMeta(builder.WithLabels(velerov1api.BackupNameLabel, backupName)). + SnapshotID("foo"). + Result(), + }, + want: wantPodWithBothLevelsSecurityContext, + }, { name: "pod volume backups in a different namespace are ignored when looking for matches due to namespace scoping", pod: builder.ForPod("ns-1", "my-pod"). From 513e93ff4bb7bf57abc0093ac853a7dcd795d0e6 Mon Sep 17 00:00:00 2001 From: Shelly Chahar Date: Tue, 11 Aug 2026 01:10:02 +0530 Subject: [PATCH 15/45] fix: correct typos in log messages and status strings (#10192) - Fix 'dataudownload' typo in DataDownload warning log message (data_download_controller.go:696) - Fix 'datadownlad' misspelled structured log field key to 'datadownload' (data_download_controller.go:700) - this caused the log field to be unqueryable by the correct key name - Fix 'retrieveable' -> 'retrievable' in BackupRepository maintenance status messages (maintenance.go:354, 417) - Update corresponding test assertion to match corrected string (maintenance_test.go:792) Signed-off-by: shellyco-code Co-authored-by: shellyco-code --- pkg/controller/data_download_controller.go | 4 ++-- pkg/repository/maintenance/maintenance.go | 4 ++-- pkg/repository/maintenance/maintenance_test.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/controller/data_download_controller.go b/pkg/controller/data_download_controller.go index 337d10936..422879d6e 100644 --- a/pkg/controller/data_download_controller.go +++ b/pkg/controller/data_download_controller.go @@ -693,11 +693,11 @@ func (r *DataDownloadReconciler) findSnapshotRestoreForPod(ctx context.Context, r.prepareDataDownload(dd) return true }); err != nil { - log.WithError(err).Warn("failed to update dataudownload, prepare will halt for this dataudownload") + log.WithError(err).Warn("failed to update datadownload, prepare will halt for this datadownload") return []reconcile.Request{} } } else if unrecoverable, reason := kube.IsPodUnrecoverable(pod, log); unrecoverable { - err := UpdateDataDownloadWithRetry(context.Background(), r.client, types.NamespacedName{Namespace: dd.Namespace, Name: dd.Name}, r.logger.WithField("datadownlad", dd.Name), + err := UpdateDataDownloadWithRetry(context.Background(), r.client, types.NamespacedName{Namespace: dd.Namespace, Name: dd.Name}, r.logger.WithField("datadownload", dd.Name), func(dataDownload *velerov2alpha1api.DataDownload) bool { if dataDownload.Spec.Cancel { return false diff --git a/pkg/repository/maintenance/maintenance.go b/pkg/repository/maintenance/maintenance.go index 33c3fb1f8..86525d54f 100644 --- a/pkg/repository/maintenance/maintenance.go +++ b/pkg/repository/maintenance/maintenance.go @@ -351,7 +351,7 @@ func WaitJobComplete(cli client.Client, ctx context.Context, jobName, ns string, if maintenanceJob.Status.Failed > 0 { if r, err := getResultFromJob(cli, maintenanceJob); err != nil { log.WithError(err).Warn("Failed to get maintenance job result") - result = "Repo maintenance failed but result is not retrieveable" + result = "Repo maintenance failed but result is not retrievable" } else { result = r } @@ -414,7 +414,7 @@ func WaitAllJobsComplete(ctx context.Context, cli client.Client, repo *velerov1a if job.Status.Failed > 0 { if msg, err := getResultFromJob(cli, job); err != nil { log.WithError(err).Warnf("Failed to get result of maintenance job %s", job.Name) - message = fmt.Sprintf("Repo maintenance failed but result is not retrieveable, err: %v", err) + message = fmt.Sprintf("Repo maintenance failed but result is not retrievable, err: %v", err) } else { message = msg } diff --git a/pkg/repository/maintenance/maintenance_test.go b/pkg/repository/maintenance/maintenance_test.go index 05fce89e9..ee34241ce 100644 --- a/pkg/repository/maintenance/maintenance_test.go +++ b/pkg/repository/maintenance/maintenance_test.go @@ -789,7 +789,7 @@ func TestWaitAllJobsComplete(t *testing.T) { { Result: velerov1api.BackupRepositoryMaintenanceFailed, StartTimestamp: &metav1.Time{Time: now.Add(time.Hour)}, - Message: "Repo maintenance failed but result is not retrieveable, err: no pod found for job job2", + Message: "Repo maintenance failed but result is not retrievable, err: no pod found for job job2", }, }, }, From 943a4d6bb414c61cd1008a57ec3e9a2baee20382 Mon Sep 17 00:00:00 2001 From: harshit saini <123226128+harshitsaini17@users.noreply.github.com> Date: Tue, 11 Aug 2026 01:30:54 +0530 Subject: [PATCH 16/45] docs: fix restore logs command name in self-signed-certificates (#10213) The list of commands supporting --insecure-skip-tls-verify referred to `velero restore log`, but the registered command is `velero restore logs` (pkg/cmd/cli/restore/logs.go). `velero restore log` silently falls through to the parent command's help text and exits 0, so a user following the docs gets no logs and no error. Fixes #10183 Signed-off-by: Harshit saini --- site/content/docs/main/self-signed-certificates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/docs/main/self-signed-certificates.md b/site/content/docs/main/self-signed-certificates.md index 41eb8b247..87576dae2 100644 --- a/site/content/docs/main/self-signed-certificates.md +++ b/site/content/docs/main/self-signed-certificates.md @@ -150,7 +150,7 @@ Velero provides a way for you to skip TLS verification on the object store when * velero backup download * velero backup logs * velero restore describe -* velero restore log +* velero restore logs If true, the object store's TLS certificate will not be checked for validity before Velero or backup repository connects to the object storage. You can permanently skip TLS verification for an object store by setting `Spec.Config.InsecureSkipTLSVerify` to true in the [BackupStorageLocation](api-types/backupstoragelocation.md) CRD. From ccbb7d1cc7e13cbe536a4c04cea3d08bff5508a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:01:13 -0400 Subject: [PATCH 17/45] Bump actions/setup-go from 6 to 7 (#10202) Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6 to 7. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-test-kind.yaml | 4 ++-- .github/workflows/pr-ci-check.yml | 2 +- .github/workflows/pr-linter-check.yml | 2 +- .github/workflows/push.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index 88cc3b641..34a98203c 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -32,7 +32,7 @@ jobs: uses: actions/checkout@v7 - name: Set up Go version - uses: actions/setup-go@v6 + uses: actions/setup-go@v7 with: go-version: ${{ needs.get-go-version.outputs.version }} @@ -122,7 +122,7 @@ jobs: uses: actions/checkout@v7 - name: Set up Go version - uses: actions/setup-go@v6 + uses: actions/setup-go@v7 with: go-version: ${{ needs.get-go-version.outputs.version }} diff --git a/.github/workflows/pr-ci-check.yml b/.github/workflows/pr-ci-check.yml index 01e86dc08..fd5948f7b 100644 --- a/.github/workflows/pr-ci-check.yml +++ b/.github/workflows/pr-ci-check.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v7 - name: Set up Go version - uses: actions/setup-go@v6 + uses: actions/setup-go@v7 with: go-version: ${{ needs.get-go-version.outputs.version }} diff --git a/.github/workflows/pr-linter-check.yml b/.github/workflows/pr-linter-check.yml index 6f8057be6..1a25569f1 100644 --- a/.github/workflows/pr-linter-check.yml +++ b/.github/workflows/pr-linter-check.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v7 - name: Set up Go version - uses: actions/setup-go@v6 + uses: actions/setup-go@v7 with: go-version: ${{ needs.get-go-version.outputs.version }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index f4f4d9c6e..f5ce8c456 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Go version - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ needs.get-go-version.outputs.version }} From 476a7ca160a8cd9a6ea941fd09ecf4d7b281cec5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:01:37 -0400 Subject: [PATCH 18/45] Bump github/codeql-action from 4.37.3 to 4.37.6 (#10203) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.37.3 to 4.37.6. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v4.37.3...v4.37.6) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.37.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/nightly-trivy-scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly-trivy-scan.yml b/.github/workflows/nightly-trivy-scan.yml index 3acb1d15b..4c1381a5b 100644 --- a/.github/workflows/nightly-trivy-scan.yml +++ b/.github/workflows/nightly-trivy-scan.yml @@ -31,6 +31,6 @@ jobs: output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@v4.37.3 + uses: github/codeql-action/upload-sarif@v4.37.6 with: sarif_file: 'trivy-results.sarif' \ No newline at end of file From 9a549f781f650e78fbf370a3db10dbb5bcb68f0e Mon Sep 17 00:00:00 2001 From: Jay Sawant Date: Tue, 11 Aug 2026 01:40:20 +0530 Subject: [PATCH 19/45] docs: fix grammar and typos in customize-installation (#10190) Signed-off-by: Jay2006sawant --- site/content/docs/main/customize-installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/content/docs/main/customize-installation.md b/site/content/docs/main/customize-installation.md index 28cc24154..194d947eb 100644 --- a/site/content/docs/main/customize-installation.md +++ b/site/content/docs/main/customize-installation.md @@ -40,7 +40,7 @@ When installing with the `--use-node-agent` flag, the node-agent will mount the By default, `velero install` does not enable the use of File System Backup (FSB) to take backups of all pod volumes. You must apply an [annotation](file-system-backup.md/#using-opt-in-pod-volume-backup) to every pod which contains volumes for Velero to use FSB for the backup. -If you are planning to only use FSB for volume backups, you can run the `velero install` command with the `--default-volumes-to-fs-backup` flag. This will default all pod volumes backups to use FSB without having to apply annotations to pods. Note that when this flag is set during install, Velero will always try to use FSB to perform the backup, even want an individual backup to use volume snapshots, by setting the `--snapshot-volumes` flag in the `backup create` command. Alternatively, you can set the `--default-volumes-to-fs-backup` on an individual backup to to make sure Velero uses FSB for each volume being backed up. +If you are planning to only use FSB for volume backups, you can run the `velero install` command with the `--default-volumes-to-fs-backup` flag. This will default all pod volume backups to use FSB without having to apply annotations to pods. Note that when this flag is set during install, Velero will always try to use FSB to perform the backup. If you want an individual backup to use volume snapshots instead, set the `--snapshot-volumes` flag in the `backup create` command. Alternatively, you can set the `--default-volumes-to-fs-backup` flag on an individual backup to make sure Velero uses FSB for each volume being backed up. ## Update an existing installation @@ -219,7 +219,7 @@ kubectl patch daemonset node-agent -n velero --patch \ '{"spec":{"template":{"spec":{"containers":[{"name": "node-agent", "resources": {"limits":{"cpu": "1", "memory": "1024Mi"}, "requests": {"cpu": "1", "memory": "512Mi"}}}]}}}}' ``` -Additionally, you may want to update the the default File System Backup operation timeout (default 240 minutes) to allow larger backups more time to complete. You can adjust this timeout by adding the `- --fs-backup-timeout` argument to the Velero Deployment spec. +Additionally, you may want to update the default File System Backup operation timeout (default 240 minutes) to allow larger backups more time to complete. You can adjust this timeout by adding the `- --fs-backup-timeout` argument to the Velero Deployment spec. **NOTE:** Changes made to this timeout value will revert back to the default value if you re-run the Velero install command. From 40de7f9f97f3004129653d0de9c90e6a63ef1c6a Mon Sep 17 00:00:00 2001 From: Xun Jiang/Bruce Jiang <59276555+blackpiglet@users.noreply.github.com> Date: Tue, 11 Aug 2026 04:29:13 +0800 Subject: [PATCH 20/45] Make backupType case insensitive in the CLI. (#10189) Signed-off-by: Xun Jiang --- pkg/cmd/cli/backup/create.go | 10 ++++++++-- pkg/cmd/cli/backup/create_test.go | 16 ++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pkg/cmd/cli/backup/create.go b/pkg/cmd/cli/backup/create.go index ae9dd2fec..5082eb239 100644 --- a/pkg/cmd/cli/backup/create.go +++ b/pkg/cmd/cli/backup/create.go @@ -242,11 +242,17 @@ func (o *CreateOptions) validateFromScheduleFlag(c *cobra.Command) error { return nil } +// validateBackupType check the backupType value and return the valid value. func (o *CreateOptions) validateBackupType() error { - backupType := strings.TrimSpace(o.BackupType) + // Allow full, and incremental from the CLI, and ignore case of the input string's case. + backupType := strings.ToLower(strings.TrimSpace(o.BackupType)) switch backupType { - case "", "Incremental", "Full": + case "": + case "incremental": + o.BackupType = string(velerov1api.BackupTypeIncremental) + case "full": + o.BackupType = string(velerov1api.BackupTypeFull) default: return fmt.Errorf("invalid backup type %s - valid values are 'Incremental', and 'Full'", backupType) } diff --git a/pkg/cmd/cli/backup/create_test.go b/pkg/cmd/cli/backup/create_test.go index 718ab0e96..46885b7c9 100644 --- a/pkg/cmd/cli/backup/create_test.go +++ b/pkg/cmd/cli/backup/create_test.go @@ -129,30 +129,34 @@ func TestCreateOptions_ValidateBackupType(t *testing.T) { o.BackupType = "" err := o.validateBackupType() require.NoError(t, err) + require.Empty(t, o.BackupType) o.BackupType = "Incremental" err = o.validateBackupType() require.NoError(t, err) + require.EqualValues(t, velerov1api.BackupTypeIncremental, o.BackupType) o.BackupType = "Full" err = o.validateBackupType() require.NoError(t, err) + require.EqualValues(t, velerov1api.BackupTypeFull, o.BackupType) o.BackupType = " Incremental " err = o.validateBackupType() require.NoError(t, err) + require.EqualValues(t, velerov1api.BackupTypeIncremental, o.BackupType) + + o.BackupType = "iNcReMeNtAl" + err = o.validateBackupType() + require.NoError(t, err) + require.EqualValues(t, velerov1api.BackupTypeIncremental, o.BackupType) }) t.Run("invalid backup type", func(t *testing.T) { o := NewCreateOptions() - o.BackupType = "incremental" - err := o.validateBackupType() - require.Error(t, err) - require.Equal(t, "invalid backup type incremental - valid values are 'Incremental', and 'Full'", err.Error()) - o.BackupType = "invalid" - err = o.validateBackupType() + err := o.validateBackupType() require.Error(t, err) require.Equal(t, "invalid backup type invalid - valid values are 'Incremental', and 'Full'", err.Error()) }) From a41cb1190250a531f1948d37755a37013055b83f Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 11 Aug 2026 12:56:23 +0800 Subject: [PATCH 21/45] add prefetch options for repo interface Signed-off-by: Lyndon-Li --- pkg/repository/udmrepo/kopialib/lib_repo.go | 4 ++-- pkg/repository/udmrepo/repo.go | 7 ++++++- pkg/uploader/block/uploader.go | 2 +- pkg/uploader/kopia/shim.go | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pkg/repository/udmrepo/kopialib/lib_repo.go b/pkg/repository/udmrepo/kopialib/lib_repo.go index c7bb65a43..b26edb76f 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo.go @@ -338,7 +338,7 @@ func (km *kopiaMaintenance) maintainProgress(uploaded int64) { } } -func (kr *kopiaRepository) OpenObject(ctx context.Context, id udmrepo.ID) (udmrepo.ObjectReader, error) { +func (kr *kopiaRepository) OpenObject(ctx context.Context, id udmrepo.ID, opt udmrepo.ObjectReadOptions) (udmrepo.ObjectReader, error) { if kr.rawRepo == nil { return nil, errors.New("repo is closed or not open") } @@ -550,7 +550,7 @@ func (kr *kopiaRepository) WriteMetadata(ctx context.Context, meta *udmrepo.Meta } func (kr *kopiaRepository) ReadMetadata(ctx context.Context, id udmrepo.ID) (*udmrepo.Metadata, error) { - reader, err := kr.OpenObject(ctx, id) + reader, err := kr.OpenObject(ctx, id, udmrepo.ObjectReadOptions{}) if err != nil { return nil, errors.Wrapf(err, "error to open metadata object %v", id) } diff --git a/pkg/repository/udmrepo/repo.go b/pkg/repository/udmrepo/repo.go index 76cdc5f1d..5873db743 100644 --- a/pkg/repository/udmrepo/repo.go +++ b/pkg/repository/udmrepo/repo.go @@ -72,6 +72,11 @@ type ObjectWriteOptions struct { ParentObject ID // The object in the previous snapshot, for incremental backup } +type ObjectReadOptions struct { + Prefetch bool + PrefetchBudgetMB int +} + type AdvancedFeatureInfo struct { MultiPartBackup bool // if set to true, it means the repo supports multiple-part backup } @@ -136,7 +141,7 @@ type BackupRepoService interface { type BackupRepo interface { // OpenObject opens an existing object for read. // id: the object's unified identifier. - OpenObject(ctx context.Context, id ID) (ObjectReader, error) + OpenObject(ctx context.Context, id ID, opt ObjectReadOptions) (ObjectReader, error) // GetManifest gets a manifest data from the backup repository. GetManifest(ctx context.Context, id ID, mani *RepoManifest) error diff --git a/pkg/uploader/block/uploader.go b/pkg/uploader/block/uploader.go index 824c0ae9f..4d8d86e84 100644 --- a/pkg/uploader/block/uploader.go +++ b/pkg/uploader/block/uploader.go @@ -176,7 +176,7 @@ func (blkup *blockUploader) Restore(snapshot udmrepo.Snapshot, dest destInfo, bi return 0, errors.Errorf("dest dev(%s) size is too small (%v vs. %v)", dest.path, dest.size, sourceSize) } - reader, err := blkup.repoWriter.OpenObject(blkup.ctx, meta.SubObjects[0].ID) + reader, err := blkup.repoWriter.OpenObject(blkup.ctx, meta.SubObjects[0].ID, udmrepo.ObjectReadOptions{}) if err != nil { return 0, errors.Wrapf(err, "error opening bdev object %v", meta.SubObjects[0].Name) } diff --git a/pkg/uploader/kopia/shim.go b/pkg/uploader/kopia/shim.go index 4a3908185..465b76c04 100644 --- a/pkg/uploader/kopia/shim.go +++ b/pkg/uploader/kopia/shim.go @@ -56,7 +56,7 @@ func NewShimRepo(repo udmrepo.BackupRepo) repo.RepositoryWriter { // OpenObject open specific object func (sr *shimRepository) OpenObject(ctx context.Context, id object.ID) (object.Reader, error) { - reader, err := sr.udmRepo.OpenObject(ctx, udmrepo.ID(id.String())) + reader, err := sr.udmRepo.OpenObject(ctx, udmrepo.ID(id.String()), udmrepo.ObjectReadOptions{}) if err != nil { return nil, errors.Wrapf(err, "failed to open object with id %v", id) } From b74824f9c0b7ad39260dbb5dda382490bd276746 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 11 Aug 2026 13:00:44 +0800 Subject: [PATCH 22/45] extend object reader for prefetch Signed-off-by: Lyndon-Li --- pkg/repository/udmrepo/kopialib/lib_repo.go | 138 +++++++++++++++++++- 1 file changed, 134 insertions(+), 4 deletions(-) diff --git a/pkg/repository/udmrepo/kopialib/lib_repo.go b/pkg/repository/udmrepo/kopialib/lib_repo.go index b26edb76f..0efde34a7 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo.go @@ -73,8 +73,22 @@ type logThrottle struct { interval time.Duration } +type objectPrefetch struct { + ctx context.Context + cancel context.CancelFunc + entries []object.IndirectObjectEntry + curOffset int64 + cond *sync.Cond + mu sync.Mutex + nextEntry int + budget int64 +} + type kopiaObjectReader struct { rawReader object.Reader + rawRepo repo.Repository + prefetch *objectPrefetch + logger logrus.FieldLogger } type kopiaObjectWriter struct { @@ -353,9 +367,43 @@ func (kr *kopiaRepository) OpenObject(ctx context.Context, id udmrepo.ID, opt ud return nil, errors.Wrap(err, "error to open object") } - return &kopiaObjectReader{ + var prefetch *objectPrefetch + if opt.Prefetch { + if e, err := kr.getFlattenedEntries(ctx, objID); err != nil { + kr.logger.WithError(err).Warnf("Failed to load entries for object %v, skip prefetch", id) + } else { + pCtx, pCancel := context.WithCancel(ctx) + prefetch = &objectPrefetch{ + ctx: pCtx, + cancel: pCancel, + budget: int64(opt.PrefetchBudgetMB) << 20, + entries: e, + } + + prefetch.cond = sync.NewCond(&prefetch.mu) + } + + } + + rd := &kopiaObjectReader{ rawReader: reader, - }, nil + rawRepo: kr.rawRepo, + prefetch: prefetch, + logger: kr.logger, + } + + if rd.prefetch != nil { + go rd.prefetchProc() + + go func() { + <-rd.prefetch.ctx.Done() + prefetch.mu.Lock() + prefetch.cond.Broadcast() + prefetch.mu.Unlock() + }() + } + + return rd, nil } func (kr *kopiaRepository) GetManifest(ctx context.Context, id udmrepo.ID, mani *udmrepo.RepoManifest) error { @@ -792,7 +840,16 @@ func (kor *kopiaObjectReader) Read(p []byte) (int, error) { return 0, errors.New("object reader is closed or not open") } - return kor.rawReader.Read(p) + n, err := kor.rawReader.Read(p) + if n > 0 { + if kor.prefetch != nil { + kor.prefetch.mu.Lock() + kor.prefetch.curOffset += int64(n) + kor.prefetch.cond.Signal() + kor.prefetch.mu.Unlock() + } + } + return n, err } func (kor *kopiaObjectReader) Seek(offset int64, whence int) (int64, error) { @@ -800,10 +857,83 @@ func (kor *kopiaObjectReader) Seek(offset int64, whence int) (int64, error) { return -1, errors.New("object reader is closed or not open") } - return kor.rawReader.Seek(offset, whence) + off, err := kor.rawReader.Seek(offset, whence) + if err == nil { + if kor.prefetch != nil { + kor.prefetch.mu.Lock() + kor.prefetch.curOffset = off + kor.prefetch.cond.Signal() + kor.prefetch.mu.Unlock() + } + } + + return off, err +} + +func (kor *kopiaObjectReader) prefetchProc() { + prefetch := kor.prefetch + if prefetch == nil { + return + } + + for { + prefetch.mu.Lock() + + select { + case <-prefetch.ctx.Done(): + prefetch.mu.Unlock() + return + default: + } + + curOffset := prefetch.curOffset + + for prefetch.nextEntry < len(prefetch.entries) { + entry := prefetch.entries[prefetch.nextEntry] + if entry.Start+entry.Length <= curOffset { + prefetch.nextEntry++ + } else { + break + } + } + + if prefetch.nextEntry >= len(prefetch.entries) { + prefetch.mu.Unlock() + return + } + + var toFetch []object.ID + for prefetch.nextEntry < len(prefetch.entries) { + entry := prefetch.entries[prefetch.nextEntry] + + if entry.Start > curOffset+prefetch.budget { + break + } + + toFetch = append(toFetch, entry.Object) + prefetch.nextEntry++ + } + + if len(toFetch) == 0 { + prefetch.cond.Wait() + prefetch.mu.Unlock() + continue + } + + prefetch.mu.Unlock() + + _, err := kor.rawRepo.PrefetchObjects(prefetch.ctx, toFetch, "") + if err != nil && err != context.Canceled { + kor.logger.WithError(err).Warnf("Failed to prefetch contents for offset %v", curOffset) + } + } } func (kor *kopiaObjectReader) Close() error { + if kor.prefetch != nil && kor.prefetch.cancel != nil { + kor.prefetch.cancel() + } + if kor.rawReader == nil { return nil } From de87def9d902df85d48c6add91c278bb754698ea Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 11 Aug 2026 13:02:11 +0800 Subject: [PATCH 23/45] enable object reader prefetch for block uploader Signed-off-by: Lyndon-Li --- pkg/uploader/block/uploader.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/uploader/block/uploader.go b/pkg/uploader/block/uploader.go index 4d8d86e84..275fd18ed 100644 --- a/pkg/uploader/block/uploader.go +++ b/pkg/uploader/block/uploader.go @@ -176,7 +176,10 @@ func (blkup *blockUploader) Restore(snapshot udmrepo.Snapshot, dest destInfo, bi return 0, errors.Errorf("dest dev(%s) size is too small (%v vs. %v)", dest.path, dest.size, sourceSize) } - reader, err := blkup.repoWriter.OpenObject(blkup.ctx, meta.SubObjects[0].ID, udmrepo.ObjectReadOptions{}) + reader, err := blkup.repoWriter.OpenObject(blkup.ctx, meta.SubObjects[0].ID, udmrepo.ObjectReadOptions{ + Prefetch: true, + PrefetchBudgetMB: 256, + }) if err != nil { return 0, errors.Wrapf(err, "error opening bdev object %v", meta.SubObjects[0].Name) } From c27343fc4e256647310d754e3c52e01afb2d45a3 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 11 Aug 2026 13:07:27 +0800 Subject: [PATCH 24/45] fix UT errors Signed-off-by: Lyndon-Li --- .../udmrepo/kopialib/lib_repo_test.go | 2 +- pkg/repository/udmrepo/mocks/BackupRepo.go | 30 +++++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/pkg/repository/udmrepo/kopialib/lib_repo_test.go b/pkg/repository/udmrepo/kopialib/lib_repo_test.go index 370b82b9e..0cc52261a 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo_test.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo_test.go @@ -318,7 +318,7 @@ func TestOpenObject(t *testing.T) { kr.rawRepo = tc.rawRepo } - _, err := kr.OpenObject(t.Context(), udmrepo.ID(tc.objectID)) + _, err := kr.OpenObject(t.Context(), udmrepo.ID(tc.objectID), udmrepo.ObjectReadOptions{}) if tc.expectedErr == "" { assert.NoError(t, err) diff --git a/pkg/repository/udmrepo/mocks/BackupRepo.go b/pkg/repository/udmrepo/mocks/BackupRepo.go index 623c4d70d..3206422b4 100644 --- a/pkg/repository/udmrepo/mocks/BackupRepo.go +++ b/pkg/repository/udmrepo/mocks/BackupRepo.go @@ -699,8 +699,8 @@ func (_c *BackupRepo_NewObjectWriter_Call) RunAndReturn(run func(ctx context.Con } // OpenObject provides a mock function for the type BackupRepo -func (_mock *BackupRepo) OpenObject(ctx context.Context, id udmrepo.ID) (udmrepo.ObjectReader, error) { - ret := _mock.Called(ctx, id) +func (_mock *BackupRepo) OpenObject(ctx context.Context, id udmrepo.ID, opt udmrepo.ObjectReadOptions) (udmrepo.ObjectReader, error) { + ret := _mock.Called(ctx, id, opt) if len(ret) == 0 { panic("no return value specified for OpenObject") @@ -708,18 +708,18 @@ func (_mock *BackupRepo) OpenObject(ctx context.Context, id udmrepo.ID) (udmrepo var r0 udmrepo.ObjectReader var r1 error - if returnFunc, ok := ret.Get(0).(func(context.Context, udmrepo.ID) (udmrepo.ObjectReader, error)); ok { - return returnFunc(ctx, id) + if returnFunc, ok := ret.Get(0).(func(context.Context, udmrepo.ID, udmrepo.ObjectReadOptions) (udmrepo.ObjectReader, error)); ok { + return returnFunc(ctx, id, opt) } - if returnFunc, ok := ret.Get(0).(func(context.Context, udmrepo.ID) udmrepo.ObjectReader); ok { - r0 = returnFunc(ctx, id) + if returnFunc, ok := ret.Get(0).(func(context.Context, udmrepo.ID, udmrepo.ObjectReadOptions) udmrepo.ObjectReader); ok { + r0 = returnFunc(ctx, id, opt) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(udmrepo.ObjectReader) } } - if returnFunc, ok := ret.Get(1).(func(context.Context, udmrepo.ID) error); ok { - r1 = returnFunc(ctx, id) + if returnFunc, ok := ret.Get(1).(func(context.Context, udmrepo.ID, udmrepo.ObjectReadOptions) error); ok { + r1 = returnFunc(ctx, id, opt) } else { r1 = ret.Error(1) } @@ -734,11 +734,12 @@ type BackupRepo_OpenObject_Call struct { // OpenObject is a helper method to define mock.On call // - ctx context.Context // - id udmrepo.ID -func (_e *BackupRepo_Expecter) OpenObject(ctx interface{}, id interface{}) *BackupRepo_OpenObject_Call { - return &BackupRepo_OpenObject_Call{Call: _e.mock.On("OpenObject", ctx, id)} +// - opt udmrepo.ObjectReadOptions +func (_e *BackupRepo_Expecter) OpenObject(ctx interface{}, id interface{}, opt interface{}) *BackupRepo_OpenObject_Call { + return &BackupRepo_OpenObject_Call{Call: _e.mock.On("OpenObject", ctx, id, opt)} } -func (_c *BackupRepo_OpenObject_Call) Run(run func(ctx context.Context, id udmrepo.ID)) *BackupRepo_OpenObject_Call { +func (_c *BackupRepo_OpenObject_Call) Run(run func(ctx context.Context, id udmrepo.ID, opt udmrepo.ObjectReadOptions)) *BackupRepo_OpenObject_Call { _c.Call.Run(func(args mock.Arguments) { var arg0 context.Context if args[0] != nil { @@ -748,9 +749,14 @@ func (_c *BackupRepo_OpenObject_Call) Run(run func(ctx context.Context, id udmre if args[1] != nil { arg1 = args[1].(udmrepo.ID) } + var arg2 udmrepo.ObjectReadOptions + if args[2] != nil { + arg2 = args[2].(udmrepo.ObjectReadOptions) + } run( arg0, arg1, + arg2, ) }) return _c @@ -761,7 +767,7 @@ func (_c *BackupRepo_OpenObject_Call) Return(objectReader udmrepo.ObjectReader, return _c } -func (_c *BackupRepo_OpenObject_Call) RunAndReturn(run func(ctx context.Context, id udmrepo.ID) (udmrepo.ObjectReader, error)) *BackupRepo_OpenObject_Call { +func (_c *BackupRepo_OpenObject_Call) RunAndReturn(run func(ctx context.Context, id udmrepo.ID, opt udmrepo.ObjectReadOptions) (udmrepo.ObjectReader, error)) *BackupRepo_OpenObject_Call { _c.Call.Return(run) return _c } From 92bcf5a3b33dc27649e12e81eb755c4520a7e33d Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 11 Aug 2026 13:36:26 +0800 Subject: [PATCH 25/45] add UT for prefetch Signed-off-by: Lyndon-Li --- .../udmrepo/kopialib/lib_repo_test.go | 216 +++++++++++++++++- 1 file changed, 212 insertions(+), 4 deletions(-) diff --git a/pkg/repository/udmrepo/kopialib/lib_repo_test.go b/pkg/repository/udmrepo/kopialib/lib_repo_test.go index 0cc52261a..6bd64009c 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo_test.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo_test.go @@ -22,12 +22,14 @@ import ( "encoding/json" "math" "os" + "sync" "testing" "time" "github.com/cockroachdb/errors" "github.com/kopia/kopia/fs" "github.com/kopia/kopia/repo" + "github.com/kopia/kopia/repo/content" "github.com/kopia/kopia/repo/manifest" "github.com/kopia/kopia/repo/object" "github.com/kopia/kopia/snapshot" @@ -285,6 +287,7 @@ func TestOpenObject(t *testing.T) { name string rawRepo *repomocks.MockRepository objectID string + opt udmrepo.ObjectReadOptions retErr error expectedErr string }{ @@ -304,21 +307,38 @@ func TestOpenObject(t *testing.T) { retErr: errors.New("fake-open-error"), expectedErr: "error to open object: fake-open-error", }, + { + name: "raw open success, without prefetch", + rawRepo: repomocks.NewMockRepository(t), + objectID: "D0123456789abcdef0123456789abcdef", + }, + { + name: "raw open success, with prefetch", + rawRepo: repomocks.NewMockRepository(t), + objectID: "D0123456789abcdef0123456789abcdef", + opt: udmrepo.ObjectReadOptions{Prefetch: true, PrefetchBudgetMB: 10}, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - kr := &kopiaRepository{} + kr := &kopiaRepository{ + logger: velerotest.NewLogger(), + } if tc.rawRepo != nil { - if tc.retErr != nil { - tc.rawRepo.On("OpenObject", mock.Anything, mock.Anything).Return(nil, tc.retErr) + if tc.name != "objectID is invalid" { + if tc.retErr != nil { + tc.rawRepo.On("OpenObject", mock.Anything, mock.Anything).Return(nil, tc.retErr) + } else { + tc.rawRepo.On("OpenObject", mock.Anything, mock.Anything).Return(nil, nil) + } } kr.rawRepo = tc.rawRepo } - _, err := kr.OpenObject(t.Context(), udmrepo.ID(tc.objectID), udmrepo.ObjectReadOptions{}) + _, err := kr.OpenObject(t.Context(), udmrepo.ID(tc.objectID), tc.opt) if tc.expectedErr == "" { assert.NoError(t, err) @@ -845,6 +865,7 @@ func TestReaderClose(t *testing.T) { name string rawObjReader *repomocks.Reader rawReaderRetErr error + withPrefetch bool expectedErr string }{ { @@ -860,6 +881,11 @@ func TestReaderClose(t *testing.T) { name: "succeed", rawObjReader: repomocks.NewReader(t), }, + { + name: "succeed with prefetch", + rawObjReader: repomocks.NewReader(t), + withPrefetch: true, + }, } for _, tc := range testCases { @@ -871,8 +897,20 @@ func TestReaderClose(t *testing.T) { kr.rawReader = tc.rawObjReader } + if tc.withPrefetch { + ctx, cancel := context.WithCancel(t.Context()) + kr.prefetch = &objectPrefetch{ + ctx: ctx, + cancel: cancel, + } + } + err := kr.Close() + if tc.withPrefetch { + assert.ErrorIs(t, kr.prefetch.ctx.Err(), context.Canceled) + } + if tc.expectedErr == "" { assert.NoError(t, err) } else { @@ -1832,3 +1870,173 @@ func TestListSnapshot(t *testing.T) { }) } } + +func mustParseID(s string) object.ID { + id, _ := object.ParseID(s) + return id +} + +func TestPrefetchProc(t *testing.T) { + testCases := []struct { + name string + setupPrefetch func(ctx context.Context, cancel context.CancelFunc) *objectPrefetch + mockRepo func(mockRepo *repomocks.MockRepository) + runConcurrently bool + trigger func(prefetch *objectPrefetch) + }{ + { + name: "nil prefetch", + setupPrefetch: func(ctx context.Context, cancel context.CancelFunc) *objectPrefetch { + return nil + }, + }, + { + name: "context canceled", + setupPrefetch: func(ctx context.Context, cancel context.CancelFunc) *objectPrefetch { + cancel() + p := &objectPrefetch{ + ctx: ctx, + } + p.cond = sync.NewCond(&p.mu) + return p + }, + }, + { + name: "fetch all entries and exit", + setupPrefetch: func(ctx context.Context, cancel context.CancelFunc) *objectPrefetch { + p := &objectPrefetch{ + ctx: ctx, + entries: []object.IndirectObjectEntry{ + {Start: 0, Length: 100, Object: mustParseID("D0123456789abcdef0123456789abcdef")}, + {Start: 100, Length: 100, Object: mustParseID("D0123456789abcdef0123456789abcdeg")}, + }, + budget: 200, + curOffset: 0, + } + p.cond = sync.NewCond(&p.mu) + return p + }, + mockRepo: func(mockRepo *repomocks.MockRepository) { + mockRepo.On("PrefetchObjects", mock.Anything, []object.ID{mustParseID("D0123456789abcdef0123456789abcdef"), mustParseID("D0123456789abcdef0123456789abcdeg")}, "").Return(([]content.ID)(nil), nil).Once() + }, + }, + { + name: "fetch partial, wait, and fetch rest", + runConcurrently: true, + setupPrefetch: func(ctx context.Context, cancel context.CancelFunc) *objectPrefetch { + p := &objectPrefetch{ + ctx: ctx, + entries: []object.IndirectObjectEntry{ + {Start: 0, Length: 100, Object: mustParseID("D0123456789abcdef0123456789abcdef")}, + {Start: 100, Length: 100, Object: mustParseID("D0123456789abcdef0123456789abcdeg")}, + }, + budget: 50, + curOffset: 0, + } + p.cond = sync.NewCond(&p.mu) + return p + }, + mockRepo: func(mockRepo *repomocks.MockRepository) { + mockRepo.On("PrefetchObjects", mock.Anything, []object.ID{mustParseID("D0123456789abcdef0123456789abcdef")}, "").Return(([]content.ID)(nil), nil).Once() + mockRepo.On("PrefetchObjects", mock.Anything, []object.ID{mustParseID("D0123456789abcdef0123456789abcdeg")}, "").Return(([]content.ID)(nil), nil).Once() + }, + trigger: func(prefetch *objectPrefetch) { + // Wait a bit for the first fetch and wait to happen + time.Sleep(50 * time.Millisecond) + prefetch.mu.Lock() + prefetch.curOffset = 100 + prefetch.cond.Signal() + prefetch.mu.Unlock() + }, + }, + { + name: "cancel while waiting on cond", + runConcurrently: true, + setupPrefetch: func(ctx context.Context, cancel context.CancelFunc) *objectPrefetch { + p := &objectPrefetch{ + ctx: ctx, + cancel: cancel, + entries: []object.IndirectObjectEntry{ + {Start: 0, Length: 100, Object: mustParseID("D0123456789abcdef0123456789abcdef")}, + {Start: 100, Length: 100, Object: mustParseID("D0123456789abcdef0123456789abcdeg")}, + }, + budget: 50, + curOffset: 0, + } + p.cond = sync.NewCond(&p.mu) + // Simulate the watcher goroutine spawned in OpenObject + go func() { + <-ctx.Done() + p.mu.Lock() + p.cond.Broadcast() + p.mu.Unlock() + }() + return p + }, + mockRepo: func(mockRepo *repomocks.MockRepository) { + mockRepo.On("PrefetchObjects", mock.Anything, []object.ID{mustParseID("D0123456789abcdef0123456789abcdef")}, "").Return(([]content.ID)(nil), nil).Once() + }, + trigger: func(prefetch *objectPrefetch) { + // Wait a bit for the first fetch and wait to happen + time.Sleep(50 * time.Millisecond) + prefetch.cancel() // This triggers the watcher, broadcasts, and exits prefetchProc + }, + }, + { + name: "prefetch error should not panic and continue", + setupPrefetch: func(ctx context.Context, cancel context.CancelFunc) *objectPrefetch { + p := &objectPrefetch{ + ctx: ctx, + entries: []object.IndirectObjectEntry{ + {Start: 0, Length: 100, Object: mustParseID("D0123456789abcdef0123456789abcdef")}, + }, + budget: 200, + curOffset: 0, + } + p.cond = sync.NewCond(&p.mu) + return p + }, + mockRepo: func(mockRepo *repomocks.MockRepository) { + mockRepo.On("PrefetchObjects", mock.Anything, []object.ID{mustParseID("D0123456789abcdef0123456789abcdef")}, "").Return(([]content.ID)(nil), errors.New("fake-error")).Once() + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(t.Context()) + defer cancel() + + mockRepo := repomocks.NewMockRepository(t) + if tc.mockRepo != nil { + tc.mockRepo(mockRepo) + } + + kor := &kopiaObjectReader{ + rawRepo: mockRepo, + logger: velerotest.NewLogger(), + prefetch: tc.setupPrefetch(ctx, cancel), + } + + if tc.runConcurrently { + done := make(chan struct{}) + go func() { + kor.prefetchProc() + close(done) + }() + if tc.trigger != nil { + tc.trigger(kor.prefetch) + } + select { + case <-done: + case <-time.After(2 * time.Second): + t.Fatal("prefetchProc did not finish in time") + } + } else { + kor.prefetchProc() + } + + mockRepo.AssertExpectations(t) + }) + } +} From c8127e243b78b8dc67b8fda6858088195cafd04e Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 11 Aug 2026 13:38:41 +0800 Subject: [PATCH 26/45] object reader throughput improvement Signed-off-by: Lyndon-Li --- changelogs/unreleased/10225-Lyndon-Li | 1 + pkg/repository/udmrepo/kopialib/lib_repo.go | 1 - pkg/repository/udmrepo/kopialib/lib_repo_test.go | 2 +- pkg/uploader/block/uploader_test.go | 2 +- pkg/uploader/kopia/shim_test.go | 6 +++--- 5 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/10225-Lyndon-Li diff --git a/changelogs/unreleased/10225-Lyndon-Li b/changelogs/unreleased/10225-Lyndon-Li new file mode 100644 index 000000000..435da13d1 --- /dev/null +++ b/changelogs/unreleased/10225-Lyndon-Li @@ -0,0 +1 @@ +Add prefetch mechanism to object reader so as to improve the restore throughput of block data mover \ No newline at end of file diff --git a/pkg/repository/udmrepo/kopialib/lib_repo.go b/pkg/repository/udmrepo/kopialib/lib_repo.go index 0efde34a7..e60128358 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo.go @@ -382,7 +382,6 @@ func (kr *kopiaRepository) OpenObject(ctx context.Context, id udmrepo.ID, opt ud prefetch.cond = sync.NewCond(&prefetch.mu) } - } rd := &kopiaObjectReader{ diff --git a/pkg/repository/udmrepo/kopialib/lib_repo_test.go b/pkg/repository/udmrepo/kopialib/lib_repo_test.go index 6bd64009c..b4d487c43 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo_test.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo_test.go @@ -908,7 +908,7 @@ func TestReaderClose(t *testing.T) { err := kr.Close() if tc.withPrefetch { - assert.ErrorIs(t, kr.prefetch.ctx.Err(), context.Canceled) + require.ErrorIs(t, kr.prefetch.ctx.Err(), context.Canceled) } if tc.expectedErr == "" { diff --git a/pkg/uploader/block/uploader_test.go b/pkg/uploader/block/uploader_test.go index 3b8930476..1b1eddbce 100644 --- a/pkg/uploader/block/uploader_test.go +++ b/pkg/uploader/block/uploader_test.go @@ -663,7 +663,7 @@ func TestBlockUploaderRestore(t *testing.T) { objReader.On("Read", mock.Anything).Return(0, io.EOF) objReader.On("Close").Return(nil) - repoWriter.On("OpenObject", mock.Anything, udmrepo.ID("data-id")).Return(objReader, nil) + repoWriter.On("OpenObject", mock.Anything, udmrepo.ID("data-id"), mock.Anything).Return(objReader, nil) snap := udmrepo.Snapshot{ Description: "test snapshot", diff --git a/pkg/uploader/kopia/shim_test.go b/pkg/uploader/kopia/shim_test.go index 7933ec6b8..3c7941405 100644 --- a/pkg/uploader/kopia/shim_test.go +++ b/pkg/uploader/kopia/shim_test.go @@ -81,7 +81,7 @@ func TestOpenObject(t *testing.T) { name: "Success", backupRepo: func() *mocks.BackupRepo { backupRepo := &mocks.BackupRepo{} - backupRepo.On("OpenObject", mock.Anything, mock.Anything).Return(&shimObjectReader{}, nil) + backupRepo.On("OpenObject", mock.Anything, mock.Anything, mock.Anything).Return(&shimObjectReader{}, nil) return backupRepo }(), }, @@ -89,7 +89,7 @@ func TestOpenObject(t *testing.T) { name: "Open object error", backupRepo: func() *mocks.BackupRepo { backupRepo := &mocks.BackupRepo{} - backupRepo.On("OpenObject", mock.Anything, mock.Anything).Return(&shimObjectReader{}, errors.New("Error open object")) + backupRepo.On("OpenObject", mock.Anything, mock.Anything, mock.Anything).Return(&shimObjectReader{}, errors.New("Error open object")) return backupRepo }(), isOpenObjectError: true, @@ -98,7 +98,7 @@ func TestOpenObject(t *testing.T) { name: "Get nil reader", backupRepo: func() *mocks.BackupRepo { backupRepo := &mocks.BackupRepo{} - backupRepo.On("OpenObject", mock.Anything, mock.Anything).Return(nil, nil) + backupRepo.On("OpenObject", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) return backupRepo }(), isReaderNil: true, From 8b7951426b5d282f041b3708f70db0f661c0e80d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wenkai=20Yin=28=E5=B0=B9=E6=96=87=E5=BC=80=29?= Date: Tue, 11 Aug 2026 15:48:31 +0800 Subject: [PATCH 27/45] Add "SnapshotClass" to DataUploadResult (#10227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add "SnapshotClass" to DataUploadResult Signed-off-by: Wenkai Yin(尹文开) --- changelogs/unreleased/10227-ywk253100 | 1 + pkg/apis/velero/v2alpha1/data_upload_types.go | 4 ++++ .../actions/dataupload_retrieve_action.go | 3 +++ .../dataupload_retrieve_action_test.go | 23 +++++++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 changelogs/unreleased/10227-ywk253100 diff --git a/changelogs/unreleased/10227-ywk253100 b/changelogs/unreleased/10227-ywk253100 new file mode 100644 index 000000000..dcbbd6ac5 --- /dev/null +++ b/changelogs/unreleased/10227-ywk253100 @@ -0,0 +1 @@ +Add "SnapshotClass" to DataUploadResult \ No newline at end of file diff --git a/pkg/apis/velero/v2alpha1/data_upload_types.go b/pkg/apis/velero/v2alpha1/data_upload_types.go index 606502254..37e273b2b 100644 --- a/pkg/apis/velero/v2alpha1/data_upload_types.go +++ b/pkg/apis/velero/v2alpha1/data_upload_types.go @@ -268,4 +268,8 @@ type DataUploadResult struct { // FSType is the file system type of the volume. // +optional FSType string `json:"fsType,omitempty"` + + // SnapshotClass is the name of the snapshot class that the volume snapshot is created with + // +optional + SnapshotClass string `json:"snapshotClass,omitempty"` } diff --git a/pkg/restore/actions/dataupload_retrieve_action.go b/pkg/restore/actions/dataupload_retrieve_action.go index 77e4766f5..27db07471 100644 --- a/pkg/restore/actions/dataupload_retrieve_action.go +++ b/pkg/restore/actions/dataupload_retrieve_action.go @@ -82,6 +82,9 @@ func (d *DataUploadRetrieveAction) Execute(input *velero.RestoreItemActionExecut NodeOS: dataUpload.Status.NodeOS, FSType: dataUpload.Spec.SourceFSType, } + if dataUpload.Spec.CSISnapshot != nil { + dataUploadResult.SnapshotClass = dataUpload.Spec.CSISnapshot.SnapshotClass + } jsonBytes, err := json.Marshal(dataUploadResult) if err != nil { diff --git a/pkg/restore/actions/dataupload_retrieve_action_test.go b/pkg/restore/actions/dataupload_retrieve_action_test.go index 64be241bf..33a46a0a3 100644 --- a/pkg/restore/actions/dataupload_retrieve_action_test.go +++ b/pkg/restore/actions/dataupload_retrieve_action_test.go @@ -66,6 +66,29 @@ func TestDataUploadRetrieveActionExectue(t *testing.T) { }, expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "testNamespace.testPVC", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","snapshotID":"fake-id","sourceNamespace":"testNamespace","snapshotSize":1000}`).Result(), }, + { + name: "DataUploadRetrieve Action test with optional fields", + dataUpload: func() *velerov2alpha1.DataUpload { + du := builder.ForDataUpload("velero", "testDU"). + SourceNamespace("testNamespace"). + SourcePVC("testPVC"). + SnapshotID("fake-id"). + TotalBytes(1000). + DataMover("velero"). + NodeOS("linux"). + CSISnapshot(&velerov2alpha1.CSISnapshotSpec{SnapshotClass: "testClass"}). + Result() + du.Status.DataMoverResult = &map[string]string{"key": "value"} + du.Spec.SourceFSType = "ext4" + return du + }(), + restore: builder.ForRestore("velero", "testRestore").ObjectMeta(builder.WithUID("testingUID")).Backup("testBackup").Result(), + runtimeScheme: scheme, + veleroObjs: []runtime.Object{ + builder.ForBackup("velero", "testBackup").StorageLocation("testLocation").Result(), + }, + expectedDataUploadResult: builder.ForConfigMap("velero", "").ObjectMeta(builder.WithGenerateName("testDU-"), builder.WithLabels(velerov1.PVCNamespaceNameLabel, "testNamespace.testPVC", velerov1.RestoreUIDLabel, "testingUID", velerov1.ResourceUsageLabel, string(velerov1.VeleroResourceUsageDataUploadResult))).Data("testingUID", `{"backupStorageLocation":"testLocation","datamover":"velero","snapshotID":"fake-id","sourceNamespace":"testNamespace","dataMoverResult":{"key":"value"},"nodeOS":"linux","snapshotSize":1000,"fsType":"ext4","snapshotClass":"testClass"}`).Result(), + }, { name: "Long source namespace and PVC name should also work", dataUpload: builder.ForDataUpload("velero", "testDU").SourceNamespace("migre209d0da-49c7-45ba-8d5a-3e59fd591ec1").SourcePVC("kibishii-data-kibishii-deployment-0").Result(), From bbb0f11f3315d656f53281f479956e4565b50700 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Tue, 11 Aug 2026 15:37:02 +0800 Subject: [PATCH 28/45] use source size in progress for block uploader restore Signed-off-by: Lyndon-Li --- pkg/uploader/block/snapshot.go | 4 ++-- pkg/uploader/block/snapshot_test.go | 8 ++++---- pkg/uploader/block/uploader.go | 24 +++++++++++++----------- pkg/uploader/block/uploader_test.go | 8 ++++---- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/pkg/uploader/block/snapshot.go b/pkg/uploader/block/snapshot.go index 53e7e7f14..adec352ef 100644 --- a/pkg/uploader/block/snapshot.go +++ b/pkg/uploader/block/snapshot.go @@ -235,12 +235,12 @@ func Restore(ctx context.Context, blkUp Uploader, rep udmrepo.BackupRepo, snapsh return 0, errors.Wrapf(err, "error reset pos of block device %s", dest) } - size, err := blkUp.Restore(snapshot, destInfo{dev: destDev, path: destPath, size: destSize}, bitmap.Iterator(), uploaderCfg) + _, totalSize, err := blkUp.Restore(snapshot, destInfo{dev: destDev, path: destPath, size: destSize}, bitmap.Iterator(), uploaderCfg) if err != nil { return 0, errors.Wrapf(err, "error restoring to block dev %s", destPath) } - return size, nil + return totalSize, nil } func findPreviousSnapshot(ctx context.Context, rep udmrepo.BackupRepo, path string, snapshotTags map[string]string, noLaterThan *time.Time, log logrus.FieldLogger) (udmrepo.Snapshot, error) { diff --git a/pkg/uploader/block/snapshot_test.go b/pkg/uploader/block/snapshot_test.go index 8f6338311..fa77b2d10 100644 --- a/pkg/uploader/block/snapshot_test.go +++ b/pkg/uploader/block/snapshot_test.go @@ -46,9 +46,9 @@ func (m *mockUploader) Backup(src sourceInfo, parent udmrepo.ID, iter cbttypes.I return args.Get(0).(udmrepo.Snapshot), args.Get(1).(int64), args.Error(2) } -func (m *mockUploader) Restore(snap udmrepo.Snapshot, dest destInfo, iter cbttypes.Iterator, cfg map[string]string) (int64, error) { +func (m *mockUploader) Restore(snap udmrepo.Snapshot, dest destInfo, iter cbttypes.Iterator, cfg map[string]string) (int64, int64, error) { args := m.Called(snap, dest, iter, cfg) - return args.Get(0).(int64), args.Error(1) + return args.Get(0).(int64), args.Get(1).(int64), args.Error(2) } func testLog() logrus.FieldLogger { @@ -574,7 +574,7 @@ func TestRestore(t *testing.T) { repo.On("GetSnapshot", mock.Anything, udmrepo.ID("snap-001")). Return(storedSnap, nil) blkup.On("Restore", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(int64(0), errors.New("restore I/O error")) + Return(int64(0), int64(0), errors.New("restore I/O error")) }, setupOpenDev: func(t *testing.T) *os.File { t.Helper() @@ -588,7 +588,7 @@ func TestRestore(t *testing.T) { repo.On("GetSnapshot", mock.Anything, udmrepo.ID("snap-001")). Return(storedSnap, nil) blkup.On("Restore", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(int64(4096), nil) + Return(int64(4096), int64(4096), nil) }, setupOpenDev: func(t *testing.T) *os.File { t.Helper() diff --git a/pkg/uploader/block/uploader.go b/pkg/uploader/block/uploader.go index 824c0ae9f..b2d879a48 100644 --- a/pkg/uploader/block/uploader.go +++ b/pkg/uploader/block/uploader.go @@ -59,7 +59,7 @@ type destInfo struct { type Uploader interface { Backup(sourceInfo, udmrepo.ID, cbt.Iterator, map[string]string) (udmrepo.Snapshot, int64, error) - Restore(udmrepo.Snapshot, destInfo, cbt.Iterator, map[string]string) (int64, error) + Restore(udmrepo.Snapshot, destInfo, cbt.Iterator, map[string]string) (int64, int64, error) } type blockUploader struct { @@ -148,18 +148,18 @@ func (blkup *blockUploader) Backup(source sourceInfo, parentObject udmrepo.ID, b }, backupSize, nil } -func (blkup *blockUploader) Restore(snapshot udmrepo.Snapshot, dest destInfo, bitmap cbt.Iterator, configs map[string]string) (int64, error) { +func (blkup *blockUploader) Restore(snapshot udmrepo.Snapshot, dest destInfo, bitmap cbt.Iterator, configs map[string]string) (int64, int64, error) { if bitmap == nil { - return 0, errors.New("bitmap is not available") + return 0, 0, errors.New("bitmap is not available") } meta, err := blkup.repoWriter.ReadMetadata(blkup.ctx, snapshot.RootObject.ID) if err != nil { - return 0, errors.Wrapf(err, "error reading snapshot metadata for %s", snapshot.Description) + return 0, 0, errors.Wrapf(err, "error reading snapshot metadata for %s", snapshot.Description) } if len(meta.SubObjects) != 1 { - return 0, errors.Errorf("unexpected number of bdev object (%d) for snapshot %s", len(meta.SubObjects), snapshot.Description) + return 0, 0, errors.Errorf("unexpected number of bdev object (%d) for snapshot %s", len(meta.SubObjects), snapshot.Description) } sourceSize, err := getSourceSize(snapshot) @@ -169,25 +169,25 @@ func (blkup *blockUploader) Restore(snapshot udmrepo.Snapshot, dest destInfo, bi } if sourceSize > meta.SubObjects[0].Size { - return 0, errors.Errorf("unexpected size (%v vs. %v) for bdev object %s", meta.SubObjects[0].Size, sourceSize, meta.SubObjects[0].Name) + return 0, 0, errors.Errorf("unexpected size (%v vs. %v) for bdev object %s", meta.SubObjects[0].Size, sourceSize, meta.SubObjects[0].Name) } if sourceSize > dest.size { - return 0, errors.Errorf("dest dev(%s) size is too small (%v vs. %v)", dest.path, dest.size, sourceSize) + return 0, 0, errors.Errorf("dest dev(%s) size is too small (%v vs. %v)", dest.path, dest.size, sourceSize) } reader, err := blkup.repoWriter.OpenObject(blkup.ctx, meta.SubObjects[0].ID) if err != nil { - return 0, errors.Wrapf(err, "error opening bdev object %v", meta.SubObjects[0].Name) + return 0, 0, errors.Wrapf(err, "error opening bdev object %v", meta.SubObjects[0].Name) } defer reader.Close() size, err := blkup.restoreData(reader, dest.dev, bitmap, sourceSize, dest.path) if err != nil { - return 0, errors.Wrapf(err, "error restoring bdev object %s to volume %s", meta.SubObjects[0].Name, dest.path) + return 0, 0, errors.Wrapf(err, "error restoring bdev object %s to volume %s", meta.SubObjects[0].Name, dest.path) } - return size, nil + return size, sourceSize, nil } func (blkup *blockUploader) backupObject(dev *os.File, dest udmrepo.ObjectWriter, bitmap cbt.Iterator, totalLength int64) (udmrepo.ID, int64, int64, error) { @@ -441,6 +441,8 @@ func (blkup *blockUploader) restoreData(reader io.ReadSeeker, dest *os.File, bit return written, errors.Wrap(writeErr, "error writing data") } + blkup.progress.UpdateProgress(&uploader.Progress{BytesDone: totalLength, TotalBytes: totalLength}) + return written, nil } @@ -576,7 +578,7 @@ func restoreWriteProc(ctx context.Context, dest *os.File, resultChan chan readRe result.resetBuffer(list) - progress.UpdateProgress(&uploader.Progress{BytesDone: written, TotalBytes: totalLength}) + progress.UpdateProgress(&uploader.Progress{BytesDone: result.offset + length, TotalBytes: totalLength}) } result.resetBuffer(list) diff --git a/pkg/uploader/block/uploader_test.go b/pkg/uploader/block/uploader_test.go index 3b8930476..340ee710f 100644 --- a/pkg/uploader/block/uploader_test.go +++ b/pkg/uploader/block/uploader_test.go @@ -623,7 +623,7 @@ func TestBlockUploaderRestore(t *testing.T) { repoWriter.On("ReadMetadata", mock.Anything, udmrepo.ID("root-id")).Return(nil, errors.New("meta not found")) iterMock := cbtmocks.NewIterator(t) - _, err := blkup.Restore(udmrepo.Snapshot{RootObject: udmrepo.ObjectMetadata{ID: "root-id"}}, destInfo{}, iterMock, nil) + _, _, err := blkup.Restore(udmrepo.Snapshot{RootObject: udmrepo.ObjectMetadata{ID: "root-id"}}, destInfo{}, iterMock, nil) require.Error(t, err) assert.Contains(t, err.Error(), "meta not found") }) @@ -685,7 +685,7 @@ func TestBlockUploaderRestore(t *testing.T) { iterMock.On("Next").Return(uint64(0), false) iterMock.On("BlockSize").Return(uint(1048576)) - written, err := blkup.Restore(snap, dest, iterMock, nil) + written, _, err := blkup.Restore(snap, dest, iterMock, nil) require.NoError(t, err) assert.Equal(t, int64(1048576), written) }) @@ -709,7 +709,7 @@ func TestBlockUploaderRestore(t *testing.T) { dest := destInfo{size: 4194304, path: "/dev/target"} iterMock := cbtmocks.NewIterator(t) - _, err := blkup.Restore(snap, dest, iterMock, nil) + _, _, err := blkup.Restore(snap, dest, iterMock, nil) require.Error(t, err) assert.Contains(t, err.Error(), "unexpected size (1048576 vs. 2097152) for bdev object bdev") }) @@ -733,7 +733,7 @@ func TestBlockUploaderRestore(t *testing.T) { dest := destInfo{size: 512, path: "/dev/small"} iterMock := cbtmocks.NewIterator(t) - _, err := blkup.Restore(snap, dest, iterMock, nil) + _, _, err := blkup.Restore(snap, dest, iterMock, nil) require.Error(t, err) assert.Contains(t, err.Error(), "dest dev(/dev/small) size is too small") }) From 79d9a5cde47980b61319b2cc6cd15c99c54ad2dc Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 6 Aug 2026 18:13:47 +0800 Subject: [PATCH 29/45] Support to set data mover for the uploader from volume policy. Refactor function ShouldPerformCustomAction and GetActionParameters: extract shared code to a new function getPVAndMatchAction. Signed-off-by: Xun Jiang --- changelogs/unreleased/10176-blackpiglet | 1 + internal/volumehelper/volume_policy_helper.go | 196 +++--- .../volumehelper/volume_policy_helper_test.go | 583 ++++++++++++++++++ pkg/backup/actions/csi/pvc_action.go | 14 +- pkg/backup/actions/csi/pvc_action_test.go | 31 +- pkg/util/volumehelper/volume_policy_helper.go | 1 + 6 files changed, 730 insertions(+), 96 deletions(-) create mode 100644 changelogs/unreleased/10176-blackpiglet diff --git a/changelogs/unreleased/10176-blackpiglet b/changelogs/unreleased/10176-blackpiglet new file mode 100644 index 000000000..301e7c8e1 --- /dev/null +++ b/changelogs/unreleased/10176-blackpiglet @@ -0,0 +1 @@ +Support to set data mover for the uploader from volume policy. \ No newline at end of file diff --git a/internal/volumehelper/volume_policy_helper.go b/internal/volumehelper/volume_policy_helper.go index 3259bdb43..7e23dd05f 100644 --- a/internal/volumehelper/volume_policy_helper.go +++ b/internal/volumehelper/volume_policy_helper.go @@ -8,6 +8,7 @@ import ( "github.com/cockroachdb/errors" "github.com/sirupsen/logrus" corev1api "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" crclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -21,6 +22,8 @@ import ( vhutil "github.com/vmware-tanzu/velero/pkg/util/volumehelper" ) +var errGetPVForPVC = errors.New("fail to get PV for PVC") + type volumeHelperImpl struct { volumePolicy *resourcepolicies.Policies snapshotVolumes *bool @@ -123,6 +126,44 @@ func NewVolumeHelperImplWithCache( }, nil } +func (v *volumeHelperImpl) getPVAndMatchAction(obj runtime.Unstructured, groupResource schema.GroupResource) (*resourcepolicies.Action, *corev1api.PersistentVolume, error) { + pvc := new(corev1api.PersistentVolumeClaim) + pv := new(corev1api.PersistentVolume) + var err error + var getPVErr error + + if groupResource == kuberesource.PersistentVolumeClaims { + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pvc); err != nil { + v.logger.WithError(err).Warn("fail to convert unstructured into PVC") + return nil, nil, err + } + + pv, err = kubeutil.GetPVForPVC(pvc, v.client) + if err != nil { + v.logger.WithError(err).Warnf("failed to get PV for PVC %s", pvc.Namespace+"/"+pvc.Name) + getPVErr = fmt.Errorf("fail to get PV for PVC %s: %w", pvc.Namespace+"/"+pvc.Name, errGetPVForPVC) + } + } else if groupResource == kuberesource.PersistentVolumes { + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pv); err != nil { + v.logger.WithError(err).Warn("fail to convert unstructured into PV") + return nil, nil, err + } + } + + if v.volumePolicy != nil { + vfd := resourcepolicies.NewVolumeFilterData(pv, nil, pvc) + action, err := v.volumePolicy.GetMatchAction(vfd) + if err != nil { + v.logger.WithError(err).Warnf("fail to get VolumePolicy match action for %+v", vfd) + return nil, nil, err + } + + return action, pv, getPVErr + } + + return nil, pv, getPVErr +} + func (v *volumeHelperImpl) ShouldPerformSnapshot(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, error) { // check if volume policy exists and also check if the object(pv/pvc) fits a volume policy criteria and see if the associated action is snapshot // if it is not snapshot then skip the code path for snapshotting the PV/PVC @@ -316,117 +357,73 @@ func (v volumeHelperImpl) shouldPerformFSBackupLegacy( } func (v *volumeHelperImpl) ShouldPerformCustomAction(obj runtime.Unstructured, groupResource schema.GroupResource, matchParams map[string]any) (bool, error) { - // check if volume policy exists and also check if the object(pv/pvc) fits a volume policy criteria and see if the associated action is custom with the provided param values - pvc := new(corev1api.PersistentVolumeClaim) - pv := new(corev1api.PersistentVolume) - var err error - - var pvNotFoundErr error - if groupResource == kuberesource.PersistentVolumeClaims { - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pvc); err != nil { - v.logger.WithError(err).Error("fail to convert unstructured into PVC") - return false, err - } - - pv, err = kubeutil.GetPVForPVC(pvc, v.client) - if err != nil { - // Any error means PV not available - save to return later if no policy matches - v.logger.Debugf("PV not found for PVC %s: %v", pvc.Namespace+"/"+pvc.Name, err) - pvNotFoundErr = err - pv = nil - } + action, pv, err := v.getPVAndMatchAction(obj, groupResource) + if err != nil && !errors.Is(err, errGetPVForPVC) { + return false, err } - if groupResource == kuberesource.PersistentVolumes { - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pv); err != nil { - v.logger.WithError(err).Error("fail to convert unstructured into PV") - return false, err - } + metadata, metaErr := meta.Accessor(obj) + if metaErr != nil { + return false, metaErr } - if v.volumePolicy != nil { - vfd := resourcepolicies.NewVolumeFilterData(pv, nil, pvc) - action, err := v.volumePolicy.GetMatchAction(vfd) - if err != nil { - v.logger.WithError(err).Errorf("fail to get VolumePolicy match action for %+v", vfd) - return false, err - } - - // If there is a match action, and the action type is custom, return true - // if the provided parameters match as well, else return false. - // If there is no match action, also return false - if action != nil { - if action.Type == resourcepolicies.Custom { - for k, requiredValue := range matchParams { - if actionValue, ok := action.Parameters[k]; !ok || actionValue != requiredValue { - v.logger.Infof("Skipping custom action for %+v as value for parameter %s is %s rather than the required %s", vfd, k, actionValue, requiredValue) - return false, nil - } + if action != nil { + if action.Type == resourcepolicies.Custom { + for k, requiredValue := range matchParams { + if actionValue, ok := action.Parameters[k]; !ok || actionValue != requiredValue { + v.logger.Infof("Skipping custom action for %s: %s as value for parameter %s is %s rather than the required %s", + groupResource.String(), + metadata.GetNamespace()+"/"+metadata.GetName(), + k, actionValue, requiredValue) + return false, nil } - v.logger.Infof("performing custom action for %+v", vfd) - return true, nil - } else { - v.logger.Infof("Skipping custom action for %+v as the action type is %s", vfd, action.Type) - return false, nil } + v.logger.Infof("performing custom action for %s: %s", groupResource.String(), metadata.GetNamespace()+"/"+metadata.GetName()) + return true, nil + } else { + v.logger.Infof("Skipping custom action for %s: %s as the action type is %s", + groupResource.String(), + metadata.GetNamespace()+"/"+metadata.GetName(), + action.Type) + return false, nil } } - // If resource is PVC, and PV is nil (e.g., Pending/Lost PVC with no matching policy), return the original error - // Don't error out on no PV, just return false - if groupResource == kuberesource.PersistentVolumeClaims && pv == nil && pvNotFoundErr != nil { - v.logger.WithError(pvNotFoundErr).Warnf("fail to get PV for PVC %s", pvc.Namespace+"/"+pvc.Name) + + if (groupResource == kuberesource.PersistentVolumeClaims) && (pv == nil) && errors.Is(err, errGetPVForPVC) { return false, nil } - v.logger.Infof("skipping custom action for pv %s due to no matching volume policy", pv.Name) + v.logger.Infof("skipping custom action for %s: %s due to no matching volume policy", + groupResource.String(), metadata.GetNamespace()+"/"+metadata.GetName()) return false, nil } // returns false if no matching action found. Returns true with the action name and Parameters map if there is a matching policy func (v *volumeHelperImpl) GetActionParameters(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, string, map[string]any, error) { - // if volume policy exists, return action parameters. - pvc := new(corev1api.PersistentVolumeClaim) - pv := new(corev1api.PersistentVolume) - var err error - - if groupResource == kuberesource.PersistentVolumeClaims { - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pvc); err != nil { - v.logger.WithError(err).Error("fail to convert unstructured into PVC") - return false, "", nil, err - } - - pv, err = kubeutil.GetPVForPVC(pvc, v.client) - if err != nil { - v.logger.WithError(err).Warnf("failed to get PV for PVC %s", pvc.Namespace+"/"+pvc.Name) + action, _, err := v.getPVAndMatchAction(obj, groupResource) + if err != nil { + if errors.Is(err, errGetPVForPVC) { return false, "", nil, nil } + + return false, "", nil, err } - if groupResource == kuberesource.PersistentVolumes { - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pv); err != nil { - v.logger.WithError(err).Error("fail to convert unstructured into PV") - return false, "", nil, err - } + metadata, metaErr := meta.Accessor(obj) + if metaErr != nil { + return false, "", nil, metaErr } - if v.volumePolicy != nil { - vfd := resourcepolicies.NewVolumeFilterData(pv, nil, pvc) - action, err := v.volumePolicy.GetMatchAction(vfd) - if err != nil { - v.logger.WithError(err).Errorf("fail to get VolumePolicy match action for PV %s", pv.Name) - return false, "", nil, err - } + if action != nil { + v.logger.Infof("found matching action for %s: %s, returning parameters", + groupResource.String(), metadata.GetNamespace()+"/"+metadata.GetName()) - // If there is a match action, and the action type is custom, return true - // if the provided parameters match as well, else return false. - // If there is no match action, also return false - if action != nil { - v.logger.Infof("found matching action for pv %s, returning parameters", pv.Name) - return true, string(action.Type), action.Parameters, nil - } + return true, string(action.Type), action.Parameters, nil } - v.logger.Infof("no matching volume policy found for pv %s, no parameters to return", pv.Name) + v.logger.Infof("no matching volume policy found for %s: %s, no parameters to return", + groupResource.String(), metadata.GetNamespace()+"/"+metadata.GetName()) + return false, "", nil, nil } @@ -486,3 +483,30 @@ func (v *volumeHelperImpl) getVolumeFromResource(resource any) (*corev1api.Persi } return nil, nil, fmt.Errorf("resource is not a PersistentVolume or Volume") } + +func (v *volumeHelperImpl) GetDataMoverFromActionParameters(obj runtime.Unstructured, groupResource schema.GroupResource) string { + action, _, err := v.getPVAndMatchAction(obj, groupResource) + if err != nil { + return "" + } + + metadata, metaErr := meta.Accessor(obj) + if metaErr != nil { + return "" + } + + if action != nil { + dataMover, err := action.GetDataMover() + if err != nil { + v.logger.WithError(err).Warn("fail to get data mover.") + return "" + } + v.logger.Infof("found matching action for %s: %s, returning data mover %s", + groupResource.String(), metadata.GetNamespace()+"/"+metadata.GetName(), dataMover) + return dataMover + } + + v.logger.Debugf("no matching volume policy found for %s: %s, no data mover parameter to return", + groupResource.String(), metadata.GetNamespace()+"/"+metadata.GetName()) + return "" +} diff --git a/internal/volumehelper/volume_policy_helper_test.go b/internal/volumehelper/volume_policy_helper_test.go index 5e52ae73b..2c8a9151c 100644 --- a/internal/volumehelper/volume_policy_helper_test.go +++ b/internal/volumehelper/volume_policy_helper_test.go @@ -1543,3 +1543,586 @@ func TestVolumeHelperImpl_ShouldPerformFSBackup_UnboundPVC(t *testing.T) { }) } } + +func TestGetDataMoverFromActionParameters(t *testing.T) { + testCases := []struct { + name string + inputObj runtime.Object + groupResource schema.GroupResource + resourcePolicies *resourcepolicies.ResourcePolicies + expected string + }{ + { + name: "VolumePolicy match with dataMover parameter, returns dataMover string", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + Parameters: map[string]any{ + resourcepolicies.DataMoverParameter: "velero-block", + }, + }, + }, + }, + }, + expected: "velero-block", + }, + { + name: "VolumePolicy match without dataMover parameter, returns default dataMover", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + Parameters: map[string]any{ + "otherParam": "value", + }, + }, + }, + }, + }, + expected: "velero-fs", + }, + { + name: "VolumePolicy match with non-string dataMover parameter, returns empty string", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + Parameters: map[string]any{ + resourcepolicies.DataMoverParameter: 123, + }, + }, + }, + }, + }, + expected: "", + }, + { + name: "VolumePolicy not match, returns empty string", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp3-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + Parameters: map[string]any{ + resourcepolicies.DataMoverParameter: "velero", + }, + }, + }, + }, + }, + expected: "", + }, + { + name: "Error converting unstructured, returns empty string", + inputObj: builder.ForPod("ns", "pod-1").Result(), // wrong type for PersistentVolumes + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + }, + expected: "", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + fakeClient := velerotest.NewFakeControllerRuntimeClient(t) + + var p *resourcepolicies.Policies + if tc.resourcePolicies != nil { + p = &resourcepolicies.Policies{} + err := p.BuildPolicy(tc.resourcePolicies) + require.NoError(t, err) + } + + vh := NewVolumeHelperImpl( + p, + ptr.To(true), + logrus.StandardLogger(), + fakeClient, + false, + false, + ) + + obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tc.inputObj) + require.NoError(t, err) + + actual := vh.GetDataMoverFromActionParameters(&unstructured.Unstructured{Object: obj}, tc.groupResource) + assert.Equal(t, tc.expected, actual) + }) + } +} + +func TestGetActionParameters(t *testing.T) { + testCases := []struct { + name string + inputObj runtime.Object + groupResource schema.GroupResource + resourcePolicies *resourcepolicies.ResourcePolicies + expectedMatched bool + expectedAction string + expectedParams map[string]any + expectedErr bool + }{ + { + name: "VolumePolicy match with parameters, returns true, action type, parameters", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Custom, + Parameters: map[string]any{ + "param1": "value1", + }, + }, + }, + }, + }, + expectedMatched: true, + expectedAction: string(resourcepolicies.Custom), + expectedParams: map[string]any{ + "param1": "value1", + }, + expectedErr: false, + }, + { + name: "VolumePolicy match without parameters, returns true, action type, nil parameters", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + }, + }, + }, + }, + expectedMatched: true, + expectedAction: string(resourcepolicies.Snapshot), + expectedParams: nil, + expectedErr: false, + }, + { + name: "VolumePolicy not match, returns false", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp3-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + }, + }, + }, + }, + expectedMatched: false, + expectedAction: "", + expectedParams: nil, + expectedErr: false, + }, + { + name: "PVC not having PV, returns false and no error", + inputObj: builder.ForPersistentVolumeClaim("ns", "pvc-1").StorageClass("gp2-csi").Result(), + groupResource: kuberesource.PersistentVolumeClaims, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + }, + expectedMatched: false, + expectedAction: "", + expectedParams: nil, + expectedErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + fakeClient := velerotest.NewFakeControllerRuntimeClient(t) + + var p *resourcepolicies.Policies + if tc.resourcePolicies != nil { + p = &resourcepolicies.Policies{} + err := p.BuildPolicy(tc.resourcePolicies) + require.NoError(t, err) + } + + vh := NewVolumeHelperImpl( + p, + ptr.To(true), + logrus.StandardLogger(), + fakeClient, + false, + false, + ) + + obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tc.inputObj) + require.NoError(t, err) + + matched, actionType, params, err := vh.GetActionParameters(&unstructured.Unstructured{Object: obj}, tc.groupResource) + if tc.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + assert.Equal(t, tc.expectedMatched, matched) + assert.Equal(t, tc.expectedAction, actionType) + assert.Equal(t, tc.expectedParams, params) + }) + } +} + +func TestShouldPerformCustomAction(t *testing.T) { + testCases := []struct { + name string + inputObj runtime.Object + groupResource schema.GroupResource + resourcePolicies *resourcepolicies.ResourcePolicies + matchParams map[string]any + expected bool + expectedErr bool + }{ + { + name: "VolumePolicy match, action type is Custom, matchParams match exactly, returns true", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Custom, + Parameters: map[string]any{ + "param1": "value1", + "param2": "value2", + }, + }, + }, + }, + }, + matchParams: map[string]any{ + "param1": "value1", + }, + expected: true, + expectedErr: false, + }, + { + name: "VolumePolicy match, action type is Custom, matchParams don't match (missing key), returns false", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Custom, + Parameters: map[string]any{ + "param1": "value1", + }, + }, + }, + }, + }, + matchParams: map[string]any{ + "param2": "value2", + }, + expected: false, + expectedErr: false, + }, + { + name: "VolumePolicy match, action type is Custom, matchParams don't match (different value), returns false", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Custom, + Parameters: map[string]any{ + "param1": "value1", + }, + }, + }, + }, + }, + matchParams: map[string]any{ + "param1": "value2", + }, + expected: false, + expectedErr: false, + }, + { + name: "VolumePolicy match, action type is not Custom, returns false", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp2-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + }, + }, + }, + }, + matchParams: map[string]any{ + "param1": "value1", + }, + expected: false, + expectedErr: false, + }, + { + name: "VolumePolicy not match, returns false", + inputObj: builder.ForPersistentVolume("example-pv").StorageClass("gp3-csi").ClaimRef("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Custom, + }, + }, + }, + }, + matchParams: map[string]any{ + "param1": "value1", + }, + expected: false, + expectedErr: false, + }, + { + name: "PVC not having PV, returns false and no error", + inputObj: builder.ForPersistentVolumeClaim("ns", "pvc-1").StorageClass("gp2-csi").Result(), + groupResource: kuberesource.PersistentVolumeClaims, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + }, + matchParams: map[string]any{ + "param1": "value1", + }, + expected: false, + expectedErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + fakeClient := velerotest.NewFakeControllerRuntimeClient(t) + + var p *resourcepolicies.Policies + if tc.resourcePolicies != nil { + p = &resourcepolicies.Policies{} + err := p.BuildPolicy(tc.resourcePolicies) + require.NoError(t, err) + } + + vh := NewVolumeHelperImpl( + p, + ptr.To(true), + logrus.StandardLogger(), + fakeClient, + false, + false, + ) + + obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tc.inputObj) + require.NoError(t, err) + + actual, err := vh.ShouldPerformCustomAction(&unstructured.Unstructured{Object: obj}, tc.groupResource, tc.matchParams) + if tc.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + assert.Equal(t, tc.expected, actual) + }) + } +} + +func TestGetPVAndMatchAction(t *testing.T) { + testCases := []struct { + name string + inputObj runtime.Object + groupResource schema.GroupResource + resourcePolicies *resourcepolicies.ResourcePolicies + expectedAction *resourcepolicies.Action + expectedPVName string + expectedErr bool + expectedErrStr string + }{ + { + name: "PVC with matching PV and VolumePolicy, returns action and PV", + inputObj: builder.ForPersistentVolumeClaim("ns", "pvc-1").VolumeName("pv-1").Phase(corev1api.ClaimBound).Result(), + groupResource: kuberesource.PersistentVolumeClaims, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + }, + }, + }, + }, + expectedAction: &resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + }, + expectedPVName: "pv-1", + expectedErr: false, + }, + { + name: "PVC without matching PV, returns errGetPVForPVC", + inputObj: builder.ForPersistentVolumeClaim("ns", "pvc-1").Result(), + groupResource: kuberesource.PersistentVolumeClaims, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + }, + expectedAction: nil, + expectedPVName: "", + expectedErr: true, + expectedErrStr: "fail to get PV for PVC ns/pvc-1: fail to get PV for PVC", + }, + { + name: "PV with matching VolumePolicy, returns action and PV", + inputObj: builder.ForPersistentVolume("pv-1").StorageClass("gp2-csi").Result(), + groupResource: kuberesource.PersistentVolumes, + resourcePolicies: &resourcepolicies.ResourcePolicies{ + Version: "v1", + VolumePolicies: []resourcepolicies.VolumePolicy{ + { + Conditions: map[string]any{ + "storageClass": []string{"gp2-csi"}, + }, + Action: resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + }, + }, + }, + }, + expectedAction: &resourcepolicies.Action{ + Type: resourcepolicies.Snapshot, + }, + expectedPVName: "pv-1", + expectedErr: false, + }, + { + name: "PV without VolumePolicy, returns nil action and PV", + inputObj: builder.ForPersistentVolume("pv-1").Result(), + groupResource: kuberesource.PersistentVolumes, + expectedAction: nil, + expectedPVName: "pv-1", + expectedErr: false, + }, + { + name: "Invalid object for PVC, returns error", + inputObj: builder.ForPod("ns", "pod-1").Result(), + groupResource: kuberesource.PersistentVolumeClaims, + expectedAction: nil, + expectedPVName: "", + expectedErr: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + pv := builder.ForPersistentVolume("pv-1").StorageClass("gp2-csi").Result() + fakeClient := velerotest.NewFakeControllerRuntimeClient(t, pv) + + var p *resourcepolicies.Policies + if tc.resourcePolicies != nil { + p = &resourcepolicies.Policies{} + err := p.BuildPolicy(tc.resourcePolicies) + require.NoError(t, err) + } + + vh := NewVolumeHelperImpl( + p, + ptr.To(true), + logrus.StandardLogger(), + fakeClient, + false, + false, + ) + + obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(tc.inputObj) + require.NoError(t, err) + + action, outPV, err := vh.(*volumeHelperImpl).getPVAndMatchAction(&unstructured.Unstructured{Object: obj}, tc.groupResource) + if tc.expectedErr { + require.Error(t, err) + if tc.expectedErrStr != "" { + assert.Contains(t, err.Error(), tc.expectedErrStr) + } + } else { + require.NoError(t, err) + assert.Equal(t, tc.expectedAction, action) + if tc.expectedPVName == "" { + assert.Nil(t, outPV) + } else { + require.NotNil(t, outPV) + assert.Equal(t, tc.expectedPVName, outPV.Name) + } + } + }) + } +} diff --git a/pkg/backup/actions/csi/pvc_action.go b/pkg/backup/actions/csi/pvc_action.go index 6998d13ce..b9debe031 100644 --- a/pkg/backup/actions/csi/pvc_action.go +++ b/pkg/backup/actions/csi/pvc_action.go @@ -407,6 +407,8 @@ func (p *pvcBackupItemAction) Execute( "Backup": backup.Name, }) + dataMoverFromVolumePolicy := vh.GetDataMoverFromActionParameters(item, kuberesource.PersistentVolumeClaims) + dataUploadLog.Info("Starting data upload of backup") dataUpload, err := createDataUpload( @@ -418,6 +420,7 @@ func (p *pvcBackupItemAction) Execute( operationID, vsc, fsType, + dataMoverFromVolumePolicy, ) if err != nil { dataUploadLog.WithError(err).Error("failed to submit DataUpload") @@ -557,6 +560,7 @@ func newDataUpload( operationID string, vsc *snapshotv1api.VolumeSnapshotContent, fsType string, + dataMoverFromVolumePolicy string, ) *velerov2alpha1.DataUpload { parentSnapshot := "" @@ -564,6 +568,11 @@ func newDataUpload( parentSnapshot = veleroshared.DataUploadParentSnapshotNone } + dataMover := backup.Spec.DataMover + if dataMoverFromVolumePolicy != "" { + dataMover = dataMoverFromVolumePolicy + } + dataUpload := &velerov2alpha1.DataUpload{ TypeMeta: metav1.TypeMeta{ APIVersion: velerov2alpha1.SchemeGroupVersion.String(), @@ -596,7 +605,7 @@ func newDataUpload( Driver: vsc.Spec.Driver, }, SourcePVC: pvc.Name, - DataMover: backup.Spec.DataMover, + DataMover: dataMover, BackupStorageLocation: backup.Spec.StorageLocation, SourceNamespace: pvc.Namespace, OperationTimeout: backup.Spec.CSISnapshotTimeout, @@ -627,8 +636,9 @@ func createDataUpload( operationID string, vsc *snapshotv1api.VolumeSnapshotContent, fsType string, + dataMoverFromVolumePolicy string, ) (*velerov2alpha1.DataUpload, error) { - dataUpload := newDataUpload(backup, vs, pvc, operationID, vsc, fsType) + dataUpload := newDataUpload(backup, vs, pvc, operationID, vsc, fsType, dataMoverFromVolumePolicy) err := crClient.Create(ctx, dataUpload) if err != nil { diff --git a/pkg/backup/actions/csi/pvc_action_test.go b/pkg/backup/actions/csi/pvc_action_test.go index e59591146..61141f2d5 100644 --- a/pkg/backup/actions/csi/pvc_action_test.go +++ b/pkg/backup/actions/csi/pvc_action_test.go @@ -2229,12 +2229,13 @@ func TestGetOrCreateVolumeHelper(t *testing.T) { func TestNewDataUpload(t *testing.T) { tests := []struct { - name string - backupType velerov1api.BackupType - vsClassName *string - uploaderConfig *velerov1api.UploaderConfigForBackup - expectedParentSnap string - expectedDataMoverCfg map[string]string + name string + backupType velerov1api.BackupType + vsClassName *string + uploaderConfig *velerov1api.UploaderConfigForBackup + dataMoverFromVolumePolicy string + expectedParentSnap string + expectedDataMoverCfg map[string]string }{ { name: "Full backup type, no uploader config, no vs class name", @@ -2262,6 +2263,15 @@ func TestNewDataUpload(t *testing.T) { expectedParentSnap: "", expectedDataMoverCfg: nil, }, + { + name: "Default backup type, uploader config with 0 parallel files", + backupType: "", + vsClassName: ptr.To("test-vs-class"), + uploaderConfig: &velerov1api.UploaderConfigForBackup{ParallelFilesUpload: 0}, + dataMoverFromVolumePolicy: "velero-block", + expectedParentSnap: "", + expectedDataMoverCfg: nil, + }, } for _, tc := range tests { @@ -2310,7 +2320,7 @@ func TestNewDataUpload(t *testing.T) { operationID := "test-op-id" fsType := "ext4" - du := newDataUpload(backup, vs, pvc, operationID, vsc, fsType) + du := newDataUpload(backup, vs, pvc, operationID, vsc, fsType, tc.dataMoverFromVolumePolicy) require.NotNil(t, du) assert.Equal(t, velerov2alpha1.SchemeGroupVersion.String(), du.APIVersion) @@ -2344,7 +2354,12 @@ func TestNewDataUpload(t *testing.T) { } assert.Equal(t, pvc.Name, du.Spec.SourcePVC) - assert.Equal(t, backup.Spec.DataMover, du.Spec.DataMover) + if tc.dataMoverFromVolumePolicy != "" { + assert.Equal(t, tc.dataMoverFromVolumePolicy, du.Spec.DataMover) + } else { + assert.Equal(t, backup.Spec.DataMover, du.Spec.DataMover) + } + assert.Equal(t, backup.Spec.StorageLocation, du.Spec.BackupStorageLocation) assert.Equal(t, pvc.Namespace, du.Spec.SourceNamespace) assert.Equal(t, backup.Spec.CSISnapshotTimeout, du.Spec.OperationTimeout) diff --git a/pkg/util/volumehelper/volume_policy_helper.go b/pkg/util/volumehelper/volume_policy_helper.go index 6abdc73f8..a148b0432 100644 --- a/pkg/util/volumehelper/volume_policy_helper.go +++ b/pkg/util/volumehelper/volume_policy_helper.go @@ -28,4 +28,5 @@ type VolumeHelper interface { ShouldPerformCustomAction(obj runtime.Unstructured, groupResource schema.GroupResource, matchParams map[string]any) (bool, error) GetActionParameters(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, string, map[string]any, error) GetSnapshotClass(obj runtime.Unstructured, groupResource schema.GroupResource) (string, error) + GetDataMoverFromActionParameters(obj runtime.Unstructured, groupResource schema.GroupResource) string } From 93df34d2ea6187b74aee94bc81c36c6366190685 Mon Sep 17 00:00:00 2001 From: Ralthos <161431341+Ralthos@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:34:26 +0530 Subject: [PATCH 30/45] Add printer columns for VolumeSnapshotLocation (#10216) kubectl get volumesnapshotlocation falls back to NAME and AGE, while BackupStorageLocation beside it shows provider and phase. This follows the same pattern for the remaining location type. Phase is worth surfacing here because the CLI does not print it. velero snapshot-location get shows only NAME and PROVIDER, so status.phase, which carries the same Available/Unavailable enum as BackupStorageLocation, is currently not visible from either tool. Raised as an open question on #10199 and left out of #10200 to keep that change to the two types the issue was filed about. Signed-off-by: saral --- changelogs/unreleased/10211-Ralthos | 1 + .../bases/velero.io_volumesnapshotlocations.yaml | 15 ++++++++++++++- config/crd/v1/crds/crds.go | 2 +- .../velero/v1/volume_snapshot_location_type.go | 3 +++ 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/10211-Ralthos diff --git a/changelogs/unreleased/10211-Ralthos b/changelogs/unreleased/10211-Ralthos new file mode 100644 index 000000000..ab77622f2 --- /dev/null +++ b/changelogs/unreleased/10211-Ralthos @@ -0,0 +1 @@ +Add printer columns for VolumeSnapshotLocation so kubectl shows provider and phase diff --git a/config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml b/config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml index 111a19df5..4fe7338ea 100644 --- a/config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml +++ b/config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml @@ -16,7 +16,19 @@ spec: singular: volumesnapshotlocation scope: Namespaced versions: - - name: v1 + - additionalPrinterColumns: + - description: Provider is the provider of the volume storage + jsonPath: .spec.provider + name: Provider + type: string + - description: Volume Snapshot Location status such as Available/Unavailable + jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: VolumeSnapshotLocation is a location where Velero stores volume @@ -93,3 +105,4 @@ spec: type: object served: true storage: true + subresources: {} diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index d910e72f3..0f645d6c1 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -39,7 +39,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=Ks\xdc8sw\xff\n\x94sؤJ#ǕG\xa5tSd;V\xbeoe\x95\xe4\xd8g\f\xd93\xc4'\x10\xe0\x02\xa0ƳI\xfe{\n\x8d\a\x1f\x03\x92\x98\xd1cwSˋJ$\xd0\x00\xfaݍ\x06f\xb5Z\xbd\xa1\r\xfb\x06J3).\bm\x18\xfc0 \xec\x7f\xfa\xfc\xe1\xdf\xf49\x93\xef\x1e߿y`\xa2\xbc W\xad6\xb2\xbe\x03-[U\xc0\a\xd80\xc1\f\x93\xe2M\r\x86\x96\xd4Ћ7\x84P!\xa4\xa1\xf6\xb5\xb6\xff\x12RHa\x94\xe4\x1c\xd4j\v\xe2\xfc\xa1]úe\xbc\x04\x85\xc0\xc3Џ\xffx\xfe\xfe_\xcf\xff\xe5\r!\x82\xd6pA\x14h#\x15\xe8\xf3G\xe0\xa0\xe49\x93ot\x03\x85\x85\xb9U\xb2m.H\xf7\xc1\xf5\xf1㹹\u07b9\xee\xf8\x863m\xfe\xd2\x7f\xfbW\xa6\r~ix\xab(\xef\x06×\xba\x92\xca\xdct\x00WD\xf9暉m˩\x8a\x1d\xde\x10\xa2\v\xd9\xc0\x05\xc1\xf6\r-\xa0|C\x88_\x14\xf6_\xf9\xf5<\xbew \x8a\nj\xea\x00\x13\"\x1b\x10\x97\xb7\xd7\xdf\xfe\xe9~\xf0\x9a\x90\x12t\xa1Xc\x105\xff\xb3\x8a\xefIX\x02a\x9aP\xf2\rQ`g\x83$!\xa6\xa2\x86(h\x14h\x10F\x13S\x01\xa1M\xc3Y\x81\x14!rӃ\x14zi\xb2Q\xb2\ue82di\xf1\xd06\xc4HB\x89\xa1j\v\x86\xfc\xa5]\x83\x12`@\x93\x82\xb7ڀ:\x8f\x80\x1a%\x1bP\x86\x05t\xb9\xa7\xc7U\xbd\xb7s\v\xb3\x8fŅ\xebEJ\xcb^\xe0\x96\xe0\xf1\t\xa5G\x1f\x91\x1bb*\xa6\xbb\xa5\x86\xe5\x11*\x88\\\xff\r\ns>\x02}\x0fʂ\xb1\xd4myi\xb9\xf2\x11\x94EV!\xb7\x82\xfd\x1aak\xbbp;(\xa7\x06\xb4!L\x18P\x82r\xf2Hy\vg\x84\x8ar\x04\xb9\xa6{\xa2\xc0\x8eIZу\x87\x1d\xf4x\x1e?#\xf1\xc4F^\x90ʘF_\xbc{\xb7e&\xc8Z!\xeb\xba\x15\xcc\xecߡذuk\xa4\xd2\xefJx\x04\xfeN\xb3튪\xa2b\x06\n\xd3*xG\x1b\xb6\u0085\b\x94\xb7\xf3\xba\xfc\xbbH\xd4\xc1\xb0foyT\x1b\xc5Ķ\xf7\x01E\xe5\b\xf2X!r\x8c\xe7@\xb9%vT\xb0\xaf,\xea\xee>\xde\x7f\xed3%Ӟ(=ޜ\xa2\x8f\xc5&\x13\x1bP\xae\x1f\xb2\xa6\x85\t\xa2l$\x13\x06\xff)8\x03a\x88n\xd753\x96\r~iA[~\x97c\xb0W\xa8\x8f\xc8\x1aH۔\xd4@9np-\xc8\x15\xad\x81_Q\r\xafL+K\x15\xbd\xb2DȢV_ˎ\x1b;\xf4\xf6>\x04]9AZ\xafE\xee\x1b(\x06\x92f\xbb\xb1MP\x17\x1b\xa9\x06J\xc6v\x19\xe2(-\xfc\xf6qZĪ\xc5\xf1\x97%.\xb3Ͽ\xc7ޖ\xdf\xec\xccZ\xc1~i\x01\x95\xa9\x13\x7f8\xd4W\xaa\xa7\xf4\x87\x8fe\xa31u'\x11m\x1f\xf8Q\xf0\xb6\x842\xea\xf5\x83\x05\xe6,\xe3\xe3\x01\x144\x87\x94\t+D\xd6.ٵ\x88\xee+*p\xaa\x80\bi\x12\xf0\x98p\xf0\b\x13\x88\x81$M\xb0\xa1\x81:1\xe3\xd9%\x13\"Z\xce\xe9\x9a\xc3\x051\xaa=D\xa3\xebK\x95\xa2\xfb\tl\x05\xdf\xe0IȊ@\xbc\xaa\xe1\xac@\x92G\x85\x82\xf8\xfa㢊i\xab(\xc3*o%g\xc5~\x01_\x1f\x93\x9d\x82\xb4z\xd9\xf5+$k\xa8\xe8#\x93*%\x06RaӞ=\xefԴ\xb4Z\xd2\x03\x19۸\xcc\x05'\x91UI\xf9\xb0\xc4\x10\x9fm\x9b\xce:\x90\x02]\u0378\x14Omo\xbb\xd7@\xe0\a\x14\xadIL\x93\x90\xb2E\xd3$\x15i\xa46\xd3t\x9fV]\xa4\xef\x1c\xa5>\xce0\xcd\xc1ʒ\xac\xee\x1e\xaf\x84\x03Q-\x0e\x06\nY\n\xb0˨-Q\xbb\xb6J\xb6\xae\xed$RȚj(\x89\x14\x93##\xbb\xb4\x1c\xb4\x1f\xabD\xce\xe8\xf4\xd0Y\xb7~\xf4x\b\xa7k\xe0D\x03\x87\xc2Hu\x88\xcc\x1c\x94\xba'G\xb1N\xa02\xa1M\x87\x12\xd0-`\x06$\xb1\x9c\xbe\xabXQ9\x0fò'\xc2!\xa5\x04m\xb5\t\xba\xcc\xfb\xa9E\x92%\xf2\xfbA\xe6\xb4G\xf7,\x88\xd5\x18^J\xa3tO\x86\x1a\xee\x9e$j;\xdd{\xa0[\xfc{#g\x97\xfd\xff\x13\xb1\xc1\x98\x9c\xc0\xb43\xf2O\xd0\xfd\xcc\xe6\xe9I\xbe\xc5\b\x0f\xf49\xb9\xde\x10\xa8\x1b\xb3?#̄\xb7K\x92@9\xef\x8d\xf1\a\xa6\xcd\xf1L\x9fI\x9a\x1c\x99x!\xc2\xc4!\xfe\x80tA\x93q\xef-F6M\xfe\xda\xefuF\xd8&\"\xbd<#\x1b\xc6\r\xa8\x11\xf6OR\xf5\x812ρ\x8c\x1c\xabG0O`\x8a\xea\xe3\x0f\xeb\xe2\xe8.=\x96\x89\x97qg\xe7\x1b\x87\bbh\x9e\x17\xe0\x12\x8c\x97\x99\x82\x1a\xe3p\xf2\x15\xb1ٽA\xa7\xfa\xf2\xe6\xc3a\xac<~28\xef`!\vB\xe7\x9e\xcbъ\xfa\xf3\xf3QA\xf8\x82>P\f\xaa\\\xce\xe5\x8cP\xf2\x00{\xe7\xbaPA,}hh\x9c1\xbc\x02L\xfe \x9f=\xc0\x1e\xc1\xa4\xb39\x87O.7\xb8\xe7\x01\x12\xae\x7f\xea\x19\xe0\xd0\xceɇ\xc5\x0eO\xf6\x05\"\x02c\xf8\\6p\x8f\x17\x85D\xee$\xfdd\xea\x92\xf0\x04ܟ\xb0\xcc,V\xe9\x8f\xd1O}\"\a\xfc\xa4\x1d-\xad\xc4T\xcc\xe745\xa0\xcc\xe4\x12\xd4=\xdf(ge\x1c\xc8\xc9ȵ8#7\xd2\xd8?\x18\xa0id\x94\x0f\x12\xf4\x8d4\xf8\xe6E0\xea&\xfe\x92\xf8t#\xa0\xa0\t\xa7\xe5-\xc2\xfa9?g\xd3,\xb7E\xdc3M\xae\x85\x8dW\x1cJ2\x87\xc2\xf4\xae\x1b\xce\rT\xb7\x1a\xd3uB\x8a\x15\xda\xcc\xe4H\x1e\xdfR\r\xd0\xfd\xe4A\xfd\x80_\xad\xb1p_\\\x92\x99\xd3\x02\xca\x10Yb\xf6\x93\x1aز\"s\xbc\x1a\xd4\x16HcUx\x1eGd*V\xbf\x9a\xe3\xd8'\xcfz\xf7\x9f\x1f\xab\x87\x98/XY\x93\xb3\xf2\x10\x8c\xac3p\xe0uw\xb9\xbc\x9e\x95\x95ٌV\x81\x13\x16\x9bN$G\xa7\x9b\xe6 \xe5\t\xe8@+\x8e.\xce\"uiY\xe2\xe6\x1a\xe5\xb7GX\x94#x\xe1X\xd5Л\xbb3\xc15m\xacZ\xf8okiQ\x9a\xfe\x974\x94)}N.q\xa7\x8c\xc3\xe0\x9b\xcf\xc3\xf5\xc0d\f\xd9ء,\xff\x8f\x16\xf5\xbdu\"7\x06\x94\xcf%:\x1b\x10\xe2\x8f'Ff\xa9]\x99\xfedc2\x90\xc6\xfc\xaeE\xf0\x027\xb9\x8d\x9b\x9c)\x1e\xe3\xb0Z\xbc\x1c\xe9\xed\x7f\xfc\xd1\xcbgZɵ\xff\xf7\x17\xf2\xdc\x0eu!뚎w5\xb3\xa6z\xe5z\x06\x9e\xf6\x80\x1c\xf5նEyε\xc8\x1d\x0f\xe1\xfe厙\x8a\tB\x83\xda\x00\xe5\x19\x8a\x92F\xa6rة\xa7\xa2\x9a\xac\x01DL\xd1\xff\x1e\\\x89\x9a\x89k\x1c\x80\xbc\x7f\x01\xd7#\xa2\xeb%\x9dݫH\x93H\xf9\xf8\u0099\xacF\x96dW\x81\x82\x01c\x1c\xe6\xdd\xd1S\x15\xd2\xf4R\x16G8\xa4\x8d,\x7f\xd2dÔ6\xfd)h\xd2\xea\\Z\x1fI>;ﯬ\x06ٚ\x97D\xf0\xc7n\x98\xc1^sM\x7f\xb0\xba\xad\t\xade댹au\xdc\xd5\xf5\xe8\xddQf\xe2\xb6\x15\xe6o\x8c\xb4$h8\x18 kؤ\xf7{SO!\x85f%\xa8P\xa5\xe0\xc8Ƥ\x15\xcc\re\xbcM\xed\x12\xa5\x9ec#`\xf1Q\xa9\x93\x02\xe0/\xaeg/\xefX\xc9\xdd\x10A\x99kǍ4 lC\x98! \n\x8bqPN%\xe3\x10\x1e\x19\x88\x1a\x96\xab\xe7\xf2\x14\xb8}@\xb4u\x1e\x02V(\x90L̦\xdc\xfa\xcd?Q\xc6_\x82l\x96\xf3>Iu\a\xb4<%G\xf3\xbdם\x80Э\xc2\xcd\x7f\xa7;v\x8c\xe7\xcd\xd9R\x8epڊ\xa2\x02TBb\xa8\x1b\x1cx&\xb4\x01\x9a\xcb\v\xd6+j\x85`b\x9bG\xbb\xecDh\xf78T\xaf\xa5\xe4@\xa7w!\xbb\xc7\xe2\xfa\x154\xd1\xf7n\x98'j\xa2\x8e\bn\xdb\x1c\xe9\x90MQ\xab\xb4\b5\x06\xeaƉ\x9c$\xaa\x15}\xeb\xf2\x02\x8a\xe8\x980\xdc\xcf\xe29\xe3k&X\x06m\at\xbd\x16\xcc\xf4\x9dG\v\xe2E\x9dG;@t\aNɰ]\x0f\x00X\x01\rq\b\xce=r\xcd\x11\x8e\xe4\x1a\b-K(]\xeeҺ\">,q\x85o\x13\xc5\r\xc9\xd5\x1d\xef\tfQ6<\x83\xa0\x13\xf3\xb0\xea\x11V\xadx\x10r'V\x18\x8c\xeb\xa3uȉY\xaa\xa7\x0eoNVF\xcb\xfa%_M/i\xa1!\xbf\xe6\xf3T\xf0\x9f^@\xcbd\xf3\xcdQ\t\x8f9.X\xd2k\xae\x00{\xe2\xe3\xe2,\xe6Ɵ\xe9\xec7\xa5\xaf\\\xb1\xf4\x93\xca\xe2\xaeӠzN\xe1\xae\x02S\x81\n\xa5\xd9+,I/gwH\xbb\xe0%\xd6\xc9Y\xa6\n.\xb2+\xff\x1cU\xceat\xd3r~fy\x9b\xb6<\x19\x0e\x1b\x89\"v\xc8YY\xf5ci\x8f!\xa7\xfa\"\x1b\x8f\xfdJ\x8ba}a\xac\x82\b\x05\x862\x8c\xeci\x9cZ/\x16\x96\xf6\xf6\xf7\x87\xe5\x14\x98\xff\v\xd3\xff\xcdK\x0f3*%\xf2ј[\xa5\x19\x91\x98\x80\x95`\xb0\x1e\x1a\xbb\xfa\n\xdf\xce\x17\xfa\xfe\xbepj\xa0\xfe\xd2x\x89\x99ta3К\x803\xaa7Ak\xd0j\xe7\nD;\xe0s\x86\xb6\xffe\xe1NA\x040)~\xfdZA\x10__\xbd\xcf4\xf9gR\xc96Q\xd57\x83\xb2\x85\xea\x8e\xe5\x05\x0f\n=\xfc\x86\x02\x18\xfa\xf8\xfe|\xf8\xc5H_\xf6\x81Y\xb4\x04 \f\x8a\xba\xcc,\x13%{deKy\x90\xda\xee\f\x81c\xa0\x8e\xcf\x12Ф\"\x82qǀ\xa1\xff\x80\xe1ȗ\xc6m\xcb\x1c\xad\xe2\xe6}ѼꐓkB\x865\x1f\x13\xd6\xf0\xd8\xed\x8bg\xa9\x82\xfdMj=\x8e\xaf\xf0ȉ$\x16\xaa9N\xa8\xe1\xc8,\x16{\xf2~KN\x95\xc611\xf7\x8bUd<\x7f\x1dF\x16~\x96k.\x8e\xc1\u038b\xd7W\xbcbU\xc5\xeb\xd4RdVP<_)d^\xf4yR)\xc0r\xc02]\x05\xb1X\xfb\xf0\xa4\x80\xe6\xa4%-\xd64\x1cSɰH\x9d<1{\xb5Z\x85W\xabPxݺ\x84Y.\x9a\xfdxL\xe5A\x8c\x93~\xa6M\xc3\xc4\xf6\x90)rYg\x96m\x96Y\xe6f4\x91\x01\xcf\xf4Ù.:\x9c\b}\xddq\xe9D$\x19ҖL\x18yN.\xc5\xde\xc3M\xc0酏B\x9a\x83\x83lvZ;\xc6y\xff\xb4\x16\x82\x9d\a\xe5\xcfLjZ\xbbYMy\xfbI\xbaJ5p\xcaO\n\x1c\xbf\x8c`\xf4\xb3\xa3\xaf\xe9\xf9\xd7-7\xac\xe1`=\xbaGV&ϐ\x99\n\xf6\x11\xc9\x7f\x93xBj\xbdGH_\xee\xa2,\x9e\x8f\x82\x18\xaa\xc9\x0e8'4\xc5\x1d\a\xcb/\xdc\xc9\xe4B\xae\xf0H\xa0%o`\x12\x7f\x9e\xf9\xccI1\x1e\x03C\xea\xd5\t\xb8\x05\x15x\xbaY'\x162i\x0es\xb4\xe8\x81_\xee\xa2\v|\xf7K\vjO\xe4#\x960x\xef\xad;\xab\xe0Ս\xb61fP\x80^\x19Om*\x1c\x842\x9d\x82\"\x97\xc2\xf9\x12\xe3\xf9`\x1f\xab\xf9\xbaPͪs\x1b\x85%ǘ\xe8.d\xec\x9d\xe8\xb6\xe4\xf6\xe7\x16\xf5\xbfl\xe0v|\xe8\xb6\xe8+\xe5\xfb\xb3\xbfQ\xb1\xfe)E\xfay\xdbA\x8bE\xf9/\x15\xc8-\x85r\xd9\xdek^\xd1\xfdq\x9b\xa8/Xd\xff\x12\xc5\xf5\x99\x98\xca)\xa6?\x0eO\xafP<\xff\xaaE\xf3\xafU,\x9f]$\x9f\xb5\x8f\x99\xbdi\x95\xbb\xcdxb\xd5\xf7\xf2\xae\xfb|\xd1{F\xb1{\xc6N\xda\xf2\"OX^F1\xfbqE\xec\x194\xcb\x15\xc5W,V\x7f\xc5\"\xf5\xd7.N_ଅ\xcf\xc7\x15\xa1\x9f\xbc\x03\x13\xb6\xfaod\t\xb7R\x99\xa5\xe0\xe4v\xdc>\xb1\x93\xda\v\xd8$/\x89\bM\x13\xab\xc4\x10Ç\x17\xa7-*\xbd\xe9\x19\xdc\xe9\x9fei綴\xc7r7j~pVy\x03\n\x84\xbb\xe6\xe3?\xef\xbf\xdcD\xf8)\x9f\xd7{ƣ\xeb%\x9c\aSz\xe4\xf8\xad9_\xcc䰅>\xc03\xef\x8bІ\xfd\a\xde\xf7\xf6\x84t\xd0\xe5\xed5\xc2\b~\x1a^ \x17\xab(\xe2\x8e\xe5\x1a\xacŊ\xa8\x9a\x14\x8b\xeb\xcd\x00\xe2\xb0\xe2\xb7\x7f\x8d\x12\x94\xeeʬ`1Y\xa8\xf1\xb2\x82w{\xed\xe615\xca'\xeb4\x8a=\x91\x8e#+\xa6\xcaUC\x95\xd9#\xdb\xe8\xb3\xc1\x1c\x82\x99\x99K\xe7L*\xd6\xc3k\xc0\x92\xe8\r\xb7\x7f\xe1^\xe4\xbe\x19\xee\xf6\x8eqw\xca<\xa6ϟ,\x9ee\x91\x0e\xc0`\x9d\xac\xa8z\x1e\xe4\x0e\x82\x8f\x19\x96\x8dҊݒ\x1a\x1c\xb8?i\xc5\xf8Y/{\xfb:e:\x99Wl\x9d|\xb9\x96Cτ\xfa\xc1\x1d\t\xab\xda\x0e1uB\x81\xceb\xb8\x9dq\xf0c>\xb1\x90y5S\x9e\xc18\xe1:&\xc4W.\xaeH\xf2\x96\xa6̛\x98~SD\xcfh5]TP\xb6\x1cN\xbd\x87\xf5\xbe\xd7\x7f\xf9&\xd60Z\xc6]\xac\x16\xd9=\x03m=\xacᝯ\x9e\x12\x1er\x9f\x92SA8&lܕ\x8f\x85\xbb\x1d\xb8(@\xebM\xcbC\xe5h\xa1\x80\x1a(Cs\xa6㌏\xaa}\xd4\x0f\xac\xf9\xe0j(\xc7a\xf7I8\x9e\x06\x17.O\xefY\a\xdcSP\x8f\xa0V\x05z\x84\xad\x822Tt\xcex\x91\xa4\x0e \x99\xeeG\xf2\x03W=\xd1\xff{\x05\x02\xb9\xd29Q\xa1t\xb4\x0f͢\xa3\x81\x92\xc0#\b\xc26\xa47/)z\x13N\x81\xffLq\x03\x0e6\x1b(\x8c\xdbХ\xe80\a\xa9=\xc0\b\xeb\xe4>\xe1Y=\xc1\xe0\xb5\r\x97\xb4\x04\xe5\x1c\xed\x05B\xfeנ\xf1H\x13\x05\x04t\x97(\xcf^@\xfb${\xd4PE9\a\xfe\x89q\xd0\x1f\xe4N\xd8ye\xa8\xd9\xdbT\xbf\xde\t\xe8\xa2U\xd6Y\xdb\x13\xd1\xd6kPD\x831\xd3iٍT\xf3g\x91\x1c\xe2\x990\xb0\x85T&{\xa7\x98\x81\xfb\x86*\r8\xa3\x8c\x15|\x1fuqy\xde\r\xa7[Wt^\xb2\x82\x1a\x88\x82\x83#LM\x1f\xfbk\x84\xc5\xf7X\x03,'\xb6\x97\xb2U\xf5\xd4\xe1\xc7Ie=u\x91w\xc2\x01K^\xe5\xed\xfc\xac\x826\x06\x8f\x9a\"\x1d\x91\x88\xc6\xc3\xc0\xeb\xf1G\xb7y\x0f\xc0Ns\x9a?0\xe4Kӵ\xa1u\"\xf6[\xd6tW\x87`\xf0\x02~U\xf6*\xdc\xfbW\x19\xc7Rv\xb2\xa3:\x1e[JFT\x1dl\a\x06՚\x05\x1d4\x93\x15E\xca8\x94s\x9c\xfa5j\xab\x9ft\x84\x835\xf7\x96\xc5\xef\rU&N\xfd\xd0;u\x91\xf9\x05)\xa9\x81\x95\xed}\x9a~J_H\xaeԉ\x857x\x86܋G\x11\x0e\xb8Z\x9fƝ\xfc\xaeAk\xba\r\xe9\xde\x1d( [\x10\x16\xefq\x17/\xe9\a\x87\xc3\xf3\xde\x05\x18\xa4{haZ\xea\ap\x8ey\xacS\n\xbf\x04\x80\xf9\xe2\xed\xa4\xe1M\xab\n\x7fL\xff\x0e\xa8\x1e\xff\xb0\xc4\x01.>\xf5\xdb\xfa\xedX\xb7bW\x85@\xddQ\n\xfci\x01\xc3b\x0e;%\xd3F\xe2\xc8G9\t\x95\x94\x0fY\xc1\xd3\xe7ذ۸a±\x12^N\xb0\x96\xad\xe9y\xaf\x1e\xe1\x89i\xe2E\xdb\xcfl_\x10\xe6\xa5;\xaa<\xb5\x8b\x99\xe7\xbf\x7f\x1e@\x8aI\vi(\x0fF\xc6\xf2elP\xcd\\\xd5s\x1f~\xa6\x80\xf3\xfd\xd9\x18\xf2\xe8\xf7O:\xd8Uwi\xb6\xd7\x04\xddE-\x13\x03\x85\xfd\xb5$\x90x\xdfv\xe7iN\xddn\xbcd\xff\x10\xea'\x9cT\x06\x8e?w\xad\xa7\xf0\xe8\xa6\xe9\xc2 \x10\xe9\xfc\x01\xc1\x90\xd2TQ2N\x98\xfaL\xec\xd1TT/\x05\x1d\xb7\xb6Mt;z\xe6*\x86\x16w\x13R\x99\xbeQbEn`\x97x됅u&(U\x89&\xd7\xe2Vɭ\x02}\xc8t+\xbc9\x80\x89\xed'\xa9ny\xbbe\xe2\xcb\xf4\x19\xab\xb9ƷT\x19f\x99\xd6\xcd'\xd1\xf7*ظķ\xe5\xde\xd3\x1f\x98\xa0\x9c\xfd\x9a\xd2\xe5\xfd\x8fK#\xcc\xe8\xbb\xc6#\xef\x14\v\x15\x10\xbf\xa4\x00\xbd\x86\xfeI\xf7\xccO\x18\xf7\x9c\xdcȤ\x18\xfbR,6\x04\xca4Y\x836+\xd8l\xa42n\xa7|\xb5\xb2\xe1\x8bw\x90\xac\x86\xc0\xe8\xdf\xfdn\fa\xa9\xe8*\x16\xb9\x04\x87e\xe3\x13\xc4\n\xad\x0e&\x12j\xbawyfZ\x146&\x80w\xda\xd0T\xc4\xf9$=\x8d\t\b/+9*\xe4\xba\xdf>fn\xa3\xfa@p\x0euxq\x8c3\xe8|\xaazdp/\x15\xd1\x16{\xa7(\x13\xe2\xd4\xd8\xf5t2%\xcf\xd4|\x8dP\xa6ԣ_\xdf\xe0'/|)\x93od\xc9VTTl'\x8f\x8eWJ\xb6\xdb*\xf0\xe6\x94CD\xca\x16\xf3!\r\xaa\x02\x1d~\xa2˴J\xf4\xcac|5㔖\x8eӝ\xf6Q\x9e\xa0\xa8Uw\x84\xb4SU36?;\xf7;\x01q\xd1\xf6' R\xbd\x17\xc5\xeca\xd7Ýǣ\\\xcb$\x12\xa26~6$D\x88SH\xe8\xfb\x12]\xc4\xf3\xbb\xc1Ȕ\x8fr\":\xe6\x9d\x18\\\xe2<\xa8\xe5E\xf7\x9d\xa0\xa1\xbbs\x1c:\xf4 \xf8;)\xd17\x80pL\xe4\x8bc\xa7\xe3\xde\xdfo\xc4\xfa\x18\xbd\xad\x8f'Ǯ\xdfF0F\x97\r\xd8(\xb6\x1b&ě\x7f\xcf6)yq\xbf\x83\xb8\xe6\xf0\x0f\a__\xf9Ҁ\x1dU\x82\x89\xedI\x18\xf9\xee\xfb&\xe2y\x0f\xf6%#\xfa0\xf3g\x8b\xe9\x93f\xe9\xe0%2x\xd9ó\x1fɿ\xf9\xbf\x00\x00\x00\xff\xff\x9d=\x85\t\xc7t\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=\xdbr\x1c+\x92\xef\xfa\nB\xfb0\x97P\xb7DZ\x97\xd8ЛG\xb6g;\xc6c+,\x1d=\x0f]\x95\xad\xe6\xa8\n\xea\x00%\xb9wv\xfe}#\x13\xa8[\x17]T\xab%ϙ1/\xb6\xaa!I2\x93\xbc@\x02\x8b\xc5\xe2\x8cW\xe2\x0e\xb4\x11J^2^\t\xf8fA\xe2_f\xf9\xf0\xdff)ԛǷg\x0fB\xe6\x97\xec\xaa6V\x95_\xc1\xa8Zg\xf0\x1e6B\n+\x94<+\xc1\xf2\x9c[~y\xc6\x18\x97RY\x8e\x9f\r\xfe\xc9X\xa6\xa4ժ(@/\xeeA.\x1f\xea5\xackQ\xe4\xa0\tx\xe8\xfa\xf1\x0f˷\xff\xb5\xfc\xcf3\xc6$/ᒙl\vy]\x80Y>B\x01Z-\x85:3\x15d\b\xf4^\xab\xba\xbad\xed\x0f\xae\x91\xef\xd0!{\xe3\xdbӧB\x18\xfb\xe7\xde\xe7O\xc2X\xfa\xa9*j͋N\x7f\xf4\xd5l\x95\xb6\x9f[\x98\v\xf7\xbb\xfbM\xc8\xfb\xba\xe0\xbamsƘ\xc9T\x05\x97\x8c\x9aT<\xa3\xaa~l\x04b\xc1x\x9e\x13\xb5xq\xad\x85\xb4\xa0\xafTQ\x97\xb2\xe9 \a\x93iQY\xa2ƍ\xe5\xb66Lm\x98\xddB\xb7\x1f,?\x1b%\xaf\xb9\xdd^\xb2\xa5\xa1z\xcbj\xcbM\xf8Ց\xcf\x01\xf0\x9f\xec\x0eq3V\vy?\xd6\xdb;v\xa5\x95d\xf0\xad\xd2`\x10e\x96\x13s\xe5={ڂdV1]KB\xe5\x8f<{\xa8\xab\x11D*Ȗ\x03<=&\xfd\x8fS\xb8\xdcn\x81\x15\xdcXfE\t\x8c\xfb\x0e\xd9\x137\x84\xc3Fif\xb7\xc2L\xd3\x04\x81\xf4\xb0u\xe8|\x1a~v\b\xe5܂G\xa7\x03*\b\xf62\xd3@2}+J0\x96\x97}\x98\xef\xee!\x01\x18\x91\xa8\xe2\xb5\xf1r\x14Z_w?9\x00k\xa5\n\xe0\xf2\xac\xad\xf4\xf8\xd6\xc9^\xb6\x85\x92_\xfaʪ\x02\xf9\xeezu\xf7\xef7\xbdϬO\xd1\xff[4\xdfY\xc3\r&\f\xe3\xec\x8ef\x10\xd3~J3\xbb\xe5\x96i@1\x00i\xb1F\xa5a\x11H\x9d3\xa5;\xa0*\xd0B\xe5\"\v,\xa2\xc6f\xab\xea\"gk@n-\x9bڕV\x15h+\xc2|r\xa5\xa3z:_\x0f\xa1\x8f\x05G\xecZ91\x05C\x92\xe9g\x1b\xe4\x9eHn\xf2\bӎ\x878\x88\x9f\xb9dj\xfd3dv9\x00}\x03\x1a\xc1\x84QdJ>\x82F\x8ad\xea^\x8a\xffm`\x1b\x9c\x12\x96$Ղ\xb1\x8c\xe6\xb3\xe4\x05{\xe4E\r\x17\x8c\xcb|\x00\xb9\xe4;\xa6\x01\xfbd\xb5\xec\xc0\xa3\x06f\x88\xc7_\x94\x06&\xe4F]\xb2\xad\xb5\x95\xb9|\xf3\xe6^ؠ\x903U\x96\xb5\x14v\xf7\x86t\xabX\xd7Vi\xf3&\x87G(\xde\x18q\xbf\xe0:\xdb\n\v\x99\xad5\xbc\xe1\x95X\xd0@$)\xe5e\x99\xff[\xe0\xb7\xe9u\xbb73]!u:\x83=\xa8g\x9dt9Pn\x88-\x17\xf0\x13\x92\xee뇛ۮ\xe4\t\xe3\x99\xd2\x11\xc0\x18\x7f\x90\x9aBn\xc0낍V%\xc1\x04\x99WJHK\x7fd\x85\x00i\x99\xa9ץ\xb0(\x06\xbf\xd4`,\xb2n\b\xf6\x8a\x8c\x16\nm]\xe1\xdc͇\x15V\x92]\xf1\x12\x8a+n\xe0\x95y\x85\\1\vdB\x12\xb7\xba\xa6xXّ\xb7\xf3C\xb0\xa7\x11\xd6\x06]qSA֛j\xd8NlD\xe6&\x14\xaa\xe4F\x95\fԲ+㳟~!\xdd7\xfc:\xc0\xc3)\xc8\xd0+\x184JvK\xccom#\x8a\x9c\x83ƔfR\xd9=\x98\xfb\xaa\xb5C\t\x0fe\x02\x93=ag{*5Œ\x8e\x00im\xebP\xbe\xa2\xac&\xbc\x1fD\xb5*K\xc8\x05\xb7P\xec\x8eB\xbf\x0fb\x8c̊\xfaak\xa7\xe7ŦG\xf4\xbc\x06&:\xedi2\xfe5\xd4ط\xc6\x7f%\xcbNF\xd4Ѥ\v\xac\x96-\x0f\a\xfdHx\xda'\rc\xab\r\xb3\x1au\xae\xc7\xeeI\x14\x05\xcedĸ\x82\xbc\x87Z\xbc;\xb1a\u0086Ѭ9a \xd9\xd2yQ\xcb\xd6gh\xec?\"8\xc0\x8eԾ\xeb\x1f=\x15n\x99\x84o\xb6\xad\x85Î\x8c`\xc3\v3\x18\x82WH\xb3\x86q\xc1ֵ=\x0e\x03(+\xbb\xbbpm7\xaa(\xd4\x133\xa4l\xd1\bn\xc4}\xad\xddd\xffm\x0e\x1b^\x17\xf6\xd2\xe1\xfc\xbb\x98\xb4\x8eO3\ve\x85&\xf3\x189\xbd\xf5mq\xc08[\xf2&\xfe\bnr\xf0C\x94w?F\x80(\xe7\xc5VZ=\x8aܛ\xf3=u\xc5\x0e\xaa,,\x8eQ\xb78ґ_\a\xa3\xf9cS\xb93\xb7\xb6\xea\x89=b\x00\x00\xe8-r\x1c\x14\x02\x85\x9c\xd5\xd5\xc5(Lƞ\x84ݲJ\x19#\xd6\x05xρ\t\x99\x15u\x8e\n\xe6c]\x14$\x82+\x99i(\xd1\xe1)Ƹ\xcd\x18Ⱥ\x1cG|AP\"?u\xe0\x8e\xd68\xa0\xa7\xb0dF\xdcH^\x99\xad\xb28\x8dTm\x13\x887*\nX\xaenV\x03h\x1d\xea\"\x8f)~\xa0\xc9m\x15{\xe2\u0092\xa1\xba\xbaY\xb1;\xa2{h͜\x86b\xb6\xd6\x12\x9d\x83H\x7f_\x81\xe7\xbb[\xf5\x93\x01\x96\xd7\xe4ׄ\x98\xe0\x82\xada\x83N\x80\x06\x84\x81?\x81\xd6h\x14\r!\xa1\xea=?3\x94['\xc78\xa1\xbc\x9b$\f{\xfb\aV\nY\xdbѩ:Ie\x94\xa6R=\x82~\x0eq\xdfs\xcb\xff\x82@\x064%Q%\xe8~\x96\x11}\xd7;\xfaq\x1d1_\xae\xac6\x1d\xa8°\xf3sT\xa1\xe7.\x86?\xbf\bS\x9aH\xb1\xaeEa\x17Bv\xfb\vz\x1d{<\x8e0\x0e\xb8c\xbe\xb9U\x1f\x8d\x9b\x98ϢS\x04\xe6\x88\x11\xadT\x1e&\xfcF\x14\xc0\xcc\xceX(\x83\xcaoæN,8,\xe4h\x15\x85\ac\x90\xee~P\xe3\x04\x91uQ\xf0u\x01\x97d!\x0f\xd0l\\Y\x8f\x11\xed+\x18+\xb2S\x92\xccA\x1c!\x98\xf6?\xf4(Cq\x17\x7f\x00\xc6#\xe0==1\xc8+\x8a\x0e\xd1\xfbԊ\xe2Vi\xc80\x00\xb8\U00101140\x82\x82\x19\xa9X\xa1\xe4=h\x87Ec\xe8\xd1\xd0\x00\nh\xce\xd0g\xd7h\x9e\x85d\x9b\x1a\xdd\xf9%Cm\x11\x95\x11!\x8d\x05\x1e\x11\xe6\x13\xf0\x0e\xbe\xa1e\x80\xfc\xaa\xa8\x8d\x05}\x93\xa9\n\xf2\xb0z7j\xd6Ry\xf8\xe1 d\x1f\xfc\x15\"\x03\xe4C\xe6*-h\x85,&\xdam\x1c\x88f\x92\x16\xf3\x90\xd5~\bm\x807\xa9c\fXlx\xfe\xfb\xf3\v\x92\x80~\xef\xfd~\f\xe3\x1a\x1a2\xcd\xd2\xd1\xe4.\x8d\xb7\x10\x16\xca\bu'u\xd4\f\xbes\xad\xf9\xee\x00כ\x95\xc8\x17\xe0{\f\xf6\x80\xf32T\xfbN\xbc\x1f\xf6\xff\xaf\xc8\xfd\xd3\xf2\xdb\xd0j>\x17\x12\xf9\\\bc{l6n\t\x10\xc9:\x16\x7f{\x02I\a\x13\xd5\xe4\x14W\xffA\x88yҹ\x13\x9b,\x8dl\xfa\t\xf0OEɭR\x0f)\xd4\xfb\x1f\xac\u05ee\xff\xb1\x8cv\x9c\xd8\x1a\xb6\xfcQ(m\x86k\xcc\xf0\r\xb2\xdaF5\v\xb7,\x17\x9b\rh\x84E{$͖\xca!b\x1d\x8e\xfdXGeE+\f\xc6\xd52\x1dYJԈ\r\x85\xa2\xfb(T\xe7\xe0`\x88A\x0eD.\x1eE^\xf3\x82|\t.37>\xde\xe0\x17\xd3j\x13\x02\xb1\x87\x7fT\xaa]q\x0eM\x18$2\xb1\xb7d\xa8$\xa0\xaf_b\x8c\xb4_5N\x89\xb0\x0es\xb0od\xa6\xae\v0\xbe\xbb\x9c\xdc\xe4V']\xb4\xccr\v4\x05_C\xc1\f\x14\x90Y\xa5\xe3\x14J\x91\x03WR\x95n\x84\xb8#Z\xb6\x1fu\xb5\x83\x99\x00\xcb(\xd4݊l\xeb\xdcW\x144\x82\xc5r\x05\x86\x96\x94xU\x15\x11\xd3ՖI\xe1\xf0\x9dM鍶$h\x90!ܘ.iK\xa2~n\xcb(\xd9۹٧\xfa\xf8&\xc9(\xbe\xffJD\x0fV\xe7Ha\x9f\xd0$\x8c6[\x92\xe7C\x94\xf4Hq\x01f\xd9Y\xda\x146|Mah\xcf\x7f\xdcۇ\xda#ʯ\x8bw\xc7M\x98\x19\xac\x9b\x9cS/˸\xa6\x9b\x7f\x12\xbe\x91ɺ\xf1\x16k\x16\xcf>u[^Ж\x8agH~\xc16\xa2\xb0@N\xd5\x14\xa2l\x06\xe7NI\xa0T\v\xcch\x87\xddf\xdb\x0f\xcd\xc6[B\x8b\x01\xad\x86\x00\x9c\x83\x1e\xa2\x1c\xe2A\x02Hָ\x16\xb4\xe3,܊\xb9YR$\xd9\xfdB\xae\xe0\xbb\xcf\xef\xe3\xb1g\xb7$J\xeaޠ\x12&\xad+\xef\x06\x8eQ\x17W\x1f\xaa\x84_\xc8_k\x02A\xb7\x0fq\xc18{\x80\x9ds\xb1\xb8d\xc87\x1e*'\xa2\xa0\x81\xd2)HS<\xc0\x8e@\x8d\xe7G\x8c\x979\xd2\xe2\xca\x03\x8cl\x99\xc6J\x8f\xae\x88\x9f߈rt\xc3\x0fD\x98\x94\xd9Ԗ\x86\xa8~\xfa\x8cd'\xc4\xcb\f\xbd\x14J\xe0ˑ\xc3N\x16\xa7n_\xfd\x8c\xa2\a\xd8\xfd\xc68^\xe3,\xdb\nڱ\xe3\xb4z\xa36\xb3\x18\xee\xca\x1d/D\xdet\xe6\xe6\xd5J^\xb0\xcf\xca\xe2?\x1f\xbe\t\x83\x1d˜\xbdW`>+K_^\x94\xcan\x10\xafA\xe3\xb0\v\x88\x03t\x96\x04\x89\xd8ͼq\xb6\x14\x05\xb5\xe1\x870l%1$s$\x9a\xd1\x1d%Z\xb9.]gemh\x9fZ*\xb9p\xcbbc\xbdy\x1e(\xddc\xc1I:\xf6\x9dޢ1r\xbf\xb8\x94\xaf\x82g\x90\x87\xad:\xcaE\xe2\x16\xeeE6\xa3\xcf\x12\xf4=\xb0\n\xcdB\xba\xb4\xccP\xd4~d\xf3\xc5+\xdds\xe8\x96o\x8b\x87z\rZ\x82\x05\xb3@\xb3\xb6\xf0P\xac*\x13\xe9\xe2m\xc2H\xc2\xceXY\xe0\\O\xac\x19\xa4%\xa9z$\x9d\xe9p\xf5Tb=\x93L\xe4E\x90ە$\x05ݬ\xe0y\xd6k\xa6\xdc\x1c\xa3b:cq.@\xc9ik\xedoh\xe9i6\xfe\x9dU\\h\xb3d\xef(-\xba\x80\xdeo~a\xb2\x03&\xb1ۊV\xd9\x7f\xa9\xc5#/\xd0\xff@\x03!\x19\x14\xce\x1bQ\x9b=_\xed\x82=m\x95qnC\xb3iw\xfe\x00;\xb7\xb3\x9c\xd4mWa\x9d\xaf\xe4\xb9\xf3e\xf6\x14O\xe3\xf8(Y\xec\xd89\xfdv\xfe\\\xf7n\x86DϨ\xda\x13\xe5\x92W\xe9\x92LI\xc7s\x02\r\fփC\x84\x8d\x9b\xec[\f\x10\xa6(\x90,ʕ2\x91\xa4\x91\bZ\t\x82~\xad\x8cu\xeb\x90=\x7f\x7ft\xa1R\x85\xc5I\xc67\x1643V\xe9\x90ϊ\x8a?e)\xbe[n\xb7`\xc0\xefC\xf9EO\a\x18\xa3\xd8\xf3V78\xabr\xee\xf6¨#\x9e\x91\xf7Dm+\xad20Ѽ\x88\xb6$ڦ\x91\xec\xa5.\x1d\x9au]\ue8bfM\x92\xd6NY\x94\x0ee\x9e#\x8f\xa4;\"2\xfa\xf0\xad\xb3D\x8d\xda\x05\xffN\x91\xd6cpdt\x10\xa6,\xf90\x97:\x19\xdd+\xd7:\xcc1\x0f̅[\xfa\xbe&\x9d3\xc7\xebhD\xf9\x1f͵)\x85\\QG\xec\xed\v\xbaC^\x8b\xc7Ҥ\xc6\xca\xf1N\xfaU\xe8\xac\xe5^\xf3\xc1'$*\xda\xf8\xd1\xd0c\xee\xfe\x9e\by\xd7R\xd9\xce2\xceL'\xbaR\xf9o\f\xdb\bml\x17\rs \xb1j\x14\xd4\x11\xa1\xa7\xfc\xa0\xf5ё\xe7\x17\xd7z\x90B\xe9\xb2\xce\xe7\xc4ہ\xa4[\xfe\b>\xed\x17d\xa6jIKa\xa8\a\xb0\x9b\x19\x10\x1dk\x9c\x15H\xb4w\x9d\xc6\xd1Ḻ\xb2 I\x12rrݬ\xdb\xe4#\x17i\xebV\xec8\xb6\xdaC\xb9\x9cc\xe5\xf8y\x14\x12=\xbbg\x11J\xfeM\x94u\xc9x\x89<$\xb7C\x94\xd0\x1cGp\xecn\xd2?\xb1\x05\x19-\xabp\x96U\x05X\xf0\xe9\x9b3\xf0Ȕ4\"\x87\xc6\xf4{\x11P\x92q\xb6ᢨ\xf5\f\xad:\x9b\xe4s\x830\xafMN\x1fY\xa5#\xb2 \x12%\xae\xb3\xcf\xf0\x82\xa75~\xa5\xe7\xf9\xb1)\x0e\xa3\x86\xf9\xfeb\xa5\x85r')N\xef2\xfa\xf4c.w?|\xc6\x1f>\xe3\x0f\x9fqNG?|Ɖ\xf2\xc3g\xfc\xe13\x1e.?|Ɣ\xf2\xc3g\x9c\x89\xc8\xf7\xf2\x19S0\\\xd0\x1a\xe7\x81\nIX%\xa6BL\xa1=їO\xfa\xf1g5N\x92˼\x1a\a9r\x88'r\xfc\"\xe6u\xb4ƫIn\xc6\x19\x18\xe6\x8e;\x82\x9a\xe00\x9f\xe0\xf4L@\xe0\xf4\xa7gV\a!\x9f\xf0\xf4\x8c\x1fBZ\x84q\xd4ٙ@\xa4\xf9\xa7'.|\x12Q\t\xaaA\xfe\x83mU\x1d9\xb51Aڄ,\xda4\x82\xf4\x92j}b\x04X\xfe\xf8v\xd9\xff\xc5*\x9fbK77D\x80\xd1e\x1e<\xa7\x1b\x1c:\az\xbc\x1e\b\xf7L\r\x852\x02Li&E\xe1$6@\xe8\xc9+\xfbR\xb9\xd5\xc1\xa3\xfd\xa6\xe95\xac\xf4Dܹ\xe9\xb7M\xb6\xe4\xb4\xfb\xfe\x8c\xa4ۓ\x1e\x8d\xfani\xb5\xc7%Ӧ\xaeP&$Φ\xa7˦\xb0Օ\xf4$\xd9\xe4\b95!v\xee\nċ&\xbf\xbeL\xcak2\xcd\xd2\xd2[\xe7R\xecURY_9\x81\xf5\xf5\xd2Vg$\xab\x9e\xfe\xd4K\xfaZ\xfa\xd1ٕi\xcb2\x87\x13N\x93\xd2L\x93\x96nR\x06|\xd4P\x93\xd2G\xe7&\x8d&q2}\xba\xbejZ\xe8\xab&\x83\xbe~\n褴MV\x98\x9b\xe49~Cd(\xd3\x0e\xc0\xde\x05ϣ\x95^BBg\xad\x97\x1e\x9c\xc0\xc5\xf7\x98`\xcfe\xb5ҽ\xf0\xe2Y\xb1\xf3\x97\x01,\x14\xf8\xe0j\xbfb,Sօ\x15U\xd1^\xc8\x17\v\x9a\xb7\xb0k.\\\xfaY\xd11\x7f\x7f\xebؗ\xafͬ]\x0e\"3n\xd8\x13\x14\x05\xe31\xfd\xb2G\x85\xcc]\x04\x9b\xa9\x05\xa0}GM\xe5/\x94\xf2\xb7\xc7^\xb8)O7\x1a\x90\x97PƖ+\xb9<|[\xd9A#\x9c\xaa\x8b\xf7\xa2\v\x173ѷ_j\xd0;Fw\xa75\xfee{0\xd6++\x83\xc1uP\xa1^\xa5\x1f\xda\xf7\xd9\v\xd2Z\x15\xc7\xdeI\xe7\xd5\fq\xa26\xa8;۠\x14\r\x83\x8c]4\xc8\xc2\x04\xdd\a!U\x03!\xd24%\x80\x99sR\xf4%B\xd4S\x04\xa9I^\xdc<\x0f\xfc;\x9e\x00=\xf6\xe4gzBM\xd2Iϗ\bY\xe7\x04\xad\xb3|\xee\xf4\x93\x9c\xf37\xcf_\xf8\xe4\xe6K\x9d\u061cA\xbd\xd4\x13\x9a\xf3i\xf7J'2_\xfd$\xe6k\x9e\xc0\x9cu\xf229\xc5lV\xd6Ĝ\xf4\xb0g\x1c\x19Lˇ\x98>I\x99x\x8221[\"m\xf0G\x0e;\xf1\x84\xe4\xfc\x93\x91\x89\xfc\x9d3\xa5_\xf9\x04\xe4+\x9f|\xfc\x1e'\x1e\x13$0\xa1\xca\xfc\x93\x8d\xcf\xdeVS:\a=\xb9u9Gj'\xe555\x96\xeb#6؛\v7\xe2b\xad^\f@fɿ\xe4@\xafv\x1c\xda\xcaG\xc9\xecxD\xbd\xbd\xd5\xd6]\xeb;\xc4\xfe9\x0f\xb7\xfdj\xa0\xe2h\x00(p\xa3\xf4\xb2\xa8\xab\xf0\x81g\xdbA\x0f[n\xd8F\xe9\x92[v\xdelx\xbfq\x1d\xe0\xdf\xe7K\xc6>\xaa&ߨ{\xe7\x9b\x11eU\xec0\x12c\xe7\xdd\x06ϓ\x92\xa8t\x86\x9e\xafU!\xb2\x88\xcf9z7\xa0k\xb0wa\x12\xdd^\x98u2^b\x81\x0f6\x17\xe1\xe6\xc8\xfe\xb5\xd2\xeeB\xffc\xd7{*\xf1'zo\xeb\x04+\x87\xef\xaeW\x04+\x88\x11=\xe4\xd5$Y6,_\x03\xba\f\xed\xd8\x0f\xe9\x93զ\a\xb5\x9f\xe7\xdc}\xad\x04r\xf74Mp[\xbcj\xce\x14j\xad\xeb\x95\xc3\xe5PO(_\\\xee\x98\xf2o\x8f\b\x9d/*\xae\xed\xce%D]\xf4\xf0\bv}j\xe5\uf835\xda\x7fz\xa7[zd\x0f\xaf\xee\xd0n\xfc\xae\xea'@\f\xe9\xf9\x1c\x9c\x0e\x9f\f\x9f<\x13\xfe\x028\x1dv\xa1\x16D\xc5\xc8O\xd1,Γ\xaf\xba\x1a\xff\xda\xc0_\xd4#\xbc\x8f\xae\xbe\xf6\x9f\xdf\x194\x19I\xaf\fP\xe9\xa2\xfc\b\x05ۜJ\xba\xa7\xfcyj/\x9e/\x19P\xf1\xf7\x9c?gq\xf2\xa6\x0fj\xfcE\x1a\xba\x05>t\x1a\xf3\xaa譯\x1d\xbb\xbe\xa3\xb8\xb5Q\xa5~\xea\xfb\xb85,O\x86$\x89\b,!\x0f>\xd2s*2Z\xa5\xf9=|R\xeeq\xa5\x141\xe9\xb7\xe8=\xbd\xe5=\xb7\x90s\xee'aL\xd1\xfb\xb1\r\x01\xb6gL\xf6\x1e+@l\x8f|\x8e\xc1\xda\xe292r{\xfbɍ\x94\u07b4y\uf7e7A}l\x00Y\x10(࠭\xf1\xbf[\xf5D\x97\xf8\xc7ט\xc3\v2\x9dG\xec\x80\x0e\xbbP\x1a\xf2Qì\xabB\xf1\x1c\xf4\x15\xbd\xa2\x930\xe2\x9fz\r\x06\xee@\xff-\x1eo7#\xe3\t=\xbf`\xa6\x0fztE\x01\xc5GQ\x80q\x88'\x9a\x86\xeb\xfd\x96\x8d\xa5\xa8˵\xf3T7\xf8c\xd3\xc9\x01\xcb\xec\x86J\x1b\f\x15h\xf4\x13\xddVDm\x82\xe4\x1f&\x06k\xf8(\xa4\x85{\x18\x8f\xa1'l\x82{g\x82\x1c\x80\xa0\xc0(\xe2\xfbsl\xe5\xb1G\x90\xbbx\xeb\x81\f4\x8b\x9119Vޭ\xba\xbe\xbb2\xac\x969m\x00\xdc\xfd\xe9\xe6(\xf9}콕\x13tB\x8az\xbf\x1bo\xd9\t\x11:ډ|\xfa\xb8\x12\x8f\xc1\xe2ƨLPTA\x8f#\xd1i\xaa\x97\xbb\a\xfdP\x80x@:j\x03_\x9e$\xe8\xaf\xc1\x02\x99\x95\x8c\xbd=3\xad\xfd~ڃ\x16}s\xc6*\xec{\x04\xc6\x00\x00Sa\x9f˸W\x8d\xc2\xf6\x9a0\xcd\xebv\xfb\xf4\x9cP!qK7\xee\xb0-\xc6\x1f\xe3Z4\x8f\x86\x9d%\x90۽\xe5\xd4\a<\xfe\xa6\xa1{\xf4)㕭uЮ\xb5\xa6\x9b\xe2\x11\b\xb8\x8bԏ{հ}\xec\xee\x18\x06\xb7\xaf͵\xfb\x0f\x93\xef\xe1\x8e\xc0i\xde%\x8c>r\xe6\"j\xf7^\xed\x02\xe1\x1f\xc7\xe3\xd1\x19\x838߸\xc7\xeb&\x88\xf0\xa9\xad96\xe0f\x188d\xff\x1cޫ\x8e\x84\x1e\x0e\x98\x18\xc35\xd6iN\xeaz9\xa2\x86\xe1\xc1\x81\x9b\x18\x13Əs.\xd8g؏\xd8\x17\xec\x83\xc4A\xec\x13\xc0\x9dل\x9c\xb6VH;\xce\x19\xe2cӊ\x0e̎h\xc8i\xb1\xbd\x1b\xc0\x18d\xe3\xd3\xc3UM\x15wbְߊ1o\x94v\xcc2\x1c\xe8\xef\xf6~\x8dj\xf0\x83\xda;\xa6\xb9G\xd5\xc8\xdeGz\t1\xefH\x8e\xf7һ_\xeau\xfb(\x04\xfb\xdb\xdf\xcf\xfe?\x00\x00\xff\xff\xeaC\x1a-[}\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcV\xcfo+5\x10\xbe\xe7\xaf\x18\x89+\xbb\xa1B \x94\x1b*\x1c*\xe0\xa9j\x9ezw\xbc\x93d\xa8\xd7^f\xc6)A\xfc\xf1\xc8\xf6n\x9b\xee:\xb4\x8f\x03\xbe\xad\xed\xf9\xe6\x9bo~x\x9b\xa6Y\x99\x81\x1e\x91\x85\x82߀\x19\b\xffT\xf4\xe9Kڧ\x1f\xa4\xa5\xb0>ݬ\x9e\xc8w\x1b\xb8\x8d\xa2\xa1\x7f@\t\x91-\xfe\x84{\xf2\xa4\x14\xfc\xaaG5\x9dQ\xb3Y\x01\x18\uf0da\xb4-\xe9\x13\xc0\x06\xaf\x1c\x9cCn\x0e\xe8ۧ\xb8\xc3]$\xd7!g\xf0\xc9\xf5\xe9\x9b\xf6\xe6\xfb\xf6\xbb\x15\x807=n@\x90ә\x1a\x8d\xc2\xf8GDQiO\xe8\x90CKa%\x03ڄ\x7f\xe0\x10\x87\r\xbc\x1e\x14\xfb\xd1w\xe1\xbd\xcdP\xdb\f\xf5P\xa0\xf2\xa9#\xd1_\xae\xdd\xf8\x95\xc6[\x83\x8bl\\\x9dP\xbe \xc7\xc0\xfa\xe9\xd5i\x03\"\\N\xc8\x1f\xa23\\5^\x01\x88\r\x03n \xdb\x0e\xc6b\xb7\x02\x18\x05\xc9Xͨ\xc5\xe9\xa6\xc0\xd9#\xf6\xa68\x01\b\x03\xfa\x1f\xef\xef\x1e\xbfݾ\xd9\x06\xe8P,ӠYֿ\x9b\x97}\xa8\x85\t$``\xa4\x04\x1a\xc0X\x8b\"`#3z\x85B\x19\xc8\xef\x03\xf79\xad`v!\xea\x05\xaa\x1e\x11\x1e\xb3\xfec\x98\xed\xcb\xe1\xc0a@V\x9a\xa4)\xeb\xa2\xe2.v\xff\x8dxZ)\xd6b\x05]*=\x94\xecy\xd4\v\xbbQ\x1e\b{\xd0#\t0\x0e\x8c\x82\xbe\x14c\xda6\x1e\xc2\xeew\xb4\xdaΠ\x8b.\x922\x19]\x97*\xf6\x84\xac\xc0h\xc3\xc1\xd3_/ؒ\x04JN\x9dѬ\x9dWdo\x1c\x9c\x8c\x8b\xf85\x18\xdf͐{s\x06\xc6\xe4\x13\xa2\xbf\xc0\xcb\x062\xe7\xf1[`\xccRo\xe0\xa8:\xc8f\xbd>\x90N}hC\xdfGOz^疢]\xd4\xc0\xb2\xee\xf0\x84n-th\f\xdb#)Z\x8d\x8ck3P\x93\x03\xf1\xb9\x17۾\xfb\x8a\xc7Ε7n\xf5\x9cjP\x94\xc9\x1f.\x0er\xeb|AzR#\x95b*P%\xc4\xd7,\xa4\xad$\xdd\xc3\xcf\xdb\xcf01)\x99*Iy\xbd\xba\xd0e\xcaOR\x93\xfc\x1e\xb9\xd8\xed9\xf4\x19\x13}7\x04\xf2\x9a?\xac\xa3\\\xb8qד\xcaT\xda)us\xd8\xdb<\xab`\x87\x10\x87\xce(v\xf3\vw\x1enM\x8f\xee\xd6\b\xfeϹJY\x91&%\xe1Cٺ\x9c\xc0\xf3\xcbEދ\x83iv^ImeJl\a\xb4)\xb9I\xdfdM{\xb2\xa5\xad\xf6\x81\xc1\xd4L\xda\x0f1\xc9\x16_\xc8e\x9cH\x85\xcdlN\xa5.\x7f\x9fM},哣\x11\x9co\xce8ݧ;s\xff\x8e\xf6h\xcf\xd6a\x81(S\bߧ\x92\x16\xfa\xd8/}6\xf0\t\x9f+\xbb\xf7\x1c҄\xc6\xf9\xa8\xb9Z\x1bP\x1e\xb1\x03\xf9E\xb8\xf3\xc8ʭ\xfc0.G~\x0eh\x04\x02\x8eާ\x96\x0e~\x01Yy\x11\x16wH\xb1\xaf\xb0\xa9\xf2\xb9\xf3\xfb\x90\xff\"Lrl\xb4\xb4\x13\x8e\xc9\x1e\xfd\x14^\x15\xc0\xeb\xb9.k9\xe7>$hY\xf9y\xfeo\xc6i.\x11c\xd5w\x93YU\x0f\x92ǚ\xe2\xf5\xfe\x1aYF\xe7\xcc\xce\xe1\x06\x94\xe3Һ\xd8\x1afs\x9eW\xcdTj\x9f\xa9GQ\xd3\x0f\xef\x14\xd0\xe2UH\xeb~\x81\x92\x9a\xe7\xf9\x88\xfeZ\x8b\xc0\xb3\x91W\xe7\x15\xc8\xdd\xf9\x9a\xe9\xed\xcb\xdf\xe6\xb2\xcfJ=o \xcd\xfaF\xa9\"䇔\xaa\xa6\xb4\xd4y\xf5\xb7f\xa1\xd2\xf6\xf2\xee4H\xde\xf4\xcb\xf4W\xb3\x8c\xe1*\x85j\x05,63|w\x11\x9eh`s\x98\x02\xfe'\x00\x00\xff\xff\xef\xf8\xa6>\x10\f\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVM\x8f\xdb6\x10\xbd\xfbW\f\x92kd7(Z\x14\xbe\x05\xdb\x1e\x82&\xc5\"N\xf7N\x93#{j\x8ad\x87C9.\xfa\xe3\v\x92Ү-\xcb\xc9nQT\x17\xc3\xe4\xf0q>\u07bca\xd34\v\x15\xe8\x019\x92wkP\x81\xf0\x8b\xa0\xcb\xff\xe2\xf2\xf0S\\\x92_\xf5o\x17\arf\rw)\x8a\xef>a\xf4\x895\xfe\x8c-9\x12\xf2nѡ(\xa3D\xad\x17\x00\xca9/*/\xc7\xfc\x17@{'\xec\xadEnv薇\xb4\xc5m\"k\x90\v\xf8xu\xff\xdd\xf2\xed\x8f\xcb\x1f\x16\x00Nu\xb8\x86\xde\xdb\xd4at*Ľ\x17\xebu\xc5\\\xf6h\x91\xfd\x92\xfc\"\x06\xd4\xf9\x8a\x1d\xfb\x14\xd6\xf0\xb4Q!\x86\xeb\xab\xeb\x0f\x05m3\xa0}\x18Њ\x81\xa5(\xbf~\xc5\xe8\x03E)\x86\xc1&V\xf6\xa6g\xc5&\xee=\xcboO\xb77\xd0G[w\xc8\xed\x92U|\xeb\xfc\x02 j\x1fp\r\xe5xP\x1a\xcd\x02`\xc8O\x81k\xc6Լ\xad\x88z\x8f\x9d\xaa\xf7\x00\xf8\x80\xee\xdd\xfd\xfb\x87\xef7\x17\xcb\x00\x06\xa3f\nR\xb2<\x1f\"P\x04\x05\xa3'p\xdc##<\x94|B\x14\xcf\x18\a\xa7\x1fA\x01F\xff\xe3\xf2q1\xb0\x0f\xc8Bc\xf0\xf5;\xe3\xd7\xd9\xeaį\xbf\x9b\x8b=\x80\x1cJ=\x05&\x13\r#\xc8\x1e\xc7t\xa0\x19\xa2\a߂\xec)\x02c`\x8c\xe8*\xf5\xf2\xb2r\xe0\xb7\x7f\xa0\x96\xe5\x04z\x83\x9car\xad\x925\x99\x9f=\xb2\x00\xa3\xf6;G\x7f=bG\x10_.\xb5J0\n\x90\x13d\xa7,\xf4\xca&|\x03ʙ\tr\xa7N\xc0\x98\xef\x84\xe4\xce\xf0ʁ8\xf5\xe3\xa3g\x04r\xad_\xc3^$\xc4\xf5j\xb5#\x19\xbbN\xfb\xaeK\x8e\xe4\xb4*\rD\xdb$\x9e\xe3\xca`\x8fv\x15i\xd7(\xd6{\x12Ԓ\x18W*PS\x02q\xb5K:\xf3\x9a\x87>\x8d\x17\xd7\xca)S,\n\x93\u06ddm\x94.yAyr\xc3T\xd6T\xa8\x1a\xe2S\x15\xf2RNݧ_6\x9fa\xf4\xa4V\xaa\x16\xe5\xc9\xf4*/c}r6ɵ\xc8\xf5\\˾+\x98\xe8L\xf0\xe4\xa4\xfcі\xd0\tĴ\xedH2\r\xfeL\x18%\x97n\n{W\x94\t\xb6\b)\x18%h\xa6\x06\xef\x1dܩ\x0e흊\xf8?\xd7*W%6\xb9\bϪֹ\xdeN\x8dkz\xcf\x1bu\x90\xc9\x1b\xa5\x9dW\x84M@}\xd1x\x19\x85Z\x1a\x14\xa2\xf5i\x8b\x15\x10|;ý\x17\xb9\x9c?t\xa9\x9b#\xe2\xbb^\x91U[{-\t\r\xfc\xee\xd4\xcdݛş\xad\xe7\xd5b̏=\xb3\x06\xe1T\xb1\a\x96\r+\xff\x04\x00\x00\xff\xffNy\xc1Q\xa1\x0e\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWM\x8f\xdb8\x12\xbd\xfbW\x14\x92k$o\xb0\xd8\xc5·F\xef\x1c\x82I\x06\x8d\xb8\xa7\xef4Y\xb2\x19S\xa4\xa6\xaa(\xc7\xf3\xf1\xdf\a$%\xb7-\xcb\xe9\xf4`0\xbat\x8b\"\x1f\xeb\xe3իrUU\v\xd5\xd9'$\xb6\xc1\xaf@u\x16\xbf\n\xfa\xf4\xc6\xf5\xfe\x7f\\۰\xec\xdf/\xf6֛\x15\xdcG\x96\xd0~F\x0e\x914\xfe\x1f\x1b\xeb\xad\xd8\xe0\x17-\x8a2J\xd4j\x01\xa0\xbc\x0f\xa2\xd22\xa7W\x00\x1d\xbcPp\x0e\xa9ڢ\xaf\xf7q\x83\x9bh\x9dA\xca\xe0\xe3\xd5\xfd\xbf\xea\xf7\xff\xad\xff\xb3\x00\xf0\xaa\xc5\x15\xf4\xc1\xc5\x16٫\x8ewA\\\xd0\x05\xb3\xee\xd1!\x85چ\x05w\xa8\xd3\x15[\n\xb1[\xc1\xf3\x87\x021\\_L\x7f\xcah\xeb\x01\xed〖78\xcb\xf2\xe376}\xb4,yc\xe7\")wӲ\xbc\x87w\x81\xe4\xa7\xe7\xdb+\xe8ٕ/\xd6o\xa3St\xeb\xfc\x02\x80u\xe8p\x05\xf9x\xa74\x9a\x05\xc0\x10\x9f\fW\x812&G\\\xb9\a\xb2^\x90\xee\x13\x96?]f\x905\xd9NrD\x1f(\xf4\xd6 \x81e\x90\x1dB7\xbe\x87&\xbf\x17;\x80%\x90\xdabF\x00\xf8\xc2\xc1?(٭\xa0N\xf1\xad\xc7C\xc3璛\x87\xcbE9&\xb3Y\xc8\xfa\xed\x9c!%\xae0\x06\x16\xc6\xc8\x02\x8b\x92\xc8\xc0Q\xef@1\xdc\xf5\xca:\xb5q\xb8\xfc٫\xf1\xff\x19\xbb\xf2\xa9\xba\xdb)\xc6K\xb3\xceVfl:\x83\x18\t[k\xc2lʣm\x91E\xb5\xdd\x05\xe0\xdd\xf6\x12\xce()\v\x03Eߗ\xcc\xea\x1d\xb6j5\xec\f\x1d\xfa\xbb\x87\x0fO\xff^_,\xc3\\H\xa6TK\x99R02\x02\x0e;$\x84\xa7\xcc\xeb\x9c&\xe4!i'P\x80\x91G\\\x9f\x16;\n\x1d\x92ؑ\x84\xe59\xab\xf3\xb3Չ]\xbfW\x17\xdf\x00\x92+\xe5\x14\x98T\xf0X\xb84\xd0\x12\xcd\xe0}\xe1\x94e \xec\b\x19}\x91\x80\xb4\xac<\x84\xcd\x17\xd4RO\xa0\xd7H\t&\xd5Lt&\xe9D\x8f$@\xa8\xc3\xd6\xdb_O\xd8\f\x12\xf2\xa5N\t\xb2@&\xbeW\x0ez\xe5\"\xbe\x03\xe5\xcd\x04\xb9UG LwB\xf4gx\xf9\x00O\xed\xf8\x14\b\xc1\xfa&\xac`'\xd2\xf1j\xb9\xdcZ\x19\xd5O\x87\xb6\x8d\xde\xcaq\x99\x85\xccn\xa2\x04\xe2\xa5\xc1\x1eݒ\xed\xb6R\xa4wVPK$\\\xaa\xceV\xd9\x11_Ԫ5oi\xd0K\xbe\xb8\xf6\x8a\x9f\xe5\xc9j\xf5\x8a\xf4$\xe1*\xac)P\xc5\xc5\xe7,\xa4\xa5\x14\xba\xcf?\xac\x1fa\xb4\xa4d\xaa$\xe5y\xebU\\\xc6\xfc\xa4hZ\xdf \x95s\r\x856c\xa27]\xb0^\xf2\x8bv\x16\xbd\x00\xc7Mk%\xd1\xe0\x97\x88,)uS\xd8\xfb\xdc!`\x83\x10\xbbTPf\xbaჇ{բ\xbbW\x8c\xffp\xaeRV\xb8JI\xf8\xael\x9d\xf7\xbd\xe9\xe6\x12\xde\xf3B\x1d\xdaՍ\xd4\xce+ºC}Qx\t\xc56vP\x88&\xd0$@jԋy\xbc\xcbx\xce\v\x05\x94\xa6\xdd\xd8\xedt\x15.\x1aЭ\xb3\xdf\b،\xdf\xf7\xf9\xa6\xc4\xe1&ЩGU\xa3\x9f\x83%\x91\x06\x87-:s\xc5ԛ1Ϯ\x10\x9a\x94b\xe5\xae\r\xbd\xb4\xe4\xb41\xcf,\xca\xfa\x12\xf2g\x80\xcc\x7fC\xfe%1\xa6\xc1\xd9\x06\xf5Q;,\x80\x10\x9a\x19\xee\xbd\xca\xe4\xf4\xa0\x8f\xed\x1c\x11\xef&?|ο]\xff,\x9a\xa6m&\xf9\xb3\xf9\xbcZ\xe44\xec\x99\x15\bł=\xb0\xec|%nN\xb3\xec\n~\xfbc\xf1g\x00\x00\x00\xff\xff+\xf2\xd32>\x10\x00\x00"), } var CRDs = crds() diff --git a/pkg/apis/velero/v1/volume_snapshot_location_type.go b/pkg/apis/velero/v1/volume_snapshot_location_type.go index 836701b77..1ff363a46 100644 --- a/pkg/apis/velero/v1/volume_snapshot_location_type.go +++ b/pkg/apis/velero/v1/volume_snapshot_location_type.go @@ -27,6 +27,9 @@ import ( // +kubebuilder:resource:shortName=vsl // +kubebuilder:object:generate=true // +kubebuilder:storageversion +// +kubebuilder:printcolumn:name="Provider",type="string",JSONPath=".spec.provider",description="Provider is the provider of the volume storage" +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",description="Volume Snapshot Location status such as Available/Unavailable" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // VolumeSnapshotLocation is a location where Velero stores volume snapshots. type VolumeSnapshotLocation struct { From 57da5e5f051ab3a3b341895d43ec36ed8b2b8259 Mon Sep 17 00:00:00 2001 From: Jay Sawant Date: Tue, 11 Aug 2026 17:32:47 +0530 Subject: [PATCH 31/45] docs: fix grammar and typos in backup-restore-windows (#10228) Signed-off-by: Jay2006sawant --- .../docs/main/backup-restore-windows.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/site/content/docs/main/backup-restore-windows.md b/site/content/docs/main/backup-restore-windows.md index 9d700f472..b0b8ef1ae 100644 --- a/site/content/docs/main/backup-restore-windows.md +++ b/site/content/docs/main/backup-restore-windows.md @@ -17,38 +17,38 @@ For volume backups, CSI and CSI snapshot should be supported by the storage. As mentioned in [Image building][2], a hybrid image is provided for all platforms, so you don't need to set different images for linux and Windows clusters, you can always use the all-in-one image, e.g., `velero/velero:v1.16.0` or `velero/velero:main`. In order to backup/restore volumes for stateful workloads, Velero node-agent needs to run in the Windows nodes. Velero provides a dedicated daemonset for Windows nodes, called `node-agent-windows`. -Therefore, in a typical cluster with linux and Windows nodes, there are two daemonsets for Velero node-agent, the existing `node-agent` deamonset for linux nodes, and the `node-agent-windows` daemonset for Windows nodes. -If you want to install `node-agent` deamonset, specify `--use-node-agent` parameter in `velero install` command; and if you want to install `node-agent-windows` daemonset, specify `--use-node-agent-windows` parameter. +Therefore, in a typical cluster with linux and Windows nodes, there are two daemonsets for Velero node-agent, the existing `node-agent` daemonset for linux nodes, and the `node-agent-windows` daemonset for Windows nodes. +If you want to install `node-agent` daemonset, specify `--use-node-agent` parameter in `velero install` command; and if you want to install `node-agent-windows` daemonset, specify `--use-node-agent-windows` parameter. ## Resource backup restore -Resource backup/restore for Windows workloads are done by Velero server as same as linux workloads. +Resource backup/restore for Windows workloads is done by the Velero server the same as for linux workloads. -Since Velero server is running in linux nodes only, all the existing plugins, i.e., BIA, RIA, BackupStore plugins, could be started by Velero in a cluster with Windows nodes. However, whether or how the plugins are functional to Windows workloads are decided by the plugins themselves. -It is recommended that plugin providers do a well round test with Velero in Windows cluster environments, and: +Since Velero server is running in linux nodes only, all the existing plugins, i.e., BIA, RIA, BackupStore plugins, could be started by Velero in a cluster with Windows nodes. However, whether or how the plugins are functional for Windows workloads is decided by the plugins themselves. +It is recommended that plugin providers do a thorough test with Velero in Windows cluster environments, and: - If they need to support Windows workloads, make the necessary modification to ensure their plugins work well with Windows workloads - If they don't want to support Windows workloads, or part of the Windows workloads, they need to ensure the plugins won't cause any failure or crash when they process the undesired Windows workload items ## Volume backup restore -Below are the status of supportive of Windows workload volumes for different backup methods: -- CSI snapshot data movement: block volumes (i.e., vSphere CNS Block Volume, Azure Disk, AWS EBS, GCP Persistent Disk, etc.) are full supported; file volumes (i.e., vSphere CNS File Volume, Azure File, AWS EFS, GCP Filestore, etc.) are not tested or officially supported. This is the same with linux workloads -- CSI snapshot backup: block volumes (i.e., vSphere CNS Block Volume, Azure Disk, AWS EBS, GCP Persistent Disk, etc.) are full supported; file volumes (i.e., vSphere CNS File Volume, Azure File, AWS EFS, GCP Filestore, etc.) are not tested or officially supported. This is the same with linux workloads -- native snapshot backup: supported as same as linux workloads +Below is the support status for Windows workload volumes for different backup methods: +- CSI snapshot data movement: block volumes (i.e., vSphere CNS Block Volume, Azure Disk, AWS EBS, GCP Persistent Disk, etc.) are fully supported; file volumes (i.e., vSphere CNS File Volume, Azure File, AWS EFS, GCP Filestore, etc.) are not tested or officially supported. This is the same for linux workloads +- CSI snapshot backup: block volumes (i.e., vSphere CNS Block Volume, Azure Disk, AWS EBS, GCP Persistent Disk, etc.) are fully supported; file volumes (i.e., vSphere CNS File Volume, Azure File, AWS EFS, GCP Filestore, etc.) are not tested or officially supported. This is the same for linux workloads +- native snapshot backup: supported the same as for linux workloads - file system backup: at present, NOT supported -For volume backups/restores conducted through Velero plugins, the supportive status is decided by the plugin themselves. +For volume backups/restores conducted through Velero plugins, the support status is decided by the plugins themselves. ### CSI snapshot data movement During backup, Velero automatically identifies the OS type of the workload and schedules data mover pods to the right nodes. Specifically, for a linux workload, linux nodes in the cluster will be used; for a Windows workload, Windows nodes in the cluster will be used. You could view the OS type that a data mover pod is running with from the DataUpload status's `nodeOS` field. -Velero takes several measures to deduce the OS type for volumes of workloads, from PVCs, VolumeAttach CRs, nodes and storage classes. If Velero fails to deduce the OS type, it fallbacks to linux, then the data mover pods will be scheduled to linux nodes. As a result, the data mover pods may not be able to start and the corresponding DataUploads will be cancelled because of timeout, so the backup will be partially failed. +Velero takes several measures to deduce the OS type for volumes of workloads, from PVCs, VolumeAttach CRs, nodes and storage classes. If Velero fails to deduce the OS type, it falls back to linux, then the data mover pods will be scheduled to linux nodes. As a result, the data mover pods may not be able to start and the corresponding DataUploads will be cancelled because of timeout, so the backup will be partially failed. Therefore, it is highly recommended you provide a dedicated storage class for Windows workloads volumes, and set `csi.storage.k8s.io/fstype` correctly. E.g., for linux workload volumes, set `csi.storage.k8s.io/fstype=ext4`; for Windows workload volumes set `csi.storage.k8s.io/fstype=ntfs`. Specifically, if you have X number of storage classes for linux workloads, you need to create another X number of storage classes for Windows workloads. -This is helpful for Velero to deduce the right OS type successfully all the time, especially when you are backing up below kind of volumes belonging to a Windows workload: +This is helpful for Velero to deduce the right OS type successfully all the time, especially when you are backing up the following kinds of volumes belonging to a Windows workload: - The PVC is with Immediate mode - There is no pod mounting the PVC at the time of backup From 48f2095dc9f704edf05d2798d34c743838e03402 Mon Sep 17 00:00:00 2001 From: Ralthos <161431341+Ralthos@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:14:02 +0530 Subject: [PATCH 32/45] Site: document artifact download failures with an in-cluster s3Url (#10231) troubleshooting.md covers SignatureDoesNotMatch but not the other way a log or results download fails: the pre-signed URL carries the s3Url host, which for an in-cluster Service name does not resolve on the client. The backup or restore itself is unaffected, which makes the error easy to misread. The fix, publicUrl, is documented only under exposing Minio, so this links there instead of duplicating it. Signed-off-by: saral --- changelogs/unreleased/10231-Ralthos | 1 + site/content/docs/main/troubleshooting.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 changelogs/unreleased/10231-Ralthos diff --git a/changelogs/unreleased/10231-Ralthos b/changelogs/unreleased/10231-Ralthos new file mode 100644 index 000000000..415cc3d27 --- /dev/null +++ b/changelogs/unreleased/10231-Ralthos @@ -0,0 +1 @@ +Add a troubleshooting entry for artifact downloads failing when the BackupStorageLocation s3Url is only resolvable inside the cluster diff --git a/site/content/docs/main/troubleshooting.md b/site/content/docs/main/troubleshooting.md index dc692771c..df5d71753 100644 --- a/site/content/docs/main/troubleshooting.md +++ b/site/content/docs/main/troubleshooting.md @@ -77,6 +77,19 @@ Here are some things to verify if you receive `SignatureDoesNotMatch` errors: * Make sure your S3-compatible layer is using [signature version 4][5] (such as Ceph RADOS v12.2.7) * For Ceph, try using a native Ceph account for credentials instead of external providers such as OpenStack Keystone +### `velero backup logs` or `velero describe` fails with `no such host` + +Downloading artifacts uses a pre-signed URL built from the `s3Url` in your `BackupStorageLocation`. If that address is only resolvable inside the cluster, such as a Kubernetes Service name, the Velero client cannot fetch the artifact even though the backup or restore itself succeeded: + +``` +Warnings: +``` + +The backup or restore is unaffected. Only the download of its log or results file fails. + +To fix this, give the location a `publicUrl` that your client can reach. See [Expose Minio outside your cluster][26] for the Minio case; the same applies to any object store addressed by an in-cluster name. + ## Velero (or a pod it was backing up) restarted during a backup and the backup is stuck InProgress Velero cannot resume backups that were interrupted. Backups stuck in the `InProgress` phase can be deleted with `kubectl delete backup -n `. @@ -250,3 +263,4 @@ Please refer to [Issue 9007](https://github.com/velero-io/velero/issues/9007) fo [11]: /plugins [12]: https://kubernetes.io/docs/concepts/configuration/secret/#editing-a-secret [25]: https://kubernetes.slack.com/messages/velero +[26]: contributions/minio.md From 3da77b9469381d8caf08b96ffb04b6c3f872d111 Mon Sep 17 00:00:00 2001 From: Shubham Pampattiwar Date: Tue, 11 Aug 2026 08:55:33 -0700 Subject: [PATCH 33/45] Site: add conference talks to resources and LinkedIn to community page (#10180) * site: add conference talks to resources page and LinkedIn to community page Add a Conference Talks section to the resources page with Velero-related talks from KubeCon EU 2026, KubeCon India 2026, KubeCon China 2024, KubeCon EU 2023, and DevConf.IN 2025. Includes YouTube embeds where recordings are available and sched.com links for all talks. Add LinkedIn page link to the community page alongside existing Twitter and Slack links. Signed-off-by: Shubham Pampattiwar * site: add Open Source Summit NA 2022 Velero talk to resources Add the Velero talk by Orlin Vasilev and Scott Seago from Open Source Summit North America 2022 with YouTube embed and sched.com link. Signed-off-by: Shubham Pampattiwar --------- Signed-off-by: Shubham Pampattiwar --- site/content/community/_index.md | 1 + site/content/resources/_index.md | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/site/content/community/_index.md b/site/content/community/_index.md index 043941685..cc1b63818 100644 --- a/site/content/community/_index.md +++ b/site/content/community/_index.md @@ -12,6 +12,7 @@ If you are ready to jump in and test, add code, or help with documentation, foll You can follow the work we do via our [GitHub milestones](https://github.com/velero-io/velero/milestones) and the project [Roadmap](https://github.com/velero-io/velero/wiki/Roadmap). * Follow us on Twitter at [@projectvelero](https://twitter.com/projectvelero) +* Follow us on LinkedIn at [Project Velero](https://www.linkedin.com/company/project-velero) * Join our Kubernetes Slack channel and talk to over 800 other community members: [#velero-users](https://kubernetes.slack.com/messages/velero-users) * Join the Velero community meetings Bi-weekly community meeting alternating every week between Beijing Friendly timezone and EST/Europe Friendly Timezone diff --git a/site/content/resources/_index.md b/site/content/resources/_index.md index 5f05a811a..2a3e6217a 100644 --- a/site/content/resources/_index.md +++ b/site/content/resources/_index.md @@ -3,7 +3,35 @@ title: Resources description: Velero Resources id: resources --- -Here you will find external resources about Velero, such as videos, podcasts, and community articles. +Here you will find external resources about Velero, including conference talks, videos, podcasts, and community articles. + +## Conference Talks + +### KubeCon + CloudNativeCon + +* **KubeCon EU 2026 (Amsterdam)** - [Snapshots Gone Wild: Taming Multi-PVC Chaos with VolumeGroupSnapshot](https://kccnceu2026.sched.com/event/2CW53/snapshots-gone-wild-taming-multi-pvc-chaos-with-volumegroupsnapshot-shubham-pampattiwar-scott-seago-red-hat) - Shubham Pampattiwar & Scott Seago, Red Hat + + {{< youtube pLmRkRO6O6E >}} + +* **KubeCon India 2026 (Mumbai)** - [Sponsored Demo: Cloud Native AI: Model Management with Harbor & Velero](https://kccncind2026.sched.com/event/2OdTx/sponsored-demo-cloud-native-ai-model-management-with-harbor-velero-dhruv-tyagi-broadcom) - Dhruv Tyagi, Broadcom + +* **KubeCon China 2024 (Hong Kong)** - [The Challenges of Kubernetes Data Protection - Real Examples and Solutions with Velero](https://kccncossaidevchn2024.sched.com/event/1eYb8/the-challenges-of-kubernetes-data-protection-real-examples-and-solutions-with-velero-kuberneteszha-velerozha-kang-reji-wenkai-yin-broadcom-bruce-zou-shanghai-jibu-tech) - Wenkai Yin, Broadcom & Bruce Zou, Shanghai Jibu Tech + +* **KubeCon EU 2023 (Amsterdam)** - [Disaster Recovery: Bringing Back Production from Scratch in Under 1 Hour Using KOps, ArgoCD and Velero](https://kccnceu2023.sched.com/event/1Hye8/disaster-recovery-bringing-back-production-from-scratch-in-under-1-hour-using-kops-argocd-and-velero-andre-jay-marcelo-tanner-ada-support) - Andre Jay Marcelo-Tanner, Ada Support + + {{< youtube oPQW99NiV_0 >}} + +### Open Source Summit + +* **Open Source Summit NA 2022 (Austin)** - [Velero - The Cloud Native Backup for Kubernetes](https://ossna2022.sched.com/event/11Nu9) - Orlin Vasilev, VMware & Scott Seago, Red Hat + + {{< youtube DKMW69OSI7c >}} + +### DevConf + +* **DevConf.IN 2025** - From Chaos to Control: Mastering Kubernetes Backups and Restore with Velero - Aziza Karol & Prasad Joshi + + {{< youtube Bo4lSle0J7k >}} ## All community meetings From ae1d869c776b86c5e38fe03e9f35ad9ff48a984e Mon Sep 17 00:00:00 2001 From: Ralthos <161431341+Ralthos@users.noreply.github.com> Date: Tue, 11 Aug 2026 22:28:19 +0530 Subject: [PATCH 34/45] Add printer columns for Backup and Restore CRDs (#10200) * Add printer columns for Backup and Restore CRDs kubectl get backup and kubectl get restore fall back to the default NAME/AGE table because neither type declares printer columns, while Schedule and BackupStorageLocation do. Anything reading the API without the velero binary cannot see a backup's phase, error count or timing. Printer columns were added in #2881 and reverted in #3652 as a workaround for #3600, a CRD install error that was never root-caused. Schedule regained columns in 2022 and BackupStorageLocation has them today, with no recurrence. Only fields expressible as plain JSONPath are included. Expiration is deliberately omitted: kubectl renders a date column as time elapsed, so a future expiration prints , which covers every backup that has not yet expired. Fixes #10199 Signed-off-by: saral * Rename changelog name to pass changelog check Signed-off-by: Tiger Kaovilai --------- Signed-off-by: saral Signed-off-by: Tiger Kaovilai Co-authored-by: Tiger Kaovilai --- changelogs/unreleased/10200-Ralthos | 1 + config/crd/v1/bases/velero.io_backups.yaml | 23 ++++++++++++++++++++- config/crd/v1/bases/velero.io_restores.yaml | 23 ++++++++++++++++++++- config/crd/v1/crds/crds.go | 4 ++-- pkg/apis/velero/v1/backup_types.go | 5 +++++ pkg/apis/velero/v1/restore_types.go | 5 +++++ 6 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/10200-Ralthos diff --git a/changelogs/unreleased/10200-Ralthos b/changelogs/unreleased/10200-Ralthos new file mode 100644 index 000000000..b54e0c7f8 --- /dev/null +++ b/changelogs/unreleased/10200-Ralthos @@ -0,0 +1 @@ +Add printer columns for Backup and Restore CRDs so kubectl shows status, errors, warnings and timing diff --git a/config/crd/v1/bases/velero.io_backups.yaml b/config/crd/v1/bases/velero.io_backups.yaml index 9695d3001..c20418c90 100644 --- a/config/crd/v1/bases/velero.io_backups.yaml +++ b/config/crd/v1/bases/velero.io_backups.yaml @@ -16,7 +16,27 @@ spec: singular: backup scope: Namespaced versions: - - name: v1 + - additionalPrinterColumns: + - description: Backup status such as New/InProgress + jsonPath: .status.phase + name: Status + type: string + - description: Total number of errors logged during the backup + jsonPath: .status.errors + name: Errors + type: integer + - description: Total number of warnings logged during the backup + jsonPath: .status.warnings + name: Warnings + type: integer + - description: The time the backup was started + jsonPath: .status.startTimestamp + name: Started + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: |- @@ -688,3 +708,4 @@ spec: type: object served: true storage: true + subresources: {} diff --git a/config/crd/v1/bases/velero.io_restores.yaml b/config/crd/v1/bases/velero.io_restores.yaml index aa4e167af..e12ea9b4f 100644 --- a/config/crd/v1/bases/velero.io_restores.yaml +++ b/config/crd/v1/bases/velero.io_restores.yaml @@ -16,7 +16,27 @@ spec: singular: restore scope: Namespaced versions: - - name: v1 + - additionalPrinterColumns: + - description: The name of the backup this restore is from + jsonPath: .spec.backupName + name: Backup + type: string + - description: Restore status such as New/InProgress + jsonPath: .status.phase + name: Status + type: string + - description: Total number of errors logged during the restore + jsonPath: .status.errors + name: Errors + type: integer + - description: Total number of warnings logged during the restore + jsonPath: .status.warnings + name: Warnings + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: |- @@ -597,3 +617,4 @@ spec: type: object served: true storage: true + subresources: {} diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index 0f645d6c1..7887493a6 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -30,13 +30,13 @@ import ( var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xccW͎\xdb6\x10\xbe\xfb)\x06鵲\x1b\x14-\n\xdf\x12\xa7\x01\x82&\xc1\xc2\x0e\xf6NSc\x99Y\x8aTɡS\xf7\xe7\u074b!%[\x96hk\xbd\x87\xa2\xbc\x89\x9c\xffo\xe6#U\x14\xc5L4\xea\x11\x9dW\xd6,A4\n\xff 4\xfc\xe5\xe7O\xbf\xf8\xb9\xb2\x8b\xc3\xebٓ2\xe5\x12V\xc1\x93\xad\xd7\xe8mp\x12\xdf\xe1N\x19EʚY\x8d$JAb9\x03\x10\xc6X\x12\xbc\xed\xf9\x13@ZC\xcej\x8d\xae\xa8\xd0̟\xc2\x16\xb7A\xe9\x12]4\u07b9>\xfc0\x7f\xfd\xf3\xfc\xa7\x19\x80\x115.a+\xe4Sh\x1c6\xd6+\xb2N\xa1\x9f\x1fP\xa3\xb3seg\xbeA\xc9\xd6+gC\xb3\x84\xf3A\xd2n=\xa7\xa8\xdfFC\xeb\xce\xd01\x1ei\xe5\xe9\xb7\xec\xf1G\xe5)\x8a4:8\xa1s\x81\xc4c\xbf\xb7\x8e>\x9f\x9d\x15\xc0\"\xe9H\x99*h\xe1F\xba\xec\xdbK\xdb\xe0\x12\xa2f#$\x963\x80\xb6\b\xd1R\x01\xa2,cY\x85~p\xca\x10\xba\x95ա6'?_\xbd5\x0f\x82\xf6K\x98w\x85\x9fK\x87\xb1\xe6_T\x8d\x9eD\xddDٮ\x96o*l\xbf\xe9\xc8\xceKA86\xc6E\x9d\x9fc\xfdrl\xf0\xc2ʹF\xd0;K\x16=9e\xaa\xd9Y\xf8\xf0:\x95B\xee\xb1\x16\xcbV\xd66h\xde<|x\xfcqs\xb1\r\xd08۠#\xd5\x153\xad^g\xf6v\x01J\xf4ҩ\x86b\xdf\xfc]\\\x9c\x01\xb0\x83\xa4\x05%\xb7(z\xa0=v5Ʋ\x8d\t\xec\x0eh\xaf<\xc3\xe6УIM\xcb\xdb\u0080\xdd~EI\xf3\x81\xe9\r:6\xc3\xd8\a]rg\x1f\xd0\x118\x94\xb62\xeaϓm\x0fd\xa3S-\b=AD\xd1\b\r\a\xa1\x03~\x0f\u0094\x03˵8\x82C\xf6\t\xc1\xf4\xecE\x05?\x8c\xe3\x93u\b\xca\xec\xec\x12\xf6D\x8d_.\x16\x95\xa2n^\xa5\xad\xeb`\x14\x1d\x17q\xf4\xd46\x90u~Q\xe2\x01\xf5«\xaa\x10N\xee\x15\xa1\xa4\xe0p!\x1aU\xc4DL\x9c\xd9y]~\xe7\xda\t\xf7\x17nG@\xa7\x15\x87\xec\x0exx\xea@y\x10\xad\xa9\x94\xe2\x19\x05\xde\xe2ҭ\x7f\xdd|\x81.\x92\x84T\x02\xe5,:\xaaK\x87\x0fWS\x99\x1d\xba\xa4\xb7s\xb6\x8e6є\x8dU\x86\xe2\x87\xd4\n\r\x81\x0f\xdbZ\x11\xb7\xc1\xef\x01=1tC\xb3\xab\xc8i\xb0E\b\r\x8fN9\x14\xf8``%j\xd4+\xe1\xf1?ƊQ\xf1\x05\x83\xf0,\xb4\xfaL=\x14N\xe5\xed\x1dt,{\x05\xda!sn\x1a\x94\x8c,\x17\x97U\xd5N\xc94S;\xeb@\x8c\xe4/+\x95\xa7\x00^\x89D7d\x9d\xa8\xf0\xa3M6\x87BSm\xc7\xebm\xceP\x171\xd3V\xe2\x04\xcc\vf\f\xd2^P\x8f\fH(s\xe2\x94l\x927\x90\x89\xe8\bf\n#\x8c\xc4\xf7\xb1\x1f\x8d\x8a\x9f\xfd\x99\n?\xfc\xcb#з\xa0,\x18\xcb\xef\x8a\xe7VF\xf7\xa0,\x013\xb9\x15\xec\xef5lM\x8c\xc4N95\xa0-e\f(A9\xd9S^\xc1\xc2\x12\xe5\brA\x0fD\x81\xed\x93T\xa2\x05\x0f\x1b\xe8\xe3q\xfc,\x15\x10&6\xf2\x8a\xec\x8c)\xf5\xd5\xeb\xd7[f\x82\xe6e\xb2(*\xc1\xcc\xe15*\x11[WF*\xfd:\x87=\xf0ךm\x97Te;f \xb3l~MK\xb6DD\x04j\xdfe\x91\xff[\x10\x0f\xdd\xe9\xd6\x1c\xac\xd8j\xa3\x98ض>\xa0\xe6\xcc`\x8fU*'\x8c\x0e\x94C\xb1\xe1\x82\xfdɒ\xee\xf3\xfbۻ\xb6\xa02\xed\x99Ғ\xd7!\xfeXj2\xb1\x01\xe5\xdam\x94,\x10&\x88܉*\xca9g \f\xd1պ`Ɗ\xc1o\x15h\xab\x03\xf2\x18\xec5Z'\xb2\x06R\x95\xb9\x15\xe3\xe3\n+A\xaei\x01\xfc\x9ajxa^Y\xae\xe8\xa5eB\x12\xb7\xda6\xf7\xb8\xb2#o\xebC0\x9d\x03\xacu\x86嶄\xac\xa3h\xb6\x15۰̩\xd3F\xaa\xc6\xee8\x1bإP\\\xf5mq\xb5\xef\xec؎\xbeD\ab+\x86\xceA\x93\x9d|\f\xd6\xc6\"lE\xce\x02\x84\x9cT\xe5\x82<2\xb3\xeb\x01%\xa4\x94Z\xb35\a\xafw\x84\x89\x8cW\xb9\x15\xc9\x0f\x15\xe7h\xccV\"SPXs\xc1\x8fYM\b\x88\xaa\xe8\x0fv\x89\xad#?\xb7`\xf5\xbe\x0e0ЖL\xb3[AK\xbd\x93\xe6\x8e\x15 +3A\xa0\x9e\x12\xdar}\xbb:\x82Ң\x9ee$\x1a\xf3JCn\xad\xd9#e\x06\x99y}\xbb\"\xf7H\xd7\xd0\x1a\xady\xa5\x89\xa9\x94\xb0\xea\x13\xe9\xeb3\xd0\xfcp'\x7f\xd1@\xf2\n\xb5>S\x80\x02\xb2 k\xd8X\x15Q`\xdb\xdbO\xa0\x94\x15\x1a\x8d\x03\x90U\xcf\n\xdbr\xb7\x03+t\xb4\xe2\xc6\x1b\x10\xa6ɛ?\x93\x82\x89\xca\xf4tp\x94\x9aV:\n\xb9\au\n\x11\xdfQC\x7f\xb6\x8d\x8fh\x87\"\x87P-\xf1֞\x8e\xeb\x03~\x8c\xa9\x81+\xabM\v\"\xd3\xe4\xe2\x82HE.\x9c\xd3r\xb1p\xa0=\xda\xd6\x1d2K&\xda}=2\xceCo\xf3\x88\xe0\x80:\xc6\xea;\xf9A;\xa5:\x89&\x03\xb0Z$z܁ف\"\xa5\xac]\x82\r\xe3@\xf4A\x1b(<\x81\xc24\xeb\xf1\x89\xf4\x84ƅs\x0fB[\xfazD\xfaȋ\x8as\xba\xe6pE\x8c\xaa`\x806k)9P1A\x9cϠ\r\xcb\xceA\x1a\a)B\x18\xe5?t(\x80^\x05}\x00B#\xa0=ͬ\xfb\xc2y\x8b\xb0]\xaaD\xc7T*\xc8\xec\xb4v\xe5\xa7K\x06\x1c\xa7h!\t\x97b\v\xca\xf5n\xad_\x100\x05V\xe0rbg\"\x05\xdcN\xb7dS\xd9I\xea\x92X-\x1f\x94\x01&\xb4\x01\x1a\x11\xce'\xf0\a\xbeX+\r\xf9\xb5\xf3Lo\xad\x83\x9d\x87\x05GoZI\xe1\xd3\xfbQ\x88\xde}\xe1,C/\xd9;\xc4Kt\xeccb\xdax1v\x8a\xc2U\x87e\xa5\x1fv㞌\xda\x05\r\xc66\xba\xf8\xd3\xc5\x029\xdc\xed\xb5ۇ&TAM\x96d\xfb\tEi\x0e\xfd\xda\xcc@\x11\xa1\xe2\xa8=I\xe4'U\x8a\x1e\x06\xb8Y/\x90\xce\xc8\xcf!\x98G\x1c\x15\xa1\xda\v\xf3\xf4\xb8\xdf\x7ff\xae\x9e\x87\x8f\x1a\x03\x05\x94\t\xcb?\xbbf\xef\xb0O\xbb\x05\xae%\x9b\x90&\x02\xcf\xf9w\x90\xe3\xdau\x84[\xbf\x13\xb1\xce\"\xf3CB^˖\x17\xde\x7fHJ\xed\xa4|\x98\xa2\xce\x0f\xb6N\xb3j$\x19\x06\xa4\xc8\x1avtϤ\xf2\xa87S-|\x81\xac2Q\xad\xa7\x86\xe4l\xb3\x01e\xe1\x94;\xaaA\xbb8\xc20A\x86\xd77\xa4eF\xa2\x1f\x8f\xf0h\x18iل\x98\x0f\r\xdd\xfa\x11dzd(v\xa0\xd6\xcd\xc6\xc98g{\x96W\x94\xe3\xbcLE\xe6\xf0\xa1\xf5\xb8bVf\x84ɽ1G%\xd3\x15\xe7\x10\x04\xa4,\x93:KI)\xc0\xfa\xbe\x85]\x1b\xf4\xab\x0ec\xbe\xa6\xd6W\x91C\xd8\x13d\x96\xaa8h\xdfU\x8endc3\x16\rS0RC8]\x03'\x1a8dF\xaa8E\xa6\xf8\xecJ\x8a\x11\x1c d\xc4\xf2uW\x1c\r\x02# \t.\xe5v,\xdb9W\xcf\n\x11\xc2!\xb9\x04\xeb\xf0\x19B˒G\xa6\x8b\xa6\x8c2\xdfw2\xa6\xebM\x99\xd0\xfacx1\xfdoJ\x82\xcdlJ\x94\xb4\x8d~u)[\x8bC|m۔\x7fN\xc2\x06\xcb\x7f\x82Ўh?\xc1\xb0Y\xb2L\x0fʭ\xa5*\x03}i\xdd)\xf4t\x16\x84\x99\xf0\xeb\x94&t|\xae^4\xb1C\x84\xaf\x9b7\xf3\x85>\x915):\xf1L\x8c\xa9\xbb\xf8\a\xe4\vN\x19\xb7~\xc6H\xe6\xc9O\xedV\v\xc265\xd1\xf3\x05\xd90n@\x1dQ\xff$S\x1f8s\x0eb\xa4\xccz\x04\xf77L\xb6{\xffź`\xba\xd9\xe4K\xa4\xcbqc\xe7\xc8\x06o\xbf;=O\xc0%\x18\xe7g.\xea\xaa/q\xc5\xd4\xfe\x05]\xab\xb7\x1f\xdf\xc5\xd7W\xed\x92 y=D&\x94Ε\xb7G\x18\xb5\xc7\xe7]\xf8\xf0\x05}\xa0z\x01\xe4b\xd6\vB\xc9\x03\x1c\x9c\xebB\x05\xb1\xfc\xa1\xa1rB\xf7\np\xd3\n\xe5\xec\x01\x0e\b&\xbe\v\xd5/\xa9\xd2\xe0\xca\x03\x1cR\xaa\x1d\xd1Ў\x89i\xbf\xbbf\xe9d\x7f@B\xe0\xe6C\xaa\x18\xb8\xe2U!\xb2\xe7\x13/\x89\xb6$\x94@\xfb\x13\xd0L\x12\x95v\x1f\xedm\\\x94\x80\xef\xb4\xe3\xa5\u0558\x1d+Ѭb\xc4An\x92\x19\xea\xca=\xe5,\xaf;r:\xb2\x12\v\xf2Q\x1a\xfb\xcf\xfb/L\xfb\x9d\xdew\x12\xf4Gi\xf0\x97g\xa1\xa8\x1b\xf8s\xd23\xec\xfcX\x84\x9c\x95\xb7\x04k\xefU\xba9\xcdJ[M{\xa6\xc9J\xd8\xe5\x8a#IbW\xb8-\xed\xbas\x1d\x15\x95\xc6mF!\xc5҅mb=yzK\xd5!\xf7\x93;\xf5\x1d\xde\xd9\xc9\xc2}q\x9b\xe3\x9cf\x90\x87m\x1bܵ\xa5\x06\xb6,K\xec\xaf\x00\xb5\x05RZ\x13\x9e&\x11\x89\x86\xd5c3O|\xd2f\xefv\xf9\xb2|\xa8\x93 \x96v\xcaYz\bF\x16\t4\xf0\xb6;\x9f\xc6giu6\xa1V\x90\x84ɪ\x03\x9b\xba\xc3US\x88\xf2\x04r\xe0,\x8e.\xce$wi\x9ec\x8a\x10\xe573f\x94\x19\xb20\xd74\xb4\xc6\xee\xa6\xe0\x82\xe2V\xcb\xffؙ\x16\xb5\xe9\xffHI\x99җ\xe4-\xe6\xfcp\xe8|\xf3A\xb3\x16\x98\x84.1g\xc7\xcaϞr;\xf7[\x03.\bp\xe7\t\xc8M\xcf/Z\x90ǝ\xd4nڮ7q.\x1e\xe0\xe0v\x0e'\xbbl\x1b\x99\x8b\x95\xb8p>D\xcf`\xd4\x0e\x87\x14\xfc@.\xf0\xdb\xc5S\\\xa9DIM\xac\xd6\x11т\x96i\x12\x8a9W\xa9\x8e\xba]\xb0\x06'\xc46\xacs\x89\xac\x93=\x86m\x92\x88\x96RG6\xf4\a\x862!\xbc7R\x1b\x17/\xeb\xf8\xccр\x9a\fA4B7.\xc1K\xaa\x90\x8dc\x8d\xf2T\xe8\xb7]\xeev\xa0\xc1\xefW\xf8\xc0\x9c\x03jWv\x17\x8d~;k\x7f\xe1\xf6K\xb0\x13\x9a\xa1ǂmK%3\xd0ѽ\xec\xa6$\xcc\x17\x91l\x916\xeeȗ\xbaU\x92\xcbY\x19\x0f\x81\x86\x92\xee\xf2ZB\xcc\\/\xbc\xff\xd2\n\x88Zݷ\x7fO\xc9\xd8\xdcq\x11̶,\nz\x9cǕ4\xc4k\xd72h\x83\a\xe4\x16\x1fj[\xa1%H\x9d\xcbk\x01\xfc\x1a\x1c\x85\x82\x89\x15v@\xde<\x83c\xe1mh,\xe9$VNse\xafC'\rw\xea\x1f\x9c*\x97\x12\xb7\n\x14t\x98\u05cf\xaa\xa3\x1f*\xa4i\x05$f\xb8\x9b\xa5̿\xd3dÔ6\xed!\xe8\x814\x95(\x98\x99\v/\xf1^\xa9\x93\xd6]\x9f\\ˣD2\x9f\xbf\xe6\b\x93\x889\xee/\x01a\x1b\xc2\f\x01\x91\xc9J`\x00\xc7\xea1v\xe1\x88\xeb,,KU\x924\xed'\x83\xb9h\xb1\xb2DIab4\xd2Ӯ\xfe\x81\xb2~\xc2Z\xac\xccd\x9b\x19\xcaf\x8b\x95\xd3t\"\xa4\xba\xb53\x16\v\xfa\x85\x15UAhay\x84\x939+\xa0\xcb\xf4&\x01ζ\xc0i\xc2H\xab1%\a\x03>\x89-q\f\x99\x14\x9a\xe5PO\xae^\x10\xa4 \x94l(\xe3\x95J\xb4\x80\xb3\xc8;g)\xe2-\xc1\xf9\xd6\x18i\x9d/\x91\x14\t\xd1\xdcD_q\xdc\x1a\x97*\xdd\xe3\x9br\xb3\x14\xcc\xf7\xb2J\xc5$\xa6\a\x9e\xd9\xd1\xf2\t\x95T\x1c\xbeyZ\xa9C\xfd\xe6i\x8d\x95o\x9e\xd6D\xf9\xe6i}\xf3\xb4Rj~\xf3\xb4\xbeyZ\xed\xf2/\xe1iM\x8d\xc8\x1dx\x1c\xf889\x8a\x84\xad\xea\xb1!\x8e\xc0\xf7\xc9\x15>\a\xfcI\xb9\x98\xab8\xa8H\xe2\xff@Zw\xcch5\x93G\x9d\x9ci\xb5&ȼ;\x7f5\xe1J>!\xeb>tz\xbe\xac\xfb\xd5(\xc43e\xdd\xfbaO\xfb\xd8'\xe5\xdc\a\xa2\xcc\xcb\xce^\xf8D\x8d\x02h\b\xab\xbbm\xf8\x18^C\x122\xd1\xff\v'\xe6\xf6\xb2\xc6\xce(\x1fϞş,#Q\x96^\xfc\xe9\xe2\xeb#\xffy\b>H\xe2>\xed\xfc\x01\xf0\bT\xbb\x02m\xa7\x85u\xb3\xf0\xbeN1>\x8bܦf\xe2\xd7D\x8c\xc0\xea\x8a\xe4\x11\x15\xbfV[`\xa0\xf8T\xfa\x19\xe9\t'VW\x118IgV\xa9>\x88l\xa7\xa4\x90\x95\xf6Q\t\v\xebm\xe6N\xfc\a\x901a\x8dj\xf8\x7f\x90\x9d\xac\"\x99\xe0#\xe4\x9b\xc8\b\x9cF\xbe\x93\x1c\xe87\xa1\xc1\xd0\xfd\x9b\xcb\xee\x17#}\xaa\xe0\xd0\x19\xe7\xc7\x1d\b\xdca\x17\xdb\xf6\x01\x80pa\x83\xbf\xb9\xe0X\xc0\"\x80\xa4\"\x82q'y\xf5u\x0fm\xb9#\x9fJ\x17{\x9a\xedw\x8c\xc7TҒ\tON!\xec\xa6\b\x0e\xf8\xa5sw\xbb\xcfrd\xe2wI\r\x9c\x9f\x10\x98\x12\x11\x9bH\xfe;!\xe5/1\xb7\xf8\xc9\xdb\xf3)I}sV\xccϖ\xc0w\xfe\xb4\xbd$\xfaL\xa7\xe8͡γ\xa7\xe3\xbd`\x12\xdeˤ\xde%&ܝ/s>-\x1e{R\xe6\xd8t\xe8`8in2Un2\xb40\x85\xd8l\x94&S\xe0\xe6$\xbeMr'M\xcd^,\xb5\xed\xc5\x12\xda^6\x8dmT\x8aF?\xceIT\x8b\xdf\xdbC&'\xdb\u07bdj\xbd\n甸\xe4Xܠ\xd2\xf1\x97R\x8eS\xd9&U\xc7\xdd>i=\xf8\xe9\b\x86\x15\xd4\xe0\x8a\xbe\x90O_Tܰ\x92\xe3\xc6\xef\x9e\xe5\xd1\xe0\x88\xd9\xc1\xa1\xbe\xf0\xe3W\x89Ge\xfd\r6\x9f>\xd7Zvy\xb42\xa1\x9a<\x02\xe7\x84\xc6\xec@\x0f\xf3\xcc]\xad\x95\xc9%\xd8\xf9\xd3Z\x13\x7f\x91\x89\xbf\x8fk\xe1\xd4\x13O\x03\xe3,\\\xc4BbT\f\xdfz38ѥ\xd8Ǟ\xc7\xed\xd6\r\xf8\xdbo\x15\xa8\x03\xc1{wj\xbf\xac9\xb4\xe6\r\x89\xb6\v\xc7`ڼ\x99\x1d\x8a\xf7\xf7\x16)\x8d\xe9!o\x85\xf3\x12\x8eǃm\xacMk\x16a\xd6P\x8b\u0605S$(X\xbf\xb9\x90u\xebH\xb3)\x87>\xf5t\xd7\xf3.\xc9\xe6/\xca&\xbd\xa0tO\xf5w:\xb5u\xcai\xad\xb4\x84\x85\xc9\xd3YϵD\x9bZ\xa4%\xfb\xa5i\xa7\xaf\xe6mn>\xe3i\xab\xe78e\x95H\xa9\x94SU\xf3\xe8\xf4\x02\xa7\xa8^\xf4\xf4\xd4K\x9d\x9aJ>-\x95\x94\x92\x93\xbck\x9d\x9aRs\xe2\xf1\x9f\xe9=\xe9\xf1\xd3O\t\xa7\x9e\x12v\xab\xa7\x91<\x01\xbd\x84SM\xf3N3%\xf0,U\x15_\xf0\xd4\xd2\v\x9eVz\xe9SJ\x13\x925\xf1y\xdei\xa4\x93\xb7X\xa4\xcaA\x8dnS\xa5J\xe1\xa8\xfc\xa5\xacm\xba\x039ڟ\t\xb7\x14\xdaZ\x1d\x7f\x19\xa7\a\x7fs,\xde\x11<\xb4\xddj%\xad\xe5mt\xf6\xce\x1a\xf7\xa7\xebL\xfa\x8b\x83\xdd\xf6\x9a\x86\x92*\xbc\x8cz}p\xe97ѩ\xf9=\xcdvG\xd0wT\x93\x8dT\x055\xe4\xa2ް|\xed\x80ۿ/.\t\xf9 \xeb\x1c\x8e\xf6=B\x9a\x15%?\xd8\x15\n\xb9h78M\x02\xa2\xd2\x16z\xbb\x91\x9ce\x11\xdf-z\x97\x94\xabܻ\xdc\x03o\xb8\xca\xda)\x0e\xa5\xad\x18w\xdd\xd0\xcd\xeb^ٹ\x91\x9c\xcbǹ\xb1\x8a\x92\xfd\x05/i\x7fB4\xeb\xed\xcd\na\x04\xf1\xc0[\xdf\xebd\xb2\x1a\x9b5\xd8i\xb9\xc1sH\xf7W\x9b\x0e\xc4n^f\xfb\xb6c\xc8\xdd\xc5\xd6\xc1-\xf0\xa63\x93ֺܬ\xdc8\x86z\xb12CŁH\xcc\x002;\xa6\xf2eI\x959\xb8ĒEg\fa.\x1d\x8bF\r\xce\x1e\xfd˺\xa3\xe4\rwt\xe3\x8e\xea\xa1\xecnR\x1f\xd3\xee\x94q\f\x9f\xb6\x9c\xe1\x8d\xfe\ars\x8fk\xb4ڴy\x15\xf5k\xb4\x10*\v\x9b\xd7\x118\xbe\xc1\xf7\xe7O\xa5\xd3F*\xba\x85\x9f\xa4\xbb4}\x8a\xed\xddڝ\xcb\xf4\xbd\xd7\x13\xf2]\x83\xd2\xc4.\f\xf6\u05f7\x1f\x01kr\xd4{\x970\xdbQμV\xda\x18~\n\xdf\xef\xee~rX\x19V\xc0\xe5\xbbʥgX\x9b\xa8\xc1\x928`\xeb \xad\xed\x7fw\xf2\x11/+\x8e\xc71\xc3#\x18\r2\n09\x1eS&g\xa1T\x95\\\xd2\x1cԵ\x14\x1b\xb6\x9d\xc0\xee\x97N\xe5\xa3i6\xc3\x1f=r\xf5\x1c\x15\xe0\x9f9g\xc2\xfa<\x9c\x03\xff\xc08h7\xac\x04\x03|\xd3oU\xdb\xe3\xaaX;\x1fnc?\xd6\x1d\f\xccq\x0e-\fE\x97\xa0\xac\x17\xe5\x82֕\x0e\xb2:\x8cx\xc3\x11&\fl\xa1\xbf\n\x1c\xb1\xc0\xee\x16l\x9c>\x839\xc1\xb5̏\xb1\xf8V\a\xf9\xfb\xe1\x96G\x9cl\x85\xbcb7\x04:'\xe4\xe6\xfeZ\x93J\xe4\x18.\xbe\xff\xcb\xed,\xa9\xdbwn\xdc\x0f\xda:eT\xef\xe3\xadZ\xceq\xcb^8\xefXn\"\b\f\xc1i=\xec\xf2Ȍ\xbfh\xec\xbc7\xc3\x0e-y\x86\x9e\xac\xc0\xa7\b\xa6\x1f\xadp/\x16\xf8\xa7n\xbc:V\n\xafu\xf5\xaf\x19\xe05\xa8Ox\xb7\xa2\x93\xac\xa6\xdf\x1a\x03Eib\xbeƴ9\xfc~\f`\xed\xa7ICyK+i\xa8\x10\xf3\xb4\xf5Adc\x89p\xde\x1a\x8dpsL\x1fc\x04\xb8\xf6\xe77\xceF\x80\x1a\xe0\x10\x01t\x95e\xa0\xf5\xa6\xe2\xfcP\x1f\x1f\xf9J\xa8\xf1\x812~>R8h\x83\x82`\xd1\x1b\x854\x89\xb0OO\a\x91\aM\x0fG\xab\xe6\x91\xc2s\xc1gojC\x8b\x93\x1e\x98\xb8\xee\x83\xc17\x98T\xdeJ\x02\xa5\xf5ةn\xd8\x1f\x9b\\\x1ap\xae%.\xb2,4\xc8\t\xecA\x10;;;\x12\x87\xe7\xc5fB\xf1'r\xdd\f\x17\xe6\xbb\x10\n\x89\xbe4E|\xb4C\xe3\x8bF\xdf\xe9\x1a&\xe6\xb6\xe2;,}\"\xf4\x9d_\x17\xad\xb8\xb2\xde?,-\x88Ӽ֡Wh\xba\xf3\xc2ӌ\xdc\xf5\xedj\b\xdc)&\xae\xffL\xcd\x13ո\x8f\xee\x93LZ\x1f\xddY\x06-\x02\xb1\x96\xf1\xf3㎪~\xda%\xf4\xd8\xd29\x1cY8\xf3G9\xf7\a3\vКn\xc3\xed\xf3\x8fv\xe9\xb1\x05\x01.<\xe76O\"@\x9bS|ݻם\xca\xd0\xccT\xd4w\x10\x12\x92[\xb5\xbeӄ\xcb\x18T|\x80\x86\x85\xa7\xdf\u009al&\xa1\xbe\x94L\xa5\xac\xe1\xde\xd7\x15-m\xd0\x13F\xee4\x8f\xf5\x01g[|\x8a\xcarnK՚na\x99I\xce\x01\xadu\x7f\\ϩ\xeb\xfe\xac\xe4g\xa0z\x12\xb5\x0f\xed\xba~\a\xd0q\xdbm|S\x97\x9e\x8fϱ\x19\xa6\xa0y\x19\xb17 \x89\x1d\xcfr\x94\x1d\x15\xa2\xcf\x06\xf6Gڮ\x1b\xb4Λe\x1f\xe7\xf5\xaf\x06.\x9a\x97\xc0\"\xe3,\xe8\xafR-H\xc1\x84\xfd\x87\x8a\xdcm\xe0\x85Ƴƿ\x93\xf2\xe16\xe2\xc4\xf6\x06\xffC]\xb1\xd9\xea`\xc2\r\x1b\x0f\xb8\xaee\xe5w\xdfk\x876\xbe\xad\x82/\t\x9cy\xb9\x890G\xe6\x83\x1e:\x83\x11\xdd\x1f:\x90&\xa7\x02\xd7\xf3\x00\xac\xdb\xf04\x1d\xe7\x87\xc51\xe4\xa3g0\x1bح\x97\x16\xbc\x1b\xd0ܟ0\xd0Qؑ\x8a\x02\xa9/\xeah\x1b\xf4SV\xbd\x9e\xccC\xced\x8f\xc6?4\xb5\x87\xe8\xe8\x86\xd9r\xf7\x06\x10\xec8\x81\xe7]\xb0\xe3\xb3\x1a\x13\xc2\x7fc\xeb\xd4w-\xb4\x16n!Kl0J7\xf4B\xdfG\xe8oW,\xc9_+\xa8\"4X\x86\a\xedn\rU\xfd\x90\xaf;\xb6\x0f9ft\xa06F\xaa\xacč\x92[\x05\xba/\xacK\xf27\xca\f\x13\xdb\x0fR\xdd\xf0j\xcbħ\xe1#Jc\x95o\xa82\xcc\n\xbb\x1bOl\xa0LP\xce\xfe\x1e\xb3k\xed\x8fӀ\xae\a\x17XK\x920\x8c\xa1\x0f\xef\xc0\xfa\xb8\x83q\x81\xa8\t-=]O\xf1W\x02O\xa6lj\xedK4\xbeH\xe8\xf6\x92|\x94Q\xc3\xe0ӡX\x17\xa6u\xc9@\x9b%l6R\x19\xb7[\xbd\\\x12\xb6\t\xc1\aks0n\xe6\x1e\x1f%,\xb6\xcd\\'\x9a4\xd3\x17\x06\xbd\x15\xce\xc2x\xf5~A\x0fng\x8afYe=\xac\xd7\xdaP\x1eqp\x9ed\xf81\xca\xf3=>\xb4\xf9˓v\xf2Vm@\xfd\xa0#\xf6\xe3H\x8a\x97\x7f8\xaf\x8f[\x14A\x90GŌ\xb1>\x95\x1cI%\xf0\xa42ַ\xe2\x9chKꓢ\x8fę\xd1\xd5pJN\x1a\xcaw5\x94!\xf3\xec\xb1\xc6\x17%\xeb\xd7L}\xf6\x91\xafeٜ\xed\xa8\xd8\x0eި\xb0S\xb2\xda\xee\x82$\x0f8\xd3$\xaf\x00\x83\xb5hRtx)\xdaTJ\xb4R\tF\x8e\xa9\x93 \f8\\\x9a=\u0eeb\xee%f\xff\x04\xf7k\xfff\xcbr\xa3d\xb1\xf4\xfdb,u\xe1w\xf2\x15\x93\xd6s1\xbb(Չ\xf3\xda\xfd\xb3\b(\te\t\x82P\xed{N\xb8\xd9\xea\xe4i\xea7;5\xdcH\xcd\x12\xbc\xfd(\xc7\xff\xda\x06\x10\x18^\x86\xbf\xbb\xcc\xf0+\x18\xec3\x86\xc7'\x7fe\x00\xec\xa90n9QO\x91\x17n\x12\xbb\x98\xb5\x90\xd1vb{R\x90\xe6\xb6\x03a\">\x83\xdd\xc5Yt\xeb\xd35\xdc\xc5e\xd7\xfe\xd9\xd8\x1a\xf0\x82h&\xc2K\xe6.\xf5\xc3I\x7ft'P\xe0ÚRų1\xc7\x03.]\x84^6ֲ\xaf=\x89\xf7'/\xc5\xef\x8f`\x1c\x1dB\xc7wT\xeb*a\xf9\xfc\a\x16\xdb\x0f\xc04\xde̢\xf2\xc7\xdf\xfdp\xf9>i\xa9\x17\xa7\xc8\xd8\xca\x0f\x17u\xc3K\xb8\ueee97\x1c\xac\xb6i\x80\xee\xa2r\x96\xce\xed\xcf\x18M;g(-\xbc\xd9\x7f\x9eX\xd2\xfe\x8cA\xb4g\x8b\xa0\x9d\x17\xe5G\x8a\x0f[\x9f\xa4\xb5\x7f\xf3m#!4\x0f\xf6\xdcA\xb4V\f-\f\xfcE\xa3h\xd19\xb7\xf7#\xda\xe9\xbce-|O\xfe\x97\xff\x0f\x00\x00\xff\xff\x93\xf6\x83\\\xa3\x84\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec}_s#)\x92\xf8{\x7f\n¿\x87\xd9ݐ\xe4\xed\xf8\xdd]\\\xf8\xcd\xe3\xee\xdeQ\xecL\xb7\xb7\xed\xf1<\xa3\xaa\x94Ę\x82\x1a\xa0\xe4\xd6\xee\xedw\xbf \x81\xfaK\xa9\x90,{z\xf7\x9a\x97n\xab !\xff\x90\x99$\t\xcc\xe7\xf37\xb4d\x0f\xa04\x93\xe2\x8aВ\xc1\x17\x03\xc2\xfe\xa5\x17\x8f\xff\xad\x17L^\xee\u07beyd\"\xbf\"7\x956\xb2\xf8\fZV*\x83w\xb0f\x82\x19&ś\x02\fͩ\xa1Wo\b\xa1BHC\xed\xcf\xda\xfeIH&\x85Q\x92sP\xf3\r\x88\xc5c\xb5\x82U\xc5x\x0e\n\x81\x87\xaew\x7f^\xbc\xfd\xaf\xc5\x7f\xbe!D\xd0\x02\xaeȊf\x8fU\xa9\x17;\xe0\xa0\xe4\x82\xc97\xba\x84̂\xdc(Y\x95W\xa4\xf9\xe0\x9a\xf8\xee\xdcP\xbf\xc7\xd6\xf8\x03g\xda\xfc\xb5\xf5\xe3\x8fL\x1b\xfcP\xf2JQ^\xf7\x84\xbf\xe9\xadT\xe6c\x03mNV\xf4\xd1}abSq\xaaB\xfd7\x84\xe8L\x96pE\xb0zI3\xc8\xdf\x10\xe2\xf1\xc1\xe6sB\xf3\x1c)D\xf9\xadb\u0080\xba\x91\xbc*D\r<\a\x9d)V\x1a\xa4\x80\x1b\x1eц\x9aJ\x13]e[B5\xf9\bO\x97Kq\xab\xe4F\x81v\x83$\xe4W-\xc5-5\xdb+\xb2p\xd5\x17\xe5\x96j\xf0_\x1d\x01\xef\xf0\x83\xff\xc9\xec\xedH\xb5QLlb}\xdfKC9\x11U\xb1\x02E䚀RRi\xc2\xe5f\x039\xc9+ێ\x98-4\xc8LJ\xe1\xdau\xc6\xf1\xbe\xfd\x93\x1b\x87%\xc5\x06T\xca@\x9e\xa8\x12LlN\x18Jh\xd9\x19\xcc/\xdd\x1f\xa7\x87\xb3\x05bX\x01\xad\x0e\xc9\x13ՖI\xca \xc3\xe3\x9d\xe3\xf7{V\x806\xb4(\xfb|i5u#ȩ\x01\xdf}\vV\x98V\x8bL\x01Ψ8\xc0\xeb\rā\xb9ϻ\xb7N~\xb3-\x14\xf4\xcaה%\x88\xeb\xdb\xe5\xc3\xff\xbf\xeb\xfcL\xba\xd8\xffϼ\xfe\x9d\x04\xf1d\x9aP\xf2\x80s\x8f(\xaf\n\x88\xd9RC\x14\x94\n4\b\xa3\x91Z\x19-M\xa5\xc02\xf1\xaf\xd5\n\x94\x00\x03\xba\x05/\xe3\x956\xa0PށPC()%\x13\x860\xe1H\xfe\x87\xeb\xdb%\x91\xab_!3\x9aP\x91\x13\xaa\xb5\xcc\x185\x90\x93\x9d\x9dG\xe0\xda\xfeqQC-\x95,A\x19\x16\xa6\xaf+-\r\xd7\xfa\xf5\x10\xae\xb6X\xf2\xb8V$\xb7\xaa\x0e\x1cZ~\x82C\xee)j\xf13[\xa6\x1b\xf4\x91U\xf6g*\xfc\xf0\x17=\xd0w\xa0,\x18\xabm*\x9e[\r\xb9\x03e\t\x98ɍ`\x7f\xafakb$vʩ\x01mPP\x95\xa0\x9c\xec(\xaf`f\x89҃\\\xd0=Q`\xfb$\x95h\xc1\xc3\x06\xba?\x8e\x9f\xa4\x02\xc2\xc4Z^\x91\xad1\xa5\xbe\xba\xbc\xdc0\x13\xf4~&\x8b\xa2\x12\xcc\xec/Q\x85\xb3Ue\xa4җ9\xec\x80_j\xb6\x99S\x95m\x99\x81̲\xf9\x92\x96l\x8e\x88\b\xd4\xfd\x8b\"\xff\x7fA\xd8\x1b\xb4\x8dd\x05\xa4*\xed$\xcd\xfb\x15\x96\x82\xdc\xd0\x02\xf8\r\xd5\xf0ʼ\xb2\\\xd1s˄$n\xb5-~\xbf\xb2#o\xebC0\xdc#\xacu\x8a宄\xac3\xd1l+\xb6f\x99\x9bNk\xa9\x1a\xbd\xe3\x14q\x97B\xf1\xa9o\x8b\xab}o\xc7\xd6\xfb\x12\x1d\x88\xad\x18:\aM\xb6\xf2)h\x1b\x8b\xb0\x159\v\x10rR\x953\xf2\xc4\xccv\x00\x94\x90Rj\xcdV\x1c\xfc\xbc#Ld\xbcʭH~\xa88Ge\xb6\x14\x99\x82ª\v\xdeg5! \xaab8\xd89\xb6\x8e\xfc܂5\xf8:\xc2@[2\xcd\xee\x04-\xf5V\xa2\xa9\x92\x95\x99 \xd0`\x12\xdars\xb7\xecAiQ\xcf\x04\xfbYiȭ6{\xa2\xcc 3o\xee\x96\xe4\x01\xe9\x1aZ\a\xcf\xc7TJ\xd8\xe9\x13\xe9\xeb3\xd0|\x7f/\x7f\xd6\x10\x1c\x81`\x1agd\x05k;E\x14\xd8\xf6\xf6\x13\xfa\"օ2nXC2\x13\xb4\xef9\xaciōW L\x93\xb7\x7f&\x05\x13\x95\x19\xcc\xc1\x83Դ\xd2Q\xc8\x1d\xa8S\x88\xf8\x8e\x1a\xfa\x93mܣ\x1d\x8a\x1cB\xb5\xc4[y:\xae\xf6-\x7f$\x86\xd6r݂\xc84\xb9\xb8 R\x91\v\xe72_\xcc\x1ch\x8f\xb6u\xc6͜\x89v_O\x8c\xf3\xd0\xdbqDp@\x1dc\xf5\xbd\xfc\xa0ݤ:\x89&#\xb0Z$zڂق\"\xa5\xac]\x825\xe3@\xf4^\x1b(\x82\xc3\xe6ͬ\xc7'\xd2\x13*\x17\xce=\bm\xe9\xeb\x11\x19\"/*\xce\xe9\x8a\xc3\x151\xaa\x82\x11ڬ\xa4\xe4@\xc5\x04q>\x836,;\ai\x1c\xa4\ba\x94\xffС\x00z\x15\xf4\x11\b\x8d\x80\xf64\xb3\xee\v\xe7-\xc2v\xa9\x12\x1dS\xa9 \xb3f\xedʛK\x06\x1cM\xb4\x90\x84K\xb1\x01\xe5z\xb7\xda/\b\x98\x02+p9\xb1\x96H\x01\xb7斬+k\xa4\x16\xc4\xce\xf2Q\x19`B\x1b\xa0\x11\xe1|\x06\x7f\xe0\x8b\xd5Ґ\xdf8\xcf\xf4\xce.\xef\xf2\xb0\xdc\x1d\x98\x95\x14>\xbd?\bѻ/\x9ce\xe8%{\x87x\x8e\xcbʘ\x986^\x8c5Q\xb8浬\xf4\xc3nܓ\x83zA\x83\xb1\x8d.\xfet1C\x0ew{\xed\xf6\xa1\tUP\x93%Y\x7fBQ\x9a\xfd\xb063PD\xa8xP\x9f$\xf2\x93*E\xf7#ܬ\x97\xe7g\xe4\xe7\x18\xcc\x1eGE\xa8\xf6\xca<\xed\xf7\xfb\xef\xcc\xd5\xf3\xf0Qc\x98\x8a2a\xf9Ǚ6\x1d\xf6i\xb7\xc0\xb5d\x13\xd2D\xe09\xff\x0er\\\xbb\x1e\xe0\xd6\xefD\xac\xb3\xc8\xfc\x98\x90ײ\xe5\x85\xf7_\x92R[)\x1f\xa7\xa8\xf3\x83\xadӬ\x1aI\x86\xe1P\xb2\x82-\xdd1\xa9<ꍩ\x85/\x90U&:\xeb\xa9!9[\xafAY8\x18\xba\xd3.\x8e0N\x90\xf1\xf5\ri\xa9\x91\xe8\xc7\x1e\x1e\r#-\x9b\x10\xf3\xb1\xa1[?\xa2o%C\xb1\x03\xb5n6\x1a\xe3\x9c\xedX^Q\x8ev\x99\x8a\xcc\xe1C\xebqŴ\xcc\x01&\x0f\xc6\x1c\x95LW\x9cC\x10\x90\xb2L\xea,%\xa5\x00\xeb\xfb\x16vm0\xac:\x8e\xf9\x8aZ_E\x8eaO\x90Y\xaa\xe2\xa0}W9\xba\x91\x8dΘ5L\xc1H\r\xe1t\x05\x9ch\xe0\x90\x19\xa9\xe2\x14\x99\xe2\xb3+)Jp\x84\x90\x11\xcd\xd7]q4\b\x1c\x00Ip)\xb7e\xd9ֹzV\x88\x10\x0e\xc9%X\x87\xcf\x10Z\x960\xe7\x80ڕ\xddE3\xbf\x9d\xb6\xbfp\xfb%\xd8\t\xcd\xd0c\xc1\xb6\xa5\x92\x19\xe8\xe8^vS\x12\xecE$[\xa4\x8d{\x1ds\xa4n\x95\xe4rV\x0e\x87@CIwy-!\x8e\\/\xbc\xff\xd2\n\x88ڹo\xff\x9e\x92\xb1c\xc7E0\u05f7(h?\x8f+i\x887\xaee\x98\r\x1e\x90[|\xa8M\x85\x9a Ֆ\xd7\x02\xf858\n\x05\x13K쀼}\x01\xc7\xc2\xeb\xd0X\xd2I\xac\x9c\xe6\xcaބN\x1a\xee\xd4?\xb8\xa9\\J\xdc*P\xd0a\xde0\xaa\x8e~\xa8\x90\xa6\x15\x908\xc2\xdd,e\xfe\x9d&k\xa6\xb4i\x0fA\x8f\xa4\xa9D\xc1\x1c\xb9\xf0\x12\x98\xbd|\x02q?\xb9\x96\xbdD2\x9f\xbf\xe6\b\x93\x889\xee/\x01ak\xc2\f\x01\x91\xc9J`\x00\xc7\xcec\xec\xc2\x11\xd7iX\x96:I\xd2f?\x19\xcdE\x8b\x959J\n\x13\a#=\xed\xea\x1f(\x1b&\xac\xc5ʑl3c\xd9l\xb1rڜ\b\xa9n\xed\x8cł~aEU\x10ZX\x1e\xa11g\x05t\x99\xde$\xc0\xd9\x16h&\x8c\xb43\xa6\xe4`\xc0'\xb1%\x8e!\x93B\xb3\x1cj\xe3\xea\x05A\nBɚ2^\xa9D\rx\x14y\x8fY\x8axMp\xbe5FZ\xe7s$EB47\xd1W<\xac\x8dK\x95\xee\xf1M\xb9Y\n\x8e\xf7\xb2J\xc5$\xa6\a\x9e\xd9\xd1\xf2\t\x95T\xec\xbfyZ\xa9C\xfd\xe6i\x1d*\xdf<\xad\x89\xf2\xcd\xd3\xfa\xe6i\xa5\xd4\xfc\xe6i}\xf3\xb4\xda\xe5\xff\x84\xa755\xa29\xc6\xd0F>N\x8e\"a\xab\xfa\xd0\x10\x0f\xc0\xf7\xc9\x15>\a\xfcY\xb9\x98\xcb8\xa8H\xe2\xffHZwLi5ƣNδ\xb3&ȼ;\x7f5\xe1J>#\xeb>tz\xbe\xac\xfb\xe5A\x88gʺ\xf7Þ\xf6\xb1Oʹ\x0fD9.;{\xe6\x135\n\xa0!\xac\xee\xb6\xe1cx\x8dI\xc8D\xff\xaf\x9c\x98;\xc8\x1a;\xa3|\xbcx\x16\x7f\xb2\x8cDYz\U000672ef\x8f\xfc\xe7!\xf8(\x89\x87\xb4\xf3\a\xc0#P\xed\n\xb4\x9d\x16\xd6\xcd\xc2\xfb:\xc5\xf8,r\x9b\x9a\x89_\x131\x02\xab+\x92=*~\xad\xba\xc0@\xf1\xa9\xf4\x16\xe9\x19'V\x97\x118IgV\xa9ދl\xab\xa4\x90\x95\xf6Q\t\v\xeb:s'\xfe\x03Ș\xb0Fg\xf8\x7f\x90\xad\xac\"\x99\xe0\a\xc87\x91\x118\x8d|'9\xd0oB\x83\xa1\xbb\xb7\x8b\xee\x17#}\xaa\xe0\xd8\x19\xe7\xa7-\b\xdca\x17\x9b\xf6\x01\x80pa\x83\xbf\xb9\xa0/`\x11@R\x11\xc1\xb8\x93\xbc\xfa\xba\x87\xb6ܑO\xa5\x8b=\x1d\xedw\x1c\x8e\xa9\xa4%\x13\x9e\x9cB\xd8M\x11\x1c\xf1K\x8f\xdd\xed>ˑ\x89\xdf%5\xf0\xf8\x84\xc0\x94\x88\xd8D\xf2\xdf\t)\x7f\x89\xb9\xc5\xcfޞOI\xea;f\xc5\xfcb\t|\xe7O\xdbK\xa2\xcft\x8a\xde1\xd4y\xf1t\xbcWL\xc2{\x9dԻĄ\xbb\xf3eΧ\xc5cO\xca\x1c\x9b\x0e\x1d\x8c'\xcdM\xa6\xcaM\x86\x16\xa6\x10;\x1a\xa5\xc9\x14\xb8c\x12\xdf&\xb9\x936\xcd^-\xb5\xed\xd5\x12\xda^7\x8d\xed\xa0\x14\x1d\xfcxL\xa2Z\xfc\xde\x1e2il\a\xb7\xfa\r*\x9cS\xe2\x92cq\xa3\x93\x8e\xbf\xd6\xe48\x95mRu\xdc\xed\x93փ\x9fz0\xac\xa0\x06W\xf4\x95|\xfa\xa2↕\x1c7~w,\x8f\x06G\xcc\x16\xf6\xf5\x85\x1f\xbfJ<*\xebo\xb0\xf9\xf4\xb9\x9ee\x8b\xdeʄj\xf2\x04\x9c\x13\x1a\xd3\x03\x03\xcc3w\xb5V&\xe7`\xed\xa7\xd5&\xfe\"\x13\x7f\x1f\xd7\xccMO<\r\x8cV\xb8\x88\x85Ĩ\x18\xbf\xf5f\xd4Х\xe8ǁ\xc7\xed\xd6\r\xf8\xdbo\x15\xa8=\xc1{wj\xbf\xac9\xb4\xe6\x15\x89\xb6\vǠڼ\x9a\x1d\x8b\xf7\x0f\x16)\x8d\xea!\xd7\xc2y\t\xfd\xf1`\x1b\xabӚE\x98U\xd4\"v\xe1\x14\t\x13l\xd8\\Ⱥu\xa4ٔC\x9fz\xba\xebe\x97d\xc7/\xca&\xbd\xa0tO\xf5w:\xb5u\xcai\xad\xb4\x84\x85\xc9\xd3Y/\xb5D\x9bZ\xa4%\xfb\xa5i\xa7\xaf\x8e\xdb\xdc|\xc1\xd3V/q\xca*\x91R)\xa7\xaa\x8e\xa3\xd3+\x9c\xa2z\xd5\xd3S\xafuj*\xf9\xb4TRJN\xf2\xaeujJ͉\xc7\x7f\xa6\xf7\xa4\x0f\x9f~J8\xf5\x94\xb0[=\x8d\xe4\t\xe8%\x9cj:\xee4S\x02\xcfR\xa7\xe2+\x9eZz\xc5\xd3J\xaf}JiB\xb2&>\x1fw\x1a\xe9\xe4-\x16\xa9rP\a\xb7\xa9R\xa5\xf0\xa0\xfc\xa5\xacm\xba\x03\xe9\xedτ[\nm\xad\x8e\xbf\x8c\xe6\xc1\xdf\x1c\x8bw\x04\x8fm\xb7ZIky\x1b\x9d\xbd\xb3\xc6\xfd\xe9:\x93\xfe\xe2`\xb7\xbd\xa6\xa1\xa4\n/\xa3^\xed]\xfaM\xd44\xbf\xa7ٶ\a}K5YKUPC.\xea\r\xcbK\a\xdc\xfe}\xb1 䃬s8\xda\xf7\biV\x94|oW(\xe4\xa2\xdd\xe04\t\x88J[\xe8\xedVr\x96E|\xb7\xe8]R\xae\xf2\xe0r\x0f\xbc\xe1*k\xa78\x94\xb6b\xdcuC7\xaf{e\xe7Zr.\x9f\x8e\x8dU\x94\xec/\xf8D\xc03\xa2Y\u05f7K\x84\x11\xc4\x03\xdf\x1c\xa8\x93\xc9jlV`\xcdr\x83\xe7\xd8\xdc_\xae;\x10\xbby\x99\xedێ!w\x17[\a\xb7\xc0\xab\xceLZ\xedr\xbbt\xe3\x18\xeb\xc5\xca\f\x15{\"1\x03\xc8l\x99\xca\xe7%Uf\xef\x12Kf\x9d1\x04[z(\x1a5j=\x86\x97uG\xc9\x1b\xee\xe8\xc6\x1d\xd5}\xd9ݤ\xee\xd3\xee\x94q\x8c\x9f\xb6\x9c\xc4[\xb5\x9c㖾pޱ\\G\x10\x18\x83\xd3z\xd8\xe5\x89\x19\x7f\xd1\xd8yo\x86\x1d[\xf2\x8c=Y\x81O\x11L?Z\xe1^,\xf0O\xdd\xf8\xe9X)\xbc\xd6տf\x80נ>\xe3݊N\xb2\x9a\xbe6\x06\x8a\xd2\xc4|\x8diu\xf8\xfd!\x80\xb5\x9f\xd6{\x80\x89\x86\n1O[\xefEv(\x11\xcek\xa3\x03\xdc<4\x1fc\x04\xb8\xf1\xe77\xceF\x80\x1a\xe0\x18\x01t\x95e\xa0\xf5\xba\xe2|_\x1f\x1f\xf9J\xa8\xf1\x812~>R8h\xa3\x82`\xd1;\bi\x12a\x9f\x9e\x0e\"\x0f3=\x1c\xad:\x8e\x14\x9e\v\xed\x17\xb1N\xa1\xc1\xcd\x10\f\xbe\xc1\xa4\xf2V\x12(m?\xfbU\xb3?f\\\x1ap\xae%.\xb2,4\xc8\t\xec@\x10k\x9d\x1d\x89\xc3\xe3vGB\xf1'r\x9d\x85\xeb>\x836\xf2\xd2\x14\xf1\xd1\x0e\x8d/\x1a}\xa7k\x98\x98ۊ\xef\xb0\f\x890t~]\xb4\xc2=-6\xb7 N\xf3Z\xc7^\xa1\xe9څ\xe7)\xb9\x9b\xbb\xe5\x18\xb8ST\xdc\xf0\x99\x9agN\xe3!\xba\xcfRiCt\x8fRh\x11\x88\xb5\x8c\x9f\x1fw\xf7:\xe0I\x97л\xf7\b\xd1\xe1\xc8\u0099?ʹ?\x98Y\x80\xd6t\x13n\x9f\x7f\xb2K\x8f\r\bp\xe19\xb7y\x12\x01ڜ\xe2\xeb\u07bd\xee\xa6\f\xcdLEyx\t\xd1%$\xb7j}\x87O\x12F\xa0\xe2\x034,<\xfd\x16\xd6dG\x12\xeaK\xc9T\xca\x1a\xee}]\xd1\xd2\x06=a\xe4N\xf3X\x1fp\xb6\xc1\xa7\xa8,\xe76T\xad\xe8\x06\xe6\x99\xe4\x1cP[\x0f\xc7\xf5\x92sݟ\x95\xfc\fTO\xa2\xf6\xa1]\xd7\xef\x00:n\xbb\x8do\xea\xd2\xf3\xf196\xc3T\xef=\xc8\u0380$v|\x94\xa3\xec\xa8\x10}6p8\xd2v\xdd0\xeb\xbcZ\xf6q^\xffj\xe0\xacy\t,2\u0382\xfe*Ռ\x14L\xd8\x7f\xa8\xc8\xdd\x06^h|\xd4\xf8\xb7R>\xdeE\x9c\xd8\xc1\xe0\x7f\xa8+6[\x1dL\xb8a\xe3\x01ו\xac\xfc\xee{\xed\xd0ƷU\xf0%\x813/7\x11\xe6\x01{0@g4\xa2\xfbC\aҤ)p=\x8f\xc0\xba\vO\xd3q\xbe\x9f\xf5!\xf7\x9e\xc1l`\xb7^Z\xf0n@s\x7f\xc2HGaG*\n\xa4\xbe\xa8\xa3\xad\xd0OY\xf5z2\x8f9\x93\x03\x1a\xff\xd0\xd4\x1e\xa3\xa3\x1bf\xcb\xdd\x1bA\xb0\xe3\x04\x9ew\xc1\x8e\xcfjL\b\xff\xad\xadSߵ\xd0Z\xb8\x85,\xb1\xd1(\xdd\xd8\v}\x1fa\xb8]1'\x7f\xab\xa0\x8a\xd0`\x1e\x1e\xb4\xc37a#\x9f\x1d\x911\xa3\x03gc\xa4\xca\xe0m\xe0\xf6\xc7_(3Ll>Hu˫\r\x13\x9fƏ(\x1d\xaa|K\x95aV\xd8\xddxb\x03e\x82r\xf6\xf7\x98^k\x7f\x9c\x06t3\xba\xc0\x9a\x93\x84a\x8c}x\a\xd6\xc7\x1d\x8d\vDUh\xe9\xe9z\x8a\xbf\x12x2\xa5Sk_\xa2\xf1EB\xb7\v\xf2QF\x15\x83O\x87b]\x98\xd6%\x03m\xe6\xb0^Ke\xdcn\xf5|N\xd8:\x04\x1f\xac\xce\xc1\xb8\x99{|\x94\xb0\xd86s\x9dhҘ/\fz+\xb4\xc2x\xf5~A\xf7ng\x8afYe=\xacKm(\x8f88\xcfR\xfc\x18\xe5\xf9\x1e\x1f\xda\xfc\xf9Y;y\xcb6\xa0a\xd0\x11\xfbq$\xc5\xcb?\x9c\xd7\xc7-\x8a ȓb\xc6X\x9fJ\x1eH%\xf0\xa42ַ\xe2\x9chKꓢ\x8fĩ\xd1\xe5xJN\x1a\xca\xf75\x941\xf5\xec\xb1\xc6\x17%\xeb\xd7L}\xf6\x91\xafeٜm\xa9،ި\xb0U\xb2\xdal\x83$\x8f8\xd3$\xaf\x00\x83\xb5\xa8Rtx)\xdaTJ\xb4R\t\x0e\x1cS'A\x18p\xb84{\xc4wW\xddK\xcc\xfe\x01\xf8K\xfff\xcb|\xadd1\xf7\xfdb,u\xe6w\xf2\x15\x93\xd6s1\xdb(Չ\xf3\xda\xfd\xb3\b(\te\t\x82P\xed{N\xb8\xd9\xead3\xf5\x9b5\r\xb7R\xb3\x04o?\xca\xf1\xbf\xb5\x01\x04\x86\x97\xe1\xef.3\xfc\n\x06\xfb\x8c\xe1\xf1\xc9_\x19\x00;*\x8c[N\xd4&\xf2\xc2\x19\xb1\x8b\xa3\x162\xddw\xd0Oڻ\xeb@\x98\x88\xcf\xf8g\xd9c\xa8\xdd\xf9t\rwq\xd9M\xffE\xf5\x19\xd1L\x84\x97\xcc]ꇓ\xfe\xe8N\xa0\xc0\x875\xa5\x8agc\x1e\x0e\xb8t\x11z\xddXˮ\xf6$ޟ\xbc\x14\x7f\xe8\xc1\xe8\x1dB\xc7wT\xeb*a\xf9\xfc\a\x16\xdb\x0f\xc04\xde̢\xf2\xc7\xdf\xfdp\xf9.i\xa9\x17\xa7ȡ\x95\x1f.\xeaƗp\xddwSo9\xd8٦\x01\xba\x8bʣ\xe6\xdc\xee\x8cѴs\x86\xd2\u009b\xfd\xe7\x89%\xed\xce\x18D{\xb1\b\xdayQ~\xa2\xf8\xb0\xf5I\xb3\xf6\x17\xdf6\x12B\xf3`\xcf\x1dDk\xc5\xd0\xc2\xc0_5\x8a\x16\xb5\xb9\x83\x1fQO\xe7-m\xe1{j\xffR\xad\x9a\xe7\x15\xc9?\xfe\xf9\xe6\x7f\x03\x00\x00\xff\xff\xc3!Ko6\x87\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xccZK\x93۸\x11\xbe\xebWt\xed\x1e\xf6\xb2\x94줒J\xe96\x96\x93*W\xc6\xf1\xd4hvr]\bhJ\xb0@\x80\x01@\xc9\xca㿧\x1a\x0f\x89\xe2C\x0f;q\u008b-\x12h\xf4\xf3\xeb\x0f\xc0\x14E1a\xb5|E\xeb\xa4\xd1s`\xb5\xc4/\x1e5\xfdr\xd3\xed\x1f\xdcT\x9a\xd9\xee\xedd+\xb5\x98âq\xdeT\xcf\xe8Lc9\xbe\xc7Rj\xe9\xa5ѓ\n=\x13̳\xf9\x04\x80im<\xa3\u05ce~\x02p\xa3\xbd5J\xa1-֨\xa7\xdbf\x85\xabF*\x816\b\xcfK\xef\xdeL\xdf\xfe~\xfa\xbb\t\x80f\x15\xcea\xc5\xf8\xb6\xa9\x9d7\x96\xadQ\x19\x1eENw\xa8К\xa94\x13W#\xa7\x15\xd6\xd64\xf5\x1cN\x1f\xa2\x84\xb4z\xd4\xfc]\x10\xb6\x8c\xc2\x1e\x93\xb0\xf0]I\xe7\xff<>\xe6Q:\x1f\xc6ժ\xb1L\x8d\xa9\x15\x86\xb8\x8d\xb1\xfe/\xa7\xa5\vX9\x15\xbfH\xbdn\x14\xb3#\xd3'\x00\x8e\x9b\x1a\xe7\x10f\u05cc\xa3\x98\x00$\xd7\x04i\x050!\x82\xb3\x99z\xb2R{\xb4\v\xa3\x9aJ\x1f\xd7\x12踕\xb5\x0fΌ\xb6@2\x06\xb25\xe0<\xf3\x8d\x03\xd7\xf0\r0\a\x0f;&\x15[)\x9c\xfd\xa2Y\xfe\x7f\x90\a\xf0\xd9\x19\xfd\xc4\xfcf\x0e\xd38kZo\x98\xcb_c\x8c\x9eZo\xfc\x81\fp\xdeJ\xbd\x1eR\xe9\x919\xffʔ\x14A\x93\x17Y!H\a~\x83\xa0\x98\xf3\xe0\xe9\x05\xfd\x8a\x1e\x02r\x11B\xf6\x10\xec\x99K\xeb\x00좔\xe0\xa3aMUo\xad3\xb5I\x15x\xedH\x89\xfaӛ\xa4}Kl\xce\xef)\xb7x\x14\xe9<\xab\xea3\xb9\x0fk\x1c\x13v\xe6\x8a\xf7X\xb2F\xf9\xb6\xa9\x14%\xd5\xce\xcbs\xb3j\xe4S\x11g\x9d\xad\xf8\xfe\xec]\\ue\x8cB\x16\xa5\xc4Q\xbb\xb71\v\xf9\x06+6O\x83M\x8d\xfa\xe1\xe9\xc3\xebo\x97g\xafa(\x91:EA\x81c\xad\xd8l\xd0\"\xbc\x86\xfa\x8bqsɴ\xa3L\x00\xb3\xfa\x8cܟ\x82X[S\xa3\xf52\x17K|ZX\xd4z\xdb\xd1\xe9\x9f\xc5\xd97\x002#\xce\x02A\xa0\x841\xafR\xfd\xa0H\x96\x83)\xc1o\xa4\x03\x8b\xb5E\x87:\xc2\x14\xbdf:)8\xed\x88^\xa2%1Tۍ\x12\x84e;\xb4\x1e,r\xb3\xd6\xf2\xefG\xd9\x0e\xbcI\xc9\xec\xd1y\b\x15\xaa\x99\xa2dm\xf0g`Zt$W\xec\x00\x16iMhtK^\x98\xe0\xbaz|\xa4j\x90\xba4s\xd8x_\xbb\xf9l\xb6\x96>#47U\xd5h\xe9\x0f\xb3\x00\xb6r\xd5xc\xddL\xe0\x0e\xd5\xcc\xc9u\xc1,\xdfH\x8f\xdc7\x16g\xac\x96E0DGH\xadď6a\xba;[\xb6W\xd2\xf1\t\x90zGx\b^c\xcaDQ\xd1\xc4S\x14\xe8\x15\xb9\xee\xf9\x8f\xcb\x17Ț\xc4HŠ\x9c\x86\xf6\xfc\x92\xe3Cޔ\xbaD\x1b\xe7\x95\xd6TA&jQ\x1b\xa9}\xf8\xc1\x95D\xed\xc15\xabJzJ\x83\xbf5\xe8<\x85\xae+v\x11\xba\x18\xac\x10\x9a:\x80Dw\xc0\a\r\vV\xa1Z0\x87\xdf9V\x14\x15WP\x10n\x8aV\xbb7w\aG\xf7\xb6>\xe4\x9e:\x12\xdaA4X\xd6\xc8\xcf\xeaN\xa0\x93\x96*\xc33\x8f\xa1\xba:\x0eJP1ޔ\xf33\f\x12\xf40\xceѹ\x8fF`\xf7KG\xe5\x87\xe3\xc03\x1dk\xb4\x95t\xa1\xbdBil\xb7\xf3\xb0#\x92\xb7\x9f\x8cx݀\x03\xa0n\xaa\xbe\"\x05<#\x13\x9f\xb4:\x8c|\xfa\xab\x95\xbe\xbf\xd0H \xe9\x89*.\x0f\x9a?\xa1\x95F\\1\xfe]g\xf8\xd1\x05\x1b\xb3\x872\xe4\xbf\xf6\xea@\xd8\xe5\x0e\x9a\xf7Q;?\x0fO\x1f2\x82\xc7\xdaJ\x85\x99|5\x85\x87TԦ\x847 \xa4#\"\xe1\x82о\xb3t\xa3\x02ј\x83\xb7\xcd]\xe6s\xa3K\xb9\xee\x1b\xdd\xe6Fc\x19sEt\xc7s\x8b\xb0\x12\xa1\x16eGm\xcdN\n\xb4\x05Շ,%O\x9a46v\x90R\xa2\x12=l\x1a\xad\xb2`\x8aEAE\xcdԕ\x18.\x8e\x03\x03\x93fR\xc7\f>\t\bXc\xabԚ\xb5G-\xb0\xdbm\x826&\x00\x9aC\x01{\xe97\x11)\xd5P\xdd\xc1\xc5ڣg\x8b\x87\xa1\xd7\x1d\xdd_6H#c\xe3Ep\xc8-\xfa\x90m\xa8(}(\x95\xa6\x00\x1f\x1b\x17\xb0\xb6\x8b\x13\xf9\t\x84/\xcf\xde\xe2\xa1\xefh\xb8\x16\xdcD\x85FT\x0e$j\x0e?\xfcpݤ^w\xcb\x0fQ\xf7l\xa8\xc5\x12-\xea\x1e\x9b\xc8\xcfK\xe8Q\x944\x94aX\x96Ƚܡ:\x84\x9eD\xe0\xf93\xac\x1a\x0f\xa2\xc1\x105Ʒ{f\x85\x03n\xaa\x9ay\xb9\x92J\xfa\x03H7\"\x9f)e\xf6(Rı\xaa\xfda\n\x1f\xb4\xf3LstG\x1eD\x1e\x8b\xa9\xc0t\x1c\x95\xaa8\x10:f\x8700\x8a\xaf\x8c\xf3\xc0\xd1R:\xaa\x03\xec\xad\xd1\xeb1c\a\xda!\xed\x01\xadF\x8f\xa1#\n\xc3\x1d5C\x8e\xb5w3\xb3C\xbb\x93\xb8\x9f\xed\x8d\xddJ\xbd.H\xc1\"\x81\xcf,\xec\xecf?\x86\x7f\xbe&\vL\x1dq\xe2\x86\xe4]\x86Z?\x10\xbd\xf5\x1b\x8c-b\x19s\xd0X \x02A\xa9]\xa5܍\xc8:TvC\xbc\xbc\xfd\xe4\x90\x0f\xf5\x8f-\xf6[\xc7\x05P\x01\xf8R\x9c|[T\xac.\xe2h\xe6M%\xf9\xa4km\xcc\xfb\xcb\xf8\x937+R\vɉܞ\xe3F\xdeĉ\xb3=̀\x1b\xba\xbb\x9c1\xb4\x1cvS47q\x85+\x1a\x7fj\x8f=m}#t\xa7\xfe\xef\xd0\x13\xeft\xa0\x91\xf8\x01\xb3}?\a\xc0\xe4FkB*o\x80\x1d\xdb\xc0O\xae\xdb\xff\xeeD\xcfU÷8\xe0\xf8\x9e)\xef\xc2\xc0\xec\xe38\x8dti\x1c\x86\xc6tM\r\xb8^\x11\x9c-\xd0ޢ\xcb(\xf2-\x1eH\u0091[0X<\xc0\xaa\xd1BaVu\xbfAM\xdb1Y\x1e\x88\xec\xbf<.\xb3c\x03\x01K[\xa7\xec\xde1 yO\xbb\x00JA1\x87_\x1c\xa6u\x9f\xb1\x04\xa9\x9dG\xd6#\xe9\xf1\x89\xbdq\x0e\xab\xc3\x00\u05fa\xd9A\xcfX~\xbb\x8f\x82\xae\xe4\xa1\xd4 8\xc6\xc4J\xb0\x92\xfa{\xde\x0f-\x1e\x02\xc4\x12\xdf \"}\xe6ґe\xeetth\xd0i\xf1\fdR\xc7\x02a\xd5\xd8\":\x1fR\x01\x8by9H䇃q\xb9.\xe0\x12\xb3\xe89\xfb>v1*\x13\x80\xdd\xc80\xe0z\xb2\xc0E\xa6\x017\xb0\x8d\x9e\x99\xa39\x05w\xb2\x0e\xf8\x0e\xcc\x03\xfe\xfb\xec\x03\xeef \xf0\xddY\bܖ)\x97\xd9\b|\x13#\xb9\xe0\x8bK\\\x05\xae\xf2\x15\xb8\xc8Y`\x94\xb7\xc05\xee\x02w\xf2\x17\bx\x82\xa5\xfcr\x032?\x85\x81\xb9\x93\xd6\xcco\xa8kH\x81\xc0\x06\xfaj<\xa1\x18q\xd0q\xd3\xfb)\x85\xef+\xfa\xee%\xd2\x17չ\x87\xf7e@\xbfB\x8c\x9eҰ\xa3\x17\xf2\xef\x04 \xe7\a c\x04mТ\xdd\xf1\xb4\xfdO\xf1X\x81\x0f\xa0\xf8\x992\xaf\xfd\x19\x17\x8e'\xf2\x99\xff\x10K\xa3Ͱ\xb1\x16]m\xb4\xa0\xb6w\xdb\xe1\xc4I\xe5\xff\xdc\x11\xc5pX\x8bs\xfa\xda\xf9\x96\xa3p\xd3\xf9\\\xb8߸\xfb\x84.\xde\xfa\xb4Ͽ\xccʡݵ\x0e\xe9:6~\x97\xb3\xb9\xc1\xce\xd6:\xb0#\xaa\xa4\xa1\xd1\xe1\xc8\"4\xad\xe9d`F\x9b\x17\xfa\xd0<\xa4\x03m\xf64\xb9%-v=\x13\xe9M8\xb4dZ\xa4\xe3b\xfa4 y/\x95\xa2\x1ef\xb12\xe4,\xd4^Zj\x96,\xb4\xb1\xddo\xa6o\xfewg\x81\x8a9\xbf\xc6Qq\xff\x99\xa6\x00[\x99\xc6\x0f\xf4\xfeV\xc2\x0f\xd6t\xb8e\xbfG\xc7\xf0\xb7\x03\xd7\xe8\t\x8d\xc9\x11፵\xe1\xb2._\"ݱ\xd1\x1cC\xe0\x87Ο8\xb4\xbf\xf5\xff\x00\xe2\x06\xbb\x06\xbbt\xefe촭\xb8&'\xb7\xdf4\xab\xe3\x15\xec\x1c\xfe\xf1\xafɿ\x03\x00\x00\xff\xff%\xff\\)\x99#\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVK\x8f\xdb6\x10\xbe\xfbW\f\xd0k%wQ\xb4(tk69,\xda\x06\xc6n\x90;M\x8e-f)\x92\x9d\x19z\xeb>\xfe{AR\xf2C\xb67\xc9%\xba\x99\xf3\xe4\xf7\xcd|t\xd34\v\x15\xedG$\xb6\xc1w\xa0\xa2ſ\x04}\xfe\xc5\xed\xf3/\xdcڰ\xdc\xdd-\x9e\xad7\x1d\xdc'\x960<\"\x87D\x1a\xdf\xe2\xc6z+6\xf8ŀ\xa2\x8c\x12\xd5-\x00\x94\xf7AT>\xe6\xfc\x13@\a/\x14\x9cCj\xb6\xe8\xdb\xe7\xb4\xc6u\xb2\xce \x95\xe4S\xe9\xdd\x0f\xed\xdd\xcf\xedO\v\x00\xaf\x06\xec\xc0\xa0C\xc1\xb5\xd2\xcf)\x12\xfe\x99\x90\x85\xdb\x1d:\xa4\xd0ڰ\xe0\x88:\xe7\xdfRH\xb1\x83\xa3\xa1Ə\xb5k\xdfoK\xaa7%\xd5cMU\xacβ\xfcv\xcb\xe3w;zE\x97H\xb9\xeb\r\x15\a\xee\x03\xc9\xfbc\xd1\x06̚\xaa\xc5\xfamr\x8a\xae\x06/\x00X\x87\x88\x1d\x94ب4\x9a\x05\xc0\bH\xc9Հ2\xa6@\xac܊\xac\x17\xa4\xfb\xe0\xd2\xe0\x8f\x95\x905\xd9(\x05\xc2\x0f=\x96\xcbC\u0600\xf4\b\xb5\x1cH\x805\x8e\x1d\x98\x12\a\xf0\x89\x83_)\xe9;h3\x92mu͍\x8c\x0e\x95\x847\xf3c\xd9\xe7\x86Y\xc8\xfa\xed\xad\x16X\x94$\x9e\x9a(um\xf0@'ȟ7P\xfc\xdb\xd8+>\xaf\xfeT\f\xb7*W\x9f\xdd]EZ\xf78\xa8n\xf4\r\x11\xfd\xaf\xab\x87\x8f?>\x9d\x1d\xc3y\xafWH\aˠ\xa6N3p\x155\b\x1e!\x10\f\x81&T\xb9=$\x8d\x14\"\x92؉\xff\xfa\x9d\xac\xd5\xc9鬅\x7f\x9b3\x1b@\xee\xbaF\x81\xc9\xfb\x85\\@\x1c\x87\x02\xcdx\xd1\n\xaee \x8c\x84\x8c\xben\\>V\x1e\xc2\xfa\x13jig\xa9\x9f\x90r\x9a<\xaeə\xbc\x96;$\x01B\x1d\xb6\xde\xfe}\xc8\xcd\xf9\u07b9\xa8SR \xc9c畃\x9dr\t\xbf\a\xe5\xcd,\xf3\xa0\xf6@\x98kB\xf2'\xf9J\x00\xcf\xfb\xf8#\x83h\xfd&tЋD\xee\x96˭\x95Ilt\x18\x86\xe4\xad\xec\x97E7\xec:I ^\x1aܡ[\xb2\xdd6\x8ato\x05\xb5$¥\x8a\xb6)\x17\xf1Ep\xda\xc1|G\xa3<\xf1Yً\xe9\xa9_ч\xaf\xa0'\xabE\x9d\x91\x9a\xaa^\xf1\xc8B>\xca\xd0=\xbe{\xfa\x00S'\x95\xa9J\xca\xd1\xf5\x02\x97\x89\x9f\x8c\xa6\xf5\x1b\xa4\x1a\xb7\xa10\x94\x9c\xe8M\f\xd6K\xf9\xa1\x9dE/\xc0i=X\xe1ib3u\xf3\xb4\xf7E\x90\xb3\x02\xa4h\x94\xa0\x99;b\xa3\x13Q\x19\xbe\x83ΫkA_\x8a\x05\x12\x05\xba8\x9d5\xf5\xae8\x95\xff\x12\xcaz\x06\xe5\xf7c H\xaf\x04^\x90\xf2\x86萲Z\xa1\x01\x93.\xf0\x1ba9}\x93\"\x05\x8d|\xb1\x8a\x00Vp\xb8\xd2\xd3+\xec\xe4\xcf'\xe7\xd4\xdaa\aB\to0\xab\x88\xd4~f+o\xdfg Xe\x9fk\x1c\x1c\xde\xfbϒP\xe0\xf6i\xb8\xac\xd4\xc0{|\xb9r\xfa\xe0W\x14\xb6\x84<\x1f\xf9l\\U\xf4p\xfe\x1e\xbc\x82\xd2ա\xbc8\xe4,\x85\xe6\x04E\x96@j{\x8a+\xa7\xf5A\xe9;\xf8\xe7\xbf\xc5\xff\x01\x00\x00\xff\xffߙ6&\xcb\n\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcW\xcdn\xe36\x10\xbe\xfb)\x06\xe8\xa5\x05Vr\x83\xa2E\xe1[\xeb\xec!\xd8t\x1b\xc4\xdb\xdc)j$\xb1\xa1H\x96\x1c:\x9b\xa2\x0f_\f)\xf9G\x96\x1d粺y8\x9c\x9fof\xbe\xa1\x8b\xa2X\b\xa7\x9e\xd0\ae\xcd\n\x84S\xf8\x95\xd0\xf0\xafP>\xff\x1aJe\x97ۛų2\xf5\n\xd61\x90\xed\x1f1\xd8\xe8%\xdeb\xa3\x8c\"e͢G\x12\xb5 \xb1Z\x00\bc,\t\x16\a\xfe\t \xad!o\xb5F_\xb4h\xca\xe7Xa\x15\x95\xae\xd1'\xe3\xa3\xeb\xed\x8f\xe5\xcd/\xe5\xcf\v\x00#z\\Am_\x8c\xb6\xa2\xf6\xf8O\xc4@\xa1ܢFoKe\x17\xc1\xa1dۭ\xb7ѭ`\x7f\x90\xef\x0e~s̷\x83\x99\xc7l&\x9dh\x15\xe8\xd3\xdc\xe9\xbd\x1a4\x9c\x8e^\xe8\xd3 \xd2a謧\xcf{G\x05\xf0y>R\xa6\x8dZ\xf8\x93\x9b\v\x80 \xad\xc3\x15\xa4\x8bNH\xac\x17\x00C\xf6\xc9P1$\xbe\xbdɦd\x87\xbd\xc8\x1e\x00\xacC\xf3\xdb\xc3\xdd\xd3O\x9b#1@\x8dAz\xe5(a\xf8_\xb1\x93\xc347P\x01\x04\f\xe1\x00\xd9]\x84 \f\bO\xaa\x11\x92\xa0\xf1\xb6\x87J\xc8\xe7\xe8\xc0V\x7f\xa3$\bd\xbdh\xf1\x03\x84(;\x10l%+\x1c\xf8Ҷ\x85Fi,w2\xe7\xadCOj\x04)\x7f\a\xbdv \xbd\x94\x05\x7f\x9cx\xbe\x0557\x1d\x06\xa0\x0eG\xf0\xb0\x1e\xb0\x02\xdb\x00u*\x80G\xe71\xa0\xc9m\xc8ba\x86lʉ\xe9\rz6\xc35\x8d\xba\xe6^ݢ'\xf0(mkԿ;ہ\x11c\xa7ZP\x02\xd3\x10z#4l\x85\x8e\xf8\x01\x84\xa9'\x96{\xf1\n\x1e\x13\x82\xd1\x1c\xd8K\x17\xc24\x8e?\xacGP\xa6\xb1+\xe8\x88\\X-\x97\xad\xa2q\x02\xa5\xed\xfbh\x14\xbd.\xd30\xa9*\x92\xf5aY\xe3\x16\xf52\xa8\xb6\x10^v\x8aPR\xf4\xb8\x14N\x15)\x11\x93\xa6\xb0\xec\xeb\xef\xfc0\xb3\xe1\xc8-\xbdrC\x06\xf2ʴ\a\aip\xdeQ\x1e\x1e\xa5\xdc]\xd9TNq_\x05\x161t\x8f\x1f7_`\x8c$Wjh\xb1\x9d\xea\t.c}\x18Me\x1a\xf4\xf9^jS\xb6\x89\xa6vV\x19J?\xa4Vh\bB\xaczEa\xecu.\xdd\xd4\xec:\xb1\x14T\b\xd1Ղ\xb0\x9e*\xdc\x19X\x8b\x1e\xf5Z\x04\xfcƵ⪄\x82\x8bpU\xb5\x0e\xb9w\xaa\x9c\xe1=8\x18\x99\xf3Li'\x94\xb1q(\xb9\xb0\x8c-\xdfT\x8d\x92y\xa4\x1a\xebA\xec\x19d@\xfa\x18\xa8y\x06H\xc1\t\xdf\"M\xa5\x93X\xbe$%v\xff҉c\xc2\xfa\x1e˶d\xce\tC \x99\x8f~\x98\x16\xeaR\f0\xdb賑\x8c\xfd\xcd00\xaeL(Lv\x871\x9d\xba\xe6\x0fM\xec\xe7\x1d\x14\xf0{\x8a\xf9\u07b6\x17\xcf\xd7\xd6\x10\xcf\xc5E\xa5'\xabc\x8f\x1b#\\\xe8\xec\x1b\xbaw\x84\xfd\x9f\x0e}\xde\xd0\x17U\xc7E\xbfۊ\x17\x14\xa3>\xeb\xf7\x11y\x83\xe0\xf9L\a\x85\xab\xac\\\x11ӠyU\xa2\xeb\xcd\xdd{ <\xa3\xfe\x8e\"ݙƾ\x91\xe2^qV\xef\f\r\x8c_zC\xbc\xdd\xd3\xfc\n\x19{\x9a\xaf\xe4݉\xf0)V\xe8\r\x12\x86=S\xbf(\xeaf-\x02\xbctJv\xe9b\x1a\b^\x02!X\xa9\xe6(\xf5\x8a\xf0\x99G\x94Ǚ\xa1,ҰΈ9\xf8\x13\xf1\x19\xf6;\xe7\xa0\x18\x18\xe9*\x06%A1\xbc\x83C\x93\xfe\b\xb5\x8cާ\x15\x95\xa5\xfc2\x99^\xb8\x96DG\xe6\xf9\xeb\xf1\xfe\r&\xbd\xddk\xa6ǸP&G\xe3<\x16A\xb5\xfc\x82\xe23\xe6\xd2\xc4q\xa7`\xe4\xef\xf8\x85w\f\xd4lE\xf1\xabSy\x00\xdf\b\xf1\xe3N1\x13>\x9a\xbc\xe7\xa7o\xd8d\x10\x03?\xb7@\n3\x13c\x85P\xa3F\xc2\x1a\xaa\u05fc\xb9^\x03a\x7f\x1awc}/h\x05\xbc\xff\vR3md\xa2֢Ҹ\x02\xf2\xf1\\\x97\xcd&\xee:\x11f\xc6\xf0(\xe7\a֙k\x8c\xdd0^\xec\f8\xbb_\n\xf8\x8c/3\xd2\ao%\x86\x80\xa7ct6\x93\xd9!8\x11\x06~\xa4\xd5\a(\r\x7f\x19\x06\xc9\xff\x01\x00\x00\xff\xff\xe5\x0fY\x99e\x0e\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4:K\x93\x1b\xb7\xd1\xf7\xfd\x15]\xeb\x83\xed*\ri\xf9\xfb\xe2J\xf1&\xad\xe2\x14\x13[\xd9\x12W\xba\xb8|\xc0\f\x9a\x1cxg\x00\x04\xc0\x90b\x1c\xff\xf7T\x03\x987H\xeeR\xb6\x85\xcb.\xf1h\xf4\xfb\x85ɲ\xec\x86i\xf1\x01\x8d\x15J\xae\x80i\x81\x1f\x1dJ\xfae\x17\x8f\x7f\xb5\v\xa1\x96\xfb\x977\x8fB\xf2\x15\xdc5֩\xfa\x1dZ\u0558\x02\xdf\xe0VHᄒ75:ƙc\xab\x1b\x00&\xa5r\x8c\xa6-\xfd\x04(\x94tFU\x15\x9al\x87r\xf1\xd8\xe4\x987\xa2\xe2h<\xf0\xf6\xea\xfd7\x8b\x97\xdf-\xfer\x03 Y\x8d+Њ\xefU\xd5Ԙ\xb3\xe2\xb1\xd1v\xb1\xc7\n\x8dZ\buc5\x16\x04{gT\xa3W\xd0/\x84\xb3\xf1ހ\xf3\xbd\xe2\x1f<\x98\xd7\x1e\x8c_\xa9\x84u\xffL\xad\xfe \xac\xf3;t\xd5\x18V͑\xf0\x8b\xb6Tƽ\xed/\xca@\xef\xf3\xb0\"䮩\x98\x99\x1d\xbc\x01\xb0\x85Ҹ\x02\x7fN\xb3\x02\xf9\r@$\xde\xc3ɀq\xee\xd9ɪ{#\xa4CsG\x10dw\vG[\x18\xa1\x9dg\xd7\x04s\xb0\x8e\xb9Ƃm\x8a\x12\x98\x85\xb7xX\xae\xe5\xbdQ;\x836\xa0\r\xf0\x8bU\xf2\x9e\xb9r\x05\x8b\xb0}\xa1Kf1\xae\x06\xb6o\xfcB\x9crGB\xd9:#\xe4.\x85ă\xa8\x11xc\xbc\xb8\x89\xfa\x02\xc1\x95\xc2ΰ;0K\x18\x1a\xe7\xc9N\xe3\xe2\xd7\t\xa2u\xac\xd6S\xa4\x06G\x03V\x9c9L\xe1t\xa7j]\xa1C\x0e\xf9\xd1aK\xc9V\x99\x9a\xb9\x15\b\xe9\xbe\xfb\xff\xd3\xec\x88\xfcZ\xf8\xa3o\x94\x1c\xf3\xe65\xcd\xc2`:`B\xb2ڡI2H9V}\n\"\x8e\x00\xbc\x1e\x9c\x0f\x98\x04\xb8\xc3\xf9\x8b\xa8\xacea\xb0Fy\x1dB\xa2?=\xc7f\bz\xb8\xaa\x8dPF\xb8\xe3\n^~\xf3T4\xc9>@m\xc1\x95\bQy6N\x19\xb6C\xf8A\x15A\xd1\x0e%\x9a\xa8hy\xd4\xfeR5\x15\x87\xbc\x15\f\x80u\xca$\x95Mc\xb1\b\xa7\"\xdc\x16\xecD\xe3\xc6w\xfe\x11\x06Q\x18dI\x83h\xdd\xe9\xc2\xef\x10J\xa6\xad\xe2\xd5\x0e\x9fd\x11C\x96Jű\xe3\x1f\xce\xd0\x12\x16\xb4Q\x05Z{\xc6P\t\xc6\b\x91\xb7\xfd\xc4E\x06\x95\xe8\xf7\xb4\xf84\xbaR\x8c\xa3\x01\xa7\xa0d\x92WHd0p\x86I\xbb\x8d*2\x17`{\xec\xe1\xa8Ǩ\xbc\x8f\v\xa7\xd0\t\xbb\xf6/\x83\xbb.J\xac\xd9*\xeeU\x1a\xe5\xab\xfb\xf5\x87\xffی\xa6I\x8d\x95F\xe3D\xeb\xef\xc3\x18\x84\xcd\xc1,\x8c\xc9\xfdo6Z\x03\xa0\v\xc2)\xe0\x14?\xd1z6\xc4@\x80<\xe2\x14\xd8#,\x18\xd4\x06-\x99\x96\xd7(\xb5\x05&A\xe5\xbf`\xe1\x16\x13\xd0\x1b4\x04\xa6\xb5\x85B\xc9=\x1a\a\x06\v\xb5\x93\xe2?\x1dlK\xbc\xa6K+\xe6\xd0:o\x8cF\xb2\n\xf6\xacj\xf0\x050\xc9'\x90kv\x04\x83t'4r\x00\xcf\x1f\xb0S<~T\x06AȭZA霶\xab\xe5r'\\\x9bL\x14\xaa\xae\x1b)\xdcq\xe9\xf3\x02\x917N\x19\xbb\xe4\xb8\xc7ji\xc5.c\xa6(\x85\xc3\xc25\x06\x97L\x8b\xcc\x13\"}B\xb1\xa8\xf9\x17&\xa6\x1fvt\xedL\xd0a\xf8\x1c\xe0\x19⡬\x80\x8c\x80EP\x81\xc4^\n4E\xac{\xf7\xb7\xcd\x03\xb4\x98\x04I\x05\xa1\xf4[g|i\xe5C\xdc\x14rK:O\xe7\xb6F\xd5\x1e&J\xae\x95\x90\xce\xff(*\x81ҁm\xf2Z8R\x83\x7f7h\x1d\x89n\n\xf6\xce'\\\x90\x93-\x91\a\xe0\xd3\rk\tw\xac\xc6\xea\x8eY\xfc\x93eER\xb1\x19\t\xe1I\xd2\x1a\xa6\x91\xd3́\xbd\x83\x856\t\x13\x86a\xc6;%:W\xaaB6\xe5%\x85\xbb\v4S\x00L\t\xcbG[W2\xd7\xe2F\x9bL#圷4\x94|\x968\xb4\xe2\x17\xf0\x8a720\xb8E\x83>\x1b\t\xbe_+\x1f!\x1c\x13\xb2\xf5i\xa1^\x01\xa7\x12\x98\xe5A\x89\x90\xc3\xd46\xe0\xac}\xc0\x99@\x99\xc4\xf8\xd5\xfd\xba\r\x86-\x13#\xee\xb3xw\x91?4\xb6\x02+\xee3\x87\xcbw'5\x97\xc6z\x1b\x90\xf0\x11\xc1)`\xa0\x05\x168\x8a\xc6 \xa4u\xc8x\x9c$'h0\xae\xbd\b\x9e\xfe$\x92\x10\x8a\xca\x18\xb5I&\xc0(\xf2\b\x0e\xff\xd8\xfc\xeb\xed\xf2\xef*\xd0\x01\xac\xa0\xd4\xcc\xd7z>\xdf~\xd1\xd5{\x1c\xad0ȩz\xc3Eͤآu\x8b\b\r\x8d\xfd\xe9۟\xd3\xfc\x03\xf8^\x19\xc0\x8f\x8c\xaa\xa6\x17 \x02ϻ`֪\x8d\xb0\x81\xf0\x0e\"\x1c\x84+=\xa2Z\xf1H\xe0\xc1\x93\xe0\xd8#Yr \xa1A\xa8\xc4c\xc2~¸\xf5\xd9\\\x8f\xe6\xafd=\xbf\xdd\xc2W\xc1y\xdd\xd2\xcfۀF\x97\xb6\f\r\xacG'X\x99\x11\xbb\x1d\xf6y\xffLY(\xccR\x80\xfa\x1a\x94!Z\xa5\x1a\x80\xf0\x80IN!> \x9f\xa1\xf7ӷ?\xdf\xc2Wc\x1e\x9c\xb8JH\x8e\x1f\xe1[\xf2>\x9e7Z\xf1\xaf\x17\xf0\xe0\xf5\xe0(\x1d\xfbH7\x15\xa5\xb2(A\xc9\xea\x18\x12\xe0=\x82U5\xc2\x01\xab*\v\t\"\x87\x03;\x82ڞ\xb8\xa7\x15\x11\xa9&\x03͌;\x9b$F>\x9c7\x9ay\xd6Ԏ\xa7ًϢ\x9ed\xbd\x9f-\x03y\"'|\xb9\xf0\t\x9c\x18\x96^Wp\xe2\xb1\xc9\xd1Ht\xe8\x99\xc1Ua\x89\x0f\x05jg\x97j\x8ff/\xf0\xb0<(\xf3(\xe4.#ê\xd4\xed\xd2\xf7\xc1\x96_\xf8?\xd7\x12\xee\xdbT\x9fJ\xbd\a\xf2\xf9X@\xb7\xdb\xe55\x1ch\xb3\xfb\xa7Ǯ\x93|\xd8Ąs\n\x93l\xfeP\x8a\xa2lk\xbd\x81\xb7\xad\x19\x0f\xee\x98\xc9\xe3g\xb2\x1d\xe2sc\b\xa3c\x16\x9b\xb8\x19\x93\x9c\xfe\xb7\xc2:\x9a\xbf\x86\xb1\x8d\xf8$\xe7\xf2~\xfd\xe6sZT#\xae\xf1$'j\x980>f=VY\xcdt\x16v3\xa7jQLvS\x0e\xbf\xe6$\xa4\xad@s!\xfd{7\xda\xdc&\xa8\x89j\xa0\xdb\xf3\xac\xfcӱ]\"\xe1\x1bv\xb1ϥ\x85g\xf9uY\x15\x1e\xd8\xce\x023\b\fj\xa6I#\x1e\U0005814cC3A\xe9\x02e\x04]c\x10\x98\xd6\x15\xc5\xf4\x90E$ \xc6\xfc7\xb2\x87YO\xdf)\x86$E\xd9v\xa56蜐\x9f\x919\xef'\x88\xfc\xbe\x8c\xeazv\x85\x92[\xb1\x8b\xdd\xce9\xa7dSU,\xafp\x05\xce4\xa7j\xae\xb3\x8c|\xa0-\xe7\xe9\x7f?\xd8\xdaj\xf8\x85\x06c\x9a\xaaQ\xdbqN\fʦ\x9e\xa3\x92\xc1\xa3҂%\xe6\rZ7\xb3^Z\xb8\xbd}\x8e\x8d\x05\xa5\xbc\xa6\xe4\x0eep\xaa*\x8d\x8a\x1e\x13\xf8\xb62u\xaa\xaf\xf2\x92B\x7f\x86o\xa0\xea\x9eʑ1\xdeY\xba]2\xd93\xe8.\xb7SZ\xf1\xc9\xcc\xd8\rN\x16\x03}O\xea!\xf9\x86\xf63\xbaH\xe1\x91-\xf24\x04G\xd7>\xbdQ\xda}m\x1f\x89\n;\xed\x90w\x8d\xfek$\xfej\n\xc4\xf7~\r\x8fF!j\xecJ\xff\xb1\xaf\v\xc5]\x8e\xa0\rj\x96\xec\n\x81\xef\xdc[\xdf\xc2\xfc\xd2\x06`\xc2Bc\x91\xfb\x0e\xda\xec\xee\x19\x84\xf6\x9d\x893\x87\x19\x9d\xbf\xce_\xa4\x1bS\xe1\xcdo\xf8RrU\x97j\x0ef\xceB\xd6r\xcd?ᴏ\x8d)\x8e\xf5\xe0:~\x05h\xc8}\x15JE\xf2\x96\x89\n9\xb4o\xdcτ\x92\xe3\x96R\x9c\xe0\xe3\xda>ND\xeft\xfdw^\x92\t&\xcc\x13\x9e?R\x98ӧ\xc6\v\x92\\O\xb6C\xa9\xaa(/\xd9\xd49\x1a2L\xff\xe0\t\x12\x0fT\xf7\x17%\x93\xbb\xa4\x93k\x1f\xec\x10*f\x1d\xe4\xfd'\x03)\xe2\x87/\xa6Sʆ/\x9c\xfd\xa8\xd1Z\xb6\xbb\xe4\xce\x7f\f\xbbB\xe7.\x1e\x01\x96\xabƥ\xed\xf7K\x1b]\xd0\xf3\xba\x87ɦ\xd8\xd8\xfb1W\xb6\xcen\xdbT\x95?3\x8c\x1b\xfd\xa7\x1d\x1e\xab\x1c\xd3\x19\xff\x99\xd6\xe19\x04Kf/\xb1\xea\x9e\xf6\xa4\xfcq\x17\xec\xce:d8\x13\xd8\xdf\xe2!1\xdb\xfa\xb9\xc4\xd2}t\x9e\x89\xa5ٗ\x18\xc3\xc5\xd0\x1bOq\xae]K\xc2\xec\xbesH\xac}\xef\xbdʳ\x98\x1d\xf1\xbb\xc6mv\xbd\xf5\xde\xf2\xfcg\v3\xfb\x1b\xe7\x1fL\xf2\xa1\xd8RM\x88\xfe|\xabA\x01Rl\xa4\xc5'\x01ﺜ\x02.\xac\xaeر\xa3ŗ~d\xaa\xe9\xf7\x91ޢZ\x8f\xa9\xf1T*{\xbe\xc3\xdd}-\x92\xaek\xcf\xfb\v\xb8\xe03\xfc\xba:\xed\f\x7f\x8f\x1bΤ\xe2V2mK\xe5\xd6o.\xa8Ʀ\xdb\xd8\xdac_V\xfa\xc0\xe2\x9f\xde⦨\n\tT{\xef\xf6,g1\xfex\xe8\x1a-ތ \\\x88\xfb\xf1[\xa6Ttݐ\x17 \a\xe4\x1fv\xef\xa6_p\xbc\xe8\x82\fs\xb1A\x1e\xe2Q\xaa\xab\xa0\xa4\xaf#\x94\x99\xbf\xb2\xc3\xc5@>&\xe8ό\xe1Iu\x9aMz\xcc\xf9\x00v|\xd3\x1c\xce4y\xf7ܿ\x82_\x7f\xbb\xf9_\x00\x00\x00\xff\xff\xfc¬w\xb0(\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4Z͒\x1b\xb7\x11\xbe\xefSt\xad\x0f\xb6\xab4d\xa4$\xae\x14o\xd2*Nmbo\xb6DI\x17\x97\x0f\xe0\xa09\x03s\x06\x80\x01\f\xb9\xb4\xe3wO5\x80\x19\xce\x0fH.\xa9\x925\x17i\xf1\xd3\xf8\xf0u\xa3\xbb\xd1`\x96e7L\x8b\x8fh\xacPr\x01L\v|r(\xe9/;\xdb\xfc\xc3΄\x9ao_\xdel\x84\xe4\v\xb8k\xacS\xf5;\xb4\xaa19\xbeŵ\x90\xc2\t%ojt\x8c3\xc7\x167\x00LJ\xe5\x185[\xfa\x13 W\xd2\x19UUh\xb2\x02\xe5lӬpՈ\x8a\xa3\xf1\xc2ۥ\xb7\x7f\x99\xbd\xfcn\xf6\xf7\x1b\x00\xc9j\\\x80V|\xab\xaa\xa6F\x83\xd6)\x83v\xb6\xc5\n\x8d\x9a\tuc5\xe6$\xbc0\xaa\xd1\v8t\x84\xc9q\xe1\x00\xfaQ\xf1\x8f^λ \xc7wUº\xff$\xbb\x7f\x10\xd6\xf9!\xbaj\f\xab\x128|\xaf-\x95q\x0f\x87\xb52\xd0[\x13z\x84,\x9a\x8a\x99\xe9\xcc\x1b\x00\x9b+\x8d\v\xf0\x135ˑ\xdf\x00D\x06\xbc\xa0\f\x18\xe7\x9eSV=\x1a!\x1d\x9a;\x12!\xbbe8\xda\xdc\b\xed\xd3%\xb3\x18{\x03\xf9K\xdf\x11\x9bܞ0[g\x84,R(ދ\x1a\x817\xc6+\x9d\xf6\x9f#\xb8R\xd8)\xbc\x1d\xb3\x04\xd18\xbf\xf14\x18\xdfO\"\xadc\xb5\x1e\xa3\xeaM\r\xb08s\x98\x02u\xa7j]\xa1C\x0e\xab\xbd\xc3v+kej\xe6\x16 \xa4\xfb\xeeo\xc7\xf9\x88\x84\xcd\xfcԷJ\x0e\xc9yC\xad\xd0k\x0eHH[\x05\x9a$Cʱ\xeaS\x808\x12\xf0\xa67? \tr\xfb\xedg\xa1\x90\xe9\x81Z\x83+\x11ް|\xd3hX:eX\x81\xf0\x83ʃ\nw%\x1a\xf4#Va\x04\x9dm\x10\xa4;e\x92\xaaӘ\xcf\xc2\xd8(\xac\x955\xd2\xdfp\xa1\xcfb_\xb9A\x96\xb4\xaf\xd6I\xcd\xfc\b\xa1d\xda\xc8^\x17\xf8,\x03\xeb\x13)\x15\xc7\x1ek\x13\\\u00826*GkO\x18>\t\x19 y84\x9c\xa5\xa8D?\xa6\x05\xd4\xe8J1\x8e\x06\x9c\x82\x92I^aС3L\xdau\xb4\x8c\xa9\n\xdbi\xef\xf7z\b\xe5C+\xaf\xd73\xc1\x14\x86n_\x067\x98\x97X\xb3E\x1c\xab4\xca\u05cf\xf7\x1f\xff\xba\x1c4\x03Ѣ\xd18\xd1\xfa\xd1\xf0\xf5BR\xaf\x15\x86{\xfe_6\xe8\x03\xa0\x05\xc2,\xe0\x14\x9b\xd0z.\xa2\x7fE\x1e1\x05\x8e\x84\x05\x83ڠE\x19\xa2\x1553\tj\xf5\v\xe6n6\x12\xbdDCb\xc8\xed7\x15\xa7\x90\xb6E\xe3\xc0`\xae\n)~\xebd[\"\x9c\x16\xad\x98C\xeb\xfcA4\x92U\xb0eU\x83/\x80I>\x92\\\xb3=\x18\xa45\xa1\x91=y~\x82\x1d\xe3\xf8\xd1[\x93\\\xab\x05\x94\xcei\xbb\x98\xcf\v\xe1\xda@\x9d\xab\xban\xa4p\xfb\xb9\x8f\xb9b\xd58e\xec\x9c\xe3\x16\xab\xb9\x15E\xc6L^\n\x87\xb9k\fΙ\x16\x99߈\xf4\xc1zV\xf3\xafL\f\xedv\xb0\xecD\xd1\xe1\xf3\xe1\xf5\x02\xf5P\xbc\xa5\x93\xc0\xa2\xa8\xb0Ń\x16\xa8\x89\xa8{\xf7\xcf\xe5{h\x91\x04M\x05\xa5\x1c\x86Nxi\xf5Cl\n\xb9&çyk\xa3j/\x13%\xd7JH\xe7\xff\xc8+\x81ҁmV\xb5pd\x06\xbf6h\x1d\xa9n,\xf6\xce'3\xb0\xa2\x03E~\x80\x8f\a\xdcK\xb8c5Vw\xcc⟬+Ҋ\xcdH\t\xcf\xd2V?E\x1b\x0f\x0e\xf4\xf6:\xda\xfc\xea\x88j\xc7\xfem\xa91'\xcd\x12\xb94U\xacE\x8c$ke\x80M\xc6\x0f\x99J\xbb\x00\xfa\x92\x11e<\xe8\x9c\xd9\xd1\xf7&%\xa8E,{\x8e<\xc6;\x1b\x03U5\fT\xfdo\x12#\rje\x85Sf\x7f\x88\x94c\x938\xaa\x1d\xfar&s\xac\xae\xd9ޝ\x9f\tBr\xe2\x1d;\x93&g\x14\xa4z\xa0J\x16\x8a\x0e\xd9D\x1dp\xefh\x1cٹE\x97ެ<\x1aل\x84C\x8e\t\xfd\\r\xbc\xed\x95R\x15\xb21\x9bZ\xf13\x9b~T\xd1q\x18\\\xa3A\x1f\xff\x83\x9b\xd5\xca;cDŽl\xddGH\xb9\xc1\xa9\xc4>V\xe4n\x8e\xa9\xe6\xb8\x1d\u0089\x90\x94\x04\xfc\xfa\xf1\xbe\r;\xadeE\xe8\x93\xc8\xd2\xe7'i\x16\xf4\xad\x05V\xdc\a\xea\xf3k'-\x84\xbe\xfbu\x00\xe1}\xafS\xc0@\v\xccq\x10\xf7@H\xeb\x90\xf1\xd8H\xee\xc6`\xec{\x11|\xeaQ\x90\x10\xaeE1>\x92J\x80\x91\x8f\x17\x1c\xfe\xbd\xfc\xef\xc3\xfc_*\xec\x03XN\x99\x90\xbf\xab`\x8dҽ\xe8\xee+\x1c\xad0\xc8\xe9\xf6\x81\xb3\x9aI\xb1F\xebfQ\x1a\x1a\xfbӫ\x9f\xd3\xfc\x01|\xaf\f\xe0\x13\xa3\xa4\xff\x05\x88\xc0y\x176Z\xab\x116l\xbc\x93\b;\xe1J\x0fT+\x1e7\xb8\xf3[plC'&l\xa1A\xa8\xc4\x06\xd3\xec\x03\xdc\xfa\xe4\xe9\x00\xf3wr)\x7f\xdc\xc27\xc1I\xdcҟ\xb7\x01F\x97 \xf4\xbd\xce\x01\x8e+\x99\x03gDQ\xe0!ў\x18\v\x054\n\x05߂2\xb4W\xa9z\"\xbc`\xd2Sp\xc4\xc8'\xf0~z\xf5\xf3-|3\xe4\xe0\xc8RBr|\x82Wt\xc6=7Z\xf1og\xf0\xde\xdb\xc1^:\xf6D+奲(A\xc9j\x1f\xf2\xcd-\x82U5\xc2\x0e\xab*\v\xa9\x18\x87\x1dۃZ\x1fY\xa7U\x11\x99&\x03͌;\x99\x8eE\x1eN\x1f\x9ai~\xd2~\xcf;/>_y\xd6\xe9\xfdb\xb1\xfe\x99L\xf8\xc4\xfc\x13\x98\xe8_u\xae`bӬ\xd0Ht\xe8\xc9\xe0*\xb7\xc4C\x8e\xdaٹڢ\xd9\n\xdc\xcdw\xcal\x84,22\xc6,h\xdd\xce}1g\xfe\x95\xff\xe7ڍ\xfb:˧\xee\xde\v\xf9r\x14\xd0\xeav~\r\x03m\x1e\xfd\xfc\xd8u\x94\x87e\xcc\xec\xc62\xe9\xcc\xefJ\x91\x97\xed\xad\xaa\xe7mkƃ;fr\xff\x85\xce\x0e\xf1\xdc\x18B\xb4\xcfb)2c\x92\xd3\xff\xad\xb0\x8eگ!\xb6\x11\x9f\xe4\\>ܿ\xfd\x92'\xaa\x11\xd7x\x92#\xb7\x85\xf0=e\aTY\xcdt\x16F3\xa7j\x91\x8fFS\xae|\xcfIIk\x81\xe6L\xf6\xf7n0\xb8\xcd\xda\x13Yw7梴\xdbJ\xa6m\xa9\xdc\xfd\xdb38\x96\xdd\xc0\x16\xc3A\x871\xe9leё8\x99k>\x03\xcfR\xfc\x96p[ID4\xb4\xc5T\xa9B\xe4\xac\x02\xeb\xdbd,VF\x98\xad\xec)\xa0T=r\f\xb7_U\xec\xe1\xf5\xbe\xe0ḧ\x1dB\x1e\x8enQ+#\n!Yu\xf0\xd8\xfe\xea(Y\xcd\xfc_\t[\xad\x99\xd6B\x16\x17q\xdbַ\x96蜐E\"\xd1\xef\x97\xdfO]\aN\x9e\x93\xf3.\xe0\xc3\b\b0\x83\xc0hO\xa4\xaa\r\uecd0uj&(e\xa4\xac0\xa6\xd6+\x04\xa6uEy]\xc8$S\xbe\xa9\xad\xd6\xe5J\xaeE\x11+\xa7S\xa6dSUlU\xe1\x02\x9ci\x8e]ڒǽ_(<\xa3\xf1\x0f\xbd\xa1\xad\xbaϔ*ӻ\x1a\x140\xa7\x9bA\xd9\xd4S(\x19l\x94\x16,\xd1N\x87s☨\xe3\xf6\xf6\x12\x93\n'\xff\f\a\xe1Μ*8D\xc7\x11\xaf!\xf1\x8a\x1d\xdcG:\x9a_\xeaP\f\xfe\xdaНj\x880K\xd7VFc\xb4\xe27c\xd2\xfa\xbex\xd4y\xf0\xa4\xe3\x8e\xe1\xa1\x1f\xf5\x06\n\x9eU\x96\xf2\x85\xf2K\nS\xe19,\xf2\x1e\xd2\x00\xd7>\x92\xd1\x05\xe3\xea\xd2\x14\xdda\xb5C\u07bd!\\S\xb7y=\x16\xe2\vʆ\xc7C\"j\xec\x8a\x1c\xd1N̡\xec\x12B\x8c6\xa8Y\xd2\"\xc0?\nX_\x18\xfd\xda\x06i\xc2Bc\x91{\xdf:Y\xfchL\xe0\xccaF\xf3\xafs \xe9bWx\x9e\xeb\xbf\xc2\\U\xf9\x9a\x8a\x99r\xc8:\xda\xfc\xfbP\xfb0\x98\xa2\xec \xaf#,\x88C\xee\xafܠ$\xac\x99\xa8\x90C\xf7,}1\xf3\t\xd0\xd3d\xecs\x92_\xa3\xb5\xac8\xe7\xb4~\f\xa3B\xe5-N\x01\xb6R\x8d;b\x95_\xdbx\xb4.\x8a\xc9R\xf1sH\x1e\x14\xf70\xe4\xf1'\xb7)\x9a\x84Z\xfa\xcfp\x17a\xf4E\xcdsEJ\x1a\x93r5\x1d\xe4Ӿ\x06Nİ\a\xdc%Z\xdb\x13\x9c\xe8z\x8cn!\xd15\xf9=@\xbf3T\x92S9Mۗ\x94\xd9=\xb6'\xfa\xbe\xf7\xc7\xe5\"\xb6#\xbek\x1cBW\x87.U\xd5\xfa\x00\xffH.\x9bz\x85\x86T\xb1Je\xc4\xc0$\xefk.UL\xe8$\xb4a8\x88\x8a\xf5\xb0X@\xf7\xa7\xdc)\xe0\xc2\xea\x8a\xed\xbb\xcd\xf8\x1b\x1c\x1d\xe9\xf4s\xc2\xe1\\\xb5\xbe\x8a\"ϑ\xbc\xedt\xa5\xba\xfb\xd1B\xfa~z:Ӈ3پ\xef\xef~\x8c\xf0yV8\x91w\x0e\x7f\x1cr\x8d\x81,\a\x12\xce\x05\x8b\xf8c\x95\xcb}\xfcp\x99?ӽ'ٛ4z\xe4\xbc';>y\xf5[\x9aU\xf7\x1e\xbc\x80\xdf\xff\xb8\xf9\x7f\x00\x00\x00\xff\xffϡa\xa5-&\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=Ks\xdc8sw\xff\n\x94sؤJ#ǕG\xa5tSd;V\xbeoe\x95\xe4\xd8g\f\xd93\xc4'\x10\xe0\x02\xa0ƳI\xfe{\n\x8d\a\x1f\x03\x92\x98\xd1cwSˋJ$\xd0\x00\xfaݍ\x06f\xb5Z\xbd\xa1\r\xfb\x06J3).\bm\x18\xfc0 \xec\x7f\xfa\xfc\xe1\xdf\xf49\x93\xef\x1e߿y`\xa2\xbc W\xad6\xb2\xbe\x03-[U\xc0\a\xd80\xc1\f\x93\xe2M\r\x86\x96\xd4Ћ7\x84P!\xa4\xa1\xf6\xb5\xb6\xff\x12RHa\x94\xe4\x1c\xd4j\v\xe2\xfc\xa1]úe\xbc\x04\x85\xc0\xc3Џ\xffx\xfe\xfe_\xcf\xff\xe5\r!\x82\xd6pA\x14h#\x15\xe8\xf3G\xe0\xa0\xe49\x93ot\x03\x85\x85\xb9U\xb2m.H\xf7\xc1\xf5\xf1㹹\u07b9\xee\xf8\x863m\xfe\xd2\x7f\xfbW\xa6\r~ix\xab(\xef\x06×\xba\x92\xca\xdct\x00WD\xf9暉m˩\x8a\x1d\xde\x10\xa2\v\xd9\xc0\x05\xc1\xf6\r-\xa0|C\x88_\x14\xf6_\xf9\xf5<\xbew \x8a\nj\xea\x00\x13\"\x1b\x10\x97\xb7\xd7\xdf\xfe\xe9~\xf0\x9a\x90\x12t\xa1Xc\x105\xff\xb3\x8a\xefIX\x02a\x9aP\xf2\rQ`g\x83$!\xa6\xa2\x86(h\x14h\x10F\x13S\x01\xa1M\xc3Y\x81\x14!rӃ\x14zi\xb2Q\xb2\ue82di\xf1\xd06\xc4HB\x89\xa1j\v\x86\xfc\xa5]\x83\x12`@\x93\x82\xb7ڀ:\x8f\x80\x1a%\x1bP\x86\x05t\xb9\xa7\xc7U\xbd\xb7s\v\xb3\x8fŅ\xebEJ\xcb^\xe0\x96\xe0\xf1\t\xa5G\x1f\x91\x1bb*\xa6\xbb\xa5\x86\xe5\x11*\x88\\\xff\r\ns>\x02}\x0fʂ\xb1\xd4myi\xb9\xf2\x11\x94EV!\xb7\x82\xfd\x1aak\xbbp;(\xa7\x06\xb4!L\x18P\x82r\xf2Hy\vg\x84\x8ar\x04\xb9\xa6{\xa2\xc0\x8eIZу\x87\x1d\xf4x\x1e?#\xf1\xc4F^\x90ʘF_\xbc{\xb7e&\xc8Z!\xeb\xba\x15\xcc\xecߡذuk\xa4\xd2\xefJx\x04\xfeN\xb3튪\xa2b\x06\n\xd3*xG\x1b\xb6\u0085\b\x94\xb7\xf3\xba\xfc\xbbH\xd4\xc1\xb0foyT\x1b\xc5Ķ\xf7\x01E\xe5\b\xf2X!r\x8c\xe7@\xb9%vT\xb0\xaf,\xea\xee>\xde\x7f\xed3%Ӟ(=ޜ\xa2\x8f\xc5&\x13\x1bP\xae\x1f\xb2\xa6\x85\t\xa2l$\x13\x06\xff)8\x03a\x88n\xd753\x96\r~iA[~\x97c\xb0W\xa8\x8f\xc8\x1aH۔\xd4@9np-\xc8\x15\xad\x81_Q\r\xafL+K\x15\xbd\xb2DȢV_ˎ\x1b;\xf4\xf6>\x04]9AZ\xafE\xee\x1b(\x06\x92f\xbb\xb1MP\x17\x1b\xa9\x06J\xc6v\x19\xe2(-\xfc\xf6qZĪ\xc5\xf1\x97%.\xb3Ͽ\xc7ޖ\xdf\xec\xccZ\xc1~i\x01\x95\xa9\x13\x7f8\xd4W\xaa\xa7\xf4\x87\x8fe\xa31u'\x11m\x1f\xf8Q\xf0\xb6\x842\xea\xf5\x83\x05\xe6,\xe3\xe3\x01\x144\x87\x94\t+D\xd6.ٵ\x88\xee+*p\xaa\x80\bi\x12\xf0\x98p\xf0\b\x13\x88\x81$M\xb0\xa1\x81:1\xe3\xd9%\x13\"Z\xce\xe9\x9a\xc3\x051\xaa=D\xa3\xebK\x95\xa2\xfb\tl\x05\xdf\xe0IȊ@\xbc\xaa\xe1\xac@\x92G\x85\x82\xf8\xfa㢊i\xab(\xc3*o%g\xc5~\x01_\x1f\x93\x9d\x82\xb4z\xd9\xf5+$k\xa8\xe8#\x93*%\x06RaӞ=\xefԴ\xb4Z\xd2\x03\x19۸\xcc\x05'\x91UI\xf9\xb0\xc4\x10\x9fm\x9b\xce:\x90\x02]\u0378\x14Omo\xbb\xd7@\xe0\a\x14\xadIL\x93\x90\xb2E\xd3$\x15i\xa46\xd3t\x9fV]\xa4\xef\x1c\xa5>\xce0\xcd\xc1ʒ\xac\xee\x1e\xaf\x84\x03Q-\x0e\x06\nY\n\xb0˨-Q\xbb\xb6J\xb6\xae\xed$RȚj(\x89\x14\x93##\xbb\xb4\x1c\xb4\x1f\xabD\xce\xe8\xf4\xd0Y\xb7~\xf4x\b\xa7k\xe0D\x03\x87\xc2Hu\x88\xcc\x1c\x94\xba'G\xb1N\xa02\xa1M\x87\x12\xd0-`\x06$\xb1\x9c\xbe\xabXQ9\x0fò'\xc2!\xa5\x04m\xb5\t\xba\xcc\xfb\xa9E\x92%\xf2\xfbA\xe6\xb4G\xf7,\x88\xd5\x18^J\xa3tO\x86\x1a\xee\x9e$j;\xdd{\xa0[\xfc{#g\x97\xfd\xff\x13\xb1\xc1\x98\x9c\xc0\xb43\xf2O\xd0\xfd\xcc\xe6\xe9I\xbe\xc5\b\x0f\xf49\xb9\xde\x10\xa8\x1b\xb3?#̄\xb7K\x92@9\xef\x8d\xf1\a\xa6\xcd\xf1L\x9fI\x9a\x1c\x99x!\xc2\xc4!\xfe\x80tA\x93q\xef-F6M\xfe\xda\xefuF\xd8&\"\xbd<#\x1b\xc6\r\xa8\x11\xf6OR\xf5\x812ρ\x8c\x1c\xabG0O`\x8a\xea\xe3\x0f\xeb\xe2\xe8.=\x96\x89\x97qg\xe7\x1b\x87\bbh\x9e\x17\xe0\x12\x8c\x97\x99\x82\x1a\xe3p\xf2\x15\xb1ٽA\xa7\xfa\xf2\xe6\xc3a\xac<~28\xef`!\vB\xe7\x9e\xcbъ\xfa\xf3\xf3QA\xf8\x82>P\f\xaa\\\xce\xe5\x8cP\xf2\x00{\xe7\xbaPA,}hh\x9c1\xbc\x02L\xfe \x9f=\xc0\x1e\xc1\xa4\xb39\x87O.7\xb8\xe7\x01\x12\xae\x7f\xea\x19\xe0\xd0\xceɇ\xc5\x0eO\xf6\x05\"\x02c\xf8\\6p\x8f\x17\x85D\xee$\xfdd\xea\x92\xf0\x04ܟ\xb0\xcc,V\xe9\x8f\xd1O}\"\a\xfc\xa4\x1d-\xad\xc4T\xcc\xe745\xa0\xcc\xe4\x12\xd4=\xdf(ge\x1c\xc8\xc9ȵ8#7\xd2\xd8?\x18\xa0id\x94\x0f\x12\xf4\x8d4\xf8\xe6E0\xea&\xfe\x92\xf8t#\xa0\xa0\t\xa7\xe5-\xc2\xfa9?g\xd3,\xb7E\xdc3M\xae\x85\x8dW\x1cJ2\x87\xc2\xf4\xae\x1b\xce\rT\xb7\x1a\xd3uB\x8a\x15\xda\xcc\xe4H\x1e\xdfR\r\xd0\xfd\xe4A\xfd\x80_\xad\xb1p_\\\x92\x99\xd3\x02\xca\x10Yb\xf6\x93\x1aز\"s\xbc\x1a\xd4\x16HcUx\x1eGd*V\xbf\x9a\xe3\xd8'\xcfz\xf7\x9f\x1f\xab\x87\x98/XY\x93\xb3\xf2\x10\x8c\xac3p\xe0uw\xb9\xbc\x9e\x95\x95ٌV\x81\x13\x16\x9bN$G\xa7\x9b\xe6 \xe5\t\xe8@+\x8e.\xce\"uiY\xe2\xe6\x1a\xe5\xb7GX\x94#x\xe1X\xd5Л\xbb3\xc15m\xacZ\xf8okiQ\x9a\xfe\x974\x94)}N.q\xa7\x8c\xc3\xe0\x9b\xcf\xc3\xf5\xc0d\f\xd9ء,\xff\x8f\x16\xf5\xbdu\"7\x06\x94\xcf%:\x1b\x10\xe2\x8f'Ff\xa9]\x99\xfedc2\x90\xc6\xfc\xaeE\xf0\x027\xb9\x8d\x9b\x9c)\x1e\xe3\xb0Z\xbc\x1c\xe9\xed\x7f\xfc\xd1\xcbgZɵ\xff\xf7\x17\xf2\xdc\x0eu!뚎w5\xb3\xa6z\xe5z\x06\x9e\xf6\x80\x1c\xf5նEyε\xc8\x1d\x0f\xe1\xfe厙\x8a\tB\x83\xda\x00\xe5\x19\x8a\x92F\xa6rة\xa7\xa2\x9a\xac\x01DL\xd1\xff\x1e\\\x89\x9a\x89k\x1c\x80\xbc\x7f\x01\xd7#\xa2\xeb%\x9dݫH\x93H\xf9\xf8\u0099\xacF\x96dW\x81\x82\x01c\x1c\xe6\xdd\xd1S\x15\xd2\xf4R\x16G8\xa4\x8d,\x7f\xd2dÔ6\xfd)h\xd2\xea\\Z\x1fI>;ﯬ\x06ٚ\x97D\xf0\xc7n\x98\xc1^sM\x7f\xb0\xba\xad\t\xade댹au\xdc\xd5\xf5\xe8\xddQf\xe2\xb6\x15\xe6o\x8c\xb4$h8\x18 kؤ\xf7{SO!\x85f%\xa8P\xa5\xe0\xc8Ƥ\x15\xcc\re\xbcM\xed\x12\xa5\x9ec#`\xf1Q\xa9\x93\x02\xe0/\xaeg/\xefX\xc9\xdd\x10A\x99kǍ4 lC\x98! \n\x8bqPN%\xe3\x10\x1e\x19\x88\x1a\x96\xab\xe7\xf2\x14\xb8}@\xb4u\x1e\x02V(\x90L̦\xdc\xfa\xcd?Q\xc6_\x82l\x96\xf3>Iu\a\xb4<%G\xf3\xbdם\x80Э\xc2\xcd\x7f\xa7;v\x8c\xe7\xcd\xd9R\x8epڊ\xa2\x02TBb\xa8\x1b\x1cx&\xb4\x01\x9a\xcb\v\xd6+j\x85`b\x9bG\xbb\xecDh\xf78T\xaf\xa5\xe4@\xa7w!\xbb\xc7\xe2\xfa\x154\xd1\xf7n\x98'j\xa2\x8e\bn\xdb\x1c\xe9\x90MQ\xab\xb4\b5\x06\xeaƉ\x9c$\xaa\x15}\xeb\xf2\x02\x8a\xe8\x980\xdc\xcf\xe29\xe3k&X\x06m\at\xbd\x16\xcc\xf4\x9dG\v\xe2E\x9dG;@t\aNɰ]\x0f\x00X\x01\rq\b\xce=r\xcd\x11\x8e\xe4\x1a\b-K(]\xeeҺ\">,q\x85o\x13\xc5\r\xc9\xd5\x1d\xef\tfQ6<\x83\xa0\x13\xf3\xb0\xea\x11V\xadx\x10r'V\x18\x8c\xeb\xa3uȉY\xaa\xa7\x0eoNVF\xcb\xfa%_M/i\xa1!\xbf\xe6\xf3T\xf0\x9f^@\xcbd\xf3\xcdQ\t\x8f9.X\xd2k\xae\x00{\xe2\xe3\xe2,\xe6Ɵ\xe9\xec7\xa5\xaf\\\xb1\xf4\x93\xca\xe2\xaeӠzN\xe1\xae\x02S\x81\n\xa5\xd9+,I/gwH\xbb\xe0%\xd6\xc9Y\xa6\n.\xb2+\xff\x1cU\xceat\xd3r~fy\x9b\xb6<\x19\x0e\x1b\x89\"v\xc8YY\xf5ci\x8f!\xa7\xfa\"\x1b\x8f\xfdJ\x8ba}a\xac\x82\b\x05\x862\x8c\xeci\x9cZ/\x16\x96\xf6\xf6\xf7\x87\xe5\x14\x98\xff\v\xd3\xff\xcdK\x0f3*%\xf2ј[\xa5\x19\x91\x98\x80\x95`\xb0\x1e\x1a\xbb\xfa\n\xdf\xce\x17\xfa\xfe\xbepj\xa0\xfe\xd2x\x89\x99ta3К\x803\xaa7Ak\xd0j\xe7\nD;\xe0s\x86\xb6\xffe\xe1NA\x040)~\xfdZA\x10__\xbd\xcf4\xf9gR\xc96Q\xd57\x83\xb2\x85\xea\x8e\xe5\x05\x0f\n=\xfc\x86\x02\x18\xfa\xf8\xfe|\xf8\xc5H_\xf6\x81Y\xb4\x04 \f\x8a\xba\xcc,\x13%{deKy\x90\xda\xee\f\x81c\xa0\x8e\xcf\x12Ф\"\x82qǀ\xa1\xff\x80\xe1ȗ\xc6m\xcb\x1c\xad\xe2\xe6}ѼꐓkB\x865\x1f\x13\xd6\xf0\xd8\xed\x8bg\xa9\x82\xfdMj=\x8e\xaf\xf0ȉ$\x16\xaa9N\xa8\xe1\xc8,\x16{\xf2~KN\x95\xc611\xf7\x8bUd<\x7f\x1dF\x16~\x96k.\x8e\xc1\u038b\xd7W\xbcbU\xc5\xeb\xd4RdVP<_)d^\xf4yR)\xc0r\xc02]\x05\xb1X\xfb\xf0\xa4\x80\xe6\xa4%-\xd64\x1cSɰH\x9d<1{\xb5Z\x85W\xabPxݺ\x84Y.\x9a\xfdxL\xe5A\x8c\x93~\xa6M\xc3\xc4\xf6\x90)rYg\x96m\x96Y\xe6f4\x91\x01\xcf\xf4Ù.:\x9c\b}\xddq\xe9D$\x19ҖL\x18yN.\xc5\xde\xc3M\xc0酏B\x9a\x83\x83lvZ;\xc6y\xff\xb4\x16\x82\x9d\a\xe5\xcfLjZ\xbbYMy\xfbI\xbaJ5p\xcaO\n\x1c\xbf\x8c`\xf4\xb3\xa3\xaf\xe9\xf9\xd7-7\xac\xe1`=\xbaGV&ϐ\x99\n\xf6\x11\xc9\x7f\x93xBj\xbdGH_\xee\xa2,\x9e\x8f\x82\x18\xaa\xc9\x0e8'4\xc5\x1d\a\xcb/\xdc\xc9\xe4B\xae\xf0H\xa0%o`\x12\x7f\x9e\xf9\xccI1\x1e\x03C\xea\xd5\t\xb8\x05\x15x\xbaY'\x162i\x0es\xb4\xe8\x81_\xee\xa2\v|\xf7K\vjO\xe4#\x960x\xef\xad;\xab\xe0Ս\xb61fP\x80^\x19Om*\x1c\x842\x9d\x82\"\x97\xc2\xf9\x12\xe3\xf9`\x1f\xab\xf9\xbaPͪs\x1b\x85%ǘ\xe8.d\xec\x9d\xe8\xb6\xe4\xf6\xe7\x16\xf5\xbfl\xe0v|\xe8\xb6\xe8+\xe5\xfb\xb3\xbfQ\xb1\xfe)E\xfay\xdbA\x8bE\xf9/\x15\xc8-\x85r\xd9\xdek^\xd1\xfdq\x9b\xa8/Xd\xff\x12\xc5\xf5\x99\x98\xca)\xa6?\x0eO\xafP<\xff\xaaE\xf3\xafU,\x9f]$\x9f\xb5\x8f\x99\xbdi\x95\xbb\xcdxb\xd5\xf7\xf2\xae\xfb|\xd1{F\xb1{\xc6N\xda\xf2\"OX^F1\xfbqE\xec\x194\xcb\x15\xc5W,V\x7f\xc5\"\xf5\xd7.N_ଅ\xcf\xc7\x15\xa1\x9f\xbc\x03\x13\xb6\xfaod\t\xb7R\x99\xa5\xe0\xe4v\xdc>\xb1\x93\xda\v\xd8$/\x89\bM\x13\xab\xc4\x10Ç\x17\xa7-*\xbd\xe9\x19\xdc\xe9\x9fei綴\xc7r7j~pVy\x03\n\x84\xbb\xe6\xe3?\xef\xbf\xdcD\xf8)\x9f\xd7{ƣ\xeb%\x9c\aSz\xe4\xf8\xad9_\xcc䰅>\xc03\xef\x8bІ\xfd\a\xde\xf7\xf6\x84t\xd0\xe5\xed5\xc2\b~\x1a^ \x17\xab(\xe2\x8e\xe5\x1a\xacŊ\xa8\x9a\x14\x8b\xeb\xcd\x00\xe2\xb0\xe2\xb7\x7f\x8d\x12\x94\xeeʬ`1Y\xa8\xf1\xb2\x82w{\xed\xe615\xca'\xeb4\x8a=\x91\x8e#+\xa6\xcaUC\x95\xd9#\xdb\xe8\xb3\xc1\x1c\x82\x99\x99K\xe7L*\xd6\xc3k\xc0\x92\xe8\r\xb7\x7f\xe1^\xe4\xbe\x19\xee\xf6\x8eqw\xca<\xa6ϟ,\x9ee\x91\x0e\xc0`\x9d\xac\xa8z\x1e\xe4\x0e\x82\x8f\x19\x96\x8dҊݒ\x1a\x1c\xb8?i\xc5\xf8Y/{\xfb:e:\x99Wl\x9d|\xb9\x96Cτ\xfa\xc1\x1d\t\xab\xda\x0e1uB\x81\xceb\xb8\x9dq\xf0c>\xb1\x90y5S\x9e\xc18\xe1:&\xc4W.\xaeH\xf2\x96\xa6̛\x98~SD\xcfh5]TP\xb6\x1cN\xbd\x87\xf5\xbe\xd7\x7f\xf9&\xd60Z\xc6]\xac\x16\xd9=\x03m=\xacᝯ\x9e\x12\x1er\x9f\x92SA8&lܕ\x8f\x85\xbb\x1d\xb8(@\xebM\xcbC\xe5h\xa1\x80\x1a(Cs\xa6㌏\xaa}\xd4\x0f\xac\xf9\xe0j(\xc7a\xf7I8\x9e\x06\x17.O\xefY\a\xdcSP\x8f\xa0V\x05z\x84\xad\x822Tt\xcex\x91\xa4\x0e \x99\xeeG\xf2\x03W=\xd1\xff{\x05\x02\xb9\xd29Q\xa1t\xb4\x0f͢\xa3\x81\x92\xc0#\b\xc26\xa47/)z\x13N\x81\xffLq\x03\x0e6\x1b(\x8c\xdbХ\xe80\a\xa9=\xc0\b\xeb\xe4>\xe1Y=\xc1\xe0\xb5\r\x97\xb4\x04\xe5\x1c\xed\x05B\xfeנ\xf1H\x13\x05\x04t\x97(\xcf^@\xfb${\xd4PE9\a\xfe\x89q\xd0\x1f\xe4N\xd8ye\xa8\xd9\xdbT\xbf\xde\t\xe8\xa2U\xd6Y\xdb\x13\xd1\xd6kPD\x831\xd3iٍT\xf3g\x91\x1c\xe2\x990\xb0\x85T&{\xa7\x98\x81\xfb\x86*\r8\xa3\x8c\x15|\x1fuqy\xde\r\xa7[Wt^\xb2\x82\x1a\x88\x82\x83#LM\x1f\xfbk\x84\xc5\xf7X\x03,'\xb6\x97\xb2U\xf5\xd4\xe1\xc7Ie=u\x91w\xc2\x01K^\xe5\xed\xfc\xac\x826\x06\x8f\x9a\"\x1d\x91\x88\xc6\xc3\xc0\xeb\xf1G\xb7y\x0f\xc0Ns\x9a?0\xe4Kӵ\xa1u\"\xf6[\xd6tW\x87`\xf0\x02~U\xf6*\xdc\xfbW\x19\xc7Rv\xb2\xa3:\x1e[JFT\x1dl\a\x06՚\x05\x1d4\x93\x15E\xca8\x94s\x9c\xfa5j\xab\x9ft\x84\x835\xf7\x96\xc5\xef\rU&N\xfd\xd0;u\x91\xf9\x05)\xa9\x81\x95\xed}\x9a~J_H\xaeԉ\x857x\x86܋G\x11\x0e\xb8Z\x9fƝ\xfc\xaeAk\xba\r\xe9\xde\x1d( [\x10\x16\xefq\x17/\xe9\a\x87\xc3\xf3\xde\x05\x18\xa4{haZ\xea\ap\x8ey\xacS\n\xbf\x04\x80\xf9\xe2\xed\xa4\xe1M\xab\n\x7fL\xff\x0e\xa8\x1e\xff\xb0\xc4\x01.>\xf5\xdb\xfa\xedX\xb7bW\x85@\xddQ\n\xfci\x01\xc3b\x0e;%\xd3F\xe2\xc8G9\t\x95\x94\x0fY\xc1\xd3\xe7ذ۸a±\x12^N\xb0\x96\xad\xe9y\xaf\x1e\xe1\x89i\xe2E\xdb\xcfl_\x10\xe6\xa5;\xaa<\xb5\x8b\x99\xe7\xbf\x7f\x1e@\x8aI\vi(\x0fF\xc6\xf2elP\xcd\\\xd5s\x1f~\xa6\x80\xf3\xfd\xd9\x18\xf2\xe8\xf7O:\xd8Uwi\xb6\xd7\x04\xddE-\x13\x03\x85\xfd\xb5$\x90x\xdfv\xe7iN\xddn\xbcd\xff\x10\xea'\x9cT\x06\x8e?w\xad\xa7\xf0\xe8\xa6\xe9\xc2 \x10\xe9\xfc\x01\xc1\x90\xd2TQ2N\x98\xfaL\xec\xd1TT/\x05\x1d\xb7\xb6Mt;z\xe6*\x86\x16w\x13R\x99\xbeQbEn`\x97x됅u&(U\x89&\xd7\xe2Vɭ\x02}\xc8t+\xbc9\x80\x89\xed'\xa9ny\xbbe\xe2\xcb\xf4\x19\xab\xb9ƷT\x19f\x99\xd6\xcd'\xd1\xf7*ظķ\xe5\xde\xd3\x1f\x98\xa0\x9c\xfd\x9a\xd2\xe5\xfd\x8fK#\xcc\xe8\xbb\xc6#\xef\x14\v\x15\x10\xbf\xa4\x00\xbd\x86\xfeI\xf7\xccO\x18\xf7\x9c\xdcȤ\x18\xfbR,6\x04\xca4Y\x836+\xd8l\xa42n\xa7|\xb5\xb2\xe1\x8bw\x90\xac\x86\xc0\xe8\xdf\xfdn\fa\xa9\xe8*\x16\xb9\x04\x87e\xe3\x13\xc4\n\xad\x0e&\x12j\xbawyfZ\x146&\x80w\xda\xd0T\xc4\xf9$=\x8d\t\b/+9*\xe4\xba\xdf>fn\xa3\xfa@p\x0euxq\x8c3\xe8|\xaazdp/\x15\xd1\x16{\xa7(\x13\xe2\xd4\xd8\xf5t2%\xcf\xd4|\x8dP\xa6ԣ_\xdf\xe0'/|)\x93od\xc9VTTl'\x8f\x8eWJ\xb6\xdb*\xf0\xe6\x94CD\xca\x16\xf3!\r\xaa\x02\x1d~\xa2˴J\xf4\xcac|5㔖\x8eӝ\xf6Q\x9e\xa0\xa8Uw\x84\xb4SU36?;\xf7;\x01q\xd1\xf6' R\xbd\x17\xc5\xeca\xd7Ýǣ\\\xcb$\x12\xa26~6$D\x88SH\xe8\xfb\x12]\xc4\xf3\xbb\xc1Ȕ\x8fr\":\xe6\x9d\x18\\\xe2<\xa8\xe5E\xf7\x9d\xa0\xa1\xbbs\x1c:\xf4 \xf8;)\xd17\x80pL\xe4\x8bc\xa7\xe3\xde\xdfo\xc4\xfa\x18\xbd\xad\x8f'Ǯ\xdfF0F\x97\r\xd8(\xb6\x1b&ě\x7f\xcf6)yq\xbf\x83\xb8\xe6\xf0\x0f\a__\xf9Ҁ\x1dU\x82\x89\xedI\x18\xf9\xee\xfb&\xe2y\x0f\xf6%#\xfa0\xf3g\x8b\xe9\x93f\xe9\xe0%2x\xd9ó\x1fɿ\xf9\xbf\x00\x00\x00\xff\xff\x9d=\x85\t\xc7t\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=]\x93\xdc(\x92\xef\xfe\x15\x84\xefa\xee\"\xba\xca7q\x1fq\xd1o\u07b6}\xee\u06ddv\x87\xdbg?SRV\x89i\x04\x1a@]\xae\xdd\xdb\xff~A\x02\x12R!\x89\xaa\xfe\x98\x99\x8d\xd1KG\xab \x81\xfc\xce$A\xab\xd5\xea\x15m\xd8WP\x9aIqIh\xc3\xe0\xbb\x01a\xff\xd3\xeb\xfb\xff\xd2k&\xdf<\xfc\xf8꞉\xf2\x92\\\xb5\xda\xc8\xfa3h٪\x02\xde\xc1\x96\tf\x98\x14\xafj0\xb4\xa4\x86^\xbe\"\x84\n!\r\xb5\xaf\xb5\xfd\x97\x90B\n\xa3$\xe7\xa0V;\x10\xeb\xfbv\x03\x9b\x96\xf1\x12\x14\x02\x0fC?\xfc\xeb\xfa\xc7\xff\\\xff\xc7+B\x04\xad\xe1\x92(\xd0F*\xd0\xeb\a\xe0\xa0\xe4\x9a\xc9W\xba\x81\xc2\xc2\xdc)\xd96\x97\xa4\xff\xc1\xf5\xf1㹹~v\xdd\xf1\rg\xda\xfc9~\xfb\x17\xa6\r\xfe\xd2\xf0VQ\xde\x0f\x86/u%\x95\xb9\xe9\x01\xae\x88\xf2\xcd5\x13\xbb\x96S\xd5uxE\x88.d\x03\x97\x04\xdb7\xb4\x80\xf2\x15!~Q\xd8\x7fEhY\"\x9a(\xbfUL\x18PW\x92\xb7\xb5蠗\xa0\v\xc5\x1a\x83h\xf8R\x01.\x86\xc8-1\x15\x90\r-\xeeۆ\x98\x8a\xe90(a\x9al\x95\xac\xb1;!?k)n\xa9\xa9.\xc9\xda\"h\xedz\xd8\xf9\xf8\x06\x0e\x9f\x7f\xc2\xd7\xfe\x959\xd89k\xa3\x98إf\xe1\xf1D\xb4\xa1\xa6\xd5D\xb7EE\xa8&7\xb0\x7fs-n\x95\xdc)\xd0:1>6_7\x15\xd5\xc3\xc1\xef\xf0\x87\xcc\xc1\xbfHC9\x11m\xbd\x01e\xd1\x00JI\xa5\t\x97\xbb\x1d\x94\xa4lm?č\x8ah\x9c\x9a\x87\xeb8\x98\xc8\xfb\xf8\x95\x9b\x88%\xc9\x0eT\xceL\xf6T\t&v\xe7\xcc%t\x1d\xcc\xe6\xdb\xf0ej>\x11\xa4 e\xebB\x01\n\xd8\x17V\x836\xb4n\x06@\xdf\xee`\x00\xaf\xa4ƽp??\xfc\xe8X\xb9\xa8\xa0\xa6\x97\xbe\xa5l@\xbc\xbd\xbd\xfe\xfaow\x83\xd7d\x88\x8e\xff[u\xefI\xc7\"L\x13J\xbe\xa2(Z$\xa0j \xa6\xa2\x86(h\x14h\x10F#\x86h\xd3pV\xe0ĉ\xdcF\x90B/\xc7\xd5=\xb4\xc0\xfa\x92Pb\xa8ځ!\x7fn7\xa0\x04\x18Ф\xe0\xad6\xa0\xd6\x1d\xa0F\xc9\x06\x94aAl\xdd\x13i\xb7\xe8\xed\xdc\xc2\xeccq\xe1z\x91Ҫ9pK\xf0r\r\xa5G\x9f\x13R\x94L\xbf\u0530\xd9)H\xab\x97\xdd\xe0\xa6n\xa0\xa2\x0fL\xaa\x94\x18H\x85M#{ޫii\xb5\xa4\a2\xb6q\x99\vN\"\xab\x92\xf2~\x89!>\xda6\xbdu \x05\x86<\xddR<\xb5\xbd\xed\xde\x00\x81\xefP\xb4&1M\x12\x9cC\xa9H#\xb5\x99\xa6\xfb\xb4\xea\"\xb1s\x94\xfaq\x86i\x8eV\x96du\xf7x%\x1c\x88jq0P\xc8R\x80]Fm\x89ڷU\xb2um'\x91B6TCI\xa4\x98\x1c\x19٥\xe5\xa0\xfdX%rF\xaf\x87.\xfa\xf5\xa3\xc7C8\xdd\x00'\x1a8\x14F\xaacd\xe6\xa0\xd4=9\x8au\x02\x95\tm:\x94\x80~\x013 \x89\xe5\xf4}Ŋ\xcay\x18\x96=\x11\x0e)%h\xabM\xd0e>L-\x92,\x91\xdf\x0f2\xa7=\xfagA\xac\xc6\xf0R\x1a\xa5\x7f2\xd4p\xff$Q\xdb\xeb\xde#\xdd\xe2\xdf\x1b9\xbb\xec\x7fL\xc4\x06cr\x06\xd3\xce\xc8?A\xf73\x9b\xa7'\xf9\x16#<\xd0kr\xbd%P7\xe6pA\x98\to\x97$\x81r\x1e\x8d\xf1;\xa6\xcd\xe9L\x9fI\x9a\x1c\x99x&\xc2tC\xfc\x0e\xe9\x82&\xe3\xce[\x8cl\x9a\xfc%\xeeuAضCzyA\xb6\x8c\x1bP#쟥\xea\x03e\x9e\x02\x199V\x8f`\x9e\xc0\x14\xd5\xfb\xef\xd6\xc5\xd1}\x9a6\x13/\xe3\xce\xce7\x0e\x11\xc4\xd0y\xd6;~\xbe\xaf\xee\xbb|\xc1ʚ\x9c\x95\x87`d\x9d\x81\x03\xaf\xbb\xcb\xe5\xf5\xac\xac\xccf\xb4\n\x9c\xb0\xd8t\"9:\xdd4\a)\x8f@\aZqtq\x16\xa9\x1b\xef^\xe6[\x94\x13x\xe1T\xd5\x10\xcdݙ\xe0\x9a6V-\xfc\xcdZZ\x94\xa6\xbf\x93\x862\xa5\xd7\xe4-\xee\xd8r\x18\xfc\xe6\xf3p\x11\x98\x8c!\x1b;\x94\xe5\x9f\aʭ\xed\xb7\n\\\x10\xe0\xce\x13\x90\xdb#\xbf\xe8\x82\xec+\xa9\x9d\xd9\xde2\xe0\xb8_\xf1\xfa\x1e\x0e\xaf/\xec\xf0\x8bC\xc6J\xe6\xf5\xb5x\xed|\x88#\x85\xd19\x1cR\xf0\x03y\x8d\xbf\xbd~\x8c+\x95ɩ\x99\xcd\x06,Z\xd3&\x8fCE2Y\xdf?\x03\x8e\x89s\xf3}R\xde;\xd9s\xab\xcdb\xd1Fj\xf31\x9d7\x9c\x98\xcfm\xe81\xf4\x8c\x139\xb6ň\xc1\xe7\xd1:}o\x9dȭ\x01\xe5s\x89\xce\x06\x84\xf8㑑YjW&\x9el\x97\f\xa4]~\xd7\"x\x81\x9b\xdc\xc6M\xce\x14OqX-^N\xf4\xf6\xdf\x7f\x8f\xf2\x99Vr\xed\xff\xf1B\x9eڡ.d]\xd3\xf1\xaef\xd6T\xaf\\\xcf\xc0\xd3\x1e\x90\xa3\xbeڵ(Ϲ\x16\xb9\xe7!ܿ\xdc3S1AhP\x1b\xa0\x83\xebѡ\xeb9\x9dݫ\x8e&\x1d\xe5\xbb\x17\xced5\xb2$\xfb\n\x14\f\x18\xe38\uf39e\xaa\x90&JY\x9c\xe0\x906\xb2\xfcA\x93-S\xda\xc4SФչ\xb4>\x91|v\xde_X\r\xb25ω\xe0\xf7\xfd0\x83\xbd\xe6\x9a~gu[\x13Z\xcb\xd6\x19s\xc3\xeanWףwO\x99鶭0\x7fc\xa4%A\xc3\xc1\x00\xd9\xc06\xbdߛz\n)4+\xa1+\x1drdc\xd2\n\xe6\x962ަv\x89Rϩ\x11\xb0\xc0\xea\xa73P\xfc\xc9\xf5\x8c\xf2\x8e\x95\xdc\x0f\x11\x94\xb9v\xdcH\x03¶\x84\x19\x02\xa2\xb0\x18\a\xe5T2\x0eᑁ\xa8a\xb9z.O\x81\xdb\aD[\xe7!`\x85\x02\xc9\xc4l\xca-n\xfe\x812\xfe\x1cd\xb3\x9c\xf7A\xaa\xcf@\xcbsr4ߢ\xee\x04\x84n\x15n\xfe;ݱg}\xeedq=\nb\xa8&{\xe0\x9c\xd0\x14w\x1c-\xbfp'\x93\v\xb9\xc2#\x81\x96\xbc\x81I\xfcy\xe6\v'\xc5x\f\f\xa9W'\xe0\x16T\xe0\xe9f\x9dXȤ9\xccѢG~\xb9\x8b.\xf0\xdd/-\xa8\x03\x91\x0fX\xc2ཷ\xfe\xac\x82W7\xdaƘA\x01ze<\xb5\xa9p\x14\xca\xf4\n\x8a\xbc\x15Η\x18\xcf\a\xfbX\xcdׇjV\x9d\xdb(,9\xc6Dw!\xbbމnKn\x7fnQ\xff\xf3\x06n\xa7\x87n\x8b\xbeR\xbe?\xfb+\x15\xeb\x9fS\xa4\x9f\xb7\x1d\xb4X\x94\xff\\\x81\xdcR(\x97\xed\xbd\xe6\x15ݟ\xb6\x89\xfa\x8cE\xf6\xcfQ\\\x9f\x89\xa9\x9cb\xfa\xd3\xf0\xf4\x02\xc5\xf3/Z4\xffR\xc5\xf2\xd9E\xf2Y\xfb\x98ٛV\xb9یgV}/\xef\xba\xcf\x17\xbdg\x14\xbbg\xec\xa4-/\xf2\x8c\xe5e\x14\xb3\x9fVĞA\xb3\\Q|\xc1b\xf5\x17,R\x7f\xe9\xe2\xf4\x05\xceZ\xf8\xf9\xb4\"\xf4\xb3w`\xc2V\xff\x8d,\xe1V*\xb3\x14\x9c\u070e\xdb'vR\xa3\x80M\xf2\x92\x88\xd04\xb1J\f1|xqޢқ\x9e\xc1\x9d\xfeI\x96vnK{,\x9fG͏\xce*oA\x81p\xd7|\xfc\xcfݧ\x9b\x0e~\xca\xe7\xf5\x9e\xf1\xe8z\t\xe7\xc1\x94\x1e9~k\xce\x1739l\xa1\x0f\xf0\xc4\xfb\"\xb4a\xff\x8d\xf7\x0e>\"\x1d\xf4\xf6\xf6\x1aa\x04?\r/2\xec\xaa(\xba\x1d\xcb\rX\x8bաjR,\xae\xb7\x03\x88Ê\xdf\xf8\x1a%(ݕY\xc1b\xb2P\xe3e\x05\xef\xf6\xda\xcdcj\x94\x0f\xd6i\x14\a\"\x1dGVL\x95\xab\x86*s@\xb6\xd1\x17\x839\x0433\x97ΙT\xac\xc7׀%\xd1\x1bn\xff½\xc8C3\xdc\xed\x1d\xe3\xee\x9cyL\x9f?YfX6Jk|sq\xfc`\xbc\xe4j\x11\x19\xbf\x88\xb2\xb7/S\xa6\x93y\xc5\xd6ٗk9\xf4L\xa8\x1fܑ\xb0\xaa\xed\x18Sg\x14\xe8,\x86\xdb\x19\a?\xe6\x13\v\x99W3\xe5\x19\x8c3\xaecB|\xe5\xe2\x8a$oiʼ\x89\xe9WE\xf4\x8cV\xd3E\x05e\xcb\xe1\xdc{X\xef\xa2\xfe\xcb7\xb1\x86\xd12\xeeb\xb5Ȏ\f\xb4\xf5\xb0\x86w\xbezJx\xc81%\xa7\x82pLظ+\x1f\vw;pQ\x80\xd6ۖ\x87\xcaQ\xbc\xc0\x1b\xcaМ\xe9n\xc6'\xd5>\xea{ּs5\x94\xe3\xb0\xfb,\x1cO\x83\v\x97\xf8G\xd6\x01\xf7\x14\xd4\x03\xa8U\x81\x1ea\xab\xa0\f\x15\x9d3^$\xa9\x03H\xa6\xe3H~\xe0\xaa'\xfa\x7f\xab@ W:'*\x94\x8e\xc6\xd0,:\x1a(\t<\x80 lK\xa2yI\x11M8\x05\xfe#\xc5\r8\xd8n\xa10nC\x97\xa2\xc3\x1c\xa4\xf6\b#\xac\x97\xfb\x84g\xf5\b\x83\xd76\\\xd2\x12\x94s\xb4\x17\b\xf9\xbf\x83\xc6#M\x14\x10\xd0_\xa2<{\x01\xed\xa3\xecQC\x15\xe5\x1c\xf8\a\xc6A\xbf\x93{a畡foS\xfd\xa2\x13\xd0E\xab\xac\xb3v\b\xb7\xf0k0f:-\xbb\x95j\xfe,\xd2\xf1\x15\xfb\xc3g\xaf\x98\x81\xbb\x86*\r8\xa3\x8c\x15|\x1buqy\xde-\xa7;Wt^\xb2\x82\x1a\xe8\x04\aG\x98\x9a>\xf6\xd7\b\x8b\x1f\xb0\x06XNl/e\xab\xea\xa9Ï\x93\xcaz\xea\"\xef\x84\x03\x96\xbc\xca\xdb\xf9Y\x05m\f\x1e5E:\"\x11M\xf8\x9c\x84\xdc\x1e\xdd\xe6=\x00;\xcdi\xfe\xc0P\xfc\xed\x83s4\xdd\xd51\x18\xbc\x80_\x95Q\x85{|\x95qW\xcaN\xf6Twǖ\x92\x11U\x0fہA\xb5fA\a\xcddE\x912\x0e\xe5\x1c\xa7~\xe9\xb4\xd5\x0f\xba\x83\x835\xf7\x96\xc5\xef\fU\xa6\x9b\xfa\xb1w\xea\"s\xf7釕\xed}\x9e~J_H\x8e_\xd08\xeb^m\xf7\x1d\x0f\x14\x8f\"\x1cp\xb5>\x8d;\xf9]\x83\xd6t\x17ҽ{P@v ,\u07bb]\xbc\xa4\x1f\x1c\x0e\xcf{\x17`\x90\ue845i)\x0f_\x10\xa1\xf8E\x13_\xa7\x14\xbe\x04\x80\xf9\xe2ݤ\xe1M\xab\n\x7fL\xff3P=\xfe\xb0\xc4\x11.>\xc4m\xfdv\xac[\xb1\xabB\xa0\xee(\x05~Z\xc005\xfe\x94\xc8`J\x12G>\xc9I\xa8\xa4\xbc\xcf\n\x9e>v\r\xfb\x8d\x1b&\x1c+\xe1\xe5\x04\x1bٚ\xc8{\xf5\bOL\x13/\xda~b\xfb\x820ߺ\xa3\xcaS\xbb\x98y\xfe\xfb\xc7\x01\xa4.i1\xfa\xd4\v\xed\x1aT3W\xf5܅\xcf\x14p~\xb8\x18C\x1e}\xff\xa4\x87]\xf5\x97f{M\xd0_\xd421P\xd8_K\x02\xe9\xee\xdb\xee=ͩۍ\x97\xec\x1fB\xfd\x80\x93\xca\xc0\xf1Ǿ\xf5\x14\x1e\xdd4]\x18\x04\"\x9d? \x18R\x9a\xaa\x93\x8c3\xa6>\x13{\xe0爖6\xe3l\x9b\xce\xed\x88\xccU\x17Z|\x9e\x90\xca\xf4\x8d\x12+r\x03\xfb\xc4[\x87,\xac3A\xa9J49\xfa\xc0R\xfc\xe37ʬ\xfb\xf3A\xaa[\xde\xee\x98\xf84}\xc6j\xae\xf1-U\x86Y\xa6u\xf3I\xf4\xbd\n6.\xf1\xdbr\xef\xe9\x1f\x98\xa0\x9c\xfd5\xa5\xcb\xe3\x1f\x97F\x98\xd1w\x8dG\xde9\x16* ~I\x01z\r\xfd\x83\x8e\xccO\x18wMndR\x8c})\x16\x1b\x02e\x9al@\x9b\x15l\xb7R\x19\xb7S\xbeZ\xd9\xf0\xc5;HVC`\xf4\xef\xbe\x1bCX*\xba\xea\x8a\\\x82ò\xf5\tb\x85V\a\x13\t5=\xb8<3-\n\x1b\x13\xc0\x1bmh*\xe2|\x94\x9e\xc6\x04\x84\x97\x95\x1c\x15r\x1d\xb7\xef2\xb7\x9d\xfa@p\x0euxq\x8c3\xe8|\xaazdp/\x15\xd1\x16{\xe7(\x13\xe2\xd4\xd8\xf5t2%\xcf\xd4|\xe9\xa0L\xa9G\xbf\xbe\xc1'/|)\x93od\xc9VTT\xec&\x8f\x8eWJ\xb6\xbb*\xf0\xe6\x94CD\xca\x16\xf3!\r\xaa\x02\x1d>\xd1eZ%\xa2\xf2\x18_\xcd8\xa5\xa5\xbb\xe9N\xfb(\x8fPԪ?Bګ\xaa\x19\x9b\x9f\x9d\xfb\x9d\x80\xb8h\xfb\x13\x10\xa9>\x88b\xf6\xb0\xeb\xf1\xce\xe3I\xaee\x12\t\x9d6~2$t\x10\xa7\x90\x10\xfb\x12}\xc4\xf3\x9b\xc1Ȕ\x8fr&:\xe6\x9d\x18\\\xe2<\xa8\xe5E\xc7N\xd0\xd0\xdd9\r\x1dz\x10\xfc\x9d\x95\xe8\x1b@8%\xf2ű\xd3q\xefo7b}輭\xf7gǮ_G0F\x97\r\xd8(\xb6\x1f&ě\xff̶)yq\xdfA\xdcp\xf8\x97\xa3__\xf8Ҁ\xf0Q\xcas0\x12\xbe]\x99\x88\xe7=\xd8\xe7\x8c\xe8\xbb/q>UL\x9f4KG/\x91\xc1\xcb\b\xcf~\xa4\xf8M\xbb\xe9\xbf\xd9D\xfe\xf6\xf7W\xff\x1f\x00\x00\xff\xff\x95Pn\x17dw\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=\xdbr\x1c+\x92\xef\xfa\nB\xfb0\x97P\xb7DZ\x97\xd8ЛG\xb6g;\xc6c+,\x1d=\x0f]\x95\xad\xe6\xa8\n\xea\x00%\xb9wv\xfe}#\x13\xa8[\x17]T\xab%ϙ1/\xb6\xaa!I2\x93\xbc@\x02\x8b\xc5\xe2\x8cW\xe2\x0e\xb4\x11J^2^\t\xf8fA\xe2_f\xf9\xf0\xdff)ԛǷg\x0fB\xe6\x97\xec\xaa6V\x95_\xc1\xa8Zg\xf0\x1e6B\n+\x94<+\xc1\xf2\x9c[~y\xc6\x18\x97RY\x8e\x9f\r\xfe\xc9X\xa6\xa4ժ(@/\xeeA.\x1f\xea5\xackQ\xe4\xa0\tx\xe8\xfa\xf1\x0f˷\xff\xb5\xfc\xcf3\xc6$/ᒙl\vy]\x80Y>B\x01Z-\x85:3\x15d\b\xf4^\xab\xba\xbad\xed\x0f\xae\x91\xef\xd0!{\xe3\xdbӧB\x18\xfb\xe7\xde\xe7O\xc2X\xfa\xa9*j͋N\x7f\xf4\xd5l\x95\xb6\x9f[\x98\v\xf7\xbb\xfbM\xc8\xfb\xba\xe0\xbamsƘ\xc9T\x05\x97\x8c\x9aT<\xa3\xaa~l\x04b\xc1x\x9e\x13\xb5xq\xad\x85\xb4\xa0\xafTQ\x97\xb2\xe9 \a\x93iQY\xa2ƍ\xe5\xb66Lm\x98\xddB\xb7\x1f,?\x1b%\xaf\xb9\xdd^\xb2\xa5\xa1z\xcbj\xcbM\xf8Ց\xcf\x01\xf0\x9f\xec\x0eq3V\vy?\xd6\xdb;v\xa5\x95d\xf0\xad\xd2`\x10e\x96\x13s\xe5={ڂdV1]KB\xe5\x8f<{\xa8\xab\x11D*Ȗ\x03<=&\xfd\x8fS\xb8\xdcn\x81\x15\xdcXfE\t\x8c\xfb\x0e\xd9\x137\x84\xc3Fif\xb7\xc2L\xd3\x04\x81\xf4\xb0u\xe8|\x1a~v\b\xe5܂G\xa7\x03*\b\xf62\xd3@2}+J0\x96\x97}\x98\xef\xee!\x01\x18\x91\xa8\xe2\xb5\xf1r\x14Z_w?9\x00k\xa5\n\xe0\xf2\xac\xad\xf4\xf8\xd6\xc9^\xb6\x85\x92_\xfaʪ\x02\xf9\xeezu\xf7\xef7\xbdϬO\xd1\xff[4\xdfY\xc3\r&\f\xe3\xec\x8ef\x10\xd3~J3\xbb\xe5\x96i@1\x00i\xb1F\xa5a\x11H\x9d3\xa5;\xa0*\xd0B\xe5\"\v,\xa2\xc6f\xab\xea\"gk@n-\x9bڕV\x15h+\xc2|r\xa5\xa3z:_\x0f\xa1\x8f\x05G\xecZ91\x05C\x92\xe9g\x1b\xe4\x9eHn\xf2\bӎ\x878\x88\x9f\xb9dj\xfd3dv9\x00}\x03\x1a\xc1\x84QdJ>\x82F\x8ad\xea^\x8a\xffm`\x1b\x9c\x12\x96$Ղ\xb1\x8c\xe6\xb3\xe4\x05{\xe4E\r\x17\x8c\xcb|\x00\xb9\xe4;\xa6\x01\xfbd\xb5\xec\xc0\xa3\x06f\x88\xc7_\x94\x06&\xe4F]\xb2\xad\xb5\x95\xb9|\xf3\xe6^ؠ\x903U\x96\xb5\x14v\xf7\x86t\xabX\xd7Vi\xf3&\x87G(\xde\x18q\xbf\xe0:\xdb\n\v\x99\xad5\xbc\xe1\x95X\xd0@$)\xe5e\x99\xff[\xe0\xb7\xe9u\xbb73]!u:\x83=\xa8g\x9dt9Pn\x88-\x17\xf0\x13\x92\xee뇛ۮ\xe4\t\xe3\x99\xd2\x11\xc0\x18\x7f\x90\x9aBn\xc0낍V%\xc1\x04\x99WJHK\x7fd\x85\x00i\x99\xa9ץ\xb0(\x06\xbf\xd4`,\xb2n\b\xf6\x8a\x8c\x16\nm]\xe1\xdc͇\x15V\x92]\xf1\x12\x8a+n\xe0\x95y\x85\\1\vdB\x12\xb7\xba\xa6xXّ\xb7\xf3C\xb0\xa7\x11\xd6\x06]qSA֛j\xd8NlD\xe6&\x14\xaa\xe4F\x95\fԲ+㳟~!\xdd7\xfc:\xc0\xc3)\xc8\xd0+\x184JvK\xccom#\x8a\x9c\x83ƔfR\xd9=\x98\xfb\xaa\xb5C\t\x0fe\x02\x93=ag{*5Œ\x8e\x00im\xebP\xbe\xa2\xac&\xbc\x1fD\xb5*K\xc8\x05\xb7P\xec\x8eB\xbf\x0fb\x8c̊\xfaak\xa7\xe7ŦG\xf4\xbc\x06&:\xedi2\xfe5\xd4ط\xc6\x7f%\xcbNF\xd4Ѥ\v\xac\x96-\x0f\a\xfdHx\xda'\rc\xab\r\xb3\x1au\xae\xc7\xeeI\x14\x05\xcedĸ\x82\xbc\x87Z\xbc;\xb1a\u0086Ѭ9a \xd9\xd2yQ\xcb\xd6gh\xec?\"8\xc0\x8eԾ\xeb\x1f=\x15n\x99\x84o\xb6\xad\x85Î\x8c`\xc3\v3\x18\x82WH\xb3\x86q\xc1ֵ=\x0e\x03(+\xbb\xbbpm7\xaa(\xd4\x133\xa4l\xd1\bn\xc4}\xad\xddd\xffm\x0e\x1b^\x17\xf6\xd2\xe1\xfc\xbb\x98\xb4\x8eO3\ve\x85&\xf3\x189\xbd\xf5mq\xc08[\xf2&\xfe\bnr\xf0C\x94w?F\x80(\xe7\xc5VZ=\x8aܛ\xf3=u\xc5\x0e\xaa,,\x8eQ\xb78ґ_\a\xa3\xf9cS\xb93\xb7\xb6\xea\x89=b\x00\x00\xe8-r\x1c\x14\x02\x85\x9c\xd5\xd5\xc5(Lƞ\x84ݲJ\x19#\xd6\x05xρ\t\x99\x15u\x8e\n\xe6c]\x14$\x82+\x99i(\xd1\xe1)Ƹ\xcd\x18Ⱥ\x1cG|AP\"?u\xe0\x8e\xd68\xa0\xa7\xb0dF\xdcH^\x99\xad\xb28\x8dTm\x13\x887*\nX\xaenV\x03h\x1d\xea\"\x8f)~\xa0\xc9m\x15{\xe2\u0092\xa1\xba\xbaY\xb1;\xa2{h͜\x86b\xb6\xd6\x12\x9d\x83H\x7f_\x81\xe7\xbb[\xf5\x93\x01\x96\xd7\xe4ׄ\x98\xe0\x82\xada\x83N\x80\x06\x84\x81?\x81\xd6h\x14\r!\xa1\xea=?3\x94['\xc78\xa1\xbc\x9b$\f{\xfb\aV\nY\xdbѩ:Ie\x94\xa6R=\x82~\x0eq\xdfs\xcb\xff\x82@\x064%Q%\xe8~\x96\x11}\xd7;\xfaq\x1d1_\xae\xac6\x1d\xa8°\xf3sT\xa1\xe7.\x86?\xbf\bS\x9aH\xb1\xaeEa\x17Bv\xfb\vz\x1d{<\x8e0\x0e\xb8c\xbe\xb9U\x1f\x8d\x9b\x98ϢS\x04\xe6\x88\x11\xadT\x1e&\xfcF\x14\xc0\xcc\xceX(\x83\xcaoæN,8,\xe4h\x15\x85\ac\x90\xee~P\xe3\x04\x91uQ\xf0u\x01\x97d!\x0f\xd0l\\Y\x8f\x11\xed+\x18+\xb2S\x92\xccA\x1c!\x98\xf6?\xf4(Cq\x17\x7f\x00\xc6#\xe0==1\xc8+\x8a\x0e\xd1\xfbԊ\xe2Vi\xc80\x00\xb8\U00101140\x82\x82\x19\xa9X\xa1\xe4=h\x87Ec\xe8\xd1\xd0\x00\nh\xce\xd0g\xd7h\x9e\x85d\x9b\x1a\xdd\xf9%Cm\x11\x95\x11!\x8d\x05\x1e\x11\xe6\x13\xf0\x0e\xbe\xa1e\x80\xfc\xaa\xa8\x8d\x05}\x93\xa9\n\xf2\xb0z7j\xd6Ry\xf8\xe1 d\x1f\xfc\x15\"\x03\xe4C\xe6*-h\x85,&\xdam\x1c\x88f\x92\x16\xf3\x90\xd5~\bm\x807\xa9c\fXlx\xfe\xfb\xf3\v\x92\x80~\xef\xfd~\f\xe3\x1a\x1a2\xcd\xd2\xd1\xe4.\x8d\xb7\x10\x16\xca\bu'u\xd4\f\xbes\xad\xf9\xee\x00כ\x95\xc8\x17\xe0{\f\xf6\x80\xf32T\xfbN\xbc\x1f\xf6\xff\xaf\xc8\xfd\xd3\xf2\xdb\xd0j>\x17\x12\xf9\\\bc{l6n\t\x10\xc9:\x16\x7f{\x02I\a\x13\xd5\xe4\x14W\xffA\x88yҹ\x13\x9b,\x8dl\xfa\t\xf0OEɭR\x0f)\xd4\xfb\x1f\xac\u05ee\xff\xb1\x8cv\x9c\xd8\x1a\xb6\xfcQ(m\x86k\xcc\xf0\r\xb2\xdaF5\v\xb7,\x17\x9b\rh\x84E{$͖\xca!b\x1d\x8e\xfdXGeE+\f\xc6\xd52\x1dYJԈ\r\x85\xa2\xfb(T\xe7\xe0`\x88A\x0eD.\x1eE^\xf3\x82|\t.37>\xde\xe0\x17\xd3j\x13\x02\xb1\x87\x7fT\xaa]q\x0eM\x18$2\xb1\xb7d\xa8$\xa0\xaf_b\x8c\xb4_5N\x89\xb0\x0es\xb0od\xa6\xae\v0\xbe\xbb\x9c\xdc\xe4V']\xb4\xccr\v4\x05_C\xc1\f\x14\x90Y\xa5\xe3\x14J\x91\x03WR\x95n\x84\xb8#Z\xb6\x1fu\xb5\x83\x99\x00\xcb(\xd4݊l\xeb\xdcW\x144\x82\xc5r\x05\x86\x96\x94xU\x15\x11\xd3ՖI\xe1\xf0\x9dM鍶$h\x90!ܘ.iK\xa2~n\xcb(\xd9۹٧\xfa\xf8&\xc9(\xbe\xffJD\x0fV\xe7Ha\x9f\xd0$\x8c6[\x92\xe7C\x94\xf4Hq\x01f\xd9Y\xda\x146|Mah\xcf\x7f\xdcۇ\xda#ʯ\x8bw\xc7M\x98\x19\xac\x9b\x9cS/˸\xa6\x9b\x7f\x12\xbe\x91ɺ\xf1\x16k\x16\xcf>u[^Ж\x8agH~\xc16\xa2\xb0@N\xd5\x14\xa2l\x06\xe7NI\xa0T\v\xcch\x87\xddf\xdb\x0f\xcd\xc6[B\x8b\x01\xad\x86\x00\x9c\x83\x1e\xa2\x1c\xe2A\x02Hָ\x16\xb4\xe3,܊\xb9YR$\xd9\xfdB\xae\xe0\xbb\xcf\xef\xe3\xb1g\xb7$J\xeaޠ\x12&\xad+\xef\x06\x8eQ\x17W\x1f\xaa\x84_\xc8_k\x02A\xb7\x0fq\xc18{\x80\x9ds\xb1\xb8d\xc87\x1e*'\xa2\xa0\x81\xd2)HS<\xc0\x8e@\x8d\xe7G\x8c\x979\xd2\xe2\xca\x03\x8cl\x99\xc6J\x8f\xae\x88\x9f߈rt\xc3\x0fD\x98\x94\xd9Ԗ\x86\xa8~\xfa\x8cd'\xc4\xcb\f\xbd\x14J\xe0ˑ\xc3N\x16\xa7n_\xfd\x8c\xa2\a\xd8\xfd\xc68^\xe3,\xdb\nڱ\xe3\xb4z\xa36\xb3\x18\xee\xca\x1d/D\xdet\xe6\xe6\xd5J^\xb0\xcf\xca\xe2?\x1f\xbe\t\x83\x1d˜\xbdW`>+K_^\x94\xcan\x10\xafA\xe3\xb0\v\x88\x03t\x96\x04\x89\xd8ͼq\xb6\x14\x05\xb5\xe1\x870l%1$s$\x9a\xd1\x1d%Z\xb9.]gemh\x9fZ*\xb9p\xcbbc\xbdy\x1e(\xddc\xc1I:\xf6\x9dޢ1r\xbf\xb8\x94\xaf\x82g\x90\x87\xad:\xcaE\xe2\x16\xeeE6\xa3\xcf\x12\xf4=\xb0\n\xcdB\xba\xb4\xccP\xd4~d\xf3\xc5+\xdds\xe8\x96o\x8b\x87z\rZ\x82\x05\xb3@\xb3\xb6\xf0P\xac*\x13\xe9\xe2m\xc2H\xc2\xceXY\xe0\\O\xac\x19\xa4%\xa9z$\x9d\xe9p\xf5Tb=\x93L\xe4E\x90ە$\x05ݬ\xe0y\xd6k\xa6\xdc\x1c\xa3b:cq.@\xc9ik\xedoh\xe9i6\xfe\x9dU\\h\xb3d\xef(-\xba\x80\xdeo~a\xb2\x03&\xb1ۊV\xd9\x7f\xa9\xc5#/\xd0\xff@\x03!\x19\x14\xce\x1bQ\x9b=_\xed\x82=m\x95qnC\xb3iw\xfe\x00;\xb7\xb3\x9c\xd4mWa\x9d\xaf\xe4\xb9\xf3e\xf6\x14O\xe3\xf8(Y\xec\xd89\xfdv\xfe\\\xf7n\x86DϨ\xda\x13\xe5\x92W\xe9\x92LI\xc7s\x02\r\fփC\x84\x8d\x9b\xec[\f\x10\xa6(\x90,ʕ2\x91\xa4\x91\bZ\t\x82~\xad\x8cu\xeb\x90=\x7f\x7ft\xa1R\x85\xc5I\xc67\x1643V\xe9\x90ϊ\x8a?e)\xbe[n\xb7`\xc0\xefC\xf9EO\a\x18\xa3\xd8\xf3V78\xabr\xee\xf6¨#\x9e\x91\xf7Dm+\xad20Ѽ\x88\xb6$ڦ\x91\xec\xa5.\x1d\x9au]\ue8bfM\x92\xd6NY\x94\x0ee\x9e#\x8f\xa4;\"2\xfa\xf0\xad\xb3D\x8d\xda\x05\xffN\x91\xd6cpdt\x10\xa6,\xf90\x97:\x19\xdd+\xd7:\xcc1\x0f̅[\xfa\xbe&\x9d3\xc7\xebhD\xf9\x1f͵)\x85\\QG\xec\xed\v\xbaC^\x8b\xc7Ҥ\xc6\xca\xf1N\xfaU\xe8\xac\xe5^\xf3\xc1'$*\xda\xf8\xd1\xd0c\xee\xfe\x9e\by\xd7R\xd9\xce2\xceL'\xbaR\xf9o\f\xdb\bml\x17\rs \xb1j\x14\xd4\x11\xa1\xa7\xfc\xa0\xf5ё\xe7\x17\xd7z\x90B\xe9\xb2\xce\xe7\xc4ہ\xa4[\xfe\b>\xed\x17d\xa6jIKa\xa8\a\xb0\x9b\x19\x10\x1dk\x9c\x15H\xb4w\x9d\xc6\xd1Ḻ\xb2 I\x12rrݬ\xdb\xe4#\x17i\xebV\xec8\xb6\xdaC\xb9\x9cc\xe5\xf8y\x14\x12=\xbbg\x11J\xfeM\x94u\xc9x\x89<$\xb7C\x94\xd0\x1cGp\xecn\xd2?\xb1\x05\x19-\xabp\x96U\x05X\xf0\xe9\x9b3\xf0Ȕ4\"\x87\xc6\xf4{\x11P\x92q\xb6ᢨ\xf5\f\xad:\x9b\xe4s\x830\xafMN\x1fY\xa5#\xb2 \x12%\xae\xb3\xcf\xf0\x82\xa75~\xa5\xe7\xf9\xb1)\x0e\xa3\x86\xf9\xfeb\xa5\x85r')N\xef2\xfa\xf4c.w?|\xc6\x1f>\xe3\x0f\x9fqNG?|Ɖ\xf2\xc3g\xfc\xe13\x1e.?|Ɣ\xf2\xc3g\x9c\x89\xc8\xf7\xf2\x19S0\\\xd0\x1a\xe7\x81\nIX%\xa6BL\xa1=їO\xfa\xf1g5N\x92˼\x1a\a9r\x88'r\xfc\"\xe6u\xb4ƫIn\xc6\x19\x18\xe6\x8e;\x82\x9a\xe00\x9f\xe0\xf4L@\xe0\xf4\xa7gV\a!\x9f\xf0\xf4\x8c\x1fBZ\x84q\xd4ٙ@\xa4\xf9\xa7'.|\x12Q\t\xaaA\xfe\x83mU\x1d9\xb51Aڄ,\xda4\x82\xf4\x92j}b\x04X\xfe\xf8v\xd9\xff\xc5*\x9fbK77D\x80\xd1e\x1e<\xa7\x1b\x1c:\az\xbc\x1e\b\xf7L\r\x852\x02Li&E\xe1$6@\xe8\xc9+\xfbR\xb9\xd5\xc1\xa3\xfd\xa6\xe95\xac\xf4Dܹ\xe9\xb7M\xb6\xe4\xb4\xfb\xfe\x8c\xa4ۓ\x1e\x8d\xfani\xb5\xc7%Ӧ\xaeP&$Φ\xa7˦\xb0Օ\xf4$\xd9\xe4\b95!v\xee\nċ&\xbf\xbeL\xcak2\xcd\xd2\xd2[\xe7R\xecURY_9\x81\xf5\xf5\xd2Vg$\xab\x9e\xfe\xd4K\xfaZ\xfa\xd1ٕi\xcb2\x87\x13N\x93\xd2L\x93\x96nR\x06|\xd4P\x93\xd2G\xe7&\x8d&q2}\xba\xbejZ\xe8\xab&\x83\xbe~\n褴MV\x98\x9b\xe49~Cd(\xd3\x0e\xc0\xde\x05ϣ\x95^BBg\xad\x97\x1e\x9c\xc0\xc5\xf7\x98`\xcfe\xb5ҽ\xf0\xe2Y\xb1\xf3\x97\x01,\x14\xf8\xe0j\xbfb,Sօ\x15U\xd1^\xc8\x17\v\x9a\xb7\xb0k.\\\xfaY\xd11\x7f\x7f\xebؗ\xafͬ]\x0e\"3n\xd8\x13\x14\x05\xe31\xfd\xb2G\x85\xcc]\x04\x9b\xa9\x05\xa0}GM\xe5/\x94\xf2\xb7\xc7^\xb8)O7\x1a\x90\x97PƖ+\xb9<|[\xd9A#\x9c\xaa\x8b\xf7\xa2\v\x173ѷ_j\xd0;Fw\xa75\xfee{0\xd6++\x83\xc1uP\xa1^\xa5\x1f\xda\xf7\xd9\v\xd2Z\x15\xc7\xdeI\xe7\xd5\fq\xa26\xa8;۠\x14\r\x83\x8c]4\xc8\xc2\x04\xdd\a!U\x03!\xd24%\x80\x99sR\xf4%B\xd4S\x04\xa9I^\xdc<\x0f\xfc;\x9e\x00=\xf6\xe4gzBM\xd2Iϗ\bY\xe7\x04\xad\xb3|\xee\xf4\x93\x9c\xf37\xcf_\xf8\xe4\xe6K\x9d\u061cA\xbd\xd4\x13\x9a\xf3i\xf7J'2_\xfd$\xe6k\x9e\xc0\x9cu\xf229\xc5lV\xd6Ĝ\xf4\xb0g\x1c\x19Lˇ\x98>I\x99x\x8221[\"m\xf0G\x0e;\xf1\x84\xe4\xfc\x93\x91\x89\xfc\x9d3\xa5_\xf9\x04\xe4+\x9f|\xfc\x1e'\x1e\x13$0\xa1\xca\xfc\x93\x8d\xcf\xdeVS:\a=\xb9u9Gj'\xe555\x96\xeb#6؛\v7\xe2b\xad^\f@fɿ\xe4@\xafv\x1c\xda\xcaG\xc9\xecxD\xbd\xbd\xd5\xd6]\xeb;\xc4\xfe9\x0f\xb7\xfdj\xa0\xe2h\x00(p\xa3\xf4\xb2\xa8\xab\xf0\x81g\xdbA\x0f[n\xd8F\xe9\x92[v\xdelx\xbfq\x1d\xe0\xdf\xe7K\xc6>\xaa&ߨ{\xe7\x9b\x11eU\xec0\x12c\xe7\xdd\x06ϓ\x92\xa8t\x86\x9e\xafU!\xb2\x88\xcf9z7\xa0k\xb0wa\x12\xdd^\x98u2^b\x81\x0f6\x17\xe1\xe6\xc8\xfe\xb5\xd2\xeeB\xffc\xd7{*\xf1'zo\xeb\x04+\x87\xef\xaeW\x04+\x88\x11=\xe4\xd5$Y6,_\x03\xba\f\xed\xd8\x0f\xe9\x93զ\a\xb5\x9f\xe7\xdc}\xad\x04r\xf74Mp[\xbcj\xce\x14j\xad\xeb\x95\xc3\xe5PO(_\\\xee\x98\xf2o\x8f\b\x9d/*\xae\xed\xce%D]\xf4\xf0\bv}j\xe5\uf835\xda\x7fz\xa7[zd\x0f\xaf\xee\xd0n\xfc\xae\xea'@\f\xe9\xf9\x1c\x9c\x0e\x9f\f\x9f<\x13\xfe\x028\x1dv\xa1\x16D\xc5\xc8O\xd1,Γ\xaf\xba\x1a\xff\xda\xc0_\xd4#\xbc\x8f\xae\xbe\xf6\x9f\xdf\x194\x19I\xaf\fP\xe9\xa2\xfc\b\x05ۜJ\xba\xa7\xfcyj/\x9e/\x19P\xf1\xf7\x9c?gq\xf2\xa6\x0fj\xfcE\x1a\xba\x05>t\x1a\xf3\xaa譯\x1d\xbb\xbe\xa3\xb8\xb5Q\xa5~\xea\xfb\xb85,O\x86$\x89\b,!\x0f>\xd2s*2Z\xa5\xf9=|R\xeeq\xa5\x141\xe9\xb7\xe8=\xbd\xe5=\xb7\x90s\xee'aL\xd1\xfb\xb1\r\x01\xb6gL\xf6\x1e+@l\x8f|\x8e\xc1\xda\xe292r{\xfbɍ\x94\u07b4y\uf7e7A}l\x00Y\x10(࠭\xf1\xbf[\xf5D\x97\xf8\xc7ט\xc3\v2\x9dG\xec\x80\x0e\xbbP\x1a\xf2Qì\xabB\xf1\x1c\xf4\x15\xbd\xa2\x930\xe2\x9fz\r\x06\xee@\xff-\x1eo7#\xe3\t=\xbf`\xa6\x0fztE\x01\xc5GQ\x80q\x88'\x9a\x86\xeb\xfd\x96\x8d\xa5\xa8˵\xf3T7\xf8c\xd3\xc9\x01\xcb\xec\x86J\x1b\f\x15h\xf4\x13\xddVDm\x82\xe4\x1f&\x06k\xf8(\xa4\x85{\x18\x8f\xa1'l\x82{g\x82\x1c\x80\xa0\xc0(\xe2\xfbsl\xe5\xb1G\x90\xbbx\xeb\x81\f4\x8b\x9119Vޭ\xba\xbe\xbb2\xac\x969m\x00\xdc\xfd\xe9\xe6(\xf9}콕\x13tB\x8az\xbf\x1bo\xd9\t\x11:ډ|\xfa\xb8\x12\x8f\xc1\xe2ƨLPTA\x8f#\xd1i\xaa\x97\xbb\a\xfdP\x80x@:j\x03_\x9e$\xe8\xaf\xc1\x02\x99\x95\x8c\xbd=3\xad\xfd~ڃ\x16}s\xc6*\xec{\x04\xc6\x00\x00Sa\x9f˸W\x8d\xc2\xf6\x9a0\xcd\xebv\xfb\xf4\x9cP!qK7\xee\xb0-\xc6\x1f\xe3Z4\x8f\x86\x9d%\x90۽\xe5\xd4\a<\xfe\xa6\xa1{\xf4)㕭uЮ\xb5\xa6\x9b\xe2\x11\b\xb8\x8bԏ{հ}\xec\xee\x18\x06\xb7\xaf͵\xfb\x0f\x93\xef\xe1\x8e\xc0i\xde%\x8c>r\xe6\"j\xf7^\xed\x02\xe1\x1f\xc7\xe3\xd1\x19\x838߸\xc7\xeb&\x88\xf0\xa9\xad96\xe0f\x188d\xff\x1cޫ\x8e\x84\x1e\x0e\x98\x18\xc35\xd6iN\xeaz9\xa2\x86\xe1\xc1\x81\x9b\x18\x13Əs.\xd8g؏\xd8\x17\xec\x83\xc4A\xec\x13\xc0\x9dل\x9c\xb6VH;\xce\x19\xe2cӊ\x0e̎h\xc8i\xb1\xbd\x1b\xc0\x18d\xe3\xd3\xc3UM\x15wbְߊ1o\x94v\xcc2\x1c\xe8\xef\xf6~\x8dj\xf0\x83\xda;\xa6\xb9G\xd5\xc8\xdeGz\t1\xefH\x8e\xf7һ_\xeau\xfb(\x04\xfb\xdb\xdf\xcf\xfe?\x00\x00\xff\xff\xeaC\x1a-[}\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcV\xcfo+5\x10\xbe\xe7\xaf\x18\x89+\xbb\xa1B \x94\x1b*\x1c*\xe0\xa9j\x9ezw\xbc\x93d\xa8\xd7^f\xc6)A\xfc\xf1\xc8\xf6n\x9b\xee:\xb4\x8f\x03\xbe\xad\xed\xf9\xe6\x9bo~x\x9b\xa6Y\x99\x81\x1e\x91\x85\x82߀\x19\b\xffT\xf4\xe9Kڧ\x1f\xa4\xa5\xb0>ݬ\x9e\xc8w\x1b\xb8\x8d\xa2\xa1\x7f@\t\x91-\xfe\x84{\xf2\xa4\x14\xfc\xaaG5\x9dQ\xb3Y\x01\x18\uf0da\xb4-\xe9\x13\xc0\x06\xaf\x1c\x9cCn\x0e\xe8ۧ\xb8\xc3]$\xd7!g\xf0\xc9\xf5\xe9\x9b\xf6\xe6\xfb\xf6\xbb\x15\x807=n@\x90ә\x1a\x8d\xc2\xf8GDQiO\xe8\x90CKa%\x03ڄ\x7f\xe0\x10\x87\r\xbc\x1e\x14\xfb\xd1w\xe1\xbd\xcdP\xdb\f\xf5P\xa0\xf2\xa9#\xd1_\xae\xdd\xf8\x95\xc6[\x83\x8bl\\\x9dP\xbe \xc7\xc0\xfa\xe9\xd5i\x03\"\\N\xc8\x1f\xa23\\5^\x01\x88\r\x03n \xdb\x0e\xc6b\xb7\x02\x18\x05\xc9Xͨ\xc5\xe9\xa6\xc0\xd9#\xf6\xa68\x01\b\x03\xfa\x1f\xef\xef\x1e\xbfݾ\xd9\x06\xe8P,ӠYֿ\x9b\x97}\xa8\x85\t$``\xa4\x04\x1a\xc0X\x8b\"`#3z\x85B\x19\xc8\xef\x03\xf79\xad`v!\xea\x05\xaa\x1e\x11\x1e\xb3\xfec\x98\xed\xcb\xe1\xc0a@V\x9a\xa4)\xeb\xa2\xe2.v\xff\x8dxZ)\xd6b\x05]*=\x94\xecy\xd4\v\xbbQ\x1e\b{\xd0#\t0\x0e\x8c\x82\xbe\x14c\xda6\x1e\xc2\xeew\xb4\xdaΠ\x8b.\x922\x19]\x97*\xf6\x84\xac\xc0h\xc3\xc1\xd3_/ؒ\x04JN\x9dѬ\x9dWdo\x1c\x9c\x8c\x8b\xf85\x18\xdf͐{s\x06\xc6\xe4\x13\xa2\xbf\xc0\xcb\x062\xe7\xf1[`\xccRo\xe0\xa8:\xc8f\xbd>\x90N}hC\xdfGOz^疢]\xd4\xc0\xb2\xee\xf0\x84n-th\f\xdb#)Z\x8d\x8ck3P\x93\x03\xf1\xb9\x17۾\xfb\x8a\xc7Ε7n\xf5\x9cjP\x94\xc9\x1f.\x0er\xeb|AzR#\x95b*P%\xc4\xd7,\xa4\xad$\xdd\xc3\xcf\xdb\xcf01)\x99*Iy\xbd\xba\xd0e\xcaOR\x93\xfc\x1e\xb9\xd8\xed9\xf4\x19\x13}7\x04\xf2\x9a?\xac\xa3\\\xb8qד\xcaT\xda)us\xd8\xdb<\xab`\x87\x10\x87\xce(v\xf3\vw\x1enM\x8f\xee\xd6\b\xfeϹJY\x91&%\xe1Cٺ\x9c\xc0\xf3\xcbEދ\x83iv^ImeJl\a\xb4)\xb9I\xdfdM{\xb2\xa5\xad\xf6\x81\xc1\xd4L\xda\x0f1\xc9\x16_\xc8e\x9cH\x85\xcdlN\xa5.\x7f\x9fM},哣\x11\x9co\xce8ݧ;s\xff\x8e\xf6h\xcf\xd6a\x81(S\bߧ\x92\x16\xfa\xd8/}6\xf0\t\x9f+\xbb\xf7\x1c҄\xc6\xf9\xa8\xb9Z\x1bP\x1e\xb1\x03\xf9E\xb8\xf3\xc8ʭ\xfc0.G~\x0eh\x04\x02\x8eާ\x96\x0e~\x01Yy\x11\x16wH\xb1\xaf\xb0\xa9\xf2\xb9\xf3\xfb\x90\xff\"Lrl\xb4\xb4\x13\x8e\xc9\x1e\xfd\x14^\x15\xc0\xeb\xb9.k9\xe7>$hY\xf9y\xfeo\xc6i.\x11c\xd5w\x93YU\x0f\x92ǚ\xe2\xf5\xfe\x1aYF\xe7\xcc\xce\xe1\x06\x94\xe3Һ\xd8\x1afs\x9eW\xcdTj\x9f\xa9GQ\xd3\x0f\xef\x14\xd0\xe2UH\xeb~\x81\x92\x9a\xe7\xf9\x88\xfeZ\x8b\xc0\xb3\x91W\xe7\x15\xc8\xdd\xf9\x9a\xe9\xed\xcb\xdf\xe6\xb2\xcfJ=o \xcd\xfaF\xa9\"䇔\xaa\xa6\xb4\xd4y\xf5\xb7f\xa1\xd2\xf6\xf2\xee4H\xde\xf4\xcb\xf4W\xb3\x8c\xe1*\x85j\x05,63|w\x11\x9eh`s\x98\x02\xfe'\x00\x00\xff\xff\xef\xf8\xa6>\x10\f\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWM\x8f\xdb8\x12\xbd\xfbW\x14\x92k$o\xb0\xd8\xc5·F\xef\x1c\x82I\x06\x8d\xb8\xa7\xef4Y\xb2\x19S\xa4\xa6\xaa(\xc7\xf3\xf1\xdf\a$%\xb7-\xcb\xe9\xf4`0\xbat\x8b\"\x1f\xeb\xe3իrUU\v\xd5\xd9'$\xb6\xc1\xaf@u\x16\xbf\n\xfa\xf4\xc6\xf5\xfe\x7f\\۰\xec\xdf/\xf6֛\x15\xdcG\x96\xd0~F\x0e\x914\xfe\x1f\x1b\xeb\xad\xd8\xe0\x17-\x8a2J\xd4j\x01\xa0\xbc\x0f\xa2\xd22\xa7W\x00\x1d\xbcPp\x0e\xa9ڢ\xaf\xf7q\x83\x9bh\x9dA\xca\xe0\xe3\xd5\xfd\xbf\xea\xf7\xff\xad\xff\xb3\x00\xf0\xaa\xc5\x15\xf4\xc1\xc5\x16٫\x8ewA\\\xd0\x05\xb3\xee\xd1!\x85چ\x05w\xa8\xd3\x15[\n\xb1[\xc1\xf3\x87\x021\\_L\x7f\xcah\xeb\x01\xed〖78\xcb\xf2\xe376}\xb4,yc\xe7\")wӲ\xbc\x87w\x81\xe4\xa7\xe7\xdb+\xe8ٕ/\xd6o\xa3St\xeb\xfc\x02\x80u\xe8p\x05\xf9x\xa74\x9a\x05\xc0\x10\x9f\fW\x812&G\\\xb9\a\xb2^\x90\xee\x13\x96?]f\x905\xd9NrD\x1f(\xf4\xd6 \x81e\x90\x1dB7\xbe\x87&\xbf\x17;\x80%\x90\xdabF\x00\xf8\xc2\xc1?(٭\xa0N\xf1\xad\xc7C\xc3璛\x87\xcbE9&\xb3Y\xc8\xfa\xed\x9c!%\xae0\x06\x16\xc6\xc8\x02\x8b\x92\xc8\xc0Q\xef@1\xdc\xf5\xca:\xb5q\xb8\xfc٫\xf1\xff\x19\xbb\xf2\xa9\xba\xdb)\xc6K\xb3\xceVfl:\x83\x18\t[k\xc2lʣm\x91E\xb5\xdd\x05\xe0\xdd\xf6\x12\xce()\v\x03Eߗ\xcc\xea\x1d\xb6j5\xec\f\x1d\xfa\xbb\x87\x0fO\xff^_,\xc3\\H\xa6TK\x99R02\x02\x0e;$\x84\xa7\xcc\xeb\x9c&\xe4!i'P\x80\x91G\\\x9f\x16;\n\x1d\x92ؑ\x84\xe59\xab\xf3\xb3Չ]\xbfW\x17\xdf\x00\x92+\xe5\x14\x98T\xf0X\xb84\xd0\x12\xcd\xe0}\xe1\x94e \xec\b\x19}\x91\x80\xb4\xac<\x84\xcd\x17\xd4RO\xa0\xd7H\t&\xd5Lt&\xe9D\x8f$@\xa8\xc3\xd6\xdb_O\xd8\f\x12\xf2\xa5N\t\xb2@&\xbeW\x0ez\xe5\"\xbe\x03\xe5\xcd\x04\xb9UG LwB\xf4gx\xf9\x00O\xed\xf8\x14\b\xc1\xfa&\xac`'\xd2\xf1j\xb9\xdcZ\x19\xd5O\x87\xb6\x8d\xde\xcaq\x99\x85\xccn\xa2\x04\xe2\xa5\xc1\x1eݒ\xed\xb6R\xa4wVPK$\\\xaa\xceV\xd9\x11_Ԫ5oi\xd0K\xbe\xb8\xf6\x8a\x9f\xe5\xc9j\xf5\x8a\xf4$\xe1*\xac)P\xc5\xc5\xe7,\xa4\xa5\x14\xba\xcf?\xac\x1fa\xb4\xa4d\xaa$\xe5y\xebU\\\xc6\xfc\xa4hZ\xdf \x95s\r\x856c\xa27]\xb0^\xf2\x8bv\x16\xbd\x00\xc7Mk%\xd1\xe0\x97\x88,)uS\xd8\xfb\xdc!`\x83\x10\xbbTPf\xbaჇ{բ\xbbW\x8c\xffp\xaeRV\xb8JI\xf8\xael\x9d\xf7\xbd\xe9\xe6\x12\xde\xf3B\x1d\xdaՍ\xd4\xce+ºC}Qx\t\xc56vP\x88&\xd0$@jԋy\xbc\xcbx\xce\v\x05\x94\xa6\xdd\xd8\xedt\x15.\x1aЭ\xb3\xdf\b،\xdf\xf7\xf9\xa6\xc4\xe1&ЩGU\xa3\x9f\x83%\x91\x06\x87-:s\xc5ԛ1Ϯ\x10\x9a\x94b\xe5\xae\r\xbd\xb4\xe4\xb41\xcf,\xca\xfa\x12\xf2g\x80\xcc\x7fC\xfe%1\xa6\xc1\xd9\x06\xf5Q;,\x80\x10\x9a\x19\xee\xbd\xca\xe4\xf4\xa0\x8f\xed\x1c\x11\xef&?|ο]\xff,\x9a\xa6m&\xf9\xb3\xf9\xbcZ\xe44\xec\x99\x15\bł=\xb0\xec|%nN\xb3\xec\n~\xfbc\xf1g\x00\x00\x00\xff\xff+\xf2\xd32>\x10\x00\x00"), diff --git a/pkg/apis/velero/v1/backup_types.go b/pkg/apis/velero/v1/backup_types.go index dd3125fa7..a53b61a04 100644 --- a/pkg/apis/velero/v1/backup_types.go +++ b/pkg/apis/velero/v1/backup_types.go @@ -520,6 +520,11 @@ type HookStatus struct { // +kubebuilder:rbac:groups=velero.io,resources=backups,verbs=create;delete;get;list;patch;update;watch // +kubebuilder:rbac:groups=velero.io,resources=backups/status,verbs=get;update;patch // +kubebuilder:resource:shortName=bak +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.phase",description="Backup status such as New/InProgress" +// +kubebuilder:printcolumn:name="Errors",type="integer",JSONPath=".status.errors",description="Total number of errors logged during the backup" +// +kubebuilder:printcolumn:name="Warnings",type="integer",JSONPath=".status.warnings",description="Total number of warnings logged during the backup" +// +kubebuilder:printcolumn:name="Started",type="date",JSONPath=".status.startTimestamp",description="The time the backup was started" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // Backup is a Velero resource that represents the capture of Kubernetes // cluster state at a point in time (API objects and associated volume state). diff --git a/pkg/apis/velero/v1/restore_types.go b/pkg/apis/velero/v1/restore_types.go index 2ef791270..416a2b8ca 100644 --- a/pkg/apis/velero/v1/restore_types.go +++ b/pkg/apis/velero/v1/restore_types.go @@ -420,6 +420,11 @@ type RestoreProgress struct { // +kubebuilder:rbac:groups=velero.io,resources=restores,verbs=create;delete;get;list;patch;update;watch // +kubebuilder:rbac:groups=velero.io,resources=restores/status,verbs=get;update;patch // +kubebuilder:resource:shortName=rst +// +kubebuilder:printcolumn:name="Backup",type="string",JSONPath=".spec.backupName",description="The name of the backup this restore is from" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.phase",description="Restore status such as New/InProgress" +// +kubebuilder:printcolumn:name="Errors",type="integer",JSONPath=".status.errors",description="Total number of errors logged during the restore" +// +kubebuilder:printcolumn:name="Warnings",type="integer",JSONPath=".status.warnings",description="Total number of warnings logged during the restore" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // Restore is a Velero resource that represents the application of // resources from a Velero backup to a target Kubernetes cluster. From 105350b78b56c0a18d395baa46bb6344d89f753a Mon Sep 17 00:00:00 2001 From: Ralthos <161431341+Ralthos@users.noreply.github.com> Date: Wed, 12 Aug 2026 00:03:02 +0530 Subject: [PATCH 35/45] Make restore logs testable by returning errors (#10234) pkg/cmd/cli/restore/logs.go was the last command in the CLI still calling cmd.Exit, which calls os.Exit directly. Two of its own tests were skipped because of it, and said so: t.Skip("Cannot test restore not complete case due to cmd.Exit() call") This gives restore logs the LogsOptions shape that backup logs already uses: Complete, BindFlags and Run returning an error, with the cobra command passing that to cmd.CheckError. Both skipped tests now run and assert on the returned errors. Exit status is unchanged; cmd.CheckError also exits 1. The two refusal messages now carry the standard "An error occurred:" prefix and match the wording backup logs uses. Signed-off-by: saral --- changelogs/unreleased/10234-Ralthos | 1 + pkg/cmd/cli/restore/logs.go | 108 ++++++++++++++++++---------- pkg/cmd/cli/restore/logs_test.go | 30 +++++--- 3 files changed, 95 insertions(+), 44 deletions(-) create mode 100644 changelogs/unreleased/10234-Ralthos diff --git a/changelogs/unreleased/10234-Ralthos b/changelogs/unreleased/10234-Ralthos new file mode 100644 index 000000000..70ac3000a --- /dev/null +++ b/changelogs/unreleased/10234-Ralthos @@ -0,0 +1 @@ +Make velero restore logs return errors instead of calling os.Exit directly, matching velero backup logs, and enable the two previously skipped tests diff --git a/pkg/cmd/cli/restore/logs.go b/pkg/cmd/cli/restore/logs.go index 26d3123ac..366fd511e 100644 --- a/pkg/cmd/cli/restore/logs.go +++ b/pkg/cmd/cli/restore/logs.go @@ -23,8 +23,9 @@ import ( "time" "github.com/spf13/cobra" + "github.com/spf13/pflag" apierrors "k8s.io/apimachinery/pkg/api/errors" - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + kbclient "sigs.k8s.io/controller-runtime/pkg/client" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/client" @@ -34,59 +35,94 @@ import ( "github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest" ) -func NewLogsCommand(f client.Factory) *cobra.Command { +// LogsOptions holds the state for the restore logs command, mirroring +// pkg/cmd/cli/backup.LogsOptions so both commands are shaped the same way. +type LogsOptions struct { + Timeout time.Duration + InsecureSkipTLSVerify bool + CaCertFile string + Client kbclient.Client + RestoreName string +} + +func NewLogsOptions() LogsOptions { config, err := client.LoadConfig() if err != nil { fmt.Fprintf(os.Stderr, "WARNING: Error reading config file: %v\n", err) } - timeout := time.Minute - insecureSkipTLSVerify := false - caCertFile := config.CACertFile() + return LogsOptions{ + Timeout: time.Minute, + InsecureSkipTLSVerify: false, + CaCertFile: config.CACertFile(), + } +} + +func (l *LogsOptions) BindFlags(flags *pflag.FlagSet) { + flags.DurationVar(&l.Timeout, "timeout", l.Timeout, "How long to wait to receive logs.") + flags.BoolVar(&l.InsecureSkipTLSVerify, "insecure-skip-tls-verify", l.InsecureSkipTLSVerify, "If true, the object store's TLS certificate will not be checked for validity. This is insecure and susceptible to man-in-the-middle attacks. Not recommended for production.") + flags.StringVar(&l.CaCertFile, "cacert", l.CaCertFile, "Path to a certificate bundle to use when verifying TLS connections. If not specified, the CA certificate from the BackupStorageLocation will be used if available.") +} + +func (l *LogsOptions) Run(c *cobra.Command, f client.Factory) error { + restore := new(velerov1api.Restore) + err := l.Client.Get(context.Background(), kbclient.ObjectKey{Namespace: f.Namespace(), Name: l.RestoreName}, restore) + if apierrors.IsNotFound(err) { + return fmt.Errorf("restore %q does not exist", l.RestoreName) + } else if err != nil { + return fmt.Errorf("error checking for restore %q: %v", l.RestoreName, err) + } + + switch restore.Status.Phase { + case velerov1api.RestorePhaseCompleted, velerov1api.RestorePhaseFailed, velerov1api.RestorePhasePartiallyFailed, velerov1api.RestorePhaseWaitingForPluginOperations, velerov1api.RestorePhaseWaitingForPluginOperationsPartiallyFailed: + // terminal and waiting for plugin operations phases, do nothing. + default: + return fmt.Errorf("logs for restore %q are not available until it's finished processing, please wait "+ + "until the restore has a phase of Completed or Failed and try again", l.RestoreName) + } + + // Get BSL cacert if available + bslCACert, err := cacert.GetCACertFromRestore(context.Background(), l.Client, f.Namespace(), restore) + if err != nil { + // Log the error but don't fail - we can still try to download without the BSL cacert + fmt.Fprintf(os.Stderr, "WARNING: Error getting cacert from BSL: %v\n", err) + bslCACert = "" + } + + return downloadrequest.StreamWithBSLCACert(context.Background(), l.Client, f.Namespace(), l.RestoreName, velerov1api.DownloadTargetKindRestoreLog, os.Stdout, l.Timeout, l.InsecureSkipTLSVerify, l.CaCertFile, bslCACert) +} + +func (l *LogsOptions) Complete(args []string, f client.Factory) error { + if len(args) > 0 { + l.RestoreName = args[0] + } + + kbClient, err := f.KubebuilderClient() + if err != nil { + return err + } + l.Client = kbClient + return nil +} + +func NewLogsCommand(f client.Factory) *cobra.Command { + l := NewLogsOptions() c := &cobra.Command{ Use: "logs RESTORE", Short: "Get restore logs", Args: cobra.ExactArgs(1), Run: func(c *cobra.Command, args []string) { - restoreName := args[0] - - kbClient, err := f.KubebuilderClient() + err := l.Complete(args, f) cmd.CheckError(err) - restore := new(velerov1api.Restore) - err = kbClient.Get(context.Background(), ctrlclient.ObjectKey{Namespace: f.Namespace(), Name: restoreName}, restore) - if apierrors.IsNotFound(err) { - cmd.Exit("Restore %q does not exist.", restoreName) - } else if err != nil { - cmd.Exit("Error checking for restore %q: %v", restoreName, err) - } - - switch restore.Status.Phase { - case velerov1api.RestorePhaseCompleted, velerov1api.RestorePhaseFailed, velerov1api.RestorePhasePartiallyFailed, velerov1api.RestorePhaseWaitingForPluginOperations, velerov1api.RestorePhaseWaitingForPluginOperationsPartiallyFailed: - // terminal and waiting for plugin operations phases, don't exit. - default: - cmd.Exit("Logs for restore %q are not available until it's finished processing. Please wait "+ - "until the restore has a phase of Completed or Failed and try again.", restoreName) - } - - // Get BSL cacert if available - bslCACert, err := cacert.GetCACertFromRestore(context.Background(), kbClient, f.Namespace(), restore) - if err != nil { - // Log the error but don't fail - we can still try to download without the BSL cacert - fmt.Fprintf(os.Stderr, "WARNING: Error getting cacert from BSL: %v\n", err) - bslCACert = "" - } - - err = downloadrequest.StreamWithBSLCACert(context.Background(), kbClient, f.Namespace(), restoreName, velerov1api.DownloadTargetKindRestoreLog, os.Stdout, timeout, insecureSkipTLSVerify, caCertFile, bslCACert) + err = l.Run(c, f) cmd.CheckError(err) }, } c.ValidArgsFunction = cli.CompleteRestoreNames(f) - c.Flags().DurationVar(&timeout, "timeout", timeout, "How long to wait to receive logs.") - c.Flags().BoolVar(&insecureSkipTLSVerify, "insecure-skip-tls-verify", insecureSkipTLSVerify, "If true, the object store's TLS certificate will not be checked for validity. This is insecure and susceptible to man-in-the-middle attacks. Not recommended for production.") - c.Flags().StringVar(&caCertFile, "cacert", caCertFile, "Path to a certificate bundle to use when verifying TLS connections. If not specified, the CA certificate from the BackupStorageLocation will be used if available.") + l.BindFlags(c.Flags()) return c } diff --git a/pkg/cmd/cli/restore/logs_test.go b/pkg/cmd/cli/restore/logs_test.go index 61c2392b6..5e020bf43 100644 --- a/pkg/cmd/cli/restore/logs_test.go +++ b/pkg/cmd/cli/restore/logs_test.go @@ -17,10 +17,12 @@ limitations under the License. package restore import ( + "fmt" "os" "testing" "time" + flag "github.com/spf13/pflag" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" kbclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -77,13 +79,20 @@ func TestNewLogsCommand(t *testing.T) { c := NewLogsCommand(f) assert.Equal(t, "Get restore logs", c.Short) - // The restore command exits with an error message when restore is not complete - // We can't easily test this since it calls cmd.Exit, which exits the process - // So we'll skip this test case - t.Skip("Cannot test restore not complete case due to cmd.Exit() call") + l := NewLogsOptions() + flags := new(flag.FlagSet) + l.BindFlags(flags) + err = l.Complete([]string{restoreName}, f) + require.NoError(t, err) + + err = l.Run(c, f) + require.Error(t, err) + require.ErrorContains(t, err, fmt.Sprintf("logs for restore %q are not available until it's finished processing", restoreName)) }) t.Run("Restore not exist test", func(t *testing.T) { + restoreName := "not-exist" + // create a factory f := &factorymocks.Factory{} @@ -95,10 +104,15 @@ func TestNewLogsCommand(t *testing.T) { c := NewLogsCommand(f) assert.Equal(t, "Get restore logs", c.Short) - // The restore command exits with an error message when restore doesn't exist - // We can't easily test this since it calls cmd.Exit, which exits the process - // So we'll skip this test case - t.Skip("Cannot test restore not exist case due to cmd.Exit() call") + l := NewLogsOptions() + flags := new(flag.FlagSet) + l.BindFlags(flags) + err := l.Complete([]string{restoreName}, f) + require.NoError(t, err) + + err = l.Run(c, f) + require.Error(t, err) + require.Equal(t, fmt.Sprintf("restore %q does not exist", restoreName), err.Error()) }) t.Run("Restore with BSL cacert test", func(t *testing.T) { From 1832f099f296366276668b484653e926da9c8ad4 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:23:56 -0400 Subject: [PATCH 36/45] backport: add pre-merge label-on-comment support; add copilot-instructions and auto-labeler for changelog exemptions (#10211) * Initial plan * chore: commit backport.yml pre-merge labeling enhancement Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com> * chore: auto-label kind/changelog-not-required for non-shipping PRs; add copilot-instructions.md Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com> * chore: add changelog naming convention to copilot-instructions; tighten labeler exclusions Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com> * fix: use # as sed delimiter to avoid conflict with | in alternation group Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com> --- .github/copilot-instructions.md | 70 +++++++++++++++++++++++++ .github/labeler.yml | 22 ++++++++ .github/workflows/backport.yml | 93 +++++++++++++++++++++++++++++++-- 3 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..c4e7d9923 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,70 @@ +# GitHub Copilot instructions for velero-io/velero + +## Changelog requirement + +Velero uses per-PR changelog fragments that are assembled into release notes. + +### File naming convention + +Every shipping PR must add exactly **one** file at: + +``` +changelogs/unreleased/- +``` + +- `` is the pull request number (e.g. `10200`). +- `` is the GitHub login of the PR author (e.g. `jdoe`). +- The file has **no extension**. +- The file content is a single line describing the change (the PR title is a + sensible default). + +**Example:** PR #10200 by `jdoe` → `changelogs/unreleased/10200-jdoe` + +The easiest way to create this file is: + +```bash +make new-changelog CHANGELOG_BODY="Brief description of the change" +``` + +`make new-changelog` reads the PR number and author from `gh pr view`; the file +is written automatically to the correct path with the correct name. + +The CI check (`hack/changelog-check.sh`) looks for +`changelogs/unreleased/-*` and fails if no file is found. + +### When a changelog is NOT required + +A changelog entry is **not** required when a PR exclusively changes non-shipping +content, i.e. the only files touched belong to one or more of these categories: + +| Category | Paths | +|---|---| +| GitHub Actions / CI workflows | `.github/**` | +| Documentation | `site/content/docs/**`, `site/**`, `docs/**`, `*.md` | +| Website (non-docs) | `site/**` (excluding `site/content/docs/**`) | + +When you open or review a PR that falls into one of the above categories (and does +**not** modify `pkg/`, `internal/`, `cmd/`, `vendor/`, `hack/`, `Makefile`, +`go.mod`, `go.sum`, or `changelogs/**`), apply the label +**`kind/changelog-not-required`** instead of requesting a changelog entry. The +`labeler.yml` auto-labeler handles this automatically for most cases; apply the +label manually if the auto-labeler did not. + +## Backport / cherry-pick workflow + +Velero uses `.github/workflows/backport.yml` to automate cherry-picks onto release +branches. + +- **Before merge:** comment `/backport release-1.17` (or `/cherrypick release-1.17`) + to add the label `backport release-1.17` to the PR. Multiple branches can be + space-delimited: `/backport release-1.17 release-1.18`. The label causes the + backport to run automatically when the PR merges. +- **After merge:** the same comment immediately creates the backport PR. +- Only repository **owners, members, and collaborators** may trigger these commands. + +## General coding guidelines + +- Follow the existing code style of the file being edited. +- Add unit tests for new exported functions in `pkg/`. +- Do not commit secrets, credentials, or API tokens. +- Keep PRs focused; prefer small, reviewable changes over large omnibus PRs. diff --git a/.github/labeler.yml b/.github/labeler.yml index 183f8365f..880977caf 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -31,3 +31,25 @@ has-e2e-2tests: has-unit-tests: - changed-files: - any-glob-to-any-file: pkg/**/*_test.go +# PRs that only touch non-shipping files (.github/ config, workflows, or docs) +# do not need a changelog entry; auto-apply the label so the changelog check passes. +kind/changelog-not-required: + - all: + - changed-files: + - any-glob-to-any-file: + - .github/**/* + - site/content/docs/**/* + - site/**/* + - '*.md' + - docs/**/* + - all-globs-to-all-files: + - '!pkg/**' + - '!internal/**' + - '!cmd/**' + - '!vendor/**' + - '!hack/**' + - '!Makefile' + - '!go.mod' + - '!go.sum' + - '!changelogs/**' + - '!**/*.go' diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index d0e13129e..670e16103 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -1,8 +1,21 @@ name: Backport merged pull request # Automates cherry-picking merged PRs onto release branches. -# - Label a merged PR with e.g. `backport release-1.17` to backport on merge. -# - Or comment `/backport release-1.17` or `/cherrypick release-1.17` on a merged PR. +# +# Pre-merge (open PR): +# An authorized /backport or /cherrypick comment adds one `backport ` +# label per requested branch. These labels are then picked up automatically +# when the PR is merged (see the pull_request_target: closed trigger below). +# +# Post-merge (merged PR): +# - Label a PR with e.g. `backport release-1.17` before merging; the label +# triggers the backport automatically when the PR closes as merged. +# - Comment `/backport release-1.17` or `/cherrypick release-1.17` on an +# already-merged PR to create the backport PR immediately. +# +# In both cases multiple target branches can be space-delimited in a comment: +# /backport release-1.17 release-1.18 +# # See: https://github.com/velero-io/velero/issues/9603 on: @@ -13,7 +26,78 @@ on: permissions: {} +# Shared condition for authorized /backport or /cherrypick comments. +# Used by both jobs below to avoid duplicating the gate logic. +env: + AUTHORIZED_COMMENT: >- + ${{ + github.event_name == 'issue_comment' && + github.event.issue.pull_request != '' && + github.event.comment.user.id != 97796249 && + contains( + fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), + github.event.comment.author_association + ) && + ( + startsWith(github.event.comment.body, '/backport') || + startsWith(github.event.comment.body, '/cherrypick') + ) + }} + jobs: + # ── Pre-merge: convert a /backport or /cherrypick comment into labels ─────── + # When the PR is still open the backport-action cannot run (it requires a + # merged commit). Instead, add one `backport ` label per requested + # branch so that the post-merge job picks them up automatically on close. + label-for-backport: + name: Label PR for deferred backport + # Run only when an authorized command is posted on an *open* (unmerged) PR. + if: > + github.repository == 'velero-io/velero' && + github.event_name == 'issue_comment' && + github.event.issue.pull_request != '' && + github.event.issue.state == 'open' && + github.event.comment.user.id != 97796249 && + contains( + fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), + github.event.comment.author_association + ) && + ( + startsWith(github.event.comment.body, '/backport') || + startsWith(github.event.comment.body, '/cherrypick') + ) + runs-on: ubuntu-latest + permissions: + issues: write # apply labels to the PR (PRs share the issues API) + steps: + - name: Parse branches and apply labels + env: + COMMENT_BODY: ${{ github.event.comment.body }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.issue.number }} + run: | + # Extract branch names from the first line of the comment. + # Strip the /backport or /cherrypick prefix; what remains is a + # space-delimited list of target branch names. + line=$(printf '%s' "$COMMENT_BODY" | head -n1 | tr -d '\r') + branches=$(printf '%s' "$line" | sed -E 's#^/(backport|cherrypick)[[:space:]]*##') + + if [ -z "$branches" ]; then + echo "No target branches specified in comment; nothing to label." + exit 0 + fi + + for branch in $branches; do + label="backport ${branch}" + echo "Applying label: '${label}'" + # Create the label if it does not exist yet (idempotent). + gh label create "${label}" --repo "${REPO}" --color "0075ca" \ + --description "Backport to ${branch}" 2>/dev/null || true + gh issue edit "${PR_NUMBER}" --repo "${REPO}" --add-label "${label}" + done + + # ── Post-merge: create backport PRs ───────────────────────────────────────── backport: name: Backport pull request # Exclude comments from the backport-action bot (user id 97796249) to prevent @@ -28,7 +112,8 @@ jobs: contains(toJSON(github.event.pull_request.labels.*.name), '"backport ') ) || ( github.event_name == 'issue_comment' && - github.event.issue.pull_request && + github.event.issue.pull_request != '' && + github.event.issue.state == 'closed' && github.event.comment.user.id != 97796249 && contains( fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), @@ -55,7 +140,7 @@ jobs: # Remaining text is a space-delimited list of target branches # (may be empty, falls back to labels). line=$(printf '%s' "$COMMENT_BODY" | head -n1 | tr -d '\r') - branches=$(printf '%s' "$line" | sed -E 's|^/(backport|cherrypick)[[:space:]]*||') + branches=$(printf '%s' "$line" | sed -E 's#^/(backport|cherrypick)[[:space:]]*##') echo "branches=${branches}" >> "$GITHUB_OUTPUT" - uses: actions/checkout@v7 From 9cb2c25eb8dd126ee0a8344806a0301898467bd7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:28:38 -0400 Subject: [PATCH 37/45] Bump kentaro-m/auto-assign-action from 2.0.0 to 2.0.2 (#10201) Bumps [kentaro-m/auto-assign-action](https://github.com/kentaro-m/auto-assign-action) from 2.0.0 to 2.0.2. - [Release notes](https://github.com/kentaro-m/auto-assign-action/releases) - [Commits](https://github.com/kentaro-m/auto-assign-action/compare/v2.0.0...v2.0.2) --- updated-dependencies: - dependency-name: kentaro-m/auto-assign-action dependency-version: 2.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/auto_assign_prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto_assign_prs.yml b/.github/workflows/auto_assign_prs.yml index b51fde199..a1ea2fb79 100644 --- a/.github/workflows/auto_assign_prs.yml +++ b/.github/workflows/auto_assign_prs.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set the author of a PR as the assignee - uses: kentaro-m/auto-assign-action@v2.0.0 + uses: kentaro-m/auto-assign-action@v2.0.2 with: configuration-path: ".github/auto-assignees.yml" From 0ba74dbf510bf63b3eb125aaadeab9a386f9451c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:32:17 -0400 Subject: [PATCH 38/45] Group Dependabot GitHub Actions updates (#10220) * Initial plan * Group Dependabot GitHub Actions updates Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kaovilai <11228024+kaovilai@users.noreply.github.com> --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 682c01231..a26f3eedf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,10 @@ updates: directory: "/" schedule: interval: "weekly" + groups: + github-actions: + patterns: + - "*" labels: - "Dependencies" - "github_actions" From c303809857fec756531379d7a045e8167c2595af Mon Sep 17 00:00:00 2001 From: Krishna Awasthi <140143710+opbot-xd@users.noreply.github.com> Date: Wed, 12 Aug 2026 01:12:48 +0530 Subject: [PATCH 39/45] Enhancement: Add missing test assertions for PVCBackupSummary in podvolume backupper (#10218) Signed-off-by: opbot_xd --- changelogs/unreleased/10218-opbot-xd | 1 + pkg/podvolume/backupper_test.go | 36 ++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 changelogs/unreleased/10218-opbot-xd diff --git a/changelogs/unreleased/10218-opbot-xd b/changelogs/unreleased/10218-opbot-xd new file mode 100644 index 000000000..d7b291f3c --- /dev/null +++ b/changelogs/unreleased/10218-opbot-xd @@ -0,0 +1 @@ +Add missing test assertions for PVCBackupSummary in podvolume backupper diff --git a/pkg/podvolume/backupper_test.go b/pkg/podvolume/backupper_test.go index 59466e02a..1ef4297af 100644 --- a/pkg/podvolume/backupper_test.go +++ b/pkg/podvolume/backupper_test.go @@ -380,6 +380,8 @@ func TestBackupPodVolumes(t *testing.T) { pvbs int mockGetRepositoryType bool errs []string + expectedBackedup []string + expectedSkipped map[string]string }{ { name: "empty volume list", @@ -573,6 +575,10 @@ func TestBackupPodVolumes(t *testing.T) { uploaderType: "kopia", bsl: "fake-bsl", errs: []string{}, + expectedSkipped: map[string]string{ + "fake-volume-1": "volume fake-volume-1 is declared in pod fake-ns/fake-pod but not mounted by any container, skipping", + "fake-volume-2": "volume fake-volume-2 is declared in pod fake-ns/fake-pod but not mounted by any container, skipping", + }, }, { name: "return completed pvbs", @@ -589,14 +595,14 @@ func TestBackupPodVolumes(t *testing.T) { ctlClientObj: []runtime.Object{ createBackupRepoObj(), }, - runtimeScheme: scheme, - uploaderType: "kopia", - bsl: "fake-bsl", - pvbs: 1, - errs: []string{}, + runtimeScheme: scheme, + uploaderType: "kopia", + bsl: "fake-bsl", + pvbs: 1, + errs: []string{}, + expectedBackedup: []string{"fake-volume-1"}, }, } - // TODO add more verification around PVCBackupSummary returned by "BackupPodVolumes" for _, test := range tests { t.Run(test.name, func(t *testing.T) { ctx := t.Context() @@ -627,7 +633,7 @@ func TestBackupPodVolumes(t *testing.T) { funcGetRepositoryType = getRepositoryType } - pvbs, _, errs := bp.BackupPodVolumes(backupObj, test.sourcePod, test.volumes, nil, velerotest.NewLogger()) + pvbs, summary, errs := bp.BackupPodVolumes(backupObj, test.sourcePod, test.volumes, nil, velerotest.NewLogger()) if test.errs != nil { for i := 0; i < len(errs); i++ { @@ -636,6 +642,22 @@ func TestBackupPodVolumes(t *testing.T) { } assert.Len(t, pvbs, test.pvbs) + + if summary != nil { + assert.Len(t, summary.Backedup, len(test.expectedBackedup)) + for _, vol := range test.expectedBackedup { + assert.Contains(t, summary.Backedup, vol) + } + + assert.Len(t, summary.Skipped, len(test.expectedSkipped)) + for vol, reason := range test.expectedSkipped { + require.Contains(t, summary.Skipped, vol) + assert.Equal(t, reason, summary.Skipped[vol].Reason) + } + } else { + assert.Empty(t, test.expectedBackedup) + assert.Empty(t, test.expectedSkipped) + } }) } } From 2aa5175594c69894e584a83d8558887a8ba45118 Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Wed, 12 Aug 2026 13:53:56 +0800 Subject: [PATCH 40/45] Mark the existed resource as skipped during restore (#10243) This commit makes sure the object is marked as "skipped" when there's object with same name exists in the cluster during restore. Otherwise, such object will appeared as "failed" in the "Resource list" in the output of "velero restore describe xxx --details" Signed-off-by: Daniel Jiang --- changelogs/unreleased/10243-reasonerjt | 1 + pkg/restore/restore.go | 4 ++ pkg/restore/restore_test.go | 54 +++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/10243-reasonerjt diff --git a/changelogs/unreleased/10243-reasonerjt b/changelogs/unreleased/10243-reasonerjt new file mode 100644 index 000000000..d650a70bd --- /dev/null +++ b/changelogs/unreleased/10243-reasonerjt @@ -0,0 +1 @@ +Mark the existed resource as skipped during restore \ No newline at end of file diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index 336add4de..a6d97d1ec 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -1954,6 +1954,8 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso e := errors.Errorf("could not restore, %s %q already exists. Warning: the in-cluster version is different than the backed-up version", obj.GetKind(), obj.GetName()) warnings.Add(namespace, e) + itemStatus.action = ItemRestoreResultSkipped + ctx.restoredItems[itemKey] = itemStatus // existingResourcePolicy is set as update, attempt patch on the resource and add warning if it fails } else if resourcePolicy == velerov1api.PolicyTypeUpdate { // processing update as existingResourcePolicy @@ -1969,6 +1971,8 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso // Preserved Velero behavior when existingResourcePolicy is not specified by the user e := errors.Errorf("could not restore, %s:%s already exists. Warning: the in-cluster version is different than the backed-up version", obj.GetKind(), obj.GetName()) + itemStatus.action = ItemRestoreResultSkipped + ctx.restoredItems[itemKey] = itemStatus warnings.Add(namespace, e) } } diff --git a/pkg/restore/restore_test.go b/pkg/restore/restore_test.go index 46667b1f9..5b013b2be 100644 --- a/pkg/restore/restore_test.go +++ b/pkg/restore/restore_test.go @@ -1086,6 +1086,7 @@ func TestRestoreItems(t *testing.T) { apiResources []*test.APIResource tarball io.Reader want []*test.APIResource + wantWarnings Result expectedRestoreItems map[itemKey]restoredItemStatus disableInformer bool }{ @@ -1328,6 +1329,52 @@ func TestRestoreItems(t *testing.T) { test.Pods(builder.ForPod("ns-1", "sa-1").ObjectMeta(builder.WithLabels("velero.io/backup-name", "foo", "velero.io/restore-name", "bar")).Result()), }, }, + { + name: "mark item as skipped when pod exists in cluster and is different from backed up one, existing resource policy is none", + restore: defaultRestore().ExistingResourcePolicy("none").Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("pods", builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("app", "backed-up")).Result()). + Done(), + apiResources: []*test.APIResource{ + test.Pods(builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("app", "in-cluster")).Result()), + }, + want: []*test.APIResource{ + test.Pods(builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("app", "in-cluster")).Result()), + }, + wantWarnings: Result{ + Namespaces: map[string][]string{ + "ns-1": {"could not restore, Pod \"pod-1\" already exists. Warning: the in-cluster version is different than the backed-up version"}, + }, + }, + expectedRestoreItems: map[itemKey]restoredItemStatus{ + {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true, createdName: "ns-1"}, + {resource: "v1/Pod", namespace: "ns-1", name: "pod-1"}: {action: "skipped", itemExists: true}, + }, + }, + { + name: "mark item as skipped when pod exists in cluster and is different from backed up one, existing resource policy is not specified", + restore: defaultRestore().Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("pods", builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("app", "backed-up")).Result()). + Done(), + apiResources: []*test.APIResource{ + test.Pods(builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("app", "in-cluster")).Result()), + }, + want: []*test.APIResource{ + test.Pods(builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("app", "in-cluster")).Result()), + }, + wantWarnings: Result{ + Namespaces: map[string][]string{ + "ns-1": {"could not restore, Pod:pod-1 already exists. Warning: the in-cluster version is different than the backed-up version"}, + }, + }, + expectedRestoreItems: map[itemKey]restoredItemStatus{ + {resource: "v1/Namespace", namespace: "", name: "ns-1"}: {action: "created", itemExists: true, createdName: "ns-1"}, + {resource: "v1/Pod", namespace: "ns-1", name: "pod-1"}: {action: "skipped", itemExists: true}, + }, + }, { name: "service account secrets and image pull secrets are restored when service account already exists in cluster", restore: defaultRestore().Result(), @@ -1437,7 +1484,12 @@ func TestRestoreItems(t *testing.T) { nil, // volume snapshotter getter ) - assertEmptyResults(t, warnings, errs) + if tc.wantWarnings.IsEmpty() { + assertEmptyResults(t, warnings) + } else { + assertWantErrsOrWarnings(t, tc.wantWarnings, warnings) + } + assertEmptyResults(t, errs) assertRestoredItems(t, h, tc.want) if len(tc.expectedRestoreItems) > 0 { assert.Equal(t, tc.expectedRestoreItems, data.RestoredItems) From 9a1d2e6eb0b06dd5e5631035c28f872b0e0238e4 Mon Sep 17 00:00:00 2001 From: AftAb-25 Date: Wed, 12 Aug 2026 12:42:58 +0530 Subject: [PATCH 41/45] Fix switch case ordering bug in `filterBackupOwnerReferences` (#10161) * Fix switch case ordering in filterBackupOwnerReferences (Issue #10160) When client.Get returns a transient (non-NotFound) error, the previous case ordering caused the UID mismatch case to fire against a zero-value struct, silently dropping the owner reference and logging a misleading 'mismatched UIDs' warning instead of the intended error log. Fix: move the general error handler before the UID mismatch check so it is evaluated while err is still relevant. The UID check now only runs when err == nil (i.e. the Schedule was successfully fetched). Also add a test case that injects a transient Get error via the fake client interceptor to verify the owner reference is preserved. Signed-off-by: aftab * Add changelog for #10160 Signed-off-by: aftab --------- Signed-off-by: aftab --- changelogs/unreleased/10161-AftAb-25 | 1 + pkg/controller/backup_sync_controller.go | 4 +- pkg/controller/backup_sync_controller_test.go | 44 +++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/10161-AftAb-25 diff --git a/changelogs/unreleased/10161-AftAb-25 b/changelogs/unreleased/10161-AftAb-25 new file mode 100644 index 000000000..f960a13df --- /dev/null +++ b/changelogs/unreleased/10161-AftAb-25 @@ -0,0 +1 @@ +Fixed a bug in the backup sync controller where transient API errors could cause backups to incorrectly lose their schedule owner references. diff --git a/pkg/controller/backup_sync_controller.go b/pkg/controller/backup_sync_controller.go index 07b5b460f..ce9af902f 100644 --- a/pkg/controller/backup_sync_controller.go +++ b/pkg/controller/backup_sync_controller.go @@ -271,11 +271,11 @@ func (b *backupSyncReconciler) filterBackupOwnerReferences(ctx context.Context, case err != nil && apierrors.IsNotFound(err): log.Warnf("Removing missing schedule ownership reference %s/%s from backup", backup.Namespace, v.Name) continue + case err != nil && !apierrors.IsNotFound(err): + log.WithError(errors.WithStack(err)).Error("Error finding schedule ownership reference, keeping schedule on backup") case schedule.UID != v.UID: log.Warnf("Removing schedule ownership reference with mismatched UIDs. Expected %s, got %s", v.UID, schedule.UID) continue - case err != nil && !apierrors.IsNotFound(err): - log.WithError(errors.WithStack(err)).Error("Error finding schedule ownership reference, keeping schedule on backup") } default: log.Warnf("Unable to check ownership reference for unknown kind, %s", v.Kind) diff --git a/pkg/controller/backup_sync_controller_test.go b/pkg/controller/backup_sync_controller_test.go index fe440ff09..fbfe65457 100644 --- a/pkg/controller/backup_sync_controller_test.go +++ b/pkg/controller/backup_sync_controller_test.go @@ -36,6 +36,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" @@ -914,4 +915,47 @@ var _ = Describe("Backup Sync Reconciler", func() { }) } }) + + It("filterBackupOwnerReferences preserves owner reference on transient API error", func() { + // This test verifies the fix for the switch case ordering bug: + // When client.Get returns a non-NotFound error (e.g. transient API failure), + // the owner reference must be kept on the backup rather than silently dropped + // due to an incorrect UID comparison against a zero-value struct. + scheduleUID := types.UID("schedule-uid-1") + backup := &velerov1api.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-backup", + Namespace: "test-namespace", + OwnerReferences: []metav1.OwnerReference{ + { + Kind: "Schedule", + Name: "my-schedule", + UID: scheduleUID, + }, + }, + }, + } + + // Build a fake client that returns a generic (non-NotFound) error on Get, + // simulating a transient API server failure. + transientErr := fmt.Errorf("transient connection error") + fakeClient := ctrlfake.NewClientBuilder(). + WithInterceptorFuncs(interceptor.Funcs{ + Get: func(ctx context.Context, c ctrlClient.WithWatch, key ctrlClient.ObjectKey, obj ctrlClient.Object, opts ...ctrlClient.GetOption) error { + return transientErr + }, + }). + Build() + + b := backupSyncReconciler{ + client: fakeClient, + } + + logger := velerotest.NewLogger() + references := b.filterBackupOwnerReferences(context.Background(), backup, logger) + + // The owner reference must be preserved when a transient error occurs. + Expect(references).To(HaveLen(1)) + Expect(references[0].UID).To(Equal(scheduleUID)) + }) }) From 8d275e69cc21875e8cc4585458dcf54cd6fbe111 Mon Sep 17 00:00:00 2001 From: Ralthos <161431341+Ralthos@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:12:53 +0530 Subject: [PATCH 42/45] Print n/a for unset timestamps in backup and restore get (#10206) velero backup get prints in CREATED for a backup that never started, and velero restore get prints it in both STARTED and COMPLETED. The timestamps are *metav1.Time and are appended to the row unformatted, so a nil pointer reaches the user as Go's nil literal. This is reachable in ordinary use. A backup that fails validation never starts, so StartTimestamp is never set, and a restore that fails validation gets neither timestamp. formatTimestamp returns n/a for an unset value, matching humanReadableTimeFromNow, which already handles a zero expiration in the same row. A set timestamp is unchanged. Adds tests for both printers, which had no row-level coverage. Signed-off-by: saral --- changelogs/unreleased/10201-Ralthos | 1 + pkg/cmd/util/output/backup_printer.go | 2 +- pkg/cmd/util/output/output.go | 14 ++ pkg/cmd/util/output/printer_timestamp_test.go | 130 ++++++++++++++++++ pkg/cmd/util/output/restore_printer.go | 4 +- 5 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/10201-Ralthos create mode 100644 pkg/cmd/util/output/printer_timestamp_test.go diff --git a/changelogs/unreleased/10201-Ralthos b/changelogs/unreleased/10201-Ralthos new file mode 100644 index 000000000..f41b37a2d --- /dev/null +++ b/changelogs/unreleased/10201-Ralthos @@ -0,0 +1 @@ +Show n/a instead of for unset timestamps in velero backup get and velero restore get diff --git a/pkg/cmd/util/output/backup_printer.go b/pkg/cmd/util/output/backup_printer.go index 873bc9fc3..53a950828 100644 --- a/pkg/cmd/util/output/backup_printer.go +++ b/pkg/cmd/util/output/backup_printer.go @@ -107,7 +107,7 @@ func printBackup(backup *velerov1api.Backup) []metav1.TableRow { status, backup.Status.Errors, backup.Status.Warnings, - backup.Status.StartTimestamp, + formatTimestamp(backup.Status.StartTimestamp), humanReadableTimeFromNow(expiration), backup.Spec.StorageLocation, queuePosition(backup.Status.QueuePosition), diff --git a/pkg/cmd/util/output/output.go b/pkg/cmd/util/output/output.go index 9dfca040b..9c46030f2 100644 --- a/pkg/cmd/util/output/output.go +++ b/pkg/cmd/util/output/output.go @@ -248,3 +248,17 @@ func NewPrinter(cmd *cobra.Command) (printers.ResourcePrinter, error) { return printer, nil } + +// formatTimestamp renders an optional timestamp for a table cell. +// +// Appending a nil *metav1.Time to a row prints "", which reaches the user +// for any object that has not reached the phase that sets the field: a backup +// that failed validation never gets a start time, and a restore that failed +// validation gets neither a start nor a completion time. An unset timestamp +// shows as "n/a" instead, matching humanReadableTimeFromNow in the same row. +func formatTimestamp(t *metav1.Time) string { + if t == nil || t.IsZero() { + return "n/a" + } + return t.String() +} diff --git a/pkg/cmd/util/output/printer_timestamp_test.go b/pkg/cmd/util/output/printer_timestamp_test.go new file mode 100644 index 000000000..f967b3b3f --- /dev/null +++ b/pkg/cmd/util/output/printer_timestamp_test.go @@ -0,0 +1,130 @@ +/* +Copyright the Velero contributors. + +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 output + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" +) + +func TestFormatTimestamp(t *testing.T) { + set := metav1.NewTime(time.Date(2026, 8, 8, 21, 6, 28, 0, time.UTC)) + + tests := []struct { + name string + input *metav1.Time + want string + }{ + { + name: "nil renders as n/a", + input: nil, + want: "n/a", + }, + { + name: "zero value renders as n/a", + input: &metav1.Time{}, + want: "n/a", + }, + { + name: "a set timestamp is unchanged", + input: &set, + want: set.String(), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.want, formatTimestamp(tc.input)) + }) + } +} + +// A backup that fails validation never starts, so StartTimestamp stays nil. +func TestPrintBackupWithoutStartTimestamp(t *testing.T) { + backup := &velerov1api.Backup{ + ObjectMeta: metav1.ObjectMeta{Name: "failed-validation"}, + Status: velerov1api.BackupStatus{ + Phase: velerov1api.BackupPhaseFailedValidation, + }, + } + + rows := printBackup(backup) + require.Len(t, rows, 1) + + // Name, Status, Errors, Warnings, Created, ... + assert.Equal(t, "n/a", rows[0].Cells[4], "unset start time should not print as ") + assert.Equal(t, string(velerov1api.BackupPhaseFailedValidation), rows[0].Cells[1]) +} + +func TestPrintBackupWithStartTimestamp(t *testing.T) { + started := metav1.NewTime(time.Date(2026, 8, 8, 21, 6, 28, 0, time.UTC)) + backup := &velerov1api.Backup{ + ObjectMeta: metav1.ObjectMeta{Name: "completed"}, + Status: velerov1api.BackupStatus{ + Phase: velerov1api.BackupPhaseCompleted, + StartTimestamp: &started, + }, + } + + rows := printBackup(backup) + require.Len(t, rows, 1) + assert.Equal(t, started.String(), rows[0].Cells[4]) +} + +// A restore that fails validation gets neither timestamp. +func TestPrintRestoreWithoutTimestamps(t *testing.T) { + restore := &velerov1api.Restore{ + ObjectMeta: metav1.ObjectMeta{Name: "failed-validation"}, + Spec: velerov1api.RestoreSpec{BackupName: "does-not-exist"}, + Status: velerov1api.RestoreStatus{ + Phase: velerov1api.RestorePhaseFailedValidation, + }, + } + + rows := printRestore(restore) + require.Len(t, rows, 1) + + // Name, Backup, Status, Started, Completed, ... + assert.Equal(t, "n/a", rows[0].Cells[3], "unset start time should not print as ") + assert.Equal(t, "n/a", rows[0].Cells[4], "unset completion time should not print as ") +} + +func TestPrintRestoreWithTimestamps(t *testing.T) { + started := metav1.NewTime(time.Date(2026, 8, 8, 21, 9, 40, 0, time.UTC)) + completed := metav1.NewTime(time.Date(2026, 8, 8, 21, 9, 41, 0, time.UTC)) + + restore := &velerov1api.Restore{ + ObjectMeta: metav1.ObjectMeta{Name: "completed"}, + Spec: velerov1api.RestoreSpec{BackupName: "nightly-1"}, + Status: velerov1api.RestoreStatus{ + Phase: velerov1api.RestorePhaseCompleted, + StartTimestamp: &started, + CompletionTimestamp: &completed, + }, + } + + rows := printRestore(restore) + require.Len(t, rows, 1) + assert.Equal(t, started.String(), rows[0].Cells[3]) + assert.Equal(t, completed.String(), rows[0].Cells[4]) +} diff --git a/pkg/cmd/util/output/restore_printer.go b/pkg/cmd/util/output/restore_printer.go index 782eb3485..d9b35a3cb 100644 --- a/pkg/cmd/util/output/restore_printer.go +++ b/pkg/cmd/util/output/restore_printer.go @@ -62,8 +62,8 @@ func printRestore(restore *v1.Restore) []metav1.TableRow { restore.Name, restore.Spec.BackupName, status, - restore.Status.StartTimestamp, - restore.Status.CompletionTimestamp, + formatTimestamp(restore.Status.StartTimestamp), + formatTimestamp(restore.Status.CompletionTimestamp), restore.Status.Errors, restore.Status.Warnings, restore.CreationTimestamp.Time, From 2d10d3685fc347562ef4872f597cc4a39ac5f56a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 16:30:29 +0800 Subject: [PATCH 43/45] Bump the github-actions group with 4 updates (#10239) Bumps the github-actions group with 4 updates: [actions/github-script](https://github.com/actions/github-script), [actions/cache](https://github.com/actions/cache), [jpmcb/prow-github-actions](https://github.com/jpmcb/prow-github-actions) and [actions/stale](https://github.com/actions/stale). Updates `actions/github-script` from 7 to 9 - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v7...v9) Updates `actions/cache` from 4 to 6 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v6) Updates `jpmcb/prow-github-actions` from 1.1.3 to 2.0.0 - [Release notes](https://github.com/jpmcb/prow-github-actions/releases) - [Commits](https://github.com/jpmcb/prow-github-actions/compare/f4d01dd4b13f289014c23fe5a19878a2479cb35b...c44ac3a57d67639e39e4a4988b52049ef45b80dd) Updates `actions/stale` from 10.1.1 to 11.0.0 - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v10.1.1...v11.0.0) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/cache dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: jpmcb/prow-github-actions dependency-version: 2.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/stale dependency-version: 11.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/auto_assign_prs.yml | 2 +- .github/workflows/e2e-test-kind.yaml | 12 ++++++------ .github/workflows/prow-action.yml | 2 +- .github/workflows/stale-issues.yml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/auto_assign_prs.yml b/.github/workflows/auto_assign_prs.yml index a1ea2fb79..bbcb3a9f4 100644 --- a/.github/workflows/auto_assign_prs.yml +++ b/.github/workflows/auto_assign_prs.yml @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Re-request review from maintainers if more approvals are needed - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: script: | const requiredApprovals = 2; diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index 34a98203c..0dec81251 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -39,14 +39,14 @@ jobs: # Look for a CLI that's made for this PR - name: Fetch built CLI id: cli-cache - uses: actions/cache@v4 + uses: actions/cache@v6 with: path: ./_output/bin/linux/amd64/velero # The cache key a combination of the current PR number and the commit SHA key: velero-cli-${{ github.event.pull_request.number }}-${{ github.sha }} - name: Fetch built image id: image-cache - uses: actions/cache@v4 + uses: actions/cache@v6 with: path: ./velero.tar # The cache key a combination of the current PR number and the commit SHA @@ -64,7 +64,7 @@ jobs: docker save velero:pr-test-linux-amd64 -o ./velero.tar # Build the MinIO image once for all e2e tests, from the reviewed bitnami/containers commit. - name: Cache MinIO Image - uses: actions/cache@v4 + uses: actions/cache@v6 id: minio-cache with: path: ./minio-image.tar @@ -128,7 +128,7 @@ jobs: # Fetch the pre-built MinIO image from the build job - name: Fetch built MinIO Image - uses: actions/cache@v4 + uses: actions/cache@v6 id: minio-cache with: path: ./minio-image.tar @@ -147,13 +147,13 @@ jobs: node_image: "kindest/node:v${{ matrix.k8s }}" - name: Fetch built CLI id: cli-cache - uses: actions/cache@v4 + uses: actions/cache@v6 with: path: ./_output/bin/linux/amd64/velero key: velero-cli-${{ github.event.pull_request.number }}-${{ github.sha }} - name: Fetch built Image id: image-cache - uses: actions/cache@v4 + uses: actions/cache@v6 with: path: ./velero.tar key: velero-image-${{ github.event.pull_request.number }}-${{ github.sha }} diff --git a/.github/workflows/prow-action.yml b/.github/workflows/prow-action.yml index 8a9190180..7f8bb7f00 100644 --- a/.github/workflows/prow-action.yml +++ b/.github/workflows/prow-action.yml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'velero-io/velero' runs-on: ubuntu-latest steps: - - uses: jpmcb/prow-github-actions@f4d01dd4b13f289014c23fe5a19878a2479cb35b # v1.1.3 + - uses: jpmcb/prow-github-actions@c44ac3a57d67639e39e4a4988b52049ef45b80dd # v2.0.0 with: # TODO: before allowing the /lgtm command, see if we can block merging if changelog labels are missing. prow-commands: | diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index 99a74872b..b66a339c8 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -8,7 +8,7 @@ jobs: if: github.repository == 'velero-io/velero' runs-on: ubuntu-latest steps: - - uses: actions/stale@v10.1.1 + - uses: actions/stale@v11.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: "This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days. If a Velero team member has requested log or more information, please provide the output of the shared commands." From 5dd0b9e8493a3d61e070769bc63bed932b47b795 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Wed, 12 Aug 2026 22:49:21 +0800 Subject: [PATCH 44/45] fix node-agent check contest Signed-off-by: Lyndon-Li --- changelogs/unreleased/10251-Lyndon-Li | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/10251-Lyndon-Li diff --git a/changelogs/unreleased/10251-Lyndon-Li b/changelogs/unreleased/10251-Lyndon-Li new file mode 100644 index 000000000..6aead3879 --- /dev/null +++ b/changelogs/unreleased/10251-Lyndon-Li @@ -0,0 +1 @@ +Fix wrong node-agent check result when PVR restorer run concurrently \ No newline at end of file From 1e368b07784facb82c03aa214e4af7f1aec21919 Mon Sep 17 00:00:00 2001 From: R4mbo Date: Wed, 12 Aug 2026 22:54:40 +0530 Subject: [PATCH 45/45] add curl --fail flag to kubectl download in e2e kind workflow (#10174) * add curl --fail flag to kubectl download in e2e kind workflow Signed-off-by: samay43 * add changelog entry Signed-off-by: samay43 --------- Signed-off-by: samay43 --- .github/workflows/e2e-test-kind.yaml | 2 +- changelogs/unreleased/10174-samay43 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/10174-samay43 diff --git a/.github/workflows/e2e-test-kind.yaml b/.github/workflows/e2e-test-kind.yaml index 0dec81251..6370a2b56 100644 --- a/.github/workflows/e2e-test-kind.yaml +++ b/.github/workflows/e2e-test-kind.yaml @@ -169,7 +169,7 @@ jobs: EOF # Match kubectl version to k8s server version - curl -LO https://dl.k8s.io/release/v${{ matrix.k8s }}/bin/linux/amd64/kubectl + curl -fLO https://dl.k8s.io/release/v${{ matrix.k8s }}/bin/linux/amd64/kubectl sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl git init -q /tmp/kibishii diff --git a/changelogs/unreleased/10174-samay43 b/changelogs/unreleased/10174-samay43 new file mode 100644 index 000000000..b88a04b6c --- /dev/null +++ b/changelogs/unreleased/10174-samay43 @@ -0,0 +1 @@ +Add curl --fail flag to kubectl download in e2e kind workflow