diff --git a/changelog/unreleased/issue-4583 b/changelog/unreleased/issue-4583 new file mode 100644 index 000000000..97b0e6ba7 --- /dev/null +++ b/changelog/unreleased/issue-4583 @@ -0,0 +1,12 @@ +Enhancement: Ignore s3.storage-class for metadata if archive tier is specified + +There is no official cold storage support in restic, use this option at your +own risk. + +Restic always stored all files on s3 using the specified `s3.storage-class`. +Now, restic will store metadata using a non-archive storage tier to avoid +problems when accessing a repository. To restore any data, it is still +necessary to manually warm up the required data beforehand. + +https://github.com/restic/restic/issues/4583 +https://github.com/restic/restic/pull/4584 diff --git a/internal/backend/s3/s3.go b/internal/backend/s3/s3.go index f0447224f..d41f4479d 100644 --- a/internal/backend/s3/s3.go +++ b/internal/backend/s3/s3.go @@ -325,16 +325,29 @@ func (be *Backend) Path() string { return be.cfg.Prefix } +// useStorageClass returns whether file should be saved in the provided Storage Class +// For archive storage classes, only data files are stored using that class; metadata +// must remain instantly accessible. +func (be *Backend) useStorageClass(h backend.Handle) bool { + notArchiveClass := be.cfg.StorageClass != "GLACIER" && be.cfg.StorageClass != "DEEP_ARCHIVE" + isDataFile := h.Type == backend.PackFile && !h.IsMetadata + return isDataFile || notArchiveClass +} + // Save stores data in the backend at the handle. func (be *Backend) Save(ctx context.Context, h backend.Handle, rd backend.RewindReader) error { objName := be.Filename(h) - opts := minio.PutObjectOptions{StorageClass: be.cfg.StorageClass} - opts.ContentType = "application/octet-stream" - // the only option with the high-level api is to let the library handle the checksum computation - opts.SendContentMd5 = true - // only use multipart uploads for very large files - opts.PartSize = 200 * 1024 * 1024 + opts := minio.PutObjectOptions{ + ContentType: "application/octet-stream", + // the only option with the high-level api is to let the library handle the checksum computation + SendContentMd5: true, + // only use multipart uploads for very large files + PartSize: 200 * 1024 * 1024, + } + if be.useStorageClass(h) { + opts.StorageClass = be.cfg.StorageClass + } info, err := be.client.PutObject(ctx, be.cfg.Bucket, objName, io.NopCloser(rd), int64(rd.Length()), opts)