Skip to content

Commit 6b329ce

Browse files
authored
rb: Fix side wide removal of an alias (#3796)
* rb: Fix side wide removal of an alias rb --force --dangerous should remove all buckets under an alias. This PR fixes a recent regression.
1 parent 44a597a commit 6b329ce

File tree

5 files changed

+137
-13
lines changed

5 files changed

+137
-13
lines changed

.github/workflows/go.yml

+5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ jobs:
3838
- name: Build on ${{ matrix.os }}
3939
if: matrix.os == 'ubuntu-latest'
4040
run: |
41+
wget https://dl.min.io/server/minio/release/linux-amd64/minio && chmod +x minio
42+
mkdir -p ~/.minio/certs/ && cp testdata/localhost.crt ~/.minio/certs/public.crt && cp testdata/localhost.key ~/.minio/certs/private.key
43+
sudo cp testdata/localhost.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates
44+
./minio server /tmp/test-xl/{1...4}/ & sleep 10
45+
export SERVER_ENDPOINT=localhost:9000 ACCESS_KEY=minioadmin SECRET_KEY=minioadmin ENABLE_HTTPS=1
4146
make
4247
make test-race
4348
make verify

cmd/rb-main.go

+52-13
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ package cmd
2020
import (
2121
"context"
2222
"fmt"
23+
"path"
2324
"path/filepath"
2425
"strings"
25-
"time"
2626

2727
"github.com/fatih/color"
2828
"github.com/minio/cli"
@@ -107,7 +107,7 @@ func checkRbSyntax(ctx context.Context, cliCtx *cli.Context) {
107107
isDangerous := cliCtx.Bool("dangerous")
108108

109109
for _, url := range cliCtx.Args() {
110-
if isNamespaceRemoval(ctx, url) {
110+
if isS3NamespaceRemoval(ctx, url) {
111111
if isForce && isDangerous {
112112
continue
113113
}
@@ -117,6 +117,40 @@ func checkRbSyntax(ctx context.Context, cliCtx *cli.Context) {
117117
}
118118
}
119119

120+
// Return a list of aliased urls of buckets under the passed url
121+
func listBucketsURLs(ctx context.Context, url string) ([]string, *probe.Error) {
122+
var buckets []string
123+
124+
targetAlias, targetURL, _ := mustExpandAlias(url)
125+
clnt, err := newClientFromAlias(targetAlias, targetURL)
126+
if err != nil {
127+
return nil, err
128+
}
129+
130+
opts := ListOptions{
131+
ShowDir: DirLast,
132+
}
133+
134+
for content := range clnt.List(ctx, opts) {
135+
if content.Err != nil {
136+
errorIf(content.Err, "")
137+
continue
138+
}
139+
140+
select {
141+
case <-ctx.Done():
142+
return nil, probe.NewError(ctx.Err())
143+
default:
144+
}
145+
146+
bucketName := strings.TrimPrefix(content.URL.Path, clnt.GetURL().Path)
147+
bucketPath := path.Join(url, bucketName)
148+
buckets = append(buckets, bucketPath)
149+
}
150+
151+
return buckets, nil
152+
}
153+
120154
// Delete a bucket and all its objects and versions will be removed as well.
121155
func deleteBucket(ctx context.Context, url string, isForce bool) *probe.Error {
122156
targetAlias, targetURL, _ := mustExpandAlias(url)
@@ -179,18 +213,15 @@ func deleteBucket(ctx context.Context, url string, isForce bool) *probe.Error {
179213
return err
180214
}
181215

182-
// isNamespaceRemoval returns true if alias
216+
// isS3NamespaceRemoval returns true if alias
183217
// is not qualified by bucket
184-
func isNamespaceRemoval(ctx context.Context, url string) bool {
218+
func isS3NamespaceRemoval(ctx context.Context, url string) bool {
185219
// clean path for aliases like s3/.
186220
//Note: UNC path using / works properly in go 1.9.2 even though it breaks the UNC specification.
187221
url = filepath.ToSlash(filepath.Clean(url))
188222
// namespace removal applies only for non FS. So filter out if passed url represents a directory
189-
if !isAliasURLDir(ctx, url, nil, time.Time{}) {
190-
_, path := url2Alias(url)
191-
return (path == "")
192-
}
193-
return false
223+
_, path := url2Alias(url)
224+
return (path == "")
194225
}
195226

196227
// mainRemoveBucket is entry point for rb command.
@@ -250,12 +281,20 @@ func mainRemoveBucket(cliCtx *cli.Context) error {
250281
fatalIf(errDummy().Trace(), "`"+targetURL+"` is not empty. Retry this command with ‘--force’ flag if you want to remove `"+targetURL+"` and all its contents")
251282
}
252283

253-
e := deleteBucket(ctx, targetURL, isForce)
254-
fatalIf(e.Trace(targetURL), "Failed to remove `"+targetURL+"`.")
284+
var bucketsURL []string
285+
if isS3NamespaceRemoval(ctx, targetURL) {
286+
bucketsURL, err = listBucketsURLs(ctx, targetURL)
287+
fatalIf(err.Trace(targetURL), "Failed to remove `"+targetURL+"`.")
288+
} else {
289+
bucketsURL = []string{targetURL}
290+
}
291+
292+
for _, bucketURL := range bucketsURL {
293+
e := deleteBucket(ctx, bucketURL, isForce)
294+
fatalIf(e.Trace(bucketURL), "Failed to remove `"+bucketURL+"`.")
255295

256-
if !isNamespaceRemoval(ctx, targetURL) {
257296
printMsg(removeBucketMessage{
258-
Bucket: targetURL, Status: "success",
297+
Bucket: bucketURL, Status: "success",
259298
})
260299
}
261300
}

functional-tests.sh

+31
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,36 @@ function test_make_bucket_error() {
255255
log_success "$start_time" "${FUNCNAME[0]}"
256256
}
257257

258+
function test_rb()
259+
{
260+
show "${FUNCNAME[0]}"
261+
262+
start_time=$(get_time)
263+
bucket1="mc-test-bucket-$RANDOM-1"
264+
bucket2="mc-test-bucket-$RANDOM-2"
265+
object_name="mc-test-object-$RANDOM"
266+
267+
# Tets rb when the bucket is empty
268+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
269+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket1}"
270+
271+
# Test rb with --force flag when the bucket is not empty
272+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
273+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket1}/${object_name}"
274+
assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket1}"
275+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket1}"
276+
277+
# Test rb with --force and --dangerous to remove a site content
278+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
279+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket2}"
280+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket1}/${object_name}"
281+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket2}/${object_name}"
282+
assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/"
283+
assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force --dangerous "${SERVER_ALIAS}"
284+
285+
log_success "$start_time" "${FUNCNAME[0]}"
286+
}
287+
258288
function setup()
259289
{
260290
start_time=$(get_time)
@@ -889,6 +919,7 @@ function run_test()
889919
{
890920
test_make_bucket
891921
test_make_bucket_error
922+
test_rb
892923

893924
setup
894925
test_put_object

testdata/localhost.crt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDojCCAoqgAwIBAgIUHE3HUt7gKVBp7wT9Hjj4wRT1xywwDQYJKoZIhvcNAQEL
3+
BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRgwFgYDVQQHDA9jdXN0b20t
4+
bG9jYXRpb24xHDAaBgNVBAoME2N1c3RvbS1vcmdhbml6YXRpb24xEjAQBgNVBAsM
5+
CWN1c3RvbS1vdTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDkyMDEyMTAyOFoY
6+
DzIxMjEwODI3MTIxMDI4WjB6MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExGDAW
7+
BgNVBAcMD2N1c3RvbS1sb2NhdGlvbjEcMBoGA1UECgwTY3VzdG9tLW9yZ2FuaXph
8+
dGlvbjESMBAGA1UECwwJY3VzdG9tLW91MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi
9+
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6mSJV5oz171+P/G1X07Y4HpTS
10+
ZR/TC5lHAYh2YxecOvuuQHBYCgjXbSBmRQXuPRZIy8mXAa6miwssGgSlMKaH6ZV/
11+
s82ViCSf4Tj1W9on1DvD8bNgCVs0aYA2DmbOyeSyQyyH35TLIaZ2C9fURArixDce
12+
rsUjLMv/GbrL2o2Ia+x4vBSEqUEXlfs7nA1jbm0fYoKlcxjnvDmkIYBCdMqNveHD
13+
DLXzCuXKq4aMLlM+1s8h5ShVAhxpCzY3xncfOvAGA1JWVjEsMUd8PQ4+K88JKVIG
14+
H3HZmL0exjNF4Ks7ocINqQJk7RY0ZUJc10JnCgdkY5bnHuGKzj4Ddq3Ta5FrAgMB
15+
AAGjHjAcMBoGA1UdEQQTMBGHBH8AAAGCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsF
16+
AAOCAQEAREoEGX34C0+osOgCPwZ4mFXVvssJRJTc4JL/kqOGPyzS/085MzeIpOhu
17+
gkOm3zj175SKiZMWWpYhB+Q/1T6tDiVLidEY7HK/dcbjYfoTAd42cQWY4qmG68vG
18+
E6WnTQjal0uPuCwKqvqIRgkWLpaIV4TmHtpCFLLlVlnDWQBpAdiK/Vk0EeTDDaqd
19+
cROr4tm/8EBxqwUnIQF8vgbXgVT5BNdcp44LWs7A558CCRrCGifch5+kxkSSdAFG
20+
Y7BEXvnnsxU1n9AAVKJYnp1wUN2Hk4KWyPcQb9/Ee45DKDR5KNyMqClsWWXMJr40
21+
FrgI6euT50Wzo8Qqbls5Bt/0IzObnA==
22+
-----END CERTIFICATE-----

testdata/localhost.key

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpAIBAAKCAQEAupkiVeaM9e9fj/xtV9O2OB6U0mUf0wuZRwGIdmMXnDr7rkBw
3+
WAoI120gZkUF7j0WSMvJlwGuposLLBoEpTCmh+mVf7PNlYgkn+E49VvaJ9Q7w/Gz
4+
YAlbNGmANg5mzsnkskMsh9+UyyGmdgvX1EQK4sQ3Hq7FIyzL/xm6y9qNiGvseLwU
5+
hKlBF5X7O5wNY25tH2KCpXMY57w5pCGAQnTKjb3hwwy18wrlyquGjC5TPtbPIeUo
6+
VQIcaQs2N8Z3HzrwBgNSVlYxLDFHfD0OPivPCSlSBh9x2Zi9HsYzReCrO6HCDakC
7+
ZO0WNGVCXNdCZwoHZGOW5x7his4+A3at02uRawIDAQABAoIBAElz2mZCGR7+mXmO
8+
fmRiPIqezyp7ECn9mNqwqc0geLzRIx2W1CJz4MMce/KGHS2I8mq5faNp0BxTA5Ta
9+
sRVtr0A1HNpmJvlD3FbrS4aaH6gqDVS2okudoz9ggE3HIYUpSFM7yh26T1Ie7u3s
10+
/4rZNgfKAYCcf5G3Ip5KvJNedvRKC2w5UX4iYU5eMuXs0YPy2+DtTKxZKIEnI3x4
11+
VpMe652I7GhjkLSsyuW5NoDeSWmmqhitm1bibuZQBR0ogFyAU94rZk8+j4hiUl9k
12+
7ZVi00tKNp7EcLIwbY02ZCpZ2xvat8W1SLeWRUpExPj/7nnA9Fafrl5M8aHgl8R1
13+
N0Fd+zECgYEA4GruRDPPNPEXPByes6jjcxfvdoYIDyma1V+FN5Nn+/QPL/vWp9t0
14+
+mH344iwWkEyZZHNUpNuy5dpOA9724iFFLp9Btq06OgzzDuJj1LDbDpB4zwltuQA
15+
4s7ekTFi9rHDOeAyTREHgDu3uya/2qq53Ms6w8gXM4/kmp9/S4N5VhcCgYEA1Nuv
16+
J1khBitNiNbzHYG9DRV4HLfIB8FFDKtgnW8HvSaWUtHKI4YitwJVFfa5Epz9MDFy
17+
tkFAD9Bu0HqZQ6OQZxGo0rDUcFics9Ftw+w3p/PIocPQBK7PNQ3L9BQS9M3stL+k
18+
fW5r+kUvfZaJVE8agCQQnzkJJh9oexJjMWyxB80CgYBa5BQSPWWLjKWba//+xcUx
19+
BR2wREKZWYFjL+e1hZcU3VkVVwsuOtza17jdR6wdMdCmgHHHIv05qd4snWDNnjJA
20+
HfOrRgMFXZ409lwVVzDc8Y9j6CViOF//fEd6SKVLQt3N3/afbek6z3TvcJc9ie3y
21+
9cCcMLrs4Dd3RGf6/omzCwKBgQChwWxCf6Xr9T5PjeFke/I5niYP1M2KryGU9itO
22+
mFCOOmOj/k8ZXdbFsl0Meti7v1dcp0cgH0fafK+peHE+CG81FCNyMPTPh1dWAwHi
23+
EIFe/ZBq9c3/sQQ/sgNasWKSbGbEGJqcwywFHUxwqNQloJNn64BCL2q3cMjKNffx
24+
WELTxQKBgQDe7adrUBtk8+YZ1/c2VsV1oBq6eI2U+1bWa/8fwXWd9ylETBMtcv20
25+
Fs8UAFWLz78aWaXWWSSEmFvUbjXPBDvzXCObb6HdhXOCF1n74hKU+z06MAUa1eFC
26+
V0GvBx4v1rc1pZ7grBZwGteeVWVgCAZ487m5TATWqxuarH6yfU0Ptg==
27+
-----END RSA PRIVATE KEY-----

0 commit comments

Comments
 (0)