-
Notifications
You must be signed in to change notification settings - Fork 99
/
revert_versioning.go
297 lines (250 loc) · 10.3 KB
/
revert_versioning.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
package lib
import (
"fmt"
"os"
"strings"
oss "github.com/aliyun/aliyun-oss-go-sdk/oss"
)
var specChineseRevert = SpecText{
synopsisText: "将object从删除状态恢复成最近的多版本状态",
paramText: "cloud_url [options]",
syntaxText: `
ossutil revert-versioning oss://bucket[/prefix] [--encoding-type encodeType] [-r] [--start-time startTime] [--end-time endTime] [--include include-pattern] [--exclude exclude-pattern] [--payer requester]
`,
detailHelpText: `
该命令通过删除最新的删除标记,使object从删除状态恢复成最近的多版本状态
--recursive选项
如果输入--recursive或者-r,表示批量操作匹配prefix的所有objects, 否则只操作key为prefix的单个object
--start-time
时间戳, 既从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数
如果输入这个选项, object的删除时间小于该时间戳将被忽略
--end-time
时间戳, 既从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数
如果输入这个选项, object的删除时间大于该时间戳将被忽略
用法:
该命令只有一种用法:
1) ossutil revert-versioning oss://bucket[/prefix] [--encoding-type encodeType] [-r] [--start-time startTime] [--end-time endTime] [--include include-pattern] [--exclude exclude-pattern] [--payer requester]
恢复bucket下面满足前缀为prefix的object为多版本状态
`,
sampleText: `
1) 恢复整个bucket的处于删除状态的objects为最近的多版本状态
ossutil revert-versioning oss://bucket -r
2) 恢复单个处于删除状态的object为最近多版本状态
ossutil revert-versioning oss://bucket/object
3) 恢复处于删除状态的objects为最近的多版本状态, key的后缀满足输入的过滤条件
ossutil revert-versioning oss://bucket/prefix -r --include *.jpg --exclude *.txt
4) 恢复处于删除状态的objects为最近的多版本状态, object的最后删除时间必须在输入范围内
起始时间为北京时间2020/6/16 16:22:58, 结束时间为北京时间2020/6/16 16:39:38
ossutil revert-versioning oss://bucket/prefix -r --start-time 1592295778 --end-time 1592296778
5) 访问者付费模式
ossutil revert-versioning oss://bucket/prefix -r --payer requester
`,
}
var specEnglishRevert = SpecText{
synopsisText: "Revert the deleted object to the latest versioning state",
paramText: "cloud_url [options]",
syntaxText: `
ossutil revert-versioning oss://bucket[/prefix] [--encoding-type encodeType] [-r] [--start-time startTime] [--end-time endTime] [--include include-pattern] [--exclude exclude-pattern] [--payer requester]
`,
detailHelpText: `
This command revert the object from the deleted state to the latest versioning state by deleting the latest delete mark
Usages:
There is only one usage for this command:
1) ossutil revert-versioning oss://bucket[/prefix] [--encoding-type encodeType] [-r] [--start-time startTime] [--end-time endTime] [--include include-pattern] [--exclude exclude-pattern] [--payer requester]
Revert the bucket's objects whose prefix are "prefix" to the versioning state
`,
sampleText: `
1) Revert the bucket's deleted objects to the latest versioning state
ossutil revert-versioning oss://bucket -r
2) Revert a single deleted object to the latest versioning state
ossutil revert-versioning oss://bucket/object
3) Revert deleted objects to the latest versioning state, the key suffix meets the input filter conditions
ossutil revert-versioning oss://bucket/prefix -r --include *.jpg --exclude *.txt
4) Revert deleted objects to the latest versioning state, the last deletion time of objects must be within the input range
The start time is Beijing time 2020/6/16 16:22:58, and the end time is Beijing time 2020/6/16 16:39:38
ossutil revert-versioning oss://bucket/prefix -r --start-time 1592295778 --end-time 1592296778
5) Use requester to pay mode
ossutil revert-versioning oss://bucket/prefix -r --payer requester
`,
}
type revertOptionType struct {
bucketName string
object string
startTime int64
endTime int64
payer string
filters []filterOptionType
options []oss.Option
recursive bool
revertCount int64
}
type RevertCommand struct {
command Command
revertOption revertOptionType
}
var revertCommand = RevertCommand{
command: Command{
name: "revert-versioning",
nameAlias: []string{"revert-versioning"},
minArgc: 1,
maxArgc: 1,
specChinese: specChineseRevert,
specEnglish: specEnglishRevert,
group: GroupTypeNormalCommand,
validOptionNames: []string{
OptionConfigFile,
OptionEndpoint,
OptionAccessKeyID,
OptionAccessKeySecret,
OptionSTSToken,
OptionProxyHost,
OptionProxyUser,
OptionProxyPwd,
OptionLogLevel,
OptionRecursion,
OptionRequestPayer,
OptionStartTime,
OptionEndTime,
OptionInclude,
OptionExclude,
OptionEncodingType,
OptionPassword,
OptionMode,
OptionECSRoleName,
OptionTokenTimeout,
OptionRamRoleArn,
OptionRoleSessionName,
OptionReadTimeout,
OptionConnectTimeout,
OptionSTSRegion,
OptionSkipVerifyCert,
OptionUserAgent,
OptionSignVersion,
OptionRegion,
OptionCloudBoxID,
},
},
}
// function for FormatHelper interface
func (revert *RevertCommand) formatHelpForWhole() string {
return revert.command.formatHelpForWhole()
}
func (revert *RevertCommand) formatIndependHelp() string {
return revert.command.formatIndependHelp()
}
// Init simulate inheritance, and polymorphism
func (revert *RevertCommand) Init(args []string, options OptionMapType) error {
return revert.command.Init(args, options, revert)
}
// RunCommand simulate inheritance, and polymorphism
func (revert *RevertCommand) RunCommand() error {
encodingType, _ := GetString(OptionEncodingType, revert.command.options)
srcBucketUrL, err := GetCloudUrl(revert.command.args[0], encodingType)
if err != nil {
return err
}
revert.revertOption.bucketName = srcBucketUrL.bucket
revert.revertOption.object = srcBucketUrL.object
revert.revertOption.recursive, _ = GetBool(OptionRecursion, revert.command.options)
if !revert.revertOption.recursive && revert.revertOption.object == "" {
return fmt.Errorf("please input object key when option recursive is false")
}
revert.revertOption.startTime, _ = GetInt(OptionStartTime, revert.command.options)
revert.revertOption.endTime, _ = GetInt(OptionEndTime, revert.command.options)
if revert.revertOption.endTime > 0 && revert.revertOption.startTime > revert.revertOption.endTime {
return fmt.Errorf("start time %d is larger than end time %d", revert.revertOption.startTime, revert.revertOption.endTime)
}
revert.revertOption.payer, _ = GetString(OptionRequestPayer, revert.command.options)
if revert.revertOption.payer != "" {
if strings.ToLower(revert.revertOption.payer) != strings.ToLower(string(oss.Requester)) &&
strings.ToLower(revert.revertOption.payer) != strings.ToLower(string(oss.BucketOwner)) {
return fmt.Errorf("option payer value must be %s or %s",
strings.ToLower(string(oss.Requester)), strings.ToLower(string(oss.BucketOwner)))
}
revert.revertOption.options = append(revert.revertOption.options, oss.RequestPayer(oss.PayerType(revert.revertOption.payer)))
}
var res bool
res, revert.revertOption.filters = getFilter(os.Args)
if !res {
return fmt.Errorf("--include or --exclude does not support format containing dir info")
}
bucket, err := revert.command.ossBucket(revert.revertOption.bucketName)
if err != nil {
return err
}
return revert.revertObjects(bucket)
}
func (revert *RevertCommand) revertObjects(bucket *oss.Bucket) error {
pre := oss.Prefix(revert.revertOption.object)
keyMarker := oss.KeyMarker("")
versionIdMarker := oss.VersionIdMarker("")
listOptions := []oss.Option{pre, keyMarker, versionIdMarker, oss.MaxKeys(1000)}
if revert.revertOption.payer != "" {
listOptions = append(listOptions, oss.RequestPayer(oss.PayerType(revert.revertOption.payer)))
}
bStopped := false
batchCount := 0
for {
if bStopped {
break
}
batchCount++
lor, err := bucket.ListObjectVersions(listOptions...)
if err != nil {
return err
}
var objectVersions []oss.DeleteObject
for _, deleteMarker := range lor.ObjectDeleteMarkers {
if !revert.revertOption.recursive && deleteMarker.Key != revert.revertOption.object {
bStopped = true
break
}
if deleteMarker.IsLatest && revert.filterDeleteMarker(&deleteMarker) {
objectVersions = append(objectVersions, oss.DeleteObject{
Key: deleteMarker.Key,
VersionId: deleteMarker.VersionId,
})
}
}
if len(objectVersions) > 0 {
deleteOptions := append(revert.revertOption.options, oss.DeleteObjectsQuiet(true))
delRes, err := bucket.DeleteObjectVersions(objectVersions, deleteOptions...)
if err != nil {
return err
}
if len(delRes.DeletedObjectsDetail) > 0 {
fmt.Printf("\n")
for _, object := range delRes.DeletedObjectsDetail {
fmt.Printf("delete deleteMarker failure, key:%s,version:%s\n", object.Key, object.VersionId)
}
return fmt.Errorf("delete deleteMarker failure")
}
revert.revertOption.revertCount += int64(len(objectVersions))
for _, object := range objectVersions {
LogInfo("revert %s %s\n", object.Key, object.VersionId)
}
}
keyMarker = oss.KeyMarker(lor.NextKeyMarker)
versionIdMarker := oss.VersionIdMarker(lor.NextVersionIdMarker)
listOptions = []oss.Option{pre, keyMarker, versionIdMarker, oss.MaxKeys(1000)}
if revert.revertOption.payer != "" {
listOptions = append(listOptions, oss.RequestPayer(oss.PayerType(revert.revertOption.payer)))
}
fmt.Printf("\rrevert versioning object count is %d, batch list count is %d", revert.revertOption.revertCount, batchCount)
if !lor.IsTruncated {
break
}
}
fmt.Printf("\n")
return nil
}
func (revert *RevertCommand) filterDeleteMarker(deleteMarker *oss.ObjectDeleteMarkerProperties) bool {
if !doesSingleObjectMatchPatterns(deleteMarker.Key, revert.revertOption.filters) {
return false
}
if (revert.revertOption.startTime > 0 && deleteMarker.LastModified.Unix() < revert.revertOption.startTime) ||
(revert.revertOption.endTime > 0 && deleteMarker.LastModified.Unix() > revert.revertOption.endTime) {
return false
}
return true
}