s3: add rclone backend restore-status command
This command shows the restore status of objects being retrieved from GLACIER. See: https://forum.rclone.org/t/aws-s3-glacier-monitor-restore-status-command-for-glacier-restoring-process/41373/7
This commit is contained in:
parent
d80890bf32
commit
f4b011e4e4
1 changed files with 97 additions and 2 deletions
|
@ -3643,6 +3643,7 @@ type listOpt struct {
|
||||||
findFile bool // if set, it will look for files called (bucket, directory)
|
findFile bool // if set, it will look for files called (bucket, directory)
|
||||||
versionAt fs.Time // if set only show versions <= this time
|
versionAt fs.Time // if set only show versions <= this time
|
||||||
noSkipMarkers bool // if set return dir marker objects
|
noSkipMarkers bool // if set return dir marker objects
|
||||||
|
restoreStatus bool // if set return restore status in listing too
|
||||||
}
|
}
|
||||||
|
|
||||||
// list lists the objects into the function supplied with the opt
|
// list lists the objects into the function supplied with the opt
|
||||||
|
@ -3682,6 +3683,10 @@ func (f *Fs) list(ctx context.Context, opt listOpt, fn listFn) error {
|
||||||
Prefix: &opt.directory,
|
Prefix: &opt.directory,
|
||||||
MaxKeys: &f.opt.ListChunk,
|
MaxKeys: &f.opt.ListChunk,
|
||||||
}
|
}
|
||||||
|
if opt.restoreStatus {
|
||||||
|
restoreStatus := "RestoreStatus"
|
||||||
|
req.OptionalObjectAttributes = []*string{&restoreStatus}
|
||||||
|
}
|
||||||
if f.opt.RequesterPays {
|
if f.opt.RequesterPays {
|
||||||
req.RequestPayer = aws.String(s3.RequestPayerRequester)
|
req.RequestPayer = aws.String(s3.RequestPayerRequester)
|
||||||
}
|
}
|
||||||
|
@ -4413,11 +4418,11 @@ if not.
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"Status": "OK",
|
"Status": "OK",
|
||||||
"Path": "test.txt"
|
"Remote": "test.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Status": "OK",
|
"Status": "OK",
|
||||||
"Path": "test/file4.txt"
|
"Remote": "test/file4.txt"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4427,6 +4432,46 @@ if not.
|
||||||
"lifetime": "Lifetime of the active copy in days",
|
"lifetime": "Lifetime of the active copy in days",
|
||||||
"description": "The optional description for the job.",
|
"description": "The optional description for the job.",
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
Name: "restore-status",
|
||||||
|
Short: "Show the restore status for objects being restored from GLACIER to normal storage",
|
||||||
|
Long: `This command can be used to show the status for objects being restored from GLACIER
|
||||||
|
to normal storage.
|
||||||
|
|
||||||
|
Usage Examples:
|
||||||
|
|
||||||
|
rclone backend restore-status s3:bucket/path/to/object
|
||||||
|
rclone backend restore-status s3:bucket/path/to/directory
|
||||||
|
rclone backend restore-status -o all s3:bucket/path/to/directory
|
||||||
|
|
||||||
|
This command does not obey the filters.
|
||||||
|
|
||||||
|
It returns a list of status dictionaries.
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Remote": "file.txt",
|
||||||
|
"VersionID": null,
|
||||||
|
"RestoreStatus": {
|
||||||
|
"IsRestoreInProgress": true,
|
||||||
|
"RestoreExpiryDate": "2023-09-06T12:29:19+01:00"
|
||||||
|
},
|
||||||
|
"StorageClass": "GLACIER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Remote": "test.pdf",
|
||||||
|
"VersionID": null,
|
||||||
|
"RestoreStatus": {
|
||||||
|
"IsRestoreInProgress": false,
|
||||||
|
"RestoreExpiryDate": "2023-09-06T12:29:19+01:00"
|
||||||
|
},
|
||||||
|
"StorageClass": "DEEP_ARCHIVE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
Opts: map[string]string{
|
||||||
|
"all": "if set then show all objects, not just ones with restore status",
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Name: "list-multipart-uploads",
|
Name: "list-multipart-uploads",
|
||||||
Short: "List the unfinished multipart uploads",
|
Short: "List the unfinished multipart uploads",
|
||||||
|
@ -4603,6 +4648,9 @@ func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[str
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
|
case "restore-status":
|
||||||
|
_, all := opt["all"]
|
||||||
|
return f.restoreStatus(ctx, all)
|
||||||
case "list-multipart-uploads":
|
case "list-multipart-uploads":
|
||||||
return f.listMultipartUploadsAll(ctx)
|
return f.listMultipartUploadsAll(ctx)
|
||||||
case "cleanup":
|
case "cleanup":
|
||||||
|
@ -4642,6 +4690,53 @@ func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returned from "restore-status"
|
||||||
|
type restoreStatusOut struct {
|
||||||
|
Remote string
|
||||||
|
VersionID *string
|
||||||
|
RestoreStatus *s3.RestoreStatus
|
||||||
|
StorageClass *string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively enumerate the current fs to find objects with a restore status
|
||||||
|
func (f *Fs) restoreStatus(ctx context.Context, all bool) (out []restoreStatusOut, err error) {
|
||||||
|
fs.Debugf(f, "all = %v", all)
|
||||||
|
bucket, directory := f.split("")
|
||||||
|
out = []restoreStatusOut{}
|
||||||
|
err = f.list(ctx, listOpt{
|
||||||
|
bucket: bucket,
|
||||||
|
directory: directory,
|
||||||
|
prefix: f.rootDirectory,
|
||||||
|
addBucket: f.rootBucket == "",
|
||||||
|
recurse: true,
|
||||||
|
withVersions: f.opt.Versions,
|
||||||
|
versionAt: f.opt.VersionAt,
|
||||||
|
restoreStatus: true,
|
||||||
|
}, func(remote string, object *s3.Object, versionID *string, isDirectory bool) error {
|
||||||
|
entry, err := f.itemToDirEntry(ctx, remote, object, versionID, isDirectory)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if entry != nil {
|
||||||
|
if o, ok := entry.(*Object); ok && (all || object.RestoreStatus != nil) {
|
||||||
|
out = append(out, restoreStatusOut{
|
||||||
|
Remote: o.remote,
|
||||||
|
VersionID: o.versionID,
|
||||||
|
RestoreStatus: object.RestoreStatus,
|
||||||
|
StorageClass: object.StorageClass,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// bucket must be present if listing succeeded
|
||||||
|
f.cache.MarkOK(bucket)
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// listMultipartUploads lists all outstanding multipart uploads for (bucket, key)
|
// listMultipartUploads lists all outstanding multipart uploads for (bucket, key)
|
||||||
//
|
//
|
||||||
// Note that rather lazily we treat key as a prefix so it matches
|
// Note that rather lazily we treat key as a prefix so it matches
|
||||||
|
|
Loading…
Add table
Reference in a new issue