diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 8f08dea1a..62803c723 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -3,10 +3,10 @@ name: Go
on:
pull_request:
branches:
- - master
+ - master
push:
branches:
- - master
+ - master
jobs:
build:
@@ -14,7 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- go-version: [1.13.x, 1.14.x]
+ go-version: [1.14.x]
os: [ubuntu-latest]
steps:
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
diff --git a/cmd/console/main.go b/cmd/console/main.go
index 7e4a44bb7..b47f0c5ba 100644
--- a/cmd/console/main.go
+++ b/cmd/console/main.go
@@ -76,21 +76,19 @@ func newApp(name string) *cli.App {
findClosestCommands := func(command string) []string {
var closestCommands []string
- for _, value := range commandsTree.PrefixMatch(command) {
- closestCommands = append(closestCommands, value.(string))
- }
+ closestCommands = append(closestCommands, commandsTree.PrefixMatch(command)...)
sort.Strings(closestCommands)
// Suggest other close commands - allow missed, wrongly added and
// even transposed characters
for _, value := range commandsTree.Walk(commandsTree.Root()) {
- if sort.SearchStrings(closestCommands, value.(string)) < len(closestCommands) {
+ if sort.SearchStrings(closestCommands, value) < len(closestCommands) {
continue
}
// 2 is arbitrary and represents the max
// allowed number of typed errors
- if words.DamerauLevenshteinDistance(command, value.(string)) < 2 {
- closestCommands = append(closestCommands, value.(string))
+ if words.DamerauLevenshteinDistance(command, value) < 2 {
+ closestCommands = append(closestCommands, value)
}
}
diff --git a/go.mod b/go.mod
index e786d11df..d30ac91fb 100644
--- a/go.mod
+++ b/go.mod
@@ -16,16 +16,16 @@ require (
github.com/jessevdk/go-flags v1.4.0
github.com/minio/cli v1.22.0
github.com/minio/kes v0.11.0
- github.com/minio/mc v0.0.0-20200901021141-b55e3e2d2987
- github.com/minio/minio v0.0.0-20200901011052-18725679c4f5
- github.com/minio/minio-go/v7 v7.0.6-0.20200901014009-5f8d15bbc5fd
+ github.com/minio/mc v0.0.0-20201001165056-7f2df96e4821
+ github.com/minio/minio v0.0.0-20200927172404-27d9bd04e544
+ github.com/minio/minio-go/v7 v7.0.6-0.20200923173112-bc846cb9b089
github.com/minio/operator v0.0.0-20200923155125-e7077234373b
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/secure-io/sio-go v0.3.1
github.com/stretchr/testify v1.6.1
github.com/unrolled/secure v1.0.7
- golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
- golang.org/x/net v0.0.0-20200707034311-ab3426394381
+ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
+ golang.org/x/net v0.0.0-20200904194848-62affa334b73
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gopkg.in/yaml.v2 v2.3.0
k8s.io/api v0.18.6
diff --git a/go.sum b/go.sum
index 9c527581d..77e391201 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,7 @@ cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0 h1:EpMNVUorLiZIELdMZbCYX/ByTFCdoYopYAGxaGVz9ms=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
@@ -30,6 +31,7 @@ cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjp
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0 h1:86K1Gel7BQ9/WmNWn7dTKMvTLFzwtBe5FNqYbi9X35g=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
code.gitea.io/sdk/gitea v0.12.0/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
@@ -43,6 +45,7 @@ git.apache.org/thrift.git v0.13.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqbl
github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU=
github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
+github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -52,6 +55,7 @@ github.com/Azure/azure-sdk-for-go v42.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
github.com/Azure/azure-storage-blob-go v0.8.0 h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFEY95rZLK0Tj6o=
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
+github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs=
github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
@@ -172,6 +176,7 @@ github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMS
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -523,9 +528,11 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
+github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI=
@@ -590,6 +597,7 @@ github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es
github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
@@ -716,6 +724,8 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
+github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -774,21 +784,20 @@ github.com/minio/highwayhash v1.0.0 h1:iMSDhgUILCr0TNm8LWlSjF8N0ZIj2qbO8WHp6Q/J2
github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc=
github.com/minio/kes v0.11.0 h1:8ma6OCVSxKT50b1uYXLJro3m7PmZtCLxBaTddQexI5k=
github.com/minio/kes v0.11.0/go.mod h1:mTF1Bv8YVEtQqF/B7Felp4tLee44Pp+dgI0rhCvgNg8=
-github.com/minio/mc v0.0.0-20200901021141-b55e3e2d2987 h1:yjZPpkMCZtUOVvkBhFLVa4AiQLYt/OfqQRHMjoqXt78=
-github.com/minio/mc v0.0.0-20200901021141-b55e3e2d2987/go.mod h1:6P0FmQWPEojL4MxIyhR5GYsvoS3cZlaOkRk0apZRr3E=
+github.com/minio/mc v0.0.0-20201001165056-7f2df96e4821 h1:+09Ta2rY29df6U4bfSC85t7jxlNuYpUfl7lIVgTiDEA=
+github.com/minio/mc v0.0.0-20201001165056-7f2df96e4821/go.mod h1:+OeGPfw7qpvO1x2Td65ejwAuFT0Cxzx0GFTJSDlPMZQ=
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio v0.0.0-20200723003940-b9be841fd222 h1:+XFGpEsqmA033nDX8LtjyPZy01Shivf6E2OL67WoGiE=
github.com/minio/minio v0.0.0-20200723003940-b9be841fd222/go.mod h1:Eu2KC2p+vW03rnYY/6R/D+QduPB7/j4kBaVA/EDLjWM=
-github.com/minio/minio v0.0.0-20200828210429-cd380251b39d/go.mod h1:RzAkUqX8ePyRXOSJmNzZvN+ArXRlszOu3tDKsa51Qos=
-github.com/minio/minio v0.0.0-20200901011052-18725679c4f5 h1:TIjV3HutcC/xeaJ7ToAwtp++E2XofA7Hs6h7Bzy3bVo=
-github.com/minio/minio v0.0.0-20200901011052-18725679c4f5/go.mod h1:53zYS6513LiG8+Co+leghfWiCj+k7kIiax32U/QXCyU=
+github.com/minio/minio v0.0.0-20200927172404-27d9bd04e544 h1:G6M9uXdFShowoLG3rMkdCtHsx37ZYB1vc+7bu22r85I=
+github.com/minio/minio v0.0.0-20200927172404-27d9bd04e544/go.mod h1:5uolst3SWpgvDNF+KJwfViU+j9WH7dB5i2YCi0nMNVo=
github.com/minio/minio-go/v7 v7.0.1/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns=
github.com/minio/minio-go/v7 v7.0.2 h1:P/7wFd4KrRBHVo7AKdcqO+9ReoS+XpMjfRFoE5quH0E=
github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns=
github.com/minio/minio-go/v7 v7.0.5-0.20200811211821-14ed05478889/go.mod h1:CSt2ETZNs+bIIhWTse0mcZKZWMGrFU7Er7RR0TmkDYk=
-github.com/minio/minio-go/v7 v7.0.6-0.20200901014009-5f8d15bbc5fd h1:38hrGmWnv+C+yBcKgAWipiwRDu7Exr0kKAfy1QArW0g=
-github.com/minio/minio-go/v7 v7.0.6-0.20200901014009-5f8d15bbc5fd/go.mod h1:CSt2ETZNs+bIIhWTse0mcZKZWMGrFU7Er7RR0TmkDYk=
+github.com/minio/minio-go/v7 v7.0.6-0.20200923173112-bc846cb9b089 h1:9DDs/Gc3fNHOQxQmwIFWs7YDLMTBh59r2XQ6RqEUA1I=
+github.com/minio/minio-go/v7 v7.0.6-0.20200923173112-bc846cb9b089/go.mod h1:CSt2ETZNs+bIIhWTse0mcZKZWMGrFU7Er7RR0TmkDYk=
github.com/minio/operator v0.0.0-20200923155125-e7077234373b h1:k9u35u4vUi9Lxl/CDYyLU/OVN5M1CG8HQsOC8XTJHxc=
github.com/minio/operator v0.0.0-20200923155125-e7077234373b/go.mod h1:6lavbNo2YuJWeQR5bZYsEWdbpRCO2KrTyfQ0PtC/AN4=
github.com/minio/selfupdate v0.3.1 h1:BWEFSNnrZVMUWXbXIgLDNDjbejkmpAmZvy/nCz1HlEs=
@@ -797,6 +806,7 @@ github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKU
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/simdjson-go v0.1.5-0.20200303142138-b17fe061ea37 h1:pDeao6M5AEd8hwTtGmE0pVKomlL56JFRa5SiXDZAuJE=
github.com/minio/simdjson-go v0.1.5-0.20200303142138-b17fe061ea37/go.mod h1:oKURrZZEBtqObgJrSjN1Ln2n9MJj2icuBTkeJzZnvSI=
+github.com/minio/simdjson-go v0.1.5 h1:6T5mHh7r3kUvgwhmFWQAjoPV5Yt5oD/VPjAI9ViH1kM=
github.com/minio/simdjson-go v0.1.5/go.mod h1:oKURrZZEBtqObgJrSjN1Ln2n9MJj2icuBTkeJzZnvSI=
github.com/minio/sio v0.2.0 h1:NCRCFLx0r5pRbXf65LVNjxbCGZgNQvNFQkgX3XF4BoA=
github.com/minio/sio v0.2.0/go.mod h1:nKM5GIWSrqbOZp0uhyj6M1iA0X6xQzSGtYSaTKSCut0=
@@ -1072,6 +1082,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
+github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
@@ -1092,6 +1103,7 @@ github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJb
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX8Wdm2/JPA=
github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
@@ -1109,6 +1121,7 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
@@ -1128,6 +1141,7 @@ go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -1172,8 +1186,8 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
-golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
+golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1254,6 +1268,9 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1332,8 +1349,8 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200806125547-5acd03effb82 h1:6cBnXxYO+CiRVrChvCosSv7magqTPbyAgz1M8iOv5wM=
-golang.org/x/sys v0.0.0-20200806125547-5acd03effb82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200915084602-288bc346aa39 h1:356XA7ITklAU2//sYkjFeco+dH1bCRD8XCJ9FIEsvo4=
+golang.org/x/sys v0.0.0-20200915084602-288bc346aa39/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1427,10 +1444,14 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d h1:szSOL78iTCl0LF1AMjhSWJj
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200814172026-c4923e618c08 h1:sfBQLM20fzeXhOixVQirwEbuW4PGStP773EXQpsBB6E=
golang.org/x/tools v0.0.0-20200814172026-c4923e618c08/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200929223013-bf155c11ec6f h1:7+Nz9MyPqt2qMCTvNiRy1G0zYfkB7UCa+ayT6uVvbyI=
+golang.org/x/tools v0.0.0-20200929223013-bf155c11ec6f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
@@ -1451,6 +1472,7 @@ google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA=
google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
diff --git a/restapi/client.go b/restapi/client.go
index 176b152a4..af453a390 100644
--- a/restapi/client.go
+++ b/restapi/client.go
@@ -123,6 +123,8 @@ type MCClient interface {
addNotificationConfig(ctx context.Context, arn string, events []string, prefix, suffix string, ignoreExisting bool) *probe.Error
removeNotificationConfig(ctx context.Context, arn string, event string, prefix string, suffix string) *probe.Error
watch(ctx context.Context, options mc.WatchOptions) (*mc.WatchObject, *probe.Error)
+ remove(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error
+ list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
}
// Interface implementation
@@ -151,6 +153,14 @@ func (c mcClient) setReplication(ctx context.Context, cfg *replication.Config, o
return c.client.SetReplication(ctx, cfg, opts)
}
+func (c mcClient) remove(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error {
+ return c.client.Remove(ctx, isIncomplete, isRemoveBucket, isBypass, contentCh)
+}
+
+func (c mcClient) list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
+ return c.client.List(ctx, opts)
+}
+
// ConsoleCredentials interface with all functions to be implemented
// by mock when testing, it should include all needed consoleCredentials.Login api calls
// that are used within this project.
@@ -274,7 +284,7 @@ func newMinioClient(claims *models.Principal) (*minio.Client, error) {
}
// newS3BucketClient creates a new mc S3Client to talk to the server based on a bucket
-func newS3BucketClient(claims *models.Principal, bucketName string) (*mc.S3Client, error) {
+func newS3BucketClient(claims *models.Principal, bucketName string, prefix string) (*mc.S3Client, error) {
endpoint := getMinIOServer()
useTLS := getMinIOEndpointIsSecure()
@@ -282,6 +292,10 @@ func newS3BucketClient(claims *models.Principal, bucketName string) (*mc.S3Clien
endpoint += fmt.Sprintf("/%s", bucketName)
}
+ if strings.TrimSpace(prefix) != "" {
+ endpoint += fmt.Sprintf("/%s", prefix)
+ }
+
if claims == nil {
return nil, fmt.Errorf("the provided credentials are invalid")
}
diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go
index 957ba14da..123f263f3 100644
--- a/restapi/embedded_spec.go
+++ b/restapi/embedded_spec.go
@@ -380,6 +380,48 @@ func init() {
}
}
}
+ },
+ "delete": {
+ "tags": [
+ "UserAPI"
+ ],
+ "summary": "Delete Object",
+ "operationId": "DeleteObject",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "bucket_name",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "name": "path",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "string",
+ "name": "version_id",
+ "in": "query"
+ },
+ {
+ "type": "boolean",
+ "name": "recursive",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "A successful response."
+ },
+ "default": {
+ "description": "Generic error response.",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
}
},
"/buckets/{bucket_name}/replication": {
@@ -4620,6 +4662,48 @@ func init() {
}
}
}
+ },
+ "delete": {
+ "tags": [
+ "UserAPI"
+ ],
+ "summary": "Delete Object",
+ "operationId": "DeleteObject",
+ "parameters": [
+ {
+ "type": "string",
+ "name": "bucket_name",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "name": "path",
+ "in": "query",
+ "required": true
+ },
+ {
+ "type": "string",
+ "name": "version_id",
+ "in": "query"
+ },
+ {
+ "type": "boolean",
+ "name": "recursive",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "A successful response."
+ },
+ "default": {
+ "description": "Generic error response.",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
}
},
"/buckets/{bucket_name}/replication": {
diff --git a/restapi/operations/console_api.go b/restapi/operations/console_api.go
index 43967c93a..92a035807 100644
--- a/restapi/operations/console_api.go
+++ b/restapi/operations/console_api.go
@@ -114,6 +114,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
UserAPIDeleteBucketEventHandler: user_api.DeleteBucketEventHandlerFunc(func(params user_api.DeleteBucketEventParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.DeleteBucketEvent has not yet been implemented")
}),
+ UserAPIDeleteObjectHandler: user_api.DeleteObjectHandlerFunc(func(params user_api.DeleteObjectParams, principal *models.Principal) middleware.Responder {
+ return middleware.NotImplemented("operation user_api.DeleteObject has not yet been implemented")
+ }),
UserAPIDeleteRemoteBucketHandler: user_api.DeleteRemoteBucketHandlerFunc(func(params user_api.DeleteRemoteBucketParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.DeleteRemoteBucket has not yet been implemented")
}),
@@ -347,6 +350,8 @@ type ConsoleAPI struct {
UserAPIDeleteBucketHandler user_api.DeleteBucketHandler
// UserAPIDeleteBucketEventHandler sets the operation handler for the delete bucket event operation
UserAPIDeleteBucketEventHandler user_api.DeleteBucketEventHandler
+ // UserAPIDeleteObjectHandler sets the operation handler for the delete object operation
+ UserAPIDeleteObjectHandler user_api.DeleteObjectHandler
// UserAPIDeleteRemoteBucketHandler sets the operation handler for the delete remote bucket operation
UserAPIDeleteRemoteBucketHandler user_api.DeleteRemoteBucketHandler
// UserAPIDeleteServiceAccountHandler sets the operation handler for the delete service account operation
@@ -571,6 +576,9 @@ func (o *ConsoleAPI) Validate() error {
if o.UserAPIDeleteBucketEventHandler == nil {
unregistered = append(unregistered, "user_api.DeleteBucketEventHandler")
}
+ if o.UserAPIDeleteObjectHandler == nil {
+ unregistered = append(unregistered, "user_api.DeleteObjectHandler")
+ }
if o.UserAPIDeleteRemoteBucketHandler == nil {
unregistered = append(unregistered, "user_api.DeleteRemoteBucketHandler")
}
@@ -892,6 +900,10 @@ func (o *ConsoleAPI) initHandlerCache() {
if o.handlers["DELETE"] == nil {
o.handlers["DELETE"] = make(map[string]http.Handler)
}
+ o.handlers["DELETE"]["/buckets/{bucket_name}/objects"] = user_api.NewDeleteObject(o.context, o.UserAPIDeleteObjectHandler)
+ if o.handlers["DELETE"] == nil {
+ o.handlers["DELETE"] = make(map[string]http.Handler)
+ }
o.handlers["DELETE"]["/remote-buckets/{source-bucket-name}/{arn}"] = user_api.NewDeleteRemoteBucket(o.context, o.UserAPIDeleteRemoteBucketHandler)
if o.handlers["DELETE"] == nil {
o.handlers["DELETE"] = make(map[string]http.Handler)
diff --git a/restapi/operations/user_api/delete_object.go b/restapi/operations/user_api/delete_object.go
new file mode 100644
index 000000000..0b0460a8f
--- /dev/null
+++ b/restapi/operations/user_api/delete_object.go
@@ -0,0 +1,90 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package user_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime/middleware"
+
+ "github.com/minio/console/models"
+)
+
+// DeleteObjectHandlerFunc turns a function with the right signature into a delete object handler
+type DeleteObjectHandlerFunc func(DeleteObjectParams, *models.Principal) middleware.Responder
+
+// Handle executing the request and returning a response
+func (fn DeleteObjectHandlerFunc) Handle(params DeleteObjectParams, principal *models.Principal) middleware.Responder {
+ return fn(params, principal)
+}
+
+// DeleteObjectHandler interface for that can handle valid delete object params
+type DeleteObjectHandler interface {
+ Handle(DeleteObjectParams, *models.Principal) middleware.Responder
+}
+
+// NewDeleteObject creates a new http.Handler for the delete object operation
+func NewDeleteObject(ctx *middleware.Context, handler DeleteObjectHandler) *DeleteObject {
+ return &DeleteObject{Context: ctx, Handler: handler}
+}
+
+/*DeleteObject swagger:route DELETE /buckets/{bucket_name}/objects UserAPI deleteObject
+
+Delete Object
+
+*/
+type DeleteObject struct {
+ Context *middleware.Context
+ Handler DeleteObjectHandler
+}
+
+func (o *DeleteObject) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ route, rCtx, _ := o.Context.RouteInfo(r)
+ if rCtx != nil {
+ r = rCtx
+ }
+ var Params = NewDeleteObjectParams()
+
+ uprinc, aCtx, err := o.Context.Authorize(r, route)
+ if err != nil {
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+ if aCtx != nil {
+ r = aCtx
+ }
+ var principal *models.Principal
+ if uprinc != nil {
+ principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
+ }
+
+ if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+
+ res := o.Handler.Handle(Params, principal) // actually handle the request
+
+ o.Context.Respond(rw, r, route.Produces, route, res)
+
+}
diff --git a/restapi/operations/user_api/delete_object_parameters.go b/restapi/operations/user_api/delete_object_parameters.go
new file mode 100644
index 000000000..85e86aee1
--- /dev/null
+++ b/restapi/operations/user_api/delete_object_parameters.go
@@ -0,0 +1,183 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package user_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/runtime/middleware"
+ "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag"
+ "github.com/go-openapi/validate"
+)
+
+// NewDeleteObjectParams creates a new DeleteObjectParams object
+// no default values defined in spec.
+func NewDeleteObjectParams() DeleteObjectParams {
+
+ return DeleteObjectParams{}
+}
+
+// DeleteObjectParams contains all the bound params for the delete object operation
+// typically these are obtained from a http.Request
+//
+// swagger:parameters DeleteObject
+type DeleteObjectParams struct {
+
+ // HTTP Request Object
+ HTTPRequest *http.Request `json:"-"`
+
+ /*
+ Required: true
+ In: path
+ */
+ BucketName string
+ /*
+ Required: true
+ In: query
+ */
+ Path string
+ /*
+ In: query
+ */
+ Recursive *bool
+ /*
+ In: query
+ */
+ VersionID *string
+}
+
+// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
+// for simple values it will use straight method calls.
+//
+// To ensure default values, the struct must have been initialized with NewDeleteObjectParams() beforehand.
+func (o *DeleteObjectParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
+ var res []error
+
+ o.HTTPRequest = r
+
+ qs := runtime.Values(r.URL.Query())
+
+ rBucketName, rhkBucketName, _ := route.Params.GetOK("bucket_name")
+ if err := o.bindBucketName(rBucketName, rhkBucketName, route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ qPath, qhkPath, _ := qs.GetOK("path")
+ if err := o.bindPath(qPath, qhkPath, route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ qRecursive, qhkRecursive, _ := qs.GetOK("recursive")
+ if err := o.bindRecursive(qRecursive, qhkRecursive, route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ qVersionID, qhkVersionID, _ := qs.GetOK("version_id")
+ if err := o.bindVersionID(qVersionID, qhkVersionID, route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
+
+// bindBucketName binds and validates parameter BucketName from path.
+func (o *DeleteObjectParams) bindBucketName(rawData []string, hasKey bool, formats strfmt.Registry) error {
+ var raw string
+ if len(rawData) > 0 {
+ raw = rawData[len(rawData)-1]
+ }
+
+ // Required: true
+ // Parameter is provided by construction from the route
+
+ o.BucketName = raw
+
+ return nil
+}
+
+// bindPath binds and validates parameter Path from query.
+func (o *DeleteObjectParams) bindPath(rawData []string, hasKey bool, formats strfmt.Registry) error {
+ if !hasKey {
+ return errors.Required("path", "query", rawData)
+ }
+ var raw string
+ if len(rawData) > 0 {
+ raw = rawData[len(rawData)-1]
+ }
+
+ // Required: true
+ // AllowEmptyValue: false
+ if err := validate.RequiredString("path", "query", raw); err != nil {
+ return err
+ }
+
+ o.Path = raw
+
+ return nil
+}
+
+// bindRecursive binds and validates parameter Recursive from query.
+func (o *DeleteObjectParams) bindRecursive(rawData []string, hasKey bool, formats strfmt.Registry) error {
+ var raw string
+ if len(rawData) > 0 {
+ raw = rawData[len(rawData)-1]
+ }
+
+ // Required: false
+ // AllowEmptyValue: false
+ if raw == "" { // empty values pass all other validations
+ return nil
+ }
+
+ value, err := swag.ConvertBool(raw)
+ if err != nil {
+ return errors.InvalidType("recursive", "query", "bool", raw)
+ }
+ o.Recursive = &value
+
+ return nil
+}
+
+// bindVersionID binds and validates parameter VersionID from query.
+func (o *DeleteObjectParams) bindVersionID(rawData []string, hasKey bool, formats strfmt.Registry) error {
+ var raw string
+ if len(rawData) > 0 {
+ raw = rawData[len(rawData)-1]
+ }
+
+ // Required: false
+ // AllowEmptyValue: false
+ if raw == "" { // empty values pass all other validations
+ return nil
+ }
+
+ o.VersionID = &raw
+
+ return nil
+}
diff --git a/restapi/operations/user_api/delete_object_responses.go b/restapi/operations/user_api/delete_object_responses.go
new file mode 100644
index 000000000..8f94ea48c
--- /dev/null
+++ b/restapi/operations/user_api/delete_object_responses.go
@@ -0,0 +1,113 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package user_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime"
+
+ "github.com/minio/console/models"
+)
+
+// DeleteObjectOKCode is the HTTP code returned for type DeleteObjectOK
+const DeleteObjectOKCode int = 200
+
+/*DeleteObjectOK A successful response.
+
+swagger:response deleteObjectOK
+*/
+type DeleteObjectOK struct {
+}
+
+// NewDeleteObjectOK creates DeleteObjectOK with default headers values
+func NewDeleteObjectOK() *DeleteObjectOK {
+
+ return &DeleteObjectOK{}
+}
+
+// WriteResponse to the client
+func (o *DeleteObjectOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
+
+ rw.WriteHeader(200)
+}
+
+/*DeleteObjectDefault Generic error response.
+
+swagger:response deleteObjectDefault
+*/
+type DeleteObjectDefault struct {
+ _statusCode int
+
+ /*
+ In: Body
+ */
+ Payload *models.Error `json:"body,omitempty"`
+}
+
+// NewDeleteObjectDefault creates DeleteObjectDefault with default headers values
+func NewDeleteObjectDefault(code int) *DeleteObjectDefault {
+ if code <= 0 {
+ code = 500
+ }
+
+ return &DeleteObjectDefault{
+ _statusCode: code,
+ }
+}
+
+// WithStatusCode adds the status to the delete object default response
+func (o *DeleteObjectDefault) WithStatusCode(code int) *DeleteObjectDefault {
+ o._statusCode = code
+ return o
+}
+
+// SetStatusCode sets the status to the delete object default response
+func (o *DeleteObjectDefault) SetStatusCode(code int) {
+ o._statusCode = code
+}
+
+// WithPayload adds the payload to the delete object default response
+func (o *DeleteObjectDefault) WithPayload(payload *models.Error) *DeleteObjectDefault {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the delete object default response
+func (o *DeleteObjectDefault) SetPayload(payload *models.Error) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *DeleteObjectDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(o._statusCode)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
diff --git a/restapi/operations/user_api/delete_object_urlbuilder.go b/restapi/operations/user_api/delete_object_urlbuilder.go
new file mode 100644
index 000000000..b45ed9ba8
--- /dev/null
+++ b/restapi/operations/user_api/delete_object_urlbuilder.go
@@ -0,0 +1,147 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package user_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "errors"
+ "net/url"
+ golangswaggerpaths "path"
+ "strings"
+
+ "github.com/go-openapi/swag"
+)
+
+// DeleteObjectURL generates an URL for the delete object operation
+type DeleteObjectURL struct {
+ BucketName string
+
+ Path string
+ Recursive *bool
+ VersionID *string
+
+ _basePath string
+ // avoid unkeyed usage
+ _ struct{}
+}
+
+// WithBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *DeleteObjectURL) WithBasePath(bp string) *DeleteObjectURL {
+ o.SetBasePath(bp)
+ return o
+}
+
+// SetBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *DeleteObjectURL) SetBasePath(bp string) {
+ o._basePath = bp
+}
+
+// Build a url path and query string
+func (o *DeleteObjectURL) Build() (*url.URL, error) {
+ var _result url.URL
+
+ var _path = "/buckets/{bucket_name}/objects"
+
+ bucketName := o.BucketName
+ if bucketName != "" {
+ _path = strings.Replace(_path, "{bucket_name}", bucketName, -1)
+ } else {
+ return nil, errors.New("bucketName is required on DeleteObjectURL")
+ }
+
+ _basePath := o._basePath
+ if _basePath == "" {
+ _basePath = "/api/v1"
+ }
+ _result.Path = golangswaggerpaths.Join(_basePath, _path)
+
+ qs := make(url.Values)
+
+ pathQ := o.Path
+ if pathQ != "" {
+ qs.Set("path", pathQ)
+ }
+
+ var recursiveQ string
+ if o.Recursive != nil {
+ recursiveQ = swag.FormatBool(*o.Recursive)
+ }
+ if recursiveQ != "" {
+ qs.Set("recursive", recursiveQ)
+ }
+
+ var versionIDQ string
+ if o.VersionID != nil {
+ versionIDQ = *o.VersionID
+ }
+ if versionIDQ != "" {
+ qs.Set("version_id", versionIDQ)
+ }
+
+ _result.RawQuery = qs.Encode()
+
+ return &_result, nil
+}
+
+// Must is a helper function to panic when the url builder returns an error
+func (o *DeleteObjectURL) Must(u *url.URL, err error) *url.URL {
+ if err != nil {
+ panic(err)
+ }
+ if u == nil {
+ panic("url can't be nil")
+ }
+ return u
+}
+
+// String returns the string representation of the path with query string
+func (o *DeleteObjectURL) String() string {
+ return o.Must(o.Build()).String()
+}
+
+// BuildFull builds a full url with scheme, host, path and query string
+func (o *DeleteObjectURL) BuildFull(scheme, host string) (*url.URL, error) {
+ if scheme == "" {
+ return nil, errors.New("scheme is required for a full url on DeleteObjectURL")
+ }
+ if host == "" {
+ return nil, errors.New("host is required for a full url on DeleteObjectURL")
+ }
+
+ base, err := o.Build()
+ if err != nil {
+ return nil, err
+ }
+
+ base.Scheme = scheme
+ base.Host = host
+ return base, nil
+}
+
+// StringFull returns the string representation of a complete url
+func (o *DeleteObjectURL) StringFull(scheme, host string) string {
+ return o.Must(o.BuildFull(scheme, host)).String()
+}
diff --git a/restapi/user_buckets.go b/restapi/user_buckets.go
index 4127cbad7..80a7d8467 100644
--- a/restapi/user_buckets.go
+++ b/restapi/user_buckets.go
@@ -132,7 +132,7 @@ func getAddBucketReplicationdResponse(session *models.Principal, bucketName stri
}
maxPrio++
- s3Client, err := newS3BucketClient(session, bucketName)
+ s3Client, err := newS3BucketClient(session, bucketName, "")
if err != nil {
log.Println("error creating S3Client:", err)
return err
diff --git a/restapi/user_buckets_events.go b/restapi/user_buckets_events.go
index cac6e6240..e6674d797 100644
--- a/restapi/user_buckets_events.go
+++ b/restapi/user_buckets_events.go
@@ -177,7 +177,7 @@ func createBucketEvent(ctx context.Context, client MCClient, arn string, notific
// getCreateBucketEventsResponse calls createBucketEvent to add a bucket event notification
func getCreateBucketEventsResponse(session *models.Principal, bucketName string, eventReq *models.BucketEventRequest) *models.Error {
ctx := context.Background()
- s3Client, err := newS3BucketClient(session, bucketName)
+ s3Client, err := newS3BucketClient(session, bucketName, "")
if err != nil {
return prepareError(err)
}
@@ -212,7 +212,7 @@ func joinNotificationEvents(events []models.NotificationEventType) string {
// getDeleteBucketEventsResponse calls deleteBucketEventNotification() to delete a bucket event notification
func getDeleteBucketEventsResponse(session *models.Principal, bucketName string, arn string, events []models.NotificationEventType, prefix, suffix *string) *models.Error {
ctx := context.Background()
- s3Client, err := newS3BucketClient(session, bucketName)
+ s3Client, err := newS3BucketClient(session, bucketName, "")
if err != nil {
return prepareError(err)
}
diff --git a/restapi/user_objects.go b/restapi/user_objects.go
index 6bbb91144..a0a93ae37 100644
--- a/restapi/user_objects.go
+++ b/restapi/user_objects.go
@@ -18,15 +18,26 @@ package restapi
import (
"context"
+ "fmt"
+ "path/filepath"
+ "regexp"
+ "strings"
"time"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
"github.com/minio/console/restapi/operations"
"github.com/minio/console/restapi/operations/user_api"
+ mc "github.com/minio/mc/cmd"
"github.com/minio/minio-go/v7"
)
+// enum types
+const (
+ objectStorage = iota // MinIO and S3 compatible cloud storage
+ fileSystem // POSIX compatible file systems
+)
+
func registerObjectsHandlers(api *operations.ConsoleAPI) {
// list objects
api.UserAPIListObjectsHandler = user_api.ListObjectsHandlerFunc(func(params user_api.ListObjectsParams, session *models.Principal) middleware.Responder {
@@ -36,24 +47,13 @@ func registerObjectsHandlers(api *operations.ConsoleAPI) {
}
return user_api.NewListObjectsOK().WithPayload(resp)
})
-}
-
-// listBucketObjects gets an array of objects in a bucket
-func listBucketObjects(ctx context.Context, client MinioClient, bucketName string, prefix string, recursive bool) ([]*models.BucketObject, error) {
- var objects []*models.BucketObject
- for lsObj := range client.listObjects(ctx, bucketName, minio.ListObjectsOptions{Prefix: prefix, Recursive: recursive}) {
- if lsObj.Err != nil {
- return nil, lsObj.Err
+ // delete object
+ api.UserAPIDeleteObjectHandler = user_api.DeleteObjectHandlerFunc(func(params user_api.DeleteObjectParams, session *models.Principal) middleware.Responder {
+ if err := getDeleteObjectResponse(session, params); err != nil {
+ return user_api.NewDeleteObjectDefault(int(err.Code)).WithPayload(err)
}
- obj := &models.BucketObject{
- Name: lsObj.Key,
- Size: lsObj.Size,
- LastModified: lsObj.LastModified.String(),
- ContentType: lsObj.ContentType,
- }
- objects = append(objects, obj)
- }
- return objects, nil
+ return user_api.NewDeleteObjectOK()
+ })
}
// getListObjectsResponse returns a list of objects
@@ -91,3 +91,214 @@ func getListObjectsResponse(session *models.Principal, params user_api.ListObjec
}
return resp, nil
}
+
+// listBucketObjects gets an array of objects in a bucket
+func listBucketObjects(ctx context.Context, client MinioClient, bucketName string, prefix string, recursive bool) ([]*models.BucketObject, error) {
+ var objects []*models.BucketObject
+ for lsObj := range client.listObjects(ctx, bucketName, minio.ListObjectsOptions{Prefix: prefix, Recursive: recursive}) {
+ if lsObj.Err != nil {
+ return nil, lsObj.Err
+ }
+ obj := &models.BucketObject{
+ Name: lsObj.Key,
+ Size: lsObj.Size,
+ LastModified: lsObj.LastModified.String(),
+ ContentType: lsObj.ContentType,
+ }
+ objects = append(objects, obj)
+ }
+ return objects, nil
+}
+
+// getDeleteObjectResponse returns whether there was an error on deletion of object
+func getDeleteObjectResponse(session *models.Principal, params user_api.DeleteObjectParams) *models.Error {
+ ctx := context.Background()
+ s3Client, err := newS3BucketClient(session, params.BucketName, params.Path)
+ if err != nil {
+ return prepareError(err)
+ }
+ // create a mc S3Client interface implementation
+ // defining the client to be used
+ mcClient := mcClient{client: s3Client}
+ var rec bool
+ var version string
+ if params.Recursive != nil {
+ rec = *params.Recursive
+ }
+ if params.VersionID != nil {
+ version = *params.VersionID
+ }
+ err = deleteObjects(ctx, mcClient, params.BucketName, params.Path, version, rec)
+ if err != nil {
+ return prepareError(err)
+ }
+ return nil
+}
+
+// deleteObjects deletes either a single object or multiple objects based on recursive flag
+func deleteObjects(ctx context.Context, client MCClient, bucket, path string, versionID string, recursive bool) error {
+ if recursive {
+ if err := deleteMultipleObjects(ctx, client, recursive); err != nil {
+ return err
+ }
+ } else {
+ if err := deleteSingleObject(ctx, client, bucket, path, versionID); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// deleteMultipleObjects uses listing before removal, it can list recursively or not,
+// Use cases:
+// * Remove objects recursively
+func deleteMultipleObjects(ctx context.Context, client MCClient, recursive bool) error {
+ isRemoveBucket := false
+ isIncomplete := false
+ isBypass := false
+ listOpts := mc.ListOptions{IsRecursive: recursive, IsIncomplete: isIncomplete, ShowDir: mc.DirNone}
+ // TODO: support older Versions
+ contentCh := make(chan *mc.ClientContent, 1)
+
+ errorCh := client.remove(ctx, isIncomplete, isRemoveBucket, isBypass, contentCh)
+ for content := range client.list(ctx, listOpts) {
+ if content.Err != nil {
+ switch content.Err.ToGoError().(type) {
+ // ignore same as mc
+ case mc.PathInsufficientPermission:
+ // Ignore Permission error.
+ continue
+ }
+ close(contentCh)
+ return content.Err.Cause
+ }
+ sent := false
+ for !sent {
+ select {
+ case contentCh <- content:
+ sent = true
+ case pErr := <-errorCh:
+ switch pErr.ToGoError().(type) {
+ // ignore same as mc
+ case mc.PathInsufficientPermission:
+ // Ignore Permission error.
+ continue
+ }
+ close(contentCh)
+ return pErr.Cause
+ }
+ }
+ }
+ close(contentCh)
+ for pErr := range errorCh {
+ if pErr != nil {
+ switch pErr.ToGoError().(type) {
+ // ignore same as mc
+ case mc.PathInsufficientPermission:
+ // Ignore Permission error.
+ continue
+ }
+ return pErr.Cause
+ }
+ }
+ return nil
+
+}
+
+func deleteSingleObject(ctx context.Context, client MCClient, bucket, object string, versionID string) error {
+ targetURL := fmt.Sprintf("%s/%s", bucket, object)
+ contentCh := make(chan *mc.ClientContent, 1)
+ contentCh <- &mc.ClientContent{URL: *newClientURL(targetURL), VersionID: versionID}
+ close(contentCh)
+
+ isRemoveBucket := false
+ isIncomplete := false
+ isBypass := false
+
+ errorCh := client.remove(ctx, isIncomplete, isRemoveBucket, isBypass, contentCh)
+ for pErr := range errorCh {
+ if pErr != nil {
+ switch pErr.ToGoError().(type) {
+ // ignore same as mc
+ case mc.PathInsufficientPermission:
+ // Ignore Permission error.
+ continue
+ }
+ return pErr.Cause
+ }
+ }
+ return nil
+}
+
+// newClientURL returns an abstracted URL for filesystems and object storage.
+func newClientURL(urlStr string) *mc.ClientURL {
+ scheme, rest := getScheme(urlStr)
+ if strings.HasPrefix(rest, "//") {
+ // if rest has '//' prefix, skip them
+ var authority string
+ authority, rest = splitSpecial(rest[2:], "/", false)
+ if rest == "" {
+ rest = "/"
+ }
+ host := getHost(authority)
+ if host != "" && (scheme == "http" || scheme == "https") {
+ return &mc.ClientURL{
+ Scheme: scheme,
+ Type: objectStorage,
+ Host: host,
+ Path: rest,
+ SchemeSeparator: "://",
+ Separator: '/',
+ }
+ }
+ }
+ return &mc.ClientURL{
+ Type: fileSystem,
+ Path: rest,
+ Separator: filepath.Separator,
+ }
+}
+
+// Maybe rawurl is of the form scheme:path. (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
+// If so, return scheme, path; else return "", rawurl.
+func getScheme(rawurl string) (scheme, path string) {
+ urlSplits := strings.Split(rawurl, "://")
+ if len(urlSplits) == 2 {
+ scheme, uri := urlSplits[0], "//"+urlSplits[1]
+ // ignore numbers in scheme
+ validScheme := regexp.MustCompile("^[a-zA-Z]+$")
+ if uri != "" {
+ if validScheme.MatchString(scheme) {
+ return scheme, uri
+ }
+ }
+ }
+ return "", rawurl
+}
+
+// Assuming s is of the form [s delimiter s].
+// If so, return s, [delimiter]s or return s, s if cutdelimiter == true
+// If no delimiter found return s, "".
+func splitSpecial(s string, delimiter string, cutdelimiter bool) (string, string) {
+ i := strings.Index(s, delimiter)
+ if i < 0 {
+ // if delimiter not found return as is.
+ return s, ""
+ }
+ // if delimiter should be removed, remove it.
+ if cutdelimiter {
+ return s[0:i], s[i+len(delimiter):]
+ }
+ // return split strings with delimiter
+ return s[0:i], s[i:]
+}
+
+// getHost - extract host from authority string, we do not support ftp style username@ yet.
+func getHost(authority string) (host string) {
+ i := strings.LastIndex(authority, "@")
+ if i >= 0 {
+ // TODO support, username@password style userinfo, useful for ftp support.
+ return
+ }
+ return authority
+}
diff --git a/restapi/user_objects_test.go b/restapi/user_objects_test.go
index 3e3c84c08..5237ebabc 100644
--- a/restapi/user_objects_test.go
+++ b/restapi/user_objects_test.go
@@ -25,17 +25,30 @@ import (
"time"
"github.com/minio/console/models"
+ mc "github.com/minio/mc/cmd"
+ "github.com/minio/mc/pkg/probe"
"github.com/minio/minio-go/v7"
)
var minioListObjectsMock func(ctx context.Context, bucket string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo
+var mcListMock func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
+var mcRemoveMock func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error
// mock function of listObjects() needed for list objects
-
func (ac minioClientMock) listObjects(ctx context.Context, bucket string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo {
return minioListObjectsMock(ctx, bucket, opts)
}
+// implements mc.S3Client.List()
+func (c s3ClientMock) list(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
+ return mcListMock(ctx, opts)
+}
+
+// implements mc.S3Client.Remove()
+func (c s3ClientMock) remove(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error {
+ return mcRemoveMock(ctx, isIncomplete, isRemoveBucket, isBypass, contentCh)
+}
+
func Test_listObjects(t *testing.T) {
ctx := context.Background()
t1 := time.Now()
@@ -160,3 +173,168 @@ func Test_listObjects(t *testing.T) {
})
}
}
+
+func Test_deleteObjects(t *testing.T) {
+ ctx := context.Background()
+ client := s3ClientMock{}
+ type args struct {
+ bucket string
+ path string
+ versionID string
+ recursive bool
+ listFunc func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent
+ removeFunc func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error
+ }
+ tests := []struct {
+ test string
+ args args
+ wantError error
+ }{
+ {
+ test: "Remove single object",
+ args: args{
+ path: "obj.txt",
+ versionID: "",
+ recursive: false,
+ removeFunc: func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error {
+ errorCh := make(chan *probe.Error)
+ go func() {
+ defer close(errorCh)
+ for {
+ return
+ }
+ }()
+ return errorCh
+ },
+ },
+ wantError: nil,
+ },
+ {
+ test: "Error on Remove single object",
+ args: args{
+ path: "obj.txt",
+ versionID: "",
+ recursive: false,
+ removeFunc: func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error {
+ errorCh := make(chan *probe.Error)
+ go func() {
+ defer close(errorCh)
+ for {
+ errorCh <- probe.NewError(errors.New("probe error"))
+ return
+ }
+ }()
+ return errorCh
+ },
+ },
+ wantError: errors.New("probe error"),
+ },
+ {
+ test: "Remove multiple objects",
+ args: args{
+ path: "path/",
+ versionID: "",
+ recursive: true,
+ removeFunc: func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error {
+ errorCh := make(chan *probe.Error)
+ go func() {
+ defer close(errorCh)
+ for {
+ return
+ }
+ }()
+ return errorCh
+ },
+ listFunc: func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
+ ch := make(chan *mc.ClientContent)
+ go func() {
+ defer close(ch)
+ for {
+ ch <- &mc.ClientContent{}
+ return
+ }
+ }()
+ return ch
+ },
+ },
+ wantError: nil,
+ },
+ {
+ // Description handle error when error happens on list function
+ // while deleting multiple objects
+ test: "Error on Remove multiple objects 1",
+ args: args{
+ path: "path/",
+ versionID: "",
+ recursive: true,
+ removeFunc: func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error {
+ errorCh := make(chan *probe.Error)
+ go func() {
+ defer close(errorCh)
+ for {
+ return
+ }
+ }()
+ return errorCh
+ },
+ listFunc: func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
+ ch := make(chan *mc.ClientContent)
+ go func() {
+ defer close(ch)
+ for {
+ ch <- &mc.ClientContent{Err: probe.NewError(errors.New("probe error"))}
+ return
+ }
+ }()
+ return ch
+ },
+ },
+ wantError: errors.New("probe error"),
+ },
+ {
+ // Description handle error when error happens on remove function
+ // while deleting multiple objects
+ test: "Error on Remove multiple objects 2",
+ args: args{
+ path: "path/",
+ versionID: "",
+ recursive: true,
+ removeFunc: func(ctx context.Context, isIncomplete, isRemoveBucket, isBypass bool, contentCh <-chan *mc.ClientContent) <-chan *probe.Error {
+ errorCh := make(chan *probe.Error)
+ go func() {
+ defer close(errorCh)
+ for {
+ errorCh <- probe.NewError(errors.New("probe error"))
+ return
+ }
+ }()
+ return errorCh
+ },
+ listFunc: func(ctx context.Context, opts mc.ListOptions) <-chan *mc.ClientContent {
+ ch := make(chan *mc.ClientContent)
+ go func() {
+ defer close(ch)
+ for {
+ ch <- &mc.ClientContent{}
+ return
+ }
+ }()
+ return ch
+ },
+ },
+ wantError: errors.New("probe error"),
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.test, func(t *testing.T) {
+ mcListMock = tt.args.listFunc
+ mcRemoveMock = tt.args.removeFunc
+ err := deleteObjects(ctx, client, tt.args.bucket, tt.args.path, tt.args.versionID, tt.args.recursive)
+ if !reflect.DeepEqual(err, tt.wantError) {
+ t.Errorf("deleteObjects() error: %v, wantErr: %v", err, tt.wantError)
+ return
+ }
+ })
+ }
+}
diff --git a/restapi/ws_handle.go b/restapi/ws_handle.go
index d8160d740..59187496f 100644
--- a/restapi/ws_handle.go
+++ b/restapi/ws_handle.go
@@ -185,7 +185,7 @@ func newWebSocketAdminClient(conn *websocket.Conn, autClaims *models.Principal)
func newWebSocketS3Client(conn *websocket.Conn, claims *models.Principal, bucketName string) (*wsS3Client, error) {
// Only start Websocket Interaction after user has been
// authenticated with MinIO
- s3Client, err := newS3BucketClient(claims, bucketName)
+ s3Client, err := newS3BucketClient(claims, bucketName, "")
if err != nil {
log.Println("error creating S3Client:", err)
conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
diff --git a/swagger.yml b/swagger.yml
index 1766688a3..78744beb7 100644
--- a/swagger.yml
+++ b/swagger.yml
@@ -251,6 +251,35 @@ paths:
$ref: "#/definitions/error"
tags:
- UserAPI
+ delete:
+ summary: Delete Object
+ operationId: DeleteObject
+ parameters:
+ - name: bucket_name
+ in: path
+ required: true
+ type: string
+ - name: path
+ in: query
+ required: true
+ type: string
+ - name: version_id
+ in: query
+ required: false
+ type: string
+ - name: recursive
+ in: query
+ required: false
+ type: boolean
+ responses:
+ 200:
+ description: A successful response.
+ default:
+ description: Generic error response.
+ schema:
+ $ref: "#/definitions/error"
+ tags:
+ - UserAPI
/buckets/{name}/set-policy:
put: