mirror of
https://github.com/rclone/rclone.git
synced 2024-11-26 10:25:03 +01:00
oracleobjectstorage: Support "backend restore" command - fixes #7371
This commit is contained in:
parent
0563cc6314
commit
1045f54128
@ -7,12 +7,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oracle/oci-go-sdk/v65/common"
|
"github.com/oracle/oci-go-sdk/v65/common"
|
||||||
"github.com/oracle/oci-go-sdk/v65/objectstorage"
|
"github.com/oracle/oci-go-sdk/v65/objectstorage"
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
|
"github.com/rclone/rclone/fs/operations"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
@ -23,6 +26,7 @@ const (
|
|||||||
operationRename = "rename"
|
operationRename = "rename"
|
||||||
operationListMultiPart = "list-multipart-uploads"
|
operationListMultiPart = "list-multipart-uploads"
|
||||||
operationCleanup = "cleanup"
|
operationCleanup = "cleanup"
|
||||||
|
operationRestore = "restore"
|
||||||
)
|
)
|
||||||
|
|
||||||
var commandHelp = []fs.CommandHelp{{
|
var commandHelp = []fs.CommandHelp{{
|
||||||
@ -77,6 +81,42 @@ Durations are parsed as per the rest of rclone, 2h, 7d, 7w etc.
|
|||||||
Opts: map[string]string{
|
Opts: map[string]string{
|
||||||
"max-age": "Max age of upload to delete",
|
"max-age": "Max age of upload to delete",
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
Name: operationRestore,
|
||||||
|
Short: "Restore objects from Archive to Standard storage",
|
||||||
|
Long: `This command can be used to restore one or more objects from Archive to Standard storage.
|
||||||
|
|
||||||
|
Usage Examples:
|
||||||
|
|
||||||
|
rclone backend restore oos:bucket/path/to/directory -o hours=HOURS
|
||||||
|
rclone backend restore oos:bucket -o hours=HOURS
|
||||||
|
|
||||||
|
This flag also obeys the filters. Test first with --interactive/-i or --dry-run flags
|
||||||
|
|
||||||
|
rclone --interactive backend restore --include "*.txt" oos:bucket/path -o hours=72
|
||||||
|
|
||||||
|
All the objects shown will be marked for restore, then
|
||||||
|
|
||||||
|
rclone backend restore --include "*.txt" oos:bucket/path -o hours=72
|
||||||
|
|
||||||
|
It returns a list of status dictionaries with Object Name and Status
|
||||||
|
keys. The Status will be "RESTORED"" if it was successful or an error message
|
||||||
|
if not.
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Object": "test.txt"
|
||||||
|
"Status": "RESTORED",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Object": "test/file4.txt"
|
||||||
|
"Status": "RESTORED",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
Opts: map[string]string{
|
||||||
|
"hours": "The number of hours for which this object will be restored. Default is 24 hrs.",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +153,8 @@ func (f *Fs) Command(ctx context.Context, commandName string, args []string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, f.cleanUp(ctx, maxAge)
|
return nil, f.cleanUp(ctx, maxAge)
|
||||||
|
case operationRestore:
|
||||||
|
return f.restore(ctx, opt)
|
||||||
default:
|
default:
|
||||||
return nil, fs.ErrorCommandNotFound
|
return nil, fs.ErrorCommandNotFound
|
||||||
}
|
}
|
||||||
@ -290,3 +332,63 @@ func (f *Fs) listMultipartUploadParts(ctx context.Context, bucketName, bucketPat
|
|||||||
}
|
}
|
||||||
return uploadedParts, nil
|
return uploadedParts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Fs) restore(ctx context.Context, opt map[string]string) (interface{}, error) {
|
||||||
|
req := objectstorage.RestoreObjectsRequest{
|
||||||
|
NamespaceName: common.String(f.opt.Namespace),
|
||||||
|
RestoreObjectsDetails: objectstorage.RestoreObjectsDetails{},
|
||||||
|
}
|
||||||
|
if hours := opt["hours"]; hours != "" {
|
||||||
|
ihours, err := strconv.Atoi(hours)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("bad value for hours: %w", err)
|
||||||
|
}
|
||||||
|
req.RestoreObjectsDetails.Hours = &ihours
|
||||||
|
}
|
||||||
|
type status struct {
|
||||||
|
Object string
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
outMu sync.Mutex
|
||||||
|
out = []status{}
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
err = operations.ListFn(ctx, f, func(obj fs.Object) {
|
||||||
|
// Remember this is run --checkers times concurrently
|
||||||
|
o, ok := obj.(*Object)
|
||||||
|
st := status{Object: obj.Remote(), Status: "RESTORED"}
|
||||||
|
defer func() {
|
||||||
|
outMu.Lock()
|
||||||
|
out = append(out, st)
|
||||||
|
outMu.Unlock()
|
||||||
|
}()
|
||||||
|
if !ok {
|
||||||
|
st.Status = "Not an OCI Object Storage object"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if o.storageTier == nil || (*o.storageTier != "archive") {
|
||||||
|
st.Status = "Object not in Archive storage tier"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if operations.SkipDestructive(ctx, obj, "restore") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bucket, bucketPath := o.split()
|
||||||
|
reqCopy := req
|
||||||
|
reqCopy.BucketName = &bucket
|
||||||
|
reqCopy.ObjectName = &bucketPath
|
||||||
|
var response objectstorage.RestoreObjectsResponse
|
||||||
|
err = f.pacer.Call(func() (bool, error) {
|
||||||
|
response, err = f.srv.RestoreObjects(ctx, reqCopy)
|
||||||
|
return shouldRetry(ctx, response.HTTPResponse(), err)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
st.Status = err.Error()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
@ -771,6 +771,47 @@ Options:
|
|||||||
|
|
||||||
- "max-age": Max age of upload to delete
|
- "max-age": Max age of upload to delete
|
||||||
|
|
||||||
|
### restore
|
||||||
|
|
||||||
|
Restore objects from Archive to Standard storage
|
||||||
|
|
||||||
|
rclone backend restore remote: [options] [<arguments>+]
|
||||||
|
|
||||||
|
This command can be used to restore one or more objects from Archive to Standard storage.
|
||||||
|
|
||||||
|
Usage Examples:
|
||||||
|
|
||||||
|
rclone backend restore oos:bucket/path/to/directory -o hours=HOURS
|
||||||
|
rclone backend restore oos:bucket -o hours=HOURS
|
||||||
|
|
||||||
|
This flag also obeys the filters. Test first with --interactive/-i or --dry-run flags
|
||||||
|
|
||||||
|
rclone --interactive backend restore --include "*.txt" oos:bucket/path -o hours=72
|
||||||
|
|
||||||
|
All the objects shown will be marked for restore, then
|
||||||
|
|
||||||
|
rclone backend restore --include "*.txt" oos:bucket/path -o hours=72
|
||||||
|
|
||||||
|
It returns a list of status dictionaries with Object Name and Status
|
||||||
|
keys. The Status will be "RESTORED"" if it was successful or an error message
|
||||||
|
if not.
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Object": "test.txt"
|
||||||
|
"Status": "RESTORED",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Object": "test/file4.txt"
|
||||||
|
"Status": "RESTORED",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
- "hours": The number of hours for which this object will be restored. Default is 24 hrs.
|
||||||
|
|
||||||
{{< rem autogenerated options stop >}}
|
{{< rem autogenerated options stop >}}
|
||||||
|
|
||||||
## Tutorials
|
## Tutorials
|
||||||
|
Loading…
Reference in New Issue
Block a user