Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
a5d32f2
Sanitize Azure HTTP responses in BSL status messages
shubham-pampattiwar Oct 10, 2025
60dd3dc
Add changelog for PR #9321
shubham-pampattiwar Oct 10, 2025
20af2c2
Address PR review comments: sanitize errors and add SAS token scrubbing
shubham-pampattiwar Nov 12, 2025
3244cc6
feat: add apply flag to install command
mjnagel Dec 4, 2025
dbeb16a
Bump actions/stale from 10.1.0 to 10.1.1
dependabot[bot] Dec 8, 2025
fdcfed8
Add the node-agent ConfigMap document. (#9434)
blackpiglet Dec 9, 2025
4677689
Merge branch 'main' into dependabot/github_actions/actions/stale-10.1.1
blackpiglet Dec 10, 2025
c594026
Merge pull request #9446 from vmware-tanzu/dependabot/github_actions/…
blackpiglet Dec 10, 2025
554b04e
Merge pull request #9132 from mjnagel/crd-upgrade
blackpiglet Dec 10, 2025
0964365
Remove VolumeSnapshotClass from CSI restore and deletion process.
blackpiglet Nov 26, 2025
add66ea
Merge pull request #9431 from vmware-tanzu/9033_fix
blackpiglet Dec 12, 2025
14b34f0
Merge pull request #9321 from shubham-pampattiwar/fix-azure-bsl-statu…
shubham-pampattiwar Dec 12, 2025
a1026cb
Update golangci-lint installation script URL to use HEAD for latest v…
kaovilai Dec 12, 2025
11facb8
merge upstream/main into oadp-dev
oadp-maintainers Dec 13, 2025
8ae7ee0
skip subresource in resource discovery (#6688)
reasonerjt Aug 23, 2023
b94b9bf
fix issue 6753
Lyndon-Li Sep 5, 2023
f91aefc
Update restore controller logic for restore deletion (#6761)
ywk253100 Sep 6, 2023
0b75c76
Fix #6752: add namespace exclude check.
Sep 5, 2023
8cd2310
add csi snapshot data movement doc
Lyndon-Li Sep 8, 2023
d6d343f
Modify changelogs for v1.12
allenxu404 Sep 19, 2023
34b2f26
issue 6786:always delete VSC regardless of the deletion policy
Lyndon-Li Sep 13, 2023
4ee23ca
issue: move plugin depdending podvolume functions to util pkg
Lyndon-Li Sep 26, 2023
aa96db6
issue 6880: set ParallelUploadAboveSize as MaxInt64
Lyndon-Li Sep 28, 2023
cec5d02
changelog
kaovilai Aug 28, 2023
33566fc
Add support for block volumes (#6680) (#6897)
dzaninovic Sep 29, 2023
b461eb6
Replace the base image with paketobuildpacks image
ywk253100 Sep 27, 2023
84206e0
issue 6734: spread backup pod evenly
Lyndon-Li Oct 10, 2023
710571c
Add doc links for new features to release note
allenxu404 Sep 28, 2023
7127b0a
fix issue 6647
Lyndon-Li Aug 28, 2023
a1e425c
Perf improvements for existing resource restore
sseago Aug 21, 2023
07d2df9
issue #6807: Retry failed create when using generateName
sseago Sep 13, 2023
984c3c7
Import auth provider plugins
0x113 Oct 12, 2023
0fe5e2b
Add v1.12.1 changelog
allenxu404 Oct 20, 2023
203d68c
Make Windows build skip BlockMode code.
Oct 20, 2023
7919ed4
udmrepo use region specified in BSL when s3URL is empty
Lyndon-Li Oct 20, 2023
6ea188b
Change v1.12.1 changelog
allenxu404 Oct 20, 2023
6b54977
Dockerfile.ubi/travis local files
dymurray Jun 29, 2020
dc7137a
Add BZ + Publish automation to repo (#82)
rayfordj Jan 28, 2021
a6eccf4
remove dependabot config from fork
sseago Nov 4, 2022
be03901
Create Makefile.prow
kaovilai Apr 5, 2023
7b495d3
set HOME in velero image for kopia, update controller-gen for CI (#280)
sseago Jul 25, 2023
fca14b7
build velero-helper binary for datamover pod
sseago Aug 16, 2023
656f64e
restore: Use warning when Create IsAlreadyExist and Get error
kaovilai Oct 23, 2023
d3c2af5
kopia/repository/config/aws.go: Set session.Options profile from config
kaovilai Oct 20, 2023
6d7fb2b
use ubi9-latest to build
sseago May 23, 2024
166800c
OADP-4225: add tzdata to Dockerfile.ubi
sseago Jun 5, 2024
ed59ae0
fix: CI (#316)
Jun 17, 2024
ab12343
fix: ARM images (#332)
Aug 6, 2024
bdc34e5
ubi: BUILDPLATFORM to build stage to enable cross compile. (#336)
kaovilai Aug 12, 2024
8391e91
OADP-4640: Downstream only to allow override kopia default algorithms…
mpryc Aug 16, 2024
65ec2ac
Downstream only: Rework of Makefile and incusion of lint
mpryc Sep 4, 2024
9c52157
Downstream only - fix lint error in downtream change (#343)
mpryc Sep 5, 2024
2172e76
run oadp-operator e2e test from the velero repo (#353)
weshayutin Oct 17, 2024
ddd3200
DS Owners
kaovilai Mar 13, 2025
96b8172
updated controller-gen version
sseago Mar 13, 2025
f2bb2fa
Include velero-restore-helper binary in velero image (#374)
sseago Apr 1, 2025
47ecdba
Fix restic checkout in Dockerfile.ubi to get default branch (#436)
sseago Aug 19, 2025
9852a7c
UPSTREAM: <drop>: Updating go modules
oadp-maintainers Sep 12, 2025
5a03bad
UPSTREAM: <drop>: update restic @ 8c4c3fbfe (branch oadp-dev)
oadp-maintainers Sep 12, 2025
eaee76c
UPSTREAM: <carry> Use context from test for the kopia algorithms
oadp-maintainers Sep 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/stale-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected].0
- uses: actions/[email protected].1
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."
Expand Down
1 change: 1 addition & 0 deletions changelogs/unreleased/9132-mjnagel
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `--apply` flag to `install` command, allowing usage of Kubernetes apply to make changes to existing installs
1 change: 1 addition & 0 deletions changelogs/unreleased/9321-shubham-pampattiwar
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Sanitize Azure HTTP responses in BSL status messages
1 change: 1 addition & 0 deletions changelogs/unreleased/9431-blackpiglet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove VolumeSnapshotClass from CSI B/R process.
70 changes: 70 additions & 0 deletions design/Implemented/apply-flag.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Apply flag for install command

## Abstract
Add an `--apply` flag to the install command that enables applying existing resources rather than creating them. This can be useful as part of the upgrade process for existing installations.

## Background
The current Velero install command creates resources but doesn't provide a direct way to apply updates to an existing installation.
Users attempting to run the install command on an existing installation receive "already exists" messages.
Upgrade steps for existing installs typically involve a three (or more) step process to apply updated CRDs (using `--dry-run` and piping to `kubectl apply`) and then updating/setting images on the Velero deployment and node-agent.

## Goals
- Provide a simple flag to enable applying resources on an existing Velero installation.
- Use server-side apply to update existing resources rather than attempting to create them.
- Maintain consistency with the regular install flow.

## Non Goals
- Implement special logic for specific version-to-version upgrades (i.e. resource deletion, etc).
- Add complex upgrade validation or pre/post-upgrade hooks.
- Provide rollback capabilities.

## High-Level Design
The `--apply` flag will be added to the Velero install command.
When this flag is set, the installation process will use server-side apply to update existing resources instead of using create on new resources.
This flag can be used as _part_ of the upgrade process, but will not always fully handle an upgrade.

## Detailed Design
The implementation adds a new boolean flag `--apply` to the install command.
This flag will be passed through to the underlying install functions where the resource creation logic resides.

When the flag is set to true:
- The `createOrApplyResource` function will use server-side apply with field manager "velero-cli" and `force=true` to update resources.
- Resources will be applied in the same order as they would be created during installation.
- Custom Resource Definitions will still be processed first, and the system will wait for them to be established before continuing.

The server-side apply approach with `force=true` ensures that resources are updated even if there are conflicts with the last applied state.
This provides a best-effort mechanism to apply resources that follows the same flow as installation but updates resources instead of creating them.

No special handling is added for specific versions or resource structures, making this a general-purpose mechanism for applying resources.

## Alternatives Considered
1. Creating a separate `upgrade` command that would duplicate much of the install command logic.
- Rejected due to code duplication and maintenance overhead.

2. Implementing version-specific upgrade logic to handle breaking changes between versions.
- Rejected as overly complex and difficult to maintain across multiple version paths.
- This could be considered again in the future, but is not in the scope of the current design.

3. Adding automatic detection of existing resources and switching to apply mode.
- Rejected as it could lead to unexpected behavior and confusion if users unintentionally apply changes to existing resources.

## Security Considerations
The apply flag maintains the same security profile as the install command.
No additional permissions are required beyond what is needed for resource creation.
The use of `force=true` with server-side apply could potentially override manual changes made to resources, but this is a necessary trade-off to ensure apply is successful.

## Compatibility
This enhancement is compatible with all existing Velero installations as it is a new opt-in flag.
It does not change any resource formats or API contracts.
The apply process is best-effort and does not guarantee compatibility between arbitrary versions of Velero.
Users should still consult release notes for any breaking changes that may require manual intervention.
This flag could be adopted by the helm chart, specifically for CRD updates, to simplify the CRD update job.

## Implementation
The implementation involves:
1. Adding support for `Apply` to the existing Kubernetes client code.
1. Adding the `--apply` flag to the install command options.
1. Changing `createResource` to `createOrApplyResource` and updating it to use server-side apply when the `apply` boolean is set.

The implementation is straightforward and follows existing code patterns.
No migration of state or special handling of specific resources is required.
2 changes: 1 addition & 1 deletion hack/build-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ RUN ARCH=$(go env GOARCH) && \
chmod +x /usr/bin/goreleaser

# get golangci-lint
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0

# install kubectl
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/$(go env GOARCH)/kubectl
Expand Down
8 changes: 8 additions & 0 deletions internal/delete/actions/csi/volumesnapshotcontent_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ func (p *volumeSnapshotContentDeleteItemAction) Execute(

snapCont.ResourceVersion = ""

if snapCont.Spec.VolumeSnapshotClassName != nil {
// Delete VolumeSnapshotClass from the VolumeSnapshotContent.
// This is necessary to make the deletion independent of the VolumeSnapshotClass.
snapCont.Spec.VolumeSnapshotClassName = nil
p.log.Debugf("Deleted VolumeSnapshotClassName from VolumeSnapshotContent %s to make deletion independent of VolumeSnapshotClass",
snapCont.Name)
}

if err := p.crClient.Create(context.TODO(), &snapCont); err != nil {
return errors.Wrapf(err, "fail to create VolumeSnapshotContent %s", snapCont.Name)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func TestVSCExecute(t *testing.T) {
},
{
name: "Normal case, VolumeSnapshot should be deleted",
vsc: builder.ForVolumeSnapshotContent("bar").ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.BackupNameLabel: "backup"})).Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: &snapshotHandleStr}).Result(),
vsc: builder.ForVolumeSnapshotContent("bar").ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.BackupNameLabel: "backup"})).VolumeSnapshotClassName("volumesnapshotclass").Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: &snapshotHandleStr}).Result(),
backup: builder.ForBackup("velero", "backup").ObjectMeta(builder.WithAnnotationsMap(map[string]string{velerov1api.ResourceTimeoutAnnotation: "5s"})).Result(),
expectErr: false,
function: func(
Expand All @@ -82,7 +82,7 @@ func TestVSCExecute(t *testing.T) {
},
},
{
name: "Normal case, VolumeSnapshot should be deleted",
name: "Error case, deletion fails",
vsc: builder.ForVolumeSnapshotContent("bar").ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.BackupNameLabel: "backup"})).Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: &snapshotHandleStr}).Result(),
backup: builder.ForBackup("velero", "backup").ObjectMeta(builder.WithAnnotationsMap(map[string]string{velerov1api.ResourceTimeoutAnnotation: "5s"})).Result(),
expectErr: true,
Expand Down
25 changes: 16 additions & 9 deletions pkg/backup/actions/csi/volumesnapshot_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,25 +84,32 @@ func (p *volumeSnapshotBackupItemAction) Execute(
return nil, nil, "", nil, errors.WithStack(err)
}

if backup.Status.Phase == velerov1api.BackupPhaseFinalizing ||
backup.Status.Phase == velerov1api.BackupPhaseFinalizingPartiallyFailed {
p.log.
WithField("Backup", fmt.Sprintf("%s/%s", backup.Namespace, backup.Name)).
WithField("BackupPhase", backup.Status.Phase).Debugf("Cleaning VolumeSnapshots.")

csi.DeleteReadyVolumeSnapshot(*vs, p.crClient, p.log)
return item, nil, "", nil, nil
}

additionalItems := make([]velero.ResourceIdentifier, 0)

if vs.Spec.VolumeSnapshotClassName != nil {
// This is still needed to add the VolumeSnapshotClass to the backup.
// The secret with VolumeSnapshotClass is still relevant to backup.
additionalItems = append(
additionalItems,
velero.ResourceIdentifier{
GroupResource: kuberesource.VolumeSnapshotClasses,
Name: *vs.Spec.VolumeSnapshotClassName,
},
)
}

if backup.Status.Phase == velerov1api.BackupPhaseFinalizing ||
backup.Status.Phase == velerov1api.BackupPhaseFinalizingPartiallyFailed {
p.log.
WithField("Backup", fmt.Sprintf("%s/%s", backup.Namespace, backup.Name)).
WithField("BackupPhase", backup.Status.Phase).Debugf("Cleaning VolumeSnapshots.")

csi.DeleteReadyVolumeSnapshot(*vs, p.crClient, p.log)
return item, nil, "", nil, nil
// Because async operation will update VolumeSnapshot during finalizing phase.
// No matter what we do, VolumeSnapshotClass cannot be deleted. So skip it.
// Just deleting VolumeSnapshotClass during restore and delete is enough.
}

p.log.Infof("Getting VolumesnapshotContent for Volumesnapshot %s/%s",
Expand Down
4 changes: 4 additions & 0 deletions pkg/backup/actions/csi/volumesnapshotcontent_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ func (p *volumeSnapshotContentBackupItemAction) Execute(
})
}

// Because async operation will update VolumeSnapshotContent during finalizing phase.
// No matter what we do, VolumeSnapshotClass cannot be deleted. So skip it.
// Just deleting VolumeSnapshotClass during restore and delete is enough.

snapContMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&snapCont)
if err != nil {
return nil, nil, "", nil, errors.WithStack(err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestVSCExecute(t *testing.T) {
expectedItems []velero.ResourceIdentifier
}{
{
name: "Invalid VolumeSnapshotClass",
name: "Invalid VolumeSnapshotContent",
item: velerotest.UnstructuredOrDie(
`
{
Expand Down
10 changes: 10 additions & 0 deletions pkg/client/dynamic.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ type StatusUpdater interface {
UpdateStatus(obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error)
}

// Applier applies changes to an object using server-side apply
type Applier interface {
Apply(name string, obj *unstructured.Unstructured, opts metav1.ApplyOptions) (*unstructured.Unstructured, error)
}

// Dynamic contains client methods that Velero needs for backing up and restoring resources.
type Dynamic interface {
Creator
Expand All @@ -111,6 +116,7 @@ type Dynamic interface {
Patcher
Deletor
StatusUpdater
Applier
}

// dynamicResourceClient implements Dynamic.
Expand All @@ -136,6 +142,10 @@ func (d *dynamicResourceClient) Get(name string, opts metav1.GetOptions) (*unstr
return d.resourceClient.Get(context.TODO(), name, opts)
}

func (d *dynamicResourceClient) Apply(name string, obj *unstructured.Unstructured, opts metav1.ApplyOptions) (*unstructured.Unstructured, error) {
return d.resourceClient.Apply(context.TODO(), name, obj, opts)
}

func (d *dynamicResourceClient) Patch(name string, data []byte) (*unstructured.Unstructured, error) {
return d.resourceClient.Patch(context.TODO(), name, types.MergePatchType, data, metav1.PatchOptions{})
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/cmd/cli/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ type Options struct {
ConcurrentBackups int
NodeAgentDisableHostPath bool
kubeletRootDir string
Apply bool
ServerPriorityClassName string
NodeAgentPriorityClassName string
}
Expand All @@ -102,6 +103,7 @@ func (o *Options) BindFlags(flags *pflag.FlagSet) {
flags.StringVar(&o.BucketName, "bucket", o.BucketName, "Name of the object storage bucket where backups should be stored")
flags.StringVar(&o.SecretFile, "secret-file", o.SecretFile, "File containing credentials for backup and volume provider. If not specified, --no-secret must be used for confirmation. Optional.")
flags.BoolVar(&o.NoSecret, "no-secret", o.NoSecret, "Flag indicating if a secret should be created. Must be used as confirmation if --secret-file is not provided. Optional.")
flags.BoolVar(&o.Apply, "apply", o.Apply, "Flag indicating if resources should be applied instead of created. This can be used for updating existing resources.")
flags.BoolVar(&o.NoDefaultBackupLocation, "no-default-backup-location", o.NoDefaultBackupLocation, "Flag indicating if a default backup location should be created. Must be used as confirmation if --bucket or --provider are not provided. Optional.")
flags.StringVar(&o.Image, "image", o.Image, "Image to use for the Velero and node agent pods. Optional.")
flags.StringVar(&o.Prefix, "prefix", o.Prefix, "Prefix under which all Velero data should be stored within the bucket. Optional.")
Expand Down Expand Up @@ -416,7 +418,7 @@ func (o *Options) Run(c *cobra.Command, f client.Factory) error {

errorMsg := fmt.Sprintf("\n\nError installing Velero. Use `kubectl logs deploy/velero -n %s` to check the deploy logs", o.Namespace)

err = install.Install(dynamicFactory, kbClient, resources, os.Stdout)
err = install.Install(dynamicFactory, kbClient, resources, os.Stdout, o.Apply)
if err != nil {
return errors.Wrap(err, errorMsg)
}
Expand Down
103 changes: 101 additions & 2 deletions pkg/controller/backup_storage_location_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package controller

import (
"context"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -46,6 +47,104 @@ const (
bslValidationEnqueuePeriod = 10 * time.Second
)

// sanitizeStorageError cleans up verbose HTTP responses from cloud provider errors,
// particularly Azure which includes full HTTP response details and XML in error messages.
// It extracts the error code and message while removing HTTP headers and response bodies.
// It also scrubs sensitive information like SAS tokens from URLs.
func sanitizeStorageError(err error) string {
if err == nil {
return ""
}

errMsg := err.Error()

// Scrub sensitive information from URLs (SAS tokens, credentials, etc.)
// Azure SAS token parameters: sig, se, st, sp, spr, sv, sr, sip, srt, ss
// These appear as query parameters in URLs like: ?sig=value&se=value
sasParamsRegex := regexp.MustCompile(`([?&])(sig|se|st|sp|spr|sv|sr|sip|srt|ss)=([^&\s<>\n]+)`)
errMsg = sasParamsRegex.ReplaceAllString(errMsg, `${1}${2}=***REDACTED***`)

// Check if this looks like an Azure HTTP response error
// Azure errors contain patterns like "RESPONSE 404:" and "ERROR CODE:"
if !strings.Contains(errMsg, "RESPONSE") || !strings.Contains(errMsg, "ERROR CODE:") {
// Not an Azure-style error, return as-is
return errMsg
}

// Extract the error code (e.g., "ContainerNotFound", "BlobNotFound")
errorCodeRegex := regexp.MustCompile(`ERROR CODE:\s*(\w+)`)
errorCodeMatch := errorCodeRegex.FindStringSubmatch(errMsg)
var errorCode string
if len(errorCodeMatch) > 1 {
errorCode = errorCodeMatch[1]
}

// Extract the error message from the XML or plain text
// Look for message between <Message> tags or after "RESPONSE XXX:"
var errorMessage string

// Try to extract from XML first
messageRegex := regexp.MustCompile(`<Message>(.*?)</Message>`)
messageMatch := messageRegex.FindStringSubmatch(errMsg)
if len(messageMatch) > 1 {
errorMessage = messageMatch[1]
// Remove RequestId and Time from the message
if idx := strings.Index(errorMessage, "\nRequestId:"); idx != -1 {
errorMessage = errorMessage[:idx]
}
} else {
// Try to extract from plain text response (e.g., "RESPONSE 404: 404 The specified container does not exist.")
responseRegex := regexp.MustCompile(`RESPONSE\s+\d+:\s+\d+\s+([^\n]+)`)
responseMatch := responseRegex.FindStringSubmatch(errMsg)
if len(responseMatch) > 1 {
errorMessage = strings.TrimSpace(responseMatch[1])
}
}

// Build a clean error message
var cleanMsg string
if errorCode != "" && errorMessage != "" {
cleanMsg = errorCode + ": " + errorMessage
} else if errorCode != "" {
cleanMsg = errorCode
} else if errorMessage != "" {
cleanMsg = errorMessage
} else {
// Fallback: try to extract the desc part from gRPC error
descRegex := regexp.MustCompile(`desc\s*=\s*(.+)`)
descMatch := descRegex.FindStringSubmatch(errMsg)
if len(descMatch) > 1 {
// Take everything up to the first newline or "RESPONSE" marker
desc := descMatch[1]
if idx := strings.Index(desc, "\n"); idx != -1 {
desc = desc[:idx]
}
if idx := strings.Index(desc, "RESPONSE"); idx != -1 {
desc = strings.TrimSpace(desc[:idx])
}
cleanMsg = desc
} else {
// Last resort: return first line
if idx := strings.Index(errMsg, "\n"); idx != -1 {
cleanMsg = errMsg[:idx]
} else {
cleanMsg = errMsg
}
}
}

// Preserve the prefix part of the error (e.g., "rpc error: code = Unknown desc = ")
// but replace the verbose description with our clean message
if strings.Contains(errMsg, "desc = ") {
parts := strings.SplitN(errMsg, "desc = ", 2)
if len(parts) == 2 {
return parts[0] + "desc = " + cleanMsg
}
}

return cleanMsg
}

// BackupStorageLocationReconciler reconciles a BackupStorageLocation object
type backupStorageLocationReconciler struct {
ctx context.Context
Expand Down Expand Up @@ -125,9 +224,9 @@ func (r *backupStorageLocationReconciler) Reconcile(ctx context.Context, req ctr
if err != nil {
log.Info("BackupStorageLocation is invalid, marking as unavailable")
err = errors.Wrapf(err, "BackupStorageLocation %q is unavailable", location.Name)
unavailableErrors = append(unavailableErrors, err.Error())
unavailableErrors = append(unavailableErrors, sanitizeStorageError(err))
location.Status.Phase = velerov1api.BackupStorageLocationPhaseUnavailable
location.Status.Message = err.Error()
location.Status.Message = sanitizeStorageError(err)
} else {
log.Info("BackupStorageLocations is valid, marking as available")
location.Status.Phase = velerov1api.BackupStorageLocationPhaseAvailable
Expand Down
Loading