Compare commits

...

65 Commits

Author SHA1 Message Date
Minio Trusted
63350e5492 update to v0.4.4 2020-11-05 18:07:46 -08:00
Alex
255c128b67 Fixed pagination un buckets lists (#371)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-11-05 10:16:03 -08:00
Cesar N
06f333395e Move trace and logs UI to Operator Console (#375)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-11-04 21:45:48 -08:00
Alex
3cd024ea2c Changed sizes for main container & table paper (#377)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-11-04 16:36:51 -08:00
Alex
9c0a407db6 Fixed page refresh on buckets creation (#372)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-11-04 15:25:36 -08:00
Alex
dc3c619f3f Added animation & disabled button / fields on sending (#369)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-11-03 11:12:41 -08:00
Alex
5000aafba6 Added functionality for create folder & replaced icons (#368)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-11-02 21:45:47 -08:00
Cesar N
b9f2a39d50 Fix tenant creation (#363)
Memory size request was not being sent, hence the tenant was not being created.
2020-11-02 11:03:40 -08:00
Daniel Valdivia
df321191f4 Build assets inside the container (#357) 2020-11-01 07:34:37 -08:00
Alex
547eb41e96 Added navigation to object browser (#358)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-31 00:22:46 -07:00
Lenin Alevski
afbb83e081 certs-dir value was ignored because of wrong variable assigning (#362) 2020-10-30 22:36:52 -07:00
Lenin Alevski
b599968570 SNI support for Console (#352)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-29 22:26:48 -07:00
Cesar N
24cc60f34e Add put object api and add list object improvements (#356) 2020-10-28 16:08:26 -07:00
Alex
f967058409 Updated Heal section (#351)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-27 21:06:24 -07:00
Alex
078e09ba76 Fixed inconsistences in create tenant modal (#349)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-27 12:43:12 -07:00
Lenin Alevski
d6f97841d4 return generic login error when invalid credentials (#350) 2020-10-27 10:05:16 -07:00
Lenin Alevski
619ac124b3 Bucket encryption checkbox and endpoints for Console (#343)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-25 12:56:23 -07:00
Alex
a2180e123d Removed warnings on console (#345)
For Operator modules this will be removed after upgrading component to use redux/formik

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-24 00:05:26 -07:00
Cesar N
0325bb7e2d Add put object retention api (#340) 2020-10-23 15:04:02 -07:00
Minio Trusted
fce361e5bd update to v0.4.3 2020-10-23 02:15:25 -07:00
Alex
ed6d6e8b9d Fixed audit issues (#342)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-23 02:03:49 -07:00
Alex
406709f66b Updated Watch view to have console consistent styles (#341)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-22 17:15:40 -07:00
Cesar N
3ac45a2211 Add Set object's legalhold status api (#339)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-22 16:23:29 -07:00
Minio Trusted
716f886780 update to v0.4.2 2020-10-22 15:35:17 -07:00
Alex
4ef498f0c3 Updated Logs page to be more consistent with current styles (#338)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-22 12:08:36 -07:00
Alex
5e764e61ba Changed trace view to be a table (#337)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-22 11:27:24 -07:00
Cesar N
1466632fd6 Add share object api (#335) 2020-10-22 11:18:27 -07:00
Lenin Alevski
0c43e5c3f4 React Router fixes for Console (#336)
- Adding protectedRoute component
- Removed unnecessary redirect login
2020-10-21 13:13:40 -07:00
Alex
7e9d581277 Updated styles & behavior for settings page (#334)
Updated styles & behavior for settings page, also implemented a couple of performance improvements on some fields

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-20 16:31:08 -07:00
Cesar N
c928972137 Change Users label to Tenants on Tenants Page (#330) 2020-10-20 11:24:52 -07:00
Daniel Valdivia
78884e3806 Make logs, trace and watch have fixed height (#333) 2020-10-20 09:06:23 -07:00
Lenin Alevski
f6ac7e047e Invalidate console session when minio user doesn't exists (#332) 2020-10-19 15:32:21 -07:00
Alex
e1fdf3fb28 Modals UI style changes (#331)
Implements new input styles & adjusts information on modal boxes for console.

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-19 11:27:54 -07:00
Cesar N
e4510cbc18 Add upload api and integrate it with object browser on UI (#327) 2020-10-14 23:09:33 -07:00
Minio Trusted
2c14142e19 update to v0.4.1 2020-10-12 20:37:21 -07:00
Kaan Kabalak
1caa3f2ce8 Implement License page (#324)
* Implement License page

Fixes #320

* License Assets

* Fix endpoint tests

Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-12 11:56:15 -07:00
Alex
6501a4b13f First set of Modal style changes (#322)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-09 12:01:24 -07:00
Daniel Valdivia
2f51621e69 Get Tenant Secret From Tenant CR (#323)
We were assuming the Tenant Credentials Secret instead of reading it from it's .spec.credsSecret this commit addresses that
2020-10-09 11:51:02 -07:00
Cesar N
7e6e64c729 Add download objects api and integrate it with UI (#321) 2020-10-09 11:43:15 -07:00
Kaan Kabalak
9007c7dd14 Consolidate Remote Buckets and Replication modals (#317)
* Consolidate Remote Buckets and Replication modals

This commit consolidates Remote Buckets and Replication modals into a
single modal in the Add Replication Rule modal located in the Buckets
section

Fixes #301

* Remove Remote Buckets section

* Properly align tabs and button on Buckets page
2020-10-08 09:55:31 -07:00
Alex
850fd3e371 Changed buttons & search boxes styles (#318)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-06 21:37:13 -07:00
Daniel Valdivia
6d8f1c439e Handle Invalid User error coming from madmin (#314)
Right now we display `Internal Server Error` when invalid credentials are presneted, this makes it so we only present `Unauthorized`
2020-10-06 16:45:26 -07:00
Alex
7166717688 Changed styles for Login page (#316)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-06 16:37:25 -07:00
Cesar N
f91346dc5b Add retention mode and legal hold mode on list objects api (#312)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-06 16:07:33 -07:00
Alex
dccdfb5533 Customization of Dashboard page & improved some styles (#315)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-05 21:30:52 -07:00
Daniel Valdivia
4f065bdedf Change Menu Order. (#313) 2020-10-05 20:48:10 -07:00
Minio Trusted
4a02c5848b update to v0.4.0 2020-10-05 12:47:31 -07:00
Lenin Alevski
e16a926ef8 Add support for loading multiple TLS certificates (#304)
- update operator version to latest version
- create tenant endpoint now supports multiple TLS certificates for
  MinIO TLS configuration
- update certificates endpoint now support multiple TLS certificates

Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-10-05 12:09:34 -07:00
Alex
78f4978a9a Changed navbar & header styles (#311)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-05 11:33:27 -07:00
Cesar N
42d617caf9 Add list objects UI and integrate with listing and delete api (#310) 2020-10-02 17:37:08 -07:00
Daniel Valdivia
28eb8784a9 Set Bucket Quota on Creation (#308)
Introces the capability to set bucket quota on bucket creation and adds the API to set the bucket on it's own
2020-10-01 18:59:20 -07:00
Cesar N
fcf5d5c9f7 Add delete objects api (#303)
Supports single and multiple objects which needs to be defined by recursive flag.
An object to be deleted needs to be defined by a query parameter, path, since it can be
an object or a folder.
2020-10-01 17:00:32 -07:00
Alex
a42f1ff4ee Added buckets-object browser view (#307)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-01 13:21:55 -07:00
Alex
98f897ed5b Added object browser main paths (#302)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-09-30 17:46:07 -07:00
Cesar N
7afd608faa Add list objects api (#291)
This includes the basic information of an object
2020-09-29 14:34:51 -07:00
Alex
8313a62f17 Add support for Remote Buckets and Replication (#287)
Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-09-28 10:46:08 -07:00
Alex
459e2bf61c Added file name visualization in file select (#289)
* Added missing validations in add tenant modal

* Added file name visualization in file selector

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-09-28 10:36:31 -07:00
Minio Trusted
858d363e97 update to version v0.3.26 2020-09-23 08:52:43 -07:00
Lenin Alevski
47704189d1 fix kes empty configuration (#286)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-09-22 20:49:25 -07:00
Daniel Valdivia
b72d424ec9 UI: Tweaks to multiple elements (#284) 2020-09-22 20:31:00 -07:00
Lenin Alevski
86426e95f7 Added Annotations, Labels and NodeSelector fields (#285)
For Console/Encryption objects in the  CreateTenant Api
2020-09-22 15:50:37 -07:00
Daniel Valdivia
e5f7870f5e Parity API (#280) 2020-09-22 11:15:21 -07:00
Lenin Alevski
c0ee739624 IV generation for ChaCha20 poly auth scheme (#283)
Generate 16 bytes IV instead of an IV of 32 bytes (and then use half of it) when using ChaCha20 to
encrypt tokens, this is to prevent tokens to become malleable.
2020-09-22 10:49:34 -07:00
Minio Trusted
1dc99498d9 update v0.3.25 2020-09-21 22:07:11 -07:00
Cesar N
319d96c725 Use operator port variables (#282) 2020-09-21 21:31:30 -07:00
299 changed files with 31187 additions and 7526 deletions

View File

@@ -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.15.x]
os: [ubuntu-latest]
steps:
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}

View File

@@ -12,6 +12,10 @@ before:
hooks:
# you may remove this if you don't use vgo
- go mod tidy
- docker build -f Dockerfile.assets -t consoleassets .
- docker create --name extract consoleassets
- docker cp extract:/app/bindata_assetfs.go ./portal-ui/
- docker rm extract
builds:
-

View File

@@ -1,4 +1,25 @@
FROM golang:1.13
FROM golang:1.15 as binlayer
RUN go get github.com/go-bindata/go-bindata/... && go get github.com/elazarl/go-bindata-assetfs/...
FROM node:10 as uilayer
WORKDIR /app
COPY --from=binlayer /go/bin/go-bindata-assetfs /bin/
COPY --from=binlayer /go/bin/go-bindata /bin/
COPY ./portal-ui/package.json ./
COPY ./portal-ui/yarn.lock ./
RUN yarn install
COPY ./portal-ui .
RUN yarn install && make build-static
USER node
FROM golang:1.15 as golayer
RUN apt-get update -y && apt-get install -y ca-certificates
@@ -12,6 +33,8 @@ RUN go mod download
ADD . /go/src/github.com/minio/console/
WORKDIR /go/src/github.com/minio/console/
COPY --from=uilayer /app/bindata_assetfs.go /go/src/github.com/minio/console/portal-ui/
ENV CGO_ENABLED=0
RUN go build -ldflags "-w -s" -a -o console ./cmd/console
@@ -20,7 +43,7 @@ FROM scratch
MAINTAINER MinIO Development "dev@min.io"
EXPOSE 9090
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=0 /go/src/github.com/minio/console/console .
COPY --from=golayer /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=golayer /go/src/github.com/minio/console/console .
ENTRYPOINT ["/console"]

20
Dockerfile.assets Normal file
View File

@@ -0,0 +1,20 @@
FROM golang:1.15 as binlayer
RUN go get github.com/go-bindata/go-bindata/... && go get github.com/elazarl/go-bindata-assetfs/...
FROM node:10 as uilayer
WORKDIR /app
COPY --from=binlayer /go/bin/go-bindata-assetfs /bin/
COPY --from=binlayer /go/bin/go-bindata /bin/
COPY ./portal-ui/package.json ./
COPY ./portal-ui/yarn.lock ./
RUN yarn install
COPY ./portal-ui .
RUN yarn install && make build-static
USER node

View File

@@ -101,8 +101,6 @@ Additionally, you can create policies to limit the privileges for `console` user
To run the server:
```
export CONSOLE_HMAC_JWT_SECRET=YOURJWTSIGNINGSECRET
#required to encrypt jwet payload
export CONSOLE_PBKDF_PASSPHRASE=SECRET
@@ -115,11 +113,41 @@ export CONSOLE_MINIO_SERVER=http://localhost:9000
./console server
```
## Connect Console to a Minio using TLS and a self-signed certificate
## Run Console with TLS enable
Copy your `public.crt` and `private.key` to `~/.console/certs`, then:
```bash
./console server
```
Additionally, `Console` has support for multiple certificates, clients can request them using `SNI`. It expects the following structure:
```bash
certs/
├─ public.crt
├─ private.key
├─ example.com/
│ │
│ ├─ public.crt
│ └─ private.key
└─ foobar.org/
├─ public.crt
└─ private.key
...
```
...
export CONSOLE_MINIO_SERVER_TLS_ROOT_CAS=<certificate_file_name>
Therefore, we read all filenames in the cert directory and check
for each directory whether it contains a public.crt and private.key.
## Connect Console to a Minio using TLS and a self-signed certificate
Copy the MinIO `ca.crt` under `~/.console/certs/CAs`, then:
```
export CONSOLE_MINIO_SERVER=https://localhost:9000
./console server
```

File diff suppressed because one or more lines are too long

View File

@@ -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)
}
}

View File

@@ -20,12 +20,16 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/go-openapi/loads"
"github.com/jessevdk/go-flags"
"github.com/minio/cli"
"github.com/minio/console/pkg/certs"
"github.com/minio/console/restapi"
"github.com/minio/console/restapi/operations"
"github.com/minio/minio/cmd/logger"
certsx "github.com/minio/minio/pkg/certs"
)
// starts the server
@@ -56,14 +60,9 @@ var serverCmd = cli.Command{
Usage: "HTTPS server port",
},
cli.StringFlag{
Name: "tls-certificate",
Value: "",
Usage: "filename of public cert",
},
cli.StringFlag{
Name: "tls-key",
Value: "",
Usage: "filename of private key",
Name: "certs-dir",
Value: certs.GlobalCertsCADir.Get(),
Usage: "path to certs directory",
},
},
}
@@ -82,7 +81,9 @@ func startServer(ctx *cli.Context) error {
parser := flags.NewParser(server, flags.Default)
parser.ShortDescription = "MinIO Console Server"
parser.LongDescription = swaggerSpec.Spec().Info.Description
server.ConfigureFlags()
for _, optsGroup := range api.CommandLineOptionsGroups {
_, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options)
if err != nil {
@@ -106,12 +107,19 @@ func startServer(ctx *cli.Context) error {
restapi.Hostname = ctx.String("host")
restapi.Port = fmt.Sprintf("%v", ctx.Int("port"))
tlsCertificatePath := ctx.String("tls-certificate")
tlsCertificateKeyPath := ctx.String("tls-key")
// Set all certs and CAs directories.
certs.GlobalCertsDir, _ = certs.NewConfigDirFromCtx(ctx, "certs-dir", certs.DefaultCertsDir.Get)
certs.GlobalCertsCADir = &certs.ConfigDir{Path: filepath.Join(certs.GlobalCertsDir.Get(), certs.CertsCADir)}
logger.FatalIf(certs.MkdirAllIgnorePerm(certs.GlobalCertsCADir.Get()), "Unable to create certs CA directory at %s", certs.GlobalCertsCADir.Get())
if tlsCertificatePath != "" && tlsCertificateKeyPath != "" {
server.TLSCertificate = flags.Filename(tlsCertificatePath)
server.TLSCertificateKey = flags.Filename(tlsCertificateKeyPath)
// load all CAs from ~/.console/certs/CAs
restapi.GlobalRootCAs, err = certsx.GetRootCAs(certs.GlobalCertsCADir.Get())
logger.FatalIf(err, "Failed to read root CAs (%v)", err)
// load all certs from ~/.console/certs
restapi.GlobalPublicCerts, restapi.GlobalTLSCertsManager, err = certs.GetTLSConfig()
logger.FatalIf(err, "Unable to load the TLS configuration")
if len(restapi.GlobalPublicCerts) > 0 && restapi.GlobalRootCAs != nil {
// If TLS certificates are provided enforce the HTTPS schema, meaning console will redirect
// plain HTTP connections to HTTPS server
server.EnabledListeners = []string{"http", "https"}

View File

@@ -2,7 +2,7 @@
`Console` will authenticate against `Kubernetes`using bearer tokens via HTTP `Authorization` header. The user will provide this token once
in the login form, Console will validate it against Kubernetes (list apis) and if valid will generate and return a new Console sessions
with encrypted claims (the user Service account token will be inside the JWT in the data field)
with encrypted claims (the user Service account token will be inside the session encrypted token
# Kubernetes

15
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/minio/console
go 1.13
go 1.15
require (
github.com/coreos/go-oidc v2.2.1+incompatible
@@ -16,16 +16,17 @@ 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-20200808005614-7e52c104bee1
github.com/minio/minio v0.0.0-20200808024306-2a9819aff876
github.com/minio/minio-go/v7 v7.0.5-0.20200807085956-d7db33ea7618
github.com/minio/operator v0.0.0-20200904194631-b8aa01dc5d70
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-20201022162018-527e5c32132b
github.com/mitchellh/go-homedir v1.1.0
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

83
go.sum
View File

@@ -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,13 +55,17 @@ 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=
github.com/Azure/go-autorest v14.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
github.com/Azure/go-autorest/autorest v0.10.2 h1:NuSF3gXetiHyUbVdneJMEVyPUYAe5wh+aN08JYAf1tI=
github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
@@ -67,10 +74,13 @@ github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMl
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
github.com/Azure/go-autorest/autorest/adal v0.9.1 h1:xjPqigMQe2+0DAJ5A6MLUPp5D2r2Io8qHCuCMMI/yJU=
github.com/Azure/go-autorest/autorest/adal v0.9.1/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
@@ -80,8 +90,10 @@ github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocm
github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -145,6 +157,7 @@ github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi
github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.29.11/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=
github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2 h1:M+TYzBcNIRyzPRg66ndEqUMd7oWDmhvdQmaPC6EZNwM=
@@ -169,6 +182,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=
@@ -520,9 +534,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=
@@ -530,6 +546,7 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV
github.com/googleapis/gnostic v0.2.2 h1:DcFegQ7+ECdmkJMfVwWlC+89I4esJ7p8nkGt9ainGDk=
github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -541,6 +558,8 @@ github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.5-0.20200711200521-98cb6bf42e08 h1:kPna6oIGlRXWmg/jkKfxbpvsl+0DHYnw1qQwN+6+gyA=
github.com/gorilla/mux v1.7.5-0.20200711200521-98cb6bf42e08/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk=
github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
@@ -585,6 +604,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=
@@ -711,6 +731,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=
@@ -734,6 +756,8 @@ github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaa
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
@@ -748,6 +772,8 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
@@ -765,30 +791,30 @@ 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-20200808005614-7e52c104bee1 h1:OrcFWsUIzKoXeIXVReZ7AryDtbPBLtkjDDOBnuU9RWY=
github.com/minio/mc v0.0.0-20200808005614-7e52c104bee1/go.mod h1:OGP9+cwQ174WKwZTgJOIFstVv19CH0wdSDZSG6NyTuE=
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-20200807001021-adcaa6f9de88 h1:v2mCqNx6N02jcYHWjMPHdTN9+ogxEN9L+cCQJ+8j2AU=
github.com/minio/minio v0.0.0-20200807001021-adcaa6f9de88/go.mod h1:r+PkhkMRxudvboO0Wa7F7nMiDfI8Rz1HZSza0uIhtMU=
github.com/minio/minio v0.0.0-20200808024306-2a9819aff876 h1:e5114Mb8Evzt1QsA8b6PrXZ1KqBLts0CokpKeU1DV2U=
github.com/minio/minio v0.0.0-20200808024306-2a9819aff876/go.mod h1:r+PkhkMRxudvboO0Wa7F7nMiDfI8Rz1HZSza0uIhtMU=
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.3/go.mod h1:TA0CQCjJZHM5SJj9IjqR0NmpmQJ6bCbXifAJ3mUU6Hw=
github.com/minio/minio-go/v7 v7.0.5-0.20200807085956-d7db33ea7618 h1:8iTb0TFs6kDGAUnhI/s2QCZOYcSTtYmY9dF+Cbc0WJo=
github.com/minio/minio-go/v7 v7.0.5-0.20200807085956-d7db33ea7618/go.mod h1:CSt2ETZNs+bIIhWTse0mcZKZWMGrFU7Er7RR0TmkDYk=
github.com/minio/operator v0.0.0-20200904194631-b8aa01dc5d70 h1:FjyhnnrOHMzhJryqNoOISgp8p1dmmn1IMOlgBAaf8r4=
github.com/minio/operator v0.0.0-20200904194631-b8aa01dc5d70/go.mod h1:NVl1+c7TYxJB22opK/m2L5SkTvlEYd1ZFPuL6SX5fCg=
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.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-20201022162018-527e5c32132b h1:ggfD6V3nodTzhHJHCYIT1F897gscrz+hHsan0a2Wtqw=
github.com/minio/operator v0.0.0-20201022162018-527e5c32132b/go.mod h1:At+++4/6W5BEXK11tN5DKIvkJKhYBZybbb5zmxb0LQI=
github.com/minio/selfupdate v0.3.1 h1:BWEFSNnrZVMUWXbXIgLDNDjbejkmpAmZvy/nCz1HlEs=
github.com/minio/selfupdate v0.3.1/go.mod h1:b8ThJzzH7u2MkF6PcIra7KaXO9Khf6alWPvMSyTDCFM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
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=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -811,6 +837,7 @@ github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 h1:UCU8+cLbbvyxi0sQ9fSeoEhZgvrrD9HKMtX6Gmc1vk8=
github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -855,6 +882,7 @@ github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olivere/elastic/v7 v7.0.12/go.mod h1:14rWX28Pnh3qCKYRVnSGXWLf9MbLonYS/4FDCY3LAPo=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -874,6 +902,7 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -986,12 +1015,15 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
github.com/smartystreets/gunit v1.1.3/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
@@ -1057,6 +1089,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=
@@ -1077,6 +1110,8 @@ 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=
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
@@ -1093,6 +1128,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=
@@ -1112,6 +1148,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=
@@ -1156,8 +1193,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=
@@ -1238,6 +1275,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=
@@ -1316,8 +1356,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=
@@ -1407,14 +1447,18 @@ golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200724172932-b5fc9d354d99 h1:OHn441rq5CeM5r1xJ0OmY7lfdTvnedi6k+vQiI7G9b8=
golang.org/x/tools v0.0.0-20200724172932-b5fc9d354d99/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d h1:szSOL78iTCl0LF1AMjhSWJj8tIM0KixlUUnBtYXsmd8=
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=
@@ -1435,6 +1479,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=
@@ -1516,6 +1561,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25 h1:Ev7yu1/f6+d+b3pi5vPdRPc6nNtP1umSfcWiEfRqv6I=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
@@ -1545,6 +1592,8 @@ gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/olivere/elastic.v5 v5.0.80 h1:AKjfcq3ZIAAqO4m8h/vJ3GP6nY8n9ft5mgf54fEqC60=
gopkg.in/olivere/elastic.v5 v5.0.80/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0=
gopkg.in/olivere/elastic.v5 v5.0.86 h1:xFy6qRCGAmo5Wjx96srho9BitLhZl2fcnpuidPwduXM=
gopkg.in/olivere/elastic.v5 v5.0.86/go.mod h1:M3WNlsF+WhYn7api4D87NIflwTV/c0iVs8cqfWhK+68=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=

View File

@@ -7,7 +7,6 @@ rules:
- ""
resources:
- namespaces
- secrets
- pods
- services
- events
@@ -18,6 +17,18 @@ rules:
- create
- list
- patch
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- watch
- create
- list
- patch
- deletecollection
- delete
- apiGroups:
- "storage.k8s.io"
resources:

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.3.24
image: minio/console:v0.4.4
imagePullPolicy: "IfNotPresent"
args:
- server

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:v0.3.24
image: minio/console:v0.4.4
imagePullPolicy: "IfNotPresent"
env:
- name: CONSOLE_OPERATOR_MODE

View File

@@ -8,4 +8,4 @@ resources:
- console-configmap.yaml
- console-service.yaml
- console-deployment.yaml
- https://github.com/minio/operator/?ref=v3.0.10
- https://github.com/minio/operator/?ref=v3.0.19

View File

@@ -0,0 +1,63 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// AddBucketReplication add bucket replication
//
// swagger:model addBucketReplication
type AddBucketReplication struct {
// arn
Arn string `json:"arn,omitempty"`
// destination bucket
DestinationBucket string `json:"destination_bucket,omitempty"`
}
// Validate validates this add bucket replication
func (m *AddBucketReplication) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *AddBucketReplication) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AddBucketReplication) UnmarshalBinary(b []byte) error {
var res AddBucketReplication
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,63 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// BucketEncryptionInfo bucket encryption info
//
// swagger:model bucketEncryptionInfo
type BucketEncryptionInfo struct {
// algorithm
Algorithm string `json:"algorithm,omitempty"`
// kms master key ID
KmsMasterKeyID string `json:"kmsMasterKeyID,omitempty"`
}
// Validate validates this bucket encryption info
func (m *BucketEncryptionInfo) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *BucketEncryptionInfo) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketEncryptionInfo) UnmarshalBinary(b []byte) error {
var res BucketEncryptionInfo
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,89 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// BucketEncryptionRequest bucket encryption request
//
// swagger:model bucketEncryptionRequest
type BucketEncryptionRequest struct {
// enc type
EncType BucketEncryptionType `json:"encType,omitempty"`
// kms key ID
KmsKeyID string `json:"kmsKeyID,omitempty"`
}
// Validate validates this bucket encryption request
func (m *BucketEncryptionRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateEncType(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *BucketEncryptionRequest) validateEncType(formats strfmt.Registry) error {
if swag.IsZero(m.EncType) { // not required
return nil
}
if err := m.EncType.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("encType")
}
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *BucketEncryptionRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketEncryptionRequest) UnmarshalBinary(b []byte) error {
var res BucketEncryptionRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,80 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
)
// BucketEncryptionType bucket encryption type
//
// swagger:model bucketEncryptionType
type BucketEncryptionType string
const (
// BucketEncryptionTypeSseS3 captures enum value "sse-s3"
BucketEncryptionTypeSseS3 BucketEncryptionType = "sse-s3"
// BucketEncryptionTypeSseKms captures enum value "sse-kms"
BucketEncryptionTypeSseKms BucketEncryptionType = "sse-kms"
)
// for schema
var bucketEncryptionTypeEnum []interface{}
func init() {
var res []BucketEncryptionType
if err := json.Unmarshal([]byte(`["sse-s3","sse-kms"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
bucketEncryptionTypeEnum = append(bucketEncryptionTypeEnum, v)
}
}
func (m BucketEncryptionType) validateBucketEncryptionTypeEnum(path, location string, value BucketEncryptionType) error {
if err := validate.EnumCase(path, location, value, bucketEncryptionTypeEnum, true); err != nil {
return err
}
return nil
}
// Validate validates this bucket encryption type
func (m BucketEncryptionType) Validate(formats strfmt.Registry) error {
var res []error
// value enum
if err := m.validateBucketEncryptionTypeEnum("", "body", m); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

99
models/bucket_object.go Normal file
View File

@@ -0,0 +1,99 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// BucketObject bucket object
//
// swagger:model bucketObject
type BucketObject struct {
// content type
ContentType string `json:"content_type,omitempty"`
// expiration
Expiration string `json:"expiration,omitempty"`
// expiration rule id
ExpirationRuleID string `json:"expiration_rule_id,omitempty"`
// is delete marker
IsDeleteMarker bool `json:"is_delete_marker,omitempty"`
// is latest
IsLatest bool `json:"is_latest,omitempty"`
// last modified
LastModified string `json:"last_modified,omitempty"`
// legal hold status
LegalHoldStatus string `json:"legal_hold_status,omitempty"`
// name
Name string `json:"name,omitempty"`
// retention mode
RetentionMode string `json:"retention_mode,omitempty"`
// retention until date
RetentionUntilDate string `json:"retention_until_date,omitempty"`
// size
Size int64 `json:"size,omitempty"`
// tags
Tags map[string]string `json:"tags,omitempty"`
// user tags
UserTags map[string]string `json:"user_tags,omitempty"`
// version id
VersionID string `json:"version_id,omitempty"`
}
// Validate validates this bucket object
func (m *BucketObject) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *BucketObject) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketObject) UnmarshalBinary(b []byte) error {
var res BucketObject
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,60 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// BucketReplicationDestination bucket replication destination
//
// swagger:model bucketReplicationDestination
type BucketReplicationDestination struct {
// bucket
Bucket string `json:"bucket,omitempty"`
}
// Validate validates this bucket replication destination
func (m *BucketReplicationDestination) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *BucketReplicationDestination) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketReplicationDestination) UnmarshalBinary(b []byte) error {
var res BucketReplicationDestination
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,97 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// BucketReplicationResponse bucket replication response
//
// swagger:model bucketReplicationResponse
type BucketReplicationResponse struct {
// rules
Rules []*BucketReplicationRule `json:"rules"`
}
// Validate validates this bucket replication response
func (m *BucketReplicationResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateRules(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *BucketReplicationResponse) validateRules(formats strfmt.Registry) error {
if swag.IsZero(m.Rules) { // not required
return nil
}
for i := 0; i < len(m.Rules); i++ {
if swag.IsZero(m.Rules[i]) { // not required
continue
}
if m.Rules[i] != nil {
if err := m.Rules[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("rules" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *BucketReplicationResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketReplicationResponse) UnmarshalBinary(b []byte) error {
var res BucketReplicationResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,173 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// BucketReplicationRule bucket replication rule
//
// swagger:model bucketReplicationRule
type BucketReplicationRule struct {
// delete marker replication
DeleteMarkerReplication *BucketReplicationRuleMarker `json:"delete_marker_replication,omitempty"`
// destination
Destination *BucketReplicationDestination `json:"destination,omitempty"`
// id
ID string `json:"id,omitempty"`
// priority
Priority int32 `json:"priority,omitempty"`
// status
// Enum: [Enabled Disabled]
Status string `json:"status,omitempty"`
}
// Validate validates this bucket replication rule
func (m *BucketReplicationRule) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateDeleteMarkerReplication(formats); err != nil {
res = append(res, err)
}
if err := m.validateDestination(formats); err != nil {
res = append(res, err)
}
if err := m.validateStatus(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *BucketReplicationRule) validateDeleteMarkerReplication(formats strfmt.Registry) error {
if swag.IsZero(m.DeleteMarkerReplication) { // not required
return nil
}
if m.DeleteMarkerReplication != nil {
if err := m.DeleteMarkerReplication.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("delete_marker_replication")
}
return err
}
}
return nil
}
func (m *BucketReplicationRule) validateDestination(formats strfmt.Registry) error {
if swag.IsZero(m.Destination) { // not required
return nil
}
if m.Destination != nil {
if err := m.Destination.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("destination")
}
return err
}
}
return nil
}
var bucketReplicationRuleTypeStatusPropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["Enabled","Disabled"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
bucketReplicationRuleTypeStatusPropEnum = append(bucketReplicationRuleTypeStatusPropEnum, v)
}
}
const (
// BucketReplicationRuleStatusEnabled captures enum value "Enabled"
BucketReplicationRuleStatusEnabled string = "Enabled"
// BucketReplicationRuleStatusDisabled captures enum value "Disabled"
BucketReplicationRuleStatusDisabled string = "Disabled"
)
// prop value enum
func (m *BucketReplicationRule) validateStatusEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, bucketReplicationRuleTypeStatusPropEnum, true); err != nil {
return err
}
return nil
}
func (m *BucketReplicationRule) validateStatus(formats strfmt.Registry) error {
if swag.IsZero(m.Status) { // not required
return nil
}
// value enum
if err := m.validateStatusEnum("status", "body", m.Status); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *BucketReplicationRule) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketReplicationRule) UnmarshalBinary(b []byte) error {
var res BucketReplicationRule
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,117 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// BucketReplicationRuleMarker bucket replication rule marker
//
// swagger:model bucketReplicationRuleMarker
type BucketReplicationRuleMarker struct {
// status
// Enum: [Enabled Disabled]
Status string `json:"status,omitempty"`
}
// Validate validates this bucket replication rule marker
func (m *BucketReplicationRuleMarker) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateStatus(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var bucketReplicationRuleMarkerTypeStatusPropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["Enabled","Disabled"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
bucketReplicationRuleMarkerTypeStatusPropEnum = append(bucketReplicationRuleMarkerTypeStatusPropEnum, v)
}
}
const (
// BucketReplicationRuleMarkerStatusEnabled captures enum value "Enabled"
BucketReplicationRuleMarkerStatusEnabled string = "Enabled"
// BucketReplicationRuleMarkerStatusDisabled captures enum value "Disabled"
BucketReplicationRuleMarkerStatusDisabled string = "Disabled"
)
// prop value enum
func (m *BucketReplicationRuleMarker) validateStatusEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, bucketReplicationRuleMarkerTypeStatusPropEnum, true); err != nil {
return err
}
return nil
}
func (m *BucketReplicationRuleMarker) validateStatus(formats strfmt.Registry) error {
if swag.IsZero(m.Status) { // not required
return nil
}
// value enum
if err := m.validateStatusEnum("status", "body", m.Status); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *BucketReplicationRuleMarker) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketReplicationRuleMarker) UnmarshalBinary(b []byte) error {
var res BucketReplicationRuleMarker
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,60 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// BucketVersioningResponse bucket versioning response
//
// swagger:model bucketVersioningResponse
type BucketVersioningResponse struct {
// is versioned
IsVersioned bool `json:"is_versioned,omitempty"`
}
// Validate validates this bucket versioning response
func (m *BucketVersioningResponse) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *BucketVersioningResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *BucketVersioningResponse) UnmarshalBinary(b []byte) error {
var res BucketVersioningResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,117 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ConsoleConfiguration console configuration
//
// swagger:model consoleConfiguration
type ConsoleConfiguration struct {
MetadataFields
// image
Image string `json:"image,omitempty"`
}
// UnmarshalJSON unmarshals this object from a JSON structure
func (m *ConsoleConfiguration) UnmarshalJSON(raw []byte) error {
// AO0
var aO0 MetadataFields
if err := swag.ReadJSON(raw, &aO0); err != nil {
return err
}
m.MetadataFields = aO0
// AO1
var dataAO1 struct {
Image string `json:"image,omitempty"`
}
if err := swag.ReadJSON(raw, &dataAO1); err != nil {
return err
}
m.Image = dataAO1.Image
return nil
}
// MarshalJSON marshals this object to a JSON structure
func (m ConsoleConfiguration) MarshalJSON() ([]byte, error) {
_parts := make([][]byte, 0, 2)
aO0, err := swag.WriteJSON(m.MetadataFields)
if err != nil {
return nil, err
}
_parts = append(_parts, aO0)
var dataAO1 struct {
Image string `json:"image,omitempty"`
}
dataAO1.Image = m.Image
jsonDataAO1, errAO1 := swag.WriteJSON(dataAO1)
if errAO1 != nil {
return nil, errAO1
}
_parts = append(_parts, jsonDataAO1)
return swag.ConcatJSON(_parts...), nil
}
// Validate validates this console configuration
func (m *ConsoleConfiguration) Validate(formats strfmt.Registry) error {
var res []error
// validation for a type composition with MetadataFields
if err := m.MetadataFields.Validate(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// MarshalBinary interface implementation
func (m *ConsoleConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ConsoleConfiguration) UnmarshalBinary(b []byte) error {
var res ConsoleConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,162 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// CreateRemoteBucket create remote bucket
//
// swagger:model createRemoteBucket
type CreateRemoteBucket struct {
// access key
// Required: true
// Min Length: 3
AccessKey *string `json:"accessKey"`
// region
Region string `json:"region,omitempty"`
// secret key
// Required: true
// Min Length: 8
SecretKey *string `json:"secretKey"`
// source bucket
// Required: true
SourceBucket *string `json:"sourceBucket"`
// target bucket
// Required: true
TargetBucket *string `json:"targetBucket"`
// target URL
// Required: true
TargetURL *string `json:"targetURL"`
}
// Validate validates this create remote bucket
func (m *CreateRemoteBucket) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAccessKey(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecretKey(formats); err != nil {
res = append(res, err)
}
if err := m.validateSourceBucket(formats); err != nil {
res = append(res, err)
}
if err := m.validateTargetBucket(formats); err != nil {
res = append(res, err)
}
if err := m.validateTargetURL(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *CreateRemoteBucket) validateAccessKey(formats strfmt.Registry) error {
if err := validate.Required("accessKey", "body", m.AccessKey); err != nil {
return err
}
if err := validate.MinLength("accessKey", "body", string(*m.AccessKey), 3); err != nil {
return err
}
return nil
}
func (m *CreateRemoteBucket) validateSecretKey(formats strfmt.Registry) error {
if err := validate.Required("secretKey", "body", m.SecretKey); err != nil {
return err
}
if err := validate.MinLength("secretKey", "body", string(*m.SecretKey), 8); err != nil {
return err
}
return nil
}
func (m *CreateRemoteBucket) validateSourceBucket(formats strfmt.Registry) error {
if err := validate.Required("sourceBucket", "body", m.SourceBucket); err != nil {
return err
}
return nil
}
func (m *CreateRemoteBucket) validateTargetBucket(formats strfmt.Registry) error {
if err := validate.Required("targetBucket", "body", m.TargetBucket); err != nil {
return err
}
return nil
}
func (m *CreateRemoteBucket) validateTargetURL(formats strfmt.Registry) error {
if err := validate.Required("targetURL", "body", m.TargetURL); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *CreateRemoteBucket) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *CreateRemoteBucket) UnmarshalBinary(b []byte) error {
var res CreateRemoteBucket
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -42,6 +42,9 @@ type CreateTenantRequest struct {
// annotations
Annotations map[string]string `json:"annotations,omitempty"`
// console
Console *ConsoleConfiguration `json:"console,omitempty"`
// console image
ConsoleImage string `json:"console_image,omitempty"`
@@ -90,9 +93,6 @@ type CreateTenantRequest struct {
// secret key
SecretKey string `json:"secret_key,omitempty"`
// service name
ServiceName string `json:"service_name,omitempty"`
// tls
TLS *TLSConfiguration `json:"tls,omitempty"`
@@ -105,6 +105,10 @@ type CreateTenantRequest struct {
func (m *CreateTenantRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateConsole(formats); err != nil {
res = append(res, err)
}
if err := m.validateEncryption(formats); err != nil {
res = append(res, err)
}
@@ -139,6 +143,24 @@ func (m *CreateTenantRequest) Validate(formats strfmt.Registry) error {
return nil
}
func (m *CreateTenantRequest) validateConsole(formats strfmt.Registry) error {
if swag.IsZero(m.Console) { // not required
return nil
}
if m.Console != nil {
if err := m.Console.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("console")
}
return err
}
}
return nil
}
func (m *CreateTenantRequest) validateEncryption(formats strfmt.Registry) error {
if swag.IsZero(m.Encryption) { // not required

View File

@@ -32,6 +32,7 @@ import (
//
// swagger:model encryptionConfiguration
type EncryptionConfiguration struct {
MetadataFields
// aws
Aws *AwsConfiguration `json:"aws,omitempty"`
@@ -52,10 +53,100 @@ type EncryptionConfiguration struct {
Vault *VaultConfiguration `json:"vault,omitempty"`
}
// UnmarshalJSON unmarshals this object from a JSON structure
func (m *EncryptionConfiguration) UnmarshalJSON(raw []byte) error {
// AO0
var aO0 MetadataFields
if err := swag.ReadJSON(raw, &aO0); err != nil {
return err
}
m.MetadataFields = aO0
// AO1
var dataAO1 struct {
Aws *AwsConfiguration `json:"aws,omitempty"`
Client *KeyPairConfiguration `json:"client,omitempty"`
Gemalto *GemaltoConfiguration `json:"gemalto,omitempty"`
Image string `json:"image,omitempty"`
Server *KeyPairConfiguration `json:"server,omitempty"`
Vault *VaultConfiguration `json:"vault,omitempty"`
}
if err := swag.ReadJSON(raw, &dataAO1); err != nil {
return err
}
m.Aws = dataAO1.Aws
m.Client = dataAO1.Client
m.Gemalto = dataAO1.Gemalto
m.Image = dataAO1.Image
m.Server = dataAO1.Server
m.Vault = dataAO1.Vault
return nil
}
// MarshalJSON marshals this object to a JSON structure
func (m EncryptionConfiguration) MarshalJSON() ([]byte, error) {
_parts := make([][]byte, 0, 2)
aO0, err := swag.WriteJSON(m.MetadataFields)
if err != nil {
return nil, err
}
_parts = append(_parts, aO0)
var dataAO1 struct {
Aws *AwsConfiguration `json:"aws,omitempty"`
Client *KeyPairConfiguration `json:"client,omitempty"`
Gemalto *GemaltoConfiguration `json:"gemalto,omitempty"`
Image string `json:"image,omitempty"`
Server *KeyPairConfiguration `json:"server,omitempty"`
Vault *VaultConfiguration `json:"vault,omitempty"`
}
dataAO1.Aws = m.Aws
dataAO1.Client = m.Client
dataAO1.Gemalto = m.Gemalto
dataAO1.Image = m.Image
dataAO1.Server = m.Server
dataAO1.Vault = m.Vault
jsonDataAO1, errAO1 := swag.WriteJSON(dataAO1)
if errAO1 != nil {
return nil, errAO1
}
_parts = append(_parts, jsonDataAO1)
return swag.ConcatJSON(_parts...), nil
}
// Validate validates this encryption configuration
func (m *EncryptionConfiguration) Validate(formats strfmt.Registry) error {
var res []error
// validation for a type composition with MetadataFields
if err := m.MetadataFields.Validate(formats); err != nil {
res = append(res, err)
}
if err := m.validateAws(formats); err != nil {
res = append(res, err)
}

View File

@@ -0,0 +1,100 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ListObjectsResponse list objects response
//
// swagger:model listObjectsResponse
type ListObjectsResponse struct {
// list of resulting objects
Objects []*BucketObject `json:"objects"`
// number of objects
Total int64 `json:"total,omitempty"`
}
// Validate validates this list objects response
func (m *ListObjectsResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateObjects(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ListObjectsResponse) validateObjects(formats strfmt.Registry) error {
if swag.IsZero(m.Objects) { // not required
return nil
}
for i := 0; i < len(m.Objects); i++ {
if swag.IsZero(m.Objects[i]) { // not required
continue
}
if m.Objects[i] != nil {
if err := m.Objects[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("objects" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ListObjectsResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ListObjectsResponse) UnmarshalBinary(b []byte) error {
var res ListObjectsResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,100 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ListRemoteBucketsResponse list remote buckets response
//
// swagger:model listRemoteBucketsResponse
type ListRemoteBucketsResponse struct {
// list of remote buckets
Buckets []*RemoteBucket `json:"buckets"`
// number of remote buckets accessible to user
Total int64 `json:"total,omitempty"`
}
// Validate validates this list remote buckets response
func (m *ListRemoteBucketsResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateBuckets(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ListRemoteBucketsResponse) validateBuckets(formats strfmt.Registry) error {
if swag.IsZero(m.Buckets) { // not required
return nil
}
for i := 0; i < len(m.Buckets); i++ {
if swag.IsZero(m.Buckets[i]) { // not required
continue
}
if m.Buckets[i] != nil {
if err := m.Buckets[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("buckets" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ListRemoteBucketsResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ListRemoteBucketsResponse) UnmarshalBinary(b []byte) error {
var res ListRemoteBucketsResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -37,6 +37,12 @@ type MakeBucketRequest struct {
// name
// Required: true
Name *string `json:"name"`
// quota
Quota *SetBucketQuota `json:"quota,omitempty"`
// versioning
Versioning bool `json:"versioning,omitempty"`
}
// Validate validates this make bucket request
@@ -47,6 +53,10 @@ func (m *MakeBucketRequest) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateQuota(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
@@ -62,6 +72,24 @@ func (m *MakeBucketRequest) validateName(formats strfmt.Registry) error {
return nil
}
func (m *MakeBucketRequest) validateQuota(formats strfmt.Registry) error {
if swag.IsZero(m.Quota) { // not required
return nil
}
if m.Quota != nil {
if err := m.Quota.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("quota")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *MakeBucketRequest) MarshalBinary() ([]byte, error) {
if m == nil {

66
models/metadata_fields.go Normal file
View File

@@ -0,0 +1,66 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// MetadataFields metadata fields
//
// swagger:model metadataFields
type MetadataFields struct {
// annotations
Annotations map[string]string `json:"annotations,omitempty"`
// labels
Labels map[string]string `json:"labels,omitempty"`
// node selector
NodeSelector map[string]string `json:"node_selector,omitempty"`
}
// Validate validates this metadata fields
func (m *MetadataFields) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *MetadataFields) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *MetadataFields) UnmarshalBinary(b []byte) error {
var res MetadataFields
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,80 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
)
// ObjectLegalHoldStatus object legal hold status
//
// swagger:model objectLegalHoldStatus
type ObjectLegalHoldStatus string
const (
// ObjectLegalHoldStatusEnabled captures enum value "enabled"
ObjectLegalHoldStatusEnabled ObjectLegalHoldStatus = "enabled"
// ObjectLegalHoldStatusDisabled captures enum value "disabled"
ObjectLegalHoldStatusDisabled ObjectLegalHoldStatus = "disabled"
)
// for schema
var objectLegalHoldStatusEnum []interface{}
func init() {
var res []ObjectLegalHoldStatus
if err := json.Unmarshal([]byte(`["enabled","disabled"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
objectLegalHoldStatusEnum = append(objectLegalHoldStatusEnum, v)
}
}
func (m ObjectLegalHoldStatus) validateObjectLegalHoldStatusEnum(path, location string, value ObjectLegalHoldStatus) error {
if err := validate.EnumCase(path, location, value, objectLegalHoldStatusEnum, true); err != nil {
return err
}
return nil
}
// Validate validates this object legal hold status
func (m ObjectLegalHoldStatus) Validate(formats strfmt.Registry) error {
var res []error
// value enum
if err := m.validateObjectLegalHoldStatusEnum("", "body", m); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,80 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
)
// ObjectRetentionMode object retention mode
//
// swagger:model objectRetentionMode
type ObjectRetentionMode string
const (
// ObjectRetentionModeGovernance captures enum value "governance"
ObjectRetentionModeGovernance ObjectRetentionMode = "governance"
// ObjectRetentionModeCompliance captures enum value "compliance"
ObjectRetentionModeCompliance ObjectRetentionMode = "compliance"
)
// for schema
var objectRetentionModeEnum []interface{}
func init() {
var res []ObjectRetentionMode
if err := json.Unmarshal([]byte(`["governance","compliance"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
objectRetentionModeEnum = append(objectRetentionModeEnum, v)
}
}
func (m ObjectRetentionMode) validateObjectRetentionModeEnum(path, location string, value ObjectRetentionMode) error {
if err := validate.EnumCase(path, location, value, objectRetentionModeEnum, true); err != nil {
return err
}
return nil
}
// Validate validates this object retention mode
func (m ObjectRetentionMode) Validate(formats strfmt.Registry) error {
var res []error
// value enum
if err := m.validateObjectRetentionModeEnum("", "body", m); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

37
models/parity_response.go Normal file
View File

@@ -0,0 +1,37 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
)
// ParityResponse parity response
//
// swagger:model parityResponse
type ParityResponse []string
// Validate validates this parity response
func (m ParityResponse) Validate(formats strfmt.Registry) error {
return nil
}

View File

@@ -0,0 +1,83 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// PutObjectLegalHoldRequest put object legal hold request
//
// swagger:model putObjectLegalHoldRequest
type PutObjectLegalHoldRequest struct {
// status
// Required: true
Status ObjectLegalHoldStatus `json:"status"`
}
// Validate validates this put object legal hold request
func (m *PutObjectLegalHoldRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateStatus(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PutObjectLegalHoldRequest) validateStatus(formats strfmt.Registry) error {
if err := m.Status.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("status")
}
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *PutObjectLegalHoldRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PutObjectLegalHoldRequest) UnmarshalBinary(b []byte) error {
var res PutObjectLegalHoldRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,104 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// PutObjectRetentionRequest put object retention request
//
// swagger:model putObjectRetentionRequest
type PutObjectRetentionRequest struct {
// expires
// Required: true
Expires *string `json:"expires"`
// governance bypass
GovernanceBypass bool `json:"governance_bypass,omitempty"`
// mode
// Required: true
Mode ObjectRetentionMode `json:"mode"`
}
// Validate validates this put object retention request
func (m *PutObjectRetentionRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateExpires(formats); err != nil {
res = append(res, err)
}
if err := m.validateMode(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PutObjectRetentionRequest) validateExpires(formats strfmt.Registry) error {
if err := validate.Required("expires", "body", m.Expires); err != nil {
return err
}
return nil
}
func (m *PutObjectRetentionRequest) validateMode(formats strfmt.Registry) error {
if err := m.Mode.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("mode")
}
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *PutObjectRetentionRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PutObjectRetentionRequest) UnmarshalBinary(b []byte) error {
var res PutObjectRetentionRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,60 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// PutObjectTagsRequest put object tags request
//
// swagger:model putObjectTagsRequest
type PutObjectTagsRequest struct {
// tags
Tags map[string]string `json:"tags,omitempty"`
}
// Validate validates this put object tags request
func (m *PutObjectTagsRequest) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *PutObjectTagsRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PutObjectTagsRequest) UnmarshalBinary(b []byte) error {
var res PutObjectTagsRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

200
models/remote_bucket.go Normal file
View File

@@ -0,0 +1,200 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// RemoteBucket remote bucket
//
// swagger:model remoteBucket
type RemoteBucket struct {
// access key
// Required: true
// Min Length: 3
AccessKey *string `json:"accessKey"`
// remote a r n
// Required: true
RemoteARN *string `json:"remoteARN"`
// secret key
// Min Length: 8
SecretKey string `json:"secretKey,omitempty"`
// service
// Enum: [replication]
Service string `json:"service,omitempty"`
// source bucket
// Required: true
SourceBucket *string `json:"sourceBucket"`
// status
Status string `json:"status,omitempty"`
// target bucket
TargetBucket string `json:"targetBucket,omitempty"`
// target URL
TargetURL string `json:"targetURL,omitempty"`
}
// Validate validates this remote bucket
func (m *RemoteBucket) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAccessKey(formats); err != nil {
res = append(res, err)
}
if err := m.validateRemoteARN(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecretKey(formats); err != nil {
res = append(res, err)
}
if err := m.validateService(formats); err != nil {
res = append(res, err)
}
if err := m.validateSourceBucket(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *RemoteBucket) validateAccessKey(formats strfmt.Registry) error {
if err := validate.Required("accessKey", "body", m.AccessKey); err != nil {
return err
}
if err := validate.MinLength("accessKey", "body", string(*m.AccessKey), 3); err != nil {
return err
}
return nil
}
func (m *RemoteBucket) validateRemoteARN(formats strfmt.Registry) error {
if err := validate.Required("remoteARN", "body", m.RemoteARN); err != nil {
return err
}
return nil
}
func (m *RemoteBucket) validateSecretKey(formats strfmt.Registry) error {
if swag.IsZero(m.SecretKey) { // not required
return nil
}
if err := validate.MinLength("secretKey", "body", string(m.SecretKey), 8); err != nil {
return err
}
return nil
}
var remoteBucketTypeServicePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["replication"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
remoteBucketTypeServicePropEnum = append(remoteBucketTypeServicePropEnum, v)
}
}
const (
// RemoteBucketServiceReplication captures enum value "replication"
RemoteBucketServiceReplication string = "replication"
)
// prop value enum
func (m *RemoteBucket) validateServiceEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, remoteBucketTypeServicePropEnum, true); err != nil {
return err
}
return nil
}
func (m *RemoteBucket) validateService(formats strfmt.Registry) error {
if swag.IsZero(m.Service) { // not required
return nil
}
// value enum
if err := m.validateServiceEnum("service", "body", m.Service); err != nil {
return err
}
return nil
}
func (m *RemoteBucket) validateSourceBucket(formats strfmt.Registry) error {
if err := validate.Required("sourceBucket", "body", m.SourceBucket); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *RemoteBucket) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *RemoteBucket) UnmarshalBinary(b []byte) error {
var res RemoteBucket
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

137
models/set_bucket_quota.go Normal file
View File

@@ -0,0 +1,137 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// SetBucketQuota set bucket quota
//
// swagger:model setBucketQuota
type SetBucketQuota struct {
// amount
Amount int64 `json:"amount,omitempty"`
// enabled
// Required: true
Enabled *bool `json:"enabled"`
// quota type
// Enum: [fifo hard]
QuotaType string `json:"quota_type,omitempty"`
}
// Validate validates this set bucket quota
func (m *SetBucketQuota) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateEnabled(formats); err != nil {
res = append(res, err)
}
if err := m.validateQuotaType(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *SetBucketQuota) validateEnabled(formats strfmt.Registry) error {
if err := validate.Required("enabled", "body", m.Enabled); err != nil {
return err
}
return nil
}
var setBucketQuotaTypeQuotaTypePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["fifo","hard"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
setBucketQuotaTypeQuotaTypePropEnum = append(setBucketQuotaTypeQuotaTypePropEnum, v)
}
}
const (
// SetBucketQuotaQuotaTypeFifo captures enum value "fifo"
SetBucketQuotaQuotaTypeFifo string = "fifo"
// SetBucketQuotaQuotaTypeHard captures enum value "hard"
SetBucketQuotaQuotaTypeHard string = "hard"
)
// prop value enum
func (m *SetBucketQuota) validateQuotaTypeEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, setBucketQuotaTypeQuotaTypePropEnum, true); err != nil {
return err
}
return nil
}
func (m *SetBucketQuota) validateQuotaType(formats strfmt.Registry) error {
if swag.IsZero(m.QuotaType) { // not required
return nil
}
// value enum
if err := m.validateQuotaTypeEnum("quota_type", "body", m.QuotaType); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *SetBucketQuota) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SetBucketQuota) UnmarshalBinary(b []byte) error {
var res SetBucketQuota
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,60 @@
// 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 <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// SetBucketVersioning set bucket versioning
//
// swagger:model setBucketVersioning
type SetBucketVersioning struct {
// versioning
Versioning bool `json:"versioning,omitempty"`
}
// Validate validates this set bucket versioning
func (m *SetBucketVersioning) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *SetBucketVersioning) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SetBucketVersioning) UnmarshalBinary(b []byte) error {
var res SetBucketVersioning
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -23,6 +23,8 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
@@ -37,7 +39,7 @@ type TLSConfiguration struct {
Console *KeyPairConfiguration `json:"console,omitempty"`
// minio
Minio *KeyPairConfiguration `json:"minio,omitempty"`
Minio []*KeyPairConfiguration `json:"minio"`
}
// Validate validates this tls configuration
@@ -82,13 +84,20 @@ func (m *TLSConfiguration) validateMinio(formats strfmt.Registry) error {
return nil
}
if m.Minio != nil {
if err := m.Minio.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("minio")
}
return err
for i := 0; i < len(m.Minio); i++ {
if swag.IsZero(m.Minio[i]) { // not required
continue
}
if m.Minio[i] != nil {
if err := m.Minio[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("minio" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil

3
package-lock.json generated
View File

@@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}

View File

@@ -22,22 +22,26 @@ import (
// endpoints definition
var (
configuration = "/configurations-list"
users = "/users"
groups = "/groups"
iamPolicies = "/policies"
dashboard = "/dashboard"
profiling = "/profiling"
trace = "/trace"
logs = "/logs"
watch = "/watch"
notifications = "/notification-endpoints"
buckets = "/buckets"
bucketsDetail = "/buckets/:bucketName"
serviceAccounts = "/service-accounts"
tenants = "/tenants"
tenantsDetail = "/namespaces/:tenantNamespace/tenants/:tenantName"
heal = "/heal"
configuration = "/configurations-list"
users = "/users"
groups = "/groups"
iamPolicies = "/policies"
dashboard = "/dashboard"
profiling = "/profiling"
watch = "/watch"
notifications = "/notification-endpoints"
buckets = "/buckets"
bucketsDetail = "/buckets/:bucketName"
serviceAccounts = "/service-accounts"
tenants = "/tenants"
tenantsDetail = "/namespaces/:tenantNamespace/tenants/:tenantName"
heal = "/heal"
remoteBuckets = "/remote-buckets"
replication = "/replication"
objectBrowser = "/object-browser/:bucket/*"
objectBrowserBucket = "/object-browser/:bucket"
mainObjectBrowser = "/object-browser"
license = "/license"
)
type ConfigurationActionSet struct {
@@ -55,16 +59,6 @@ var configurationActionSet = ConfigurationActionSet{
),
}
// logsActionSet contains the list of admin actions required for this endpoint to work
var logsActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(
iampolicy.AllAdminActions,
),
actions: iampolicy.NewActionSet(
iampolicy.ConsoleLogAdminAction,
),
}
// dashboardActionSet contains the list of admin actions required for this endpoint to work
var dashboardActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(
@@ -113,16 +107,6 @@ var profilingActionSet = ConfigurationActionSet{
),
}
// traceActionSet contains the list of admin actions required for this endpoint to work
var traceActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(
iampolicy.AllAdminActions,
),
actions: iampolicy.NewActionSet(
iampolicy.TraceAdminAction,
),
}
// usersActionSet contains the list of admin actions required for this endpoint to work
var usersActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(
@@ -208,22 +192,56 @@ var healActionSet = ConfigurationActionSet{
),
}
var remoteBucketsActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(
iampolicy.AllAdminActions,
),
actions: iampolicy.NewActionSet(
iampolicy.ConfigUpdateAdminAction,
),
}
var replicationActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(
iampolicy.AllAdminActions,
),
actions: iampolicy.NewActionSet(
iampolicy.ConfigUpdateAdminAction,
),
}
// objectBrowserActionSet no actions needed for this module to work
var objectBrowserActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(),
actions: iampolicy.NewActionSet(),
}
// licenseActionSet no actions needed for this module to work
var licenseActionSet = ConfigurationActionSet{
actionTypes: iampolicy.NewActionSet(),
actions: iampolicy.NewActionSet(),
}
// endpointRules contains the mapping between endpoints and ActionSets, additional rules can be added here
var endpointRules = map[string]ConfigurationActionSet{
configuration: configurationActionSet,
users: usersActionSet,
groups: groupsActionSet,
iamPolicies: iamPoliciesActionSet,
dashboard: dashboardActionSet,
profiling: profilingActionSet,
trace: traceActionSet,
logs: logsActionSet,
watch: watchActionSet,
notifications: notificationsActionSet,
buckets: bucketsActionSet,
bucketsDetail: bucketsActionSet,
serviceAccounts: serviceAccountsActionSet,
heal: healActionSet,
configuration: configurationActionSet,
users: usersActionSet,
groups: groupsActionSet,
iamPolicies: iamPoliciesActionSet,
dashboard: dashboardActionSet,
profiling: profilingActionSet,
watch: watchActionSet,
notifications: notificationsActionSet,
buckets: bucketsActionSet,
bucketsDetail: bucketsActionSet,
serviceAccounts: serviceAccountsActionSet,
heal: healActionSet,
remoteBuckets: remoteBucketsActionSet,
replication: replicationActionSet,
objectBrowser: objectBrowserActionSet,
mainObjectBrowser: objectBrowserActionSet,
objectBrowserBucket: objectBrowserActionSet,
license: licenseActionSet,
}
// operatorRules contains the mapping between endpoints and ActionSets for operator only mode

View File

@@ -50,7 +50,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
args: args{
[]string{"admin:ServerInfo"},
},
want: 2,
want: 6,
},
{
name: "policies endpoint",
@@ -63,7 +63,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"admin:ListUserPolicies",
},
},
want: 2,
want: 6,
},
{
name: "all admin endpoints",
@@ -72,7 +72,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"admin:*",
},
},
want: 11,
want: 15,
},
{
name: "all s3 endpoints",
@@ -81,7 +81,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"s3:*",
},
},
want: 4,
want: 8,
},
{
name: "all admin and s3 endpoints",
@@ -91,7 +91,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
"s3:*",
},
},
want: 14,
want: 18,
},
{
name: "no endpoints",

View File

@@ -155,10 +155,10 @@ const (
// or data key provided as plaintext.
//
// The returned ciphertext data consists of:
// iv | AEAD ID | nonce | encrypted data
// 32 1 12 ~ len(data)
// AEAD ID | iv | nonce | encrypted data
// 1 16 12 ~ len(data)
func encrypt(plaintext, associatedData []byte) ([]byte, error) {
iv, err := sioutil.Random(32) // 32 bytes IV
iv, err := sioutil.Random(16) // 16 bytes IV
if err != nil {
return nil, err
}
@@ -186,7 +186,7 @@ func encrypt(plaintext, associatedData []byte) ([]byte, error) {
}
case c20p1305:
var sealingKey []byte
sealingKey, err = chacha20.HChaCha20(derivedKey, iv[:16]) // HChaCha20 expects nonce of 16 bytes
sealingKey, err = chacha20.HChaCha20(derivedKey, iv) // HChaCha20 expects nonce of 16 bytes
if err != nil {
return nil, err
}
@@ -202,11 +202,11 @@ func encrypt(plaintext, associatedData []byte) ([]byte, error) {
sealedBytes := aead.Seal(nil, nonce, plaintext, associatedData)
// ciphertext = iv | AEAD ID | nonce | sealed bytes
// ciphertext = AEAD ID | iv | nonce | sealed bytes
var buf bytes.Buffer
buf.Write(iv)
buf.WriteByte(algorithm)
buf.Write(iv)
buf.Write(nonce)
buf.Write(sealedBytes)
@@ -218,16 +218,16 @@ func encrypt(plaintext, associatedData []byte) ([]byte, error) {
// and a pbkdf2 derived key
func decrypt(ciphertext []byte, associatedData []byte) ([]byte, error) {
var (
iv [32]byte
algorithm [1]byte
iv [16]byte
nonce [12]byte // This depends on the AEAD but both used ciphers have the same nonce length.
)
r := bytes.NewReader(ciphertext)
if _, err := io.ReadFull(r, iv[:]); err != nil {
if _, err := io.ReadFull(r, algorithm[:]); err != nil {
return nil, err
}
if _, err := io.ReadFull(r, algorithm[:]); err != nil {
if _, err := io.ReadFull(r, iv[:]); err != nil {
return nil, err
}
if _, err := io.ReadFull(r, nonce[:]); err != nil {
@@ -249,7 +249,7 @@ func decrypt(ciphertext []byte, associatedData []byte) ([]byte, error) {
return nil, err
}
case c20p1305:
sealingKey, err := chacha20.HChaCha20(derivedKey, iv[:16]) // HChaCha20 expects nonce of 16 bytes
sealingKey, err := chacha20.HChaCha20(derivedKey, iv[:]) // HChaCha20 expects nonce of 16 bytes
if err != nil {
return nil, err
}

View File

@@ -23,10 +23,9 @@ import (
"github.com/minio/minio/pkg/env"
)
// ConsoleSTSAndJWTDurationSeconds returns the default session duration for the STS requested tokens and the generated JWTs.
// Ideally both values should match so jwt and Minio sts sessions expires at the same time.
func GetConsoleSTSAndJWTDurationInSeconds() int {
duration, err := strconv.Atoi(env.Get(ConsoleSTSAndJWTDurationSeconds, "3600"))
// ConsoleSTSDurationSeconds returns the default session duration for the STS requested tokens.
func GetConsoleSTSDurationInSeconds() int {
duration, err := strconv.Atoi(env.Get(ConsoleSTSDurationSeconds, "3600"))
if err != nil {
duration = 3600
}

View File

@@ -17,7 +17,7 @@
package token
const (
ConsoleSTSAndJWTDurationSeconds = "CONSOLE_STS_AND_JWT_DURATION_SECONDS"
ConsolePBKDFPassphrase = "CONSOLE_PBKDF_PASSPHRASE"
ConsolePBKDFSalt = "CONSOLE_PBKDF_SALT"
ConsoleSTSDurationSeconds = "CONSOLE_STS_DURATION_SECONDS"
ConsolePBKDFPassphrase = "CONSOLE_PBKDF_PASSPHRASE"
ConsolePBKDFSalt = "CONSOLE_PBKDF_SALT"
)

View File

@@ -60,17 +60,17 @@ func TestJWTAuthenticate(t *testing.T) {
funcAssert.Equal(claims.SecretAccessKey, creds.SecretAccessKey)
funcAssert.Equal(claims.SessionToken, creds.SessionToken)
}
// Test-2 : SessionTokenAuthenticate() return an error because of a tampered jwt
// Test-2 : SessionTokenAuthenticate() return an error because of a tampered token
if _, err := SessionTokenAuthenticate(badToken); err != nil {
funcAssert.Equal("session token internal data is malformed", err.Error())
}
// Test-3 : SessionTokenAuthenticate() return an error because of an empty jwt
// Test-3 : SessionTokenAuthenticate() return an error because of an empty token
if _, err := SessionTokenAuthenticate(""); err != nil {
funcAssert.Equal("session token missing", err.Error())
}
}
func TestIsJWTValid(t *testing.T) {
func TestSessionTokenValid(t *testing.T) {
funcAssert := assert.New(t)
// Test-1 : SessionTokenAuthenticate() provided token is valid
funcAssert.Equal(true, IsSessionTokenValid(goodToken))

222
pkg/certs/certs.go Normal file
View File

@@ -0,0 +1,222 @@
// 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 <http://www.gnu.org/licenses/>.
package certs
import (
"context"
"crypto/x509"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/minio/cli"
"github.com/minio/minio/cmd/config"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/certs"
"github.com/mitchellh/go-homedir"
)
type GetCertificateFunc = certs.GetCertificateFunc
// ConfigDir - points to a user set directory.
type ConfigDir struct {
Path string
}
// Get - returns current directory.
func (dir *ConfigDir) Get() string {
return dir.Path
}
func getDefaultConfigDir() string {
homeDir, err := homedir.Dir()
if err != nil {
return ""
}
return filepath.Join(homeDir, DefaultConsoleConfigDir)
}
func getDefaultCertsDir() string {
return filepath.Join(getDefaultConfigDir(), CertsDir)
}
func getDefaultCertsCADir() string {
return filepath.Join(getDefaultCertsDir(), CertsCADir)
}
// isFile - returns whether given Path is a file or not.
func isFile(path string) bool {
if fi, err := os.Stat(path); err == nil {
return fi.Mode().IsRegular()
}
return false
}
var (
// DefaultCertsDir certs directory.
DefaultCertsDir = &ConfigDir{Path: getDefaultCertsDir()}
// DefaultCertsCADir CA directory.
DefaultCertsCADir = &ConfigDir{Path: getDefaultCertsCADir()}
// GlobalCertsDir points to current certs directory set by user with --certs-dir
GlobalCertsDir = DefaultCertsDir
// GlobalCertsCADir points to relative Path to certs directory and is <value-of-certs-dir>/CAs
GlobalCertsCADir = DefaultCertsCADir
)
// MkdirAllIgnorePerm attempts to create all directories, ignores any permission denied errors.
func MkdirAllIgnorePerm(path string) error {
err := os.MkdirAll(path, 0700)
if err != nil {
// It is possible in kubernetes like deployments this directory
// is already mounted and is not writable, ignore any write errors.
if os.IsPermission(err) {
err = nil
}
}
return err
}
func NewConfigDirFromCtx(ctx *cli.Context, option string, getDefaultDir func() string) (*ConfigDir, bool) {
var dir string
var dirSet bool
switch {
case ctx.IsSet(option):
dir = ctx.String(option)
dirSet = true
case ctx.GlobalIsSet(option):
dir = ctx.GlobalString(option)
dirSet = true
// cli package does not expose parent's option option. Below code is workaround.
if dir == "" || dir == getDefaultDir() {
dirSet = false // Unset to false since GlobalIsSet() true is a false positive.
if ctx.Parent().GlobalIsSet(option) {
dir = ctx.Parent().GlobalString(option)
dirSet = true
}
}
default:
// Neither local nor global option is provided. In this case, try to use
// default directory.
dir = getDefaultDir()
if dir == "" {
logger.FatalIf(errors.New("invalid arguments specified"), "%s option must be provided", option)
}
}
if dir == "" {
logger.FatalIf(errors.New("empty directory"), "%s directory cannot be empty", option)
}
// Disallow relative paths, figure out absolute paths.
dirAbs, err := filepath.Abs(dir)
logger.FatalIf(err, "Unable to fetch absolute path for %s=%s", option, dir)
logger.FatalIf(MkdirAllIgnorePerm(dirAbs), "Unable to create directory specified %s=%s", option, dir)
return &ConfigDir{Path: dirAbs}, dirSet
}
func getPublicCertFile() string {
return filepath.Join(GlobalCertsDir.Get(), PublicCertFile)
}
func getPrivateKeyFile() string {
return filepath.Join(GlobalCertsDir.Get(), PrivateKeyFile)
}
func GetTLSConfig() (x509Certs []*x509.Certificate, manager *certs.Manager, err error) {
ctx := context.Background()
if !(isFile(getPublicCertFile()) && isFile(getPrivateKeyFile())) {
return nil, nil, nil
}
if x509Certs, err = config.ParsePublicCertFile(getPublicCertFile()); err != nil {
return nil, nil, err
}
manager, err = certs.NewManager(ctx, getPublicCertFile(), getPrivateKeyFile(), config.LoadX509KeyPair)
if err != nil {
return nil, nil, err
}
//Console has support for multiple certificates. It expects the following structure:
// certs/
// │
// ├─ public.crt
// ├─ private.key
// │
// ├─ example.com/
// │ │
// │ ├─ public.crt
// │ └─ private.key
// └─ foobar.org/
// │
// ├─ public.crt
// └─ private.key
// ...
//
//Therefore, we read all filenames in the cert directory and check
//for each directory whether it contains a public.crt and private.key.
// If so, we try to add it to certificate manager.
root, err := os.Open(GlobalCertsDir.Get())
if err != nil {
return nil, nil, err
}
defer root.Close()
files, err := root.Readdir(-1)
if err != nil {
return nil, nil, err
}
for _, file := range files {
// Ignore all
// - regular files
// - "CAs" directory
// - any directory which starts with ".."
if file.Mode().IsRegular() || file.Name() == "CAs" || strings.HasPrefix(file.Name(), "..") {
continue
}
if file.Mode()&os.ModeSymlink == os.ModeSymlink {
file, err = os.Stat(filepath.Join(root.Name(), file.Name()))
if err != nil {
// not accessible ignore
continue
}
if !file.IsDir() {
continue
}
}
var (
certFile = filepath.Join(root.Name(), file.Name(), PublicCertFile)
keyFile = filepath.Join(root.Name(), file.Name(), PrivateKeyFile)
)
if !isFile(certFile) || !isFile(keyFile) {
continue
}
if err = manager.AddCertificate(certFile, keyFile); err != nil {
err = fmt.Errorf("unable to load TLS certificate '%s,%s': %w", certFile, keyFile, err)
logger.LogIf(ctx, err, logger.Application)
}
}
return x509Certs, manager, nil
}

34
pkg/certs/const.go Normal file
View File

@@ -0,0 +1,34 @@
// 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 <http://www.gnu.org/licenses/>.
package certs
const (
// Default minio configuration directory where below configuration files/directories are stored.
DefaultConsoleConfigDir = ".console"
// Directory contains below files/directories for HTTPS configuration.
CertsDir = "certs"
// Directory contains all CA certificates other than system defaults for HTTPS.
CertsCADir = "CAs"
// Public certificate file for HTTPS.
PublicCertFile = "public.crt"
// Private key file for HTTPS.
PrivateKeyFile = "private.key"
)

219
pkg/utils/parity.go Normal file
View File

@@ -0,0 +1,219 @@
// 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 <http://www.gnu.org/licenses/>.
package utils
import (
"errors"
"fmt"
"sort"
"github.com/minio/minio/pkg/ellipses"
)
// This file implements and supports ellipses pattern for
// `minio server` command line arguments.
// Supported set sizes this is used to find the optimal
// single set size.
var setSizes = []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
// getDivisibleSize - returns a greatest common divisor of
// all the ellipses sizes.
func getDivisibleSize(totalSizes []uint64) (result uint64) {
gcd := func(x, y uint64) uint64 {
for y != 0 {
x, y = y, x%y
}
return x
}
result = totalSizes[0]
for i := 1; i < len(totalSizes); i++ {
result = gcd(result, totalSizes[i])
}
return result
}
// isValidSetSize - checks whether given count is a valid set size for erasure coding.
var isValidSetSize = func(count uint64) bool {
return (count >= setSizes[0] && count <= setSizes[len(setSizes)-1])
}
// possibleSetCountsWithSymmetry returns symmetrical setCounts based on the
// input argument patterns, the symmetry calculation is to ensure that
// we also use uniform number of drives common across all ellipses patterns.
func possibleSetCountsWithSymmetry(setCounts []uint64, argPatterns []ellipses.ArgPattern) []uint64 {
var newSetCounts = make(map[uint64]struct{})
for _, ss := range setCounts {
var symmetry bool
for _, argPattern := range argPatterns {
for _, p := range argPattern {
if uint64(len(p.Seq)) > ss {
symmetry = uint64(len(p.Seq))%ss == 0
} else {
symmetry = ss%uint64(len(p.Seq)) == 0
}
}
}
// With no arg patterns, it is expected that user knows
// the right symmetry, so either ellipses patterns are
// provided (recommended) or no ellipses patterns.
if _, ok := newSetCounts[ss]; !ok && (symmetry || argPatterns == nil) {
newSetCounts[ss] = struct{}{}
}
}
setCounts = []uint64{}
for setCount := range newSetCounts {
setCounts = append(setCounts, setCount)
}
// Not necessarily needed but it ensures to the readers
// eyes that we prefer a sorted setCount slice for the
// subsequent function to figure out the right common
// divisor, it avoids loops.
sort.Slice(setCounts, func(i, j int) bool {
return setCounts[i] < setCounts[j]
})
return setCounts
}
func commonSetDriveCount(divisibleSize uint64, setCounts []uint64) (setSize uint64) {
// prefers setCounts to be sorted for optimal behavior.
if divisibleSize < setCounts[len(setCounts)-1] {
return divisibleSize
}
// Figure out largest value of total_drives_in_erasure_set which results
// in least number of total_drives/total_drives_erasure_set ratio.
prevD := divisibleSize / setCounts[0]
for _, cnt := range setCounts {
if divisibleSize%cnt == 0 {
d := divisibleSize / cnt
if d <= prevD {
prevD = d
setSize = cnt
}
}
}
return setSize
}
// getSetIndexes returns list of indexes which provides the set size
// on each index, this function also determines the final set size
// The final set size has the affinity towards choosing smaller
// indexes (total sets)
func getSetIndexes(args []string, totalSizes []uint64, argPatterns []ellipses.ArgPattern) (setIndexes [][]uint64, err error) {
if len(totalSizes) == 0 || len(args) == 0 {
return nil, errors.New("invalid argument")
}
setIndexes = make([][]uint64, len(totalSizes))
for _, totalSize := range totalSizes {
// Check if totalSize has minimum range upto setSize
if totalSize < setSizes[0] {
return nil, fmt.Errorf("incorrect number of endpoints provided %s", args)
}
}
commonSize := getDivisibleSize(totalSizes)
possibleSetCounts := func(setSize uint64) (ss []uint64) {
for _, s := range setSizes {
if setSize%s == 0 {
ss = append(ss, s)
}
}
return ss
}
setCounts := possibleSetCounts(commonSize)
if len(setCounts) == 0 {
err = fmt.Errorf("incorrect number of endpoints provided %s, number of disks %d is not divisible by any supported erasure set sizes %d", args, commonSize, setSizes)
return nil, err
}
// Returns possible set counts with symmetry.
setCounts = possibleSetCountsWithSymmetry(setCounts, argPatterns)
if len(setCounts) == 0 {
err = fmt.Errorf("no symmetric distribution detected with input endpoints provided %s, disks %d cannot be spread symmetrically by any supported erasure set sizes %d", args, commonSize, setSizes)
return nil, err
}
// Final set size with all the symmetry accounted for.
setSize := commonSetDriveCount(commonSize, setCounts)
// Check whether setSize is with the supported range.
if !isValidSetSize(setSize) {
err = fmt.Errorf("incorrect number of endpoints provided %s, number of disks %d is not divisible by any supported erasure set sizes %d", args, commonSize, setSizes)
return nil, err
}
for i := range totalSizes {
for j := uint64(0); j < totalSizes[i]/setSize; j++ {
setIndexes[i] = append(setIndexes[i], setSize)
}
}
return setIndexes, nil
}
// Return the total size for each argument patterns.
func getTotalSizes(argPatterns []ellipses.ArgPattern) []uint64 {
var totalSizes []uint64
for _, argPattern := range argPatterns {
var totalSize uint64 = 1
for _, p := range argPattern {
totalSize = totalSize * uint64(len(p.Seq))
}
totalSizes = append(totalSizes, totalSize)
}
return totalSizes
}
// PossibleParityValues returns possible parities for input args,
// parties are calculated in uniform manner for one zone or
// multiple zones, ensuring that parities returned are common
// and applicable across all zones.
func PossibleParityValues(args ...string) ([]string, error) {
setIndexes, err := parseEndpointSet(args...)
if err != nil {
return nil, err
}
maximumParity := setIndexes[0][0] / 2
var parities []string
for maximumParity >= 2 {
parities = append(parities, fmt.Sprintf("EC:%d", maximumParity))
maximumParity--
}
return parities, nil
}
// Parses all arguments and returns an endpointSet which is a collection
// of endpoints following the ellipses pattern, this is what is used
// by the object layer for initializing itself.
func parseEndpointSet(args ...string) (setIndexes [][]uint64, err error) {
var argPatterns = make([]ellipses.ArgPattern, len(args))
for i, arg := range args {
patterns, err := ellipses.FindEllipsesPatterns(arg)
if err != nil {
return nil, err
}
argPatterns[i] = patterns
}
return getSetIndexes(args, getTotalSizes(argPatterns), argPatterns)
}

281
pkg/utils/parity_test.go Normal file
View File

@@ -0,0 +1,281 @@
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// All rights reserved
package utils
import (
"reflect"
"testing"
"github.com/minio/minio/pkg/ellipses"
)
func TestGetDivisibleSize(t *testing.T) {
testCases := []struct {
totalSizes []uint64
result uint64
}{{[]uint64{24, 32, 16}, 8},
{[]uint64{32, 8, 4}, 4},
{[]uint64{8, 8, 8}, 8},
{[]uint64{24}, 24},
}
for _, testCase := range testCases {
testCase := testCase
t.Run("", func(t *testing.T) {
gotGCD := getDivisibleSize(testCase.totalSizes)
if testCase.result != gotGCD {
t.Errorf("Expected %v, got %v", testCase.result, gotGCD)
}
})
}
}
// Test tests calculating set indexes.
func TestGetSetIndexes(t *testing.T) {
testCases := []struct {
args []string
totalSizes []uint64
indexes [][]uint64
success bool
}{
// Invalid inputs.
{
[]string{"data{1...3}"},
[]uint64{3},
nil,
false,
},
{
[]string{"data/controller1/export{1...2}, data/controller2/export{1...4}, data/controller3/export{1...8}"},
[]uint64{2, 4, 8},
nil,
false,
},
{
[]string{"data{1...17}/export{1...52}"},
[]uint64{14144},
nil,
false,
},
// Valid inputs.
{
[]string{"data{1...27}"},
[]uint64{27},
[][]uint64{{9, 9, 9}},
true,
},
{
[]string{"http://host{1...3}/data{1...180}"},
[]uint64{540},
[][]uint64{{15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}},
true,
},
{
[]string{"http://host{1...2}.rack{1...4}/data{1...180}"},
[]uint64{1440},
[][]uint64{{16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}},
true,
},
{
[]string{"http://host{1...2}/data{1...180}"},
[]uint64{360},
[][]uint64{{12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}},
true,
},
{
[]string{"data/controller1/export{1...4}, data/controller2/export{1...8}, data/controller3/export{1...12}"},
[]uint64{4, 8, 12},
[][]uint64{{4}, {4, 4}, {4, 4, 4}},
true,
},
{
[]string{"data{1...64}"},
[]uint64{64},
[][]uint64{{16, 16, 16, 16}},
true,
},
{
[]string{"data{1...24}"},
[]uint64{24},
[][]uint64{{12, 12}},
true,
},
{
[]string{"data/controller{1...11}/export{1...8}"},
[]uint64{88},
[][]uint64{{11, 11, 11, 11, 11, 11, 11, 11}},
true,
},
{
[]string{"data{1...4}"},
[]uint64{4},
[][]uint64{{4}},
true,
},
{
[]string{"data/controller1/export{1...10}, data/controller2/export{1...10}, data/controller3/export{1...10}"},
[]uint64{10, 10, 10},
[][]uint64{{10}, {10}, {10}},
true,
},
{
[]string{"data{1...16}/export{1...52}"},
[]uint64{832},
[][]uint64{{16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}},
true,
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run("", func(t *testing.T) {
var argPatterns = make([]ellipses.ArgPattern, len(testCase.args))
for i, arg := range testCase.args {
patterns, err := ellipses.FindEllipsesPatterns(arg)
if err != nil {
t.Fatalf("Unexpected failure %s", err)
}
argPatterns[i] = patterns
}
gotIndexes, err := getSetIndexes(testCase.args, testCase.totalSizes, argPatterns)
if err != nil && testCase.success {
t.Errorf("Expected success but failed instead %s", err)
}
if err == nil && !testCase.success {
t.Errorf("Expected failure but passed instead")
}
if !reflect.DeepEqual(testCase.indexes, gotIndexes) {
t.Errorf("Expected %v, got %v", testCase.indexes, gotIndexes)
}
})
}
}
// Test tests possible parities returned for any input args
func TestPossibleParities(t *testing.T) {
testCases := []struct {
arg string
parities []string
success bool
}{
// Tests invalid inputs.
{
"...",
nil,
false,
},
// No range specified.
{
"{...}",
nil,
false,
},
// Invalid range.
{
"http://minio{2...3}/export/set{1...0}",
nil,
false,
},
// Range cannot be smaller than 4 minimum.
{
"/export{1..2}",
nil,
false,
},
// Unsupported characters.
{
"/export/test{1...2O}",
nil,
false,
},
// Tests valid inputs.
{
"{1...27}",
[]string{"EC:4", "EC:3", "EC:2"},
true,
},
{
"/export/set{1...64}",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// Valid input for distributed setup.
{
"http://minio{2...3}/export/set{1...64}",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// Supporting some advanced cases.
{
"http://minio{1...64}.mydomain.net/data",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
{
"http://rack{1...4}.mydomain.minio{1...16}/data",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// Supporting kubernetes cases.
{
"http://minio{0...15}.mydomain.net/data{0...1}",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// No host regex, just disks.
{
"http://server1/data{1...32}",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// No host regex, just disks with two position numerics.
{
"http://server1/data{01...32}",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// More than 2 ellipses are supported as well.
{
"http://minio{2...3}/export/set{1...64}/test{1...2}",
[]string{"EC:8", "EC:7", "EC:6", "EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// More than 1 ellipses per argument for standalone setup.
{
"/export{1...10}/disk{1...10}",
[]string{"EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// IPv6 ellipses with hexadecimal expansion
{
"http://[2001:3984:3989::{1...a}]/disk{1...10}",
[]string{"EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
// IPv6 ellipses with hexadecimal expansion with 3 position numerics.
{
"http://[2001:3984:3989::{001...00a}]/disk{1...10}",
[]string{"EC:5", "EC:4", "EC:3", "EC:2"},
true,
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run("", func(t *testing.T) {
gotPs, err := PossibleParityValues(testCase.arg)
if err != nil && testCase.success {
t.Errorf("Expected success but failed instead %s", err)
}
if err == nil && !testCase.success {
t.Errorf("Expected failure but passed instead")
}
if !reflect.DeepEqual(testCase.parities, gotPs) {
t.Errorf("Expected %v, got %v", testCase.parities, gotPs)
}
})
}
}

View File

@@ -0,0 +1,15 @@
{
"name": "consoleTestUserAddOnly",
"Statement": [
{
"Action": [
"admin:CreateUser"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::*"
]
}
],
"version": "2012-10-17"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
const rewireReactHotLoader = require('react-app-rewire-hot-loader');
/* config-overrides.js */
module.exports = function override(config, env) {
if (env === 'development') {
config.resolve.alias['react-dom'] = '@hot-loader/react-dom';
}
config = rewireReactHotLoader(config, env);
return config;
};

View File

@@ -5,6 +5,7 @@
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.7.4",
"@babel/plugin-transform-react-jsx-development": "^7.9.0",
"@hot-loader/react-dom": "^16.9.0",
"@material-ui/core": "^4.9.12",
"@material-ui/icons": "^4.9.1",
"@types/history": "^4.7.3",
@@ -27,25 +28,29 @@
"local-storage-fallback": "^4.1.1",
"lodash": "^4.17.19",
"moment": "^2.24.0",
"npm": "^6.14.4",
"react": "^16.13.1",
"react-app-rewire-hot-loader": "^2.0.1",
"react-app-rewired": "^2.1.6",
"react-async-hook": "^3.6.1",
"react-chartjs-2": "^2.9.0",
"react-codemirror2": "^7.1.0",
"react-dom": "^16.12.0",
"react-hot-loader": "^4.13.0",
"react-moment": "^0.9.7",
"react-redux": "^7.1.3",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.1",
"react-scripts": "3.4.4",
"recharts": "^1.8.5",
"redux": "^4.0.4",
"redux-thunk": "^2.3.0",
"superagent": "^5.1.0",
"typeface-roboto": "^0.0.75",
"typescript": "3.6.4",
"use-debounce": "^5.0.1",
"websocket": "^1.0.31"
},
"scripts": {
"start": "PORT=5000 react-scripts start",
"start": "PORT=5000 react-app-rewired start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -0,0 +1,67 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 368.999 192.934">
<defs>
<style>
.cls-1{opacity:0.35;}.cls-12,.cls-15,.cls-16,.cls-17,.cls-2,.cls-5,.cls-6,.cls-7,.cls-8{opacity:0.5;}.cls-10,.cls-11,.cls-12,.cls-13,.cls-14,.cls-15,.cls-16,.cls-17,.cls-3,.cls-4,.cls-5,.cls-6,.cls-7,.cls-9{fill:none;stroke:#707070;stroke-miterlimit:10;}.cls-4{stroke-width:1px;}.cls-10,.cls-11,.cls-5,.cls-9{stroke-width:1.2px;}.cls-5{stroke-dasharray:2.619
2.182;}.cls-12,.cls-15,.cls-16,.cls-17,.cls-5,.cls-6,.cls-7,.cls-8{isolation:isolate;}.cls-6{stroke-width:1.6px;stroke-dasharray:2.144
1.786;}.cls-7{stroke-width:1.6px;stroke-dasharray:2.23 1.858;}.cls-10{stroke-dasharray:2.646
2.204;}.cls-11{stroke-dasharray:2.585 2.154;}.cls-12{stroke-width:1.8px;stroke-dasharray:2.484
2.07;}.cls-13{stroke-dasharray:2.984 2.487;}.cls-14{stroke-dasharray:2.773
2.311;}.cls-16{stroke-width:1.8px;}.cls-17{stroke-width:1.8px;}
</style>
</defs>
<title>BG_Illustration</title>
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<g id="BG_Illustration" data-name="BG Illustration" class="cls-1">
<g id="Group_118" data-name="Group 118" class="cls-2">
<path id="Path_56" data-name="Path 56" class="cls-3"
d="M211.5,140.678l-52.726,29.078L79.687,126.139V29.652L132.411.571,211.5,44.188Z"/>
<path id="Path_58" data-name="Path 58" class="cls-3"
d="M158.776,169.756V73.271L211.5,44.193,158.776,73.271,79.688,29.654"/>
<path id="Path_59" data-name="Path 59" class="cls-4" d="M84.681,41l69.1,38.11v79.3l-69.1-38.11Z"/>
<line id="Line_37" data-name="Line 37" class="cls-4" x1="106.25" y1="52.782" x2="106.25"
y2="132.086"/>
<line id="Line_38" data-name="Line 38" class="cls-4" x1="153.783" y1="92.327" x2="106.25"
y2="65.999"/>
<line id="Line_39" data-name="Line 39" class="cls-4" x1="153.783" y1="105.545" x2="106.25"
y2="79.217"/>
<line id="Line_40" data-name="Line 40" class="cls-4" x1="153.783" y1="118.762" x2="106.25"
y2="92.434"/>
<line id="Line_41" data-name="Line 41" class="cls-4" x1="153.783" y1="131.979" x2="106.25"
y2="105.651"/>
<line id="Line_42" data-name="Line 42" class="cls-4" x1="153.783" y1="145.197" x2="106.25"
y2="118.869"/>
<path id="Path_60" data-name="Path 60" class="cls-4"
d="M166.723,151.031l38.8-22.487V62.916L166.723,85.4Z"/>
</g>
<path id="Path_62" data-name="Path 62" class="cls-5" d="M117.106,148.062l-76.18,43.33"/>
<path id="Path_63" data-name="Path 63" class="cls-6" d="M271.394,167.271l-44.483,25.3"/>
<path id="Path_64" data-name="Path 64" class="cls-7" d="M190.722,155.708l61.951,36.031"/>
<path id="Path_65" data-name="Path 65" class="cls-5" d="M237.7,36.385l28.182,17.229"/>
<g id="Path_66" data-name="Path 66" class="cls-8">
<line class="cls-9" x1="362.563" y1="69.327" x2="361.42" y2="68.688"/>
<line class="cls-10" x1="359.496" y1="67.613" x2="305.418" y2="37.39"/>
<polyline class="cls-9" points="304.456 36.852 303.313 36.213 302.158 36.83"/>
<line class="cls-11" x1="300.258" y1="37.844" x2="213.418" y2="84.213"/>
<line class="cls-9" x1="212.468" y1="84.72" x2="211.313" y2="85.337"/>
</g>
<path id="Path_67" data-name="Path 67" class="cls-12"
d="M79.648,192.571,31.786,166.344h-.868l-23.579,14.2"/>
<g id="Path_68" data-name="Path 68" class="cls-8">
<line class="cls-3" x1="22.871" y1="84.641" x2="24.156" y2="83.867"/>
<line class="cls-13" x1="26.286" y1="82.584" x2="48.654" y2="69.113"/>
<polyline class="cls-3" points="49.719 68.471 51.004 67.698 52.307 68.441"/>
<line class="cls-14" x1="54.315" y1="69.585" x2="75.395" y2="81.606"/>
<line class="cls-3" x1="76.399" y1="82.178" x2="77.702" y2="82.921"/>
</g>
<circle id="Ellipse_11" data-name="Ellipse 11" class="cls-15" cx="4.092" cy="183.59" r="3.592"/>
<circle id="Ellipse_12" data-name="Ellipse 12" class="cls-15" cx="274.986" cy="165.477" r="3.592"/>
<ellipse id="Ellipse_13" data-name="Ellipse 13" class="cls-16" cx="364.957" cy="71.922" rx="3.592"
ry="2.904"/>
<circle id="Ellipse_14" data-name="Ellipse 14" class="cls-15" cx="19.279" cy="87.681" r="3.592"/>
<ellipse id="Ellipse_15" data-name="Ellipse 15" class="cls-17" cx="234.106" cy="32.58" rx="3.592"
ry="2.649"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.174" height="11" viewBox="0 0 11.174 11">
<defs>
<style>.a{fill:none;stroke:#081c42;stroke-linecap:round;}</style>
</defs>
<path class="a" d="M8.392,10H1.608L0,0H10Z" transform="translate(0.587 0.5)"/>
</svg>

After

Width:  |  Height:  |  Size: 279 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.174" height="11" viewBox="0 0 11.174 11">
<defs>
<style>.a{fill:#081c42;stroke:#081c42;stroke-linecap:round;}</style>
</defs>
<path class="a" d="M8.392,10H1.608L0,0H10Z" transform="translate(0.587 0.5)"/>
</svg>

After

Width:  |  Height:  |  Size: 282 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.442" height="15.302" viewBox="0 0 11.442 15.302">
<defs>
<style>.a,.b{fill:none;stroke:#081c42;}.b{stroke-linejoin:round;}</style>
</defs>
<g transform="translate(0.5 0.5)">
<path class="a" d="M-12060-11667.842v14.261h10.442v-10.591l-3.671-3.67Z"
transform="translate(12059.999 11667.883)"/>
<path class="b" d="M-12051.353-11664.255v-3.639l3.528,3.639Z" transform="translate(12058.188 11667.894)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 515 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="11.442" height="15.302" viewBox="0 0 11.442 15.302">
<defs>
<style>.a,.b{fill:#081c42;stroke:#081c42;}.b{stroke-linejoin:round;fill:#fff}</style>
</defs>
<g transform="translate(0.5 0.5)">
<path class="a" d="M-12060-11667.842v14.261h10.442v-10.591l-3.671-3.67Z"
transform="translate(12059.999 11667.883)"/>
<path class="b" d="M-12051.353-11664.255v-3.639l3.528,3.639Z" transform="translate(12058.188 11667.894)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="15.999" height="13.999" viewBox="0 0 15.999 13.999">
<defs>
<style>.a{fill:none;stroke-linecap:square;}.b,.c{stroke:none;}.c{fill:#081c42;}</style>
</defs>
<g class="a" transform="translate(-0.001 0.001)">
<path class="b" d="M0,14V0H8.572V2.411H16V14Z"/>
<path class="c"
d="M 15.00020027160645 12.99860000610352 L 15.00020027160645 3.411099910736084 L 8.571599960327148 3.411099910736084 L 7.571600437164307 3.411099910736084 L 7.571600437164307 2.411099910736084 L 7.571600437164307 0.9990998506546021 L 1.000900268554688 0.9990998506546021 L 1.000900268554688 2.411099910736084 L 1.000900268554688 12.99860000610352 L 15.00020027160645 12.99860000610352 M 16.00020027160645 13.99860000610352 L 0.0009002700680866838 13.99860000610352 L 0.0009002700680866838 2.411099910736084 L 0.0009002700680866838 -0.0009001312428154051 L 8.571599960327148 -0.0009001312428154051 L 8.571599960327148 2.411099910736084 L 16.00020027160645 2.411099910736084 L 16.00020027160645 13.99860000610352 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="15.999" height="13.999" viewBox="0 0 15.999 13.999">
<defs>
<style>.a{fill:none;stroke-linecap:square;}.b,.c{stroke:none;fill:#081c42}.c{fill:#081c42;}</style>
</defs>
<g class="a" transform="translate(-0.001 0.001)">
<path class="b" d="M0,14V0H8.572V2.411H16V14Z"/>
<path class="c"
d="M 15.00020027160645 12.99860000610352 L 15.00020027160645 3.411099910736084 L 8.571599960327148 3.411099910736084 L 7.571600437164307 3.411099910736084 L 7.571600437164307 2.411099910736084 L 7.571600437164307 0.9990998506546021 L 1.000900268554688 0.9990998506546021 L 1.000900268554688 2.411099910736084 L 1.000900268554688 12.99860000610352 L 15.00020027160645 12.99860000610352 M 16.00020027160645 13.99860000610352 L 0.0009002700680866838 13.99860000610352 L 0.0009002700680866838 2.411099910736084 L 0.0009002700680866838 -0.0009001312428154051 L 8.571599960327148 -0.0009001312428154051 L 8.571599960327148 2.411099910736084 L 16.00020027160645 2.411099910736084 L 16.00020027160645 13.99860000610352 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -19,12 +19,28 @@ import { Redirect, Route, Router, Switch } from "react-router-dom";
import history from "./history";
import Login from "./screens/LoginPage/LoginPage";
import Console from "./screens/Console/Console";
import NotFoundPage from "./screens/NotFoundPage";
import storage from "local-storage-fallback";
import { connect } from "react-redux";
import { AppState } from "./store";
import { userLoggedIn } from "./actions";
import LoginCallback from "./screens/LoginPage/LoginCallback";
import { hot } from "react-hot-loader/root";
interface ProtectedRouteProps {
loggedIn: boolean;
component: any;
}
export class ProtectedRoute extends React.Component<ProtectedRouteProps> {
render() {
const Component = this.props.component;
return this.props.loggedIn ? (
<Component />
) : (
<Redirect to={{ pathname: "/login" }} />
);
}
}
const isLoggedIn = () => {
return (
@@ -46,33 +62,18 @@ interface RoutesProps {
}
class Routes extends React.Component<RoutesProps> {
componentDidMount(): void {
if (isLoggedIn()) {
this.props.userLoggedIn(true);
}
}
render() {
const loggedIn = isLoggedIn();
return (
<Router history={history}>
<Switch>
<Route exact path="/oauth_callback" component={LoginCallback} />
<Route exact path="/login" component={Login} />
{this.props.loggedIn ? (
<Switch>
<Route path="/*" component={Console} />
<Route component={NotFoundPage} />
</Switch>
) : (
<Switch>
<Route exact path="/" component={Login} />
<Redirect to="/" />
</Switch>
)}
<ProtectedRoute component={Console} loggedIn={loggedIn} />
</Switch>
</Router>
);
}
}
export default connector(Routes);
export default hot(connector(Routes));

View File

@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import storage from "local-storage-fallback";
import { ICapacity, IStorageType, IZoneModel } from "./types";
import { ICapacity, IZoneModel } from "./types";
const minStReq = 1073741824; // Minimal Space required for MinIO
const minMemReq = 2147483648; // Minimal Memory required for MinIO in bytes

View File

@@ -0,0 +1,34 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class AddIcon extends React.Component {
render() {
return (
<SvgIcon viewBox="0 0 12 12">
<path
fill="#081c42"
className="a"
d="M-13160.269,1885.114h-3.235v-4.381h-4.382V1877.5h4.382v-4.381h3.235v4.381h4.383v3.238h-4.383v4.38Z"
transform="translate(13167.886 -1873.114)"
/>
</SvgIcon>
);
}
}
export default AddIcon;

View File

@@ -0,0 +1,75 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class AllBucketsIcon extends React.Component {
render() {
return (
<SvgIcon viewBox="0 0 15.834 17.375">
<defs>
<linearGradient
id="a"
y1="0.5"
x2="1"
y2="0.5"
gradientUnits="objectBoundingBox"
>
<stop offset="0.044" stopColor="#362585" />
<stop offset="0.301" stopColor="#281b6f" />
<stop offset="1" stopColor="#1e1560" />
</linearGradient>
</defs>
<g transform="translate(0 0.375)">
<circle
style={{ opacity: 0.1, fill: "url(#a)" }}
cx="6.625"
cy="6.625"
r="6.625"
transform="translate(0 3.75)"
/>
<g transform="translate(3.092)">
<ellipse
style={{
fill: "none",
stroke: "#707070",
strokeMiterlimit: 10,
strokeWidth: "0.75px",
}}
cx="6.183"
cy="1.244"
rx="6.183"
ry="1.244"
transform="translate(0)"
/>
<path
style={{
fill: "none",
stroke: "#707070",
strokeMiterlimit: 10,
strokeWidth: "0.75px",
}}
d="M-3722.174,1225.225l-1.687,10.292a.858.858,0,0,1-.578.669,12.182,12.182,0,0,1-3.918.647,12.187,12.187,0,0,1-3.894-.639.878.878,0,0,1-.6-.678q-.843-5.145-1.687-10.291"
transform="translate(3734.541 -1223.981)"
/>
</g>
</g>
</SvgIcon>
);
}
}
export default AllBucketsIcon;

View File

@@ -0,0 +1,37 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class ConsoleIcon extends React.Component {
render() {
return (
<SvgIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
<g transform="translate(-518 -361)">
<path
d="M-126,0V10h10V0Zm1.5,8.5V2.95h7V8.5Z"
transform="translate(644 361)"
/>
<rect width="2" height="1" transform="translate(520.272 364.772)" />
</g>
</svg>
</SvgIcon>
);
}
}
export default ConsoleIcon;

View File

@@ -1,5 +1,5 @@
// This file is part of MinIO Console Server
// Copyright (c) 2019 MinIO, Inc.
// 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
@@ -15,21 +15,36 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import {SvgIcon} from "@material-ui/core";
import { SvgIcon } from "@material-ui/core";
class CreateIcon extends React.Component {
render() {
return (<SvgIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<title>ic_h_create-new_sl</title>
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<path className="cls-1"
d="M0,0V16H16V0ZM11.886,9.048H9.048v2.838h-2.1V9.048H4.114v-2.1H6.952V4.114h2.1V6.952h2.838Z"/>
</g>
</g>
</svg>
</SvgIcon>)
}
render() {
return (
<SvgIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12">
<g
id="Group_55"
data-name="Group 55"
transform="translate(1002 -2555)"
>
<rect
id="Rectangle_29"
width="2"
height="12"
transform="translate(-997 2555)"
fill="#fff"
/>
<rect
id="Rectangle_30"
width="2"
height="12"
transform="translate(-990 2560) rotate(90)"
fill="#fff"
/>
</g>
</svg>
</SvgIcon>
);
}
}
export default CreateIcon;

View File

@@ -0,0 +1,73 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class EgressIcon extends React.Component {
render() {
return (
<SvgIcon viewBox="0 0 18.344 17.009">
<defs>
<linearGradient
id="a"
y1="0.5"
x2="1"
y2="0.5"
gradientUnits="objectBoundingBox"
>
<stop offset="0.044" stopColor="#362585" />
<stop offset="0.301" stopColor="#281b6f" />
<stop offset="1" stopColor="#1e1560" />
</linearGradient>
</defs>
<g transform="translate(0 0.25)">
<ellipse
style={{ opacity: 0.1, fill: "url(#a)" }}
cx="7.462"
cy="7.462"
rx="7.462"
ry="7.462"
transform="translate(0 1.835)"
/>
<rect
style={{
fill: "none",
stroke: "#707070",
strokeMiterlimit: 10,
strokeWidth: "0.5px",
}}
width="9.323"
height="9.323"
transform="translate(4.083)"
/>
<rect
style={{
fill: "none",
stroke: "#707070",
strokeMiterlimit: 10,
strokeWidth: "0.5px",
}}
width="8.223"
height="8.223"
transform="translate(9.871 5.307)"
/>
</g>
</SvgIcon>
);
}
}
export default EgressIcon;

View File

@@ -0,0 +1,53 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class HealIcon extends React.Component {
render() {
return (
<SvgIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10.014 9.993">
<path
className="a"
d="M9.162,5.971h0L8.192,5,9.346,3.846a2.257,2.257,0,0,0,0-3.192,2.311,2.311,0,0,0-3.192,0L5,1.808,4.029.837,3.846.654a2.311,2.311,0,0,0-3.192,0,2.257,2.257,0,0,0,0,3.192l.184.183h0L1.808,5,.654,6.154A2.257,2.257,0,0,0,3.846,9.346L5,8.192l.971.971.183.183A2.257,2.257,0,0,0,9.346,6.154Zm-2.29-4.6a1.27,1.27,0,0,1,1.757,0,1.242,1.242,0,0,1,0,1.757L7.475,4.283,5.717,2.525Zm-5.5,1.757A1.243,1.243,0,0,1,3.129,1.371l.183.183L1.555,3.312Zm1.757,5.5a1.27,1.27,0,0,1-1.757,0,1.242,1.242,0,0,1,0-1.757L2.525,5.717,4.283,7.475Zm2.843-.9-.254-.253L2.525,4.283l-.253-.254L4.029,2.272l.254.253L7.475,5.717l.253.254Zm2.657.9a1.271,1.271,0,0,1-1.757,0l-.183-.183L8.446,6.688l.183.183h0a1.241,1.241,0,0,1,0,1.757Z"
transform="translate(0.007 -0.014)"
/>
<circle
cx="0.5"
cy="0.5"
r="0.5"
transform="translate(4.507 4.486)"
/>
<circle
cx="0.5"
cy="0.5"
r="0.5"
transform="translate(3.507 3.486)"
/>
<circle
cx="0.5"
cy="0.5"
r="0.5"
transform="translate(5.507 5.486)"
/>
</svg>
</SvgIcon>
);
}
}
export default HealIcon;

View File

@@ -0,0 +1,47 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class LicenseIcon extends React.Component {
render() {
return (
<SvgIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 11">
<path fill="#fff" d="M11 11H0V2h11v9zM2 8v1h7V8zm0-3v1h5V5z"></path>
<g
fill="#07274a"
stroke="#fdfdfd"
strokeWidth="0.5"
transform="translate(7)"
>
<circle cx="3" cy="3" r="3" stroke="none"></circle>
<circle cx="3" cy="3" r="2.75" fill="none"></circle>
</g>
<path
fill="none"
stroke="#fff"
strokeWidth="0.5"
d="M8.73 2.794l.954.953 1.471-1.471"
></path>
</svg>
</SvgIcon>
);
}
}
export default LicenseIcon;

View File

@@ -0,0 +1,47 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class LogoutIcon extends React.Component {
render() {
return (
<SvgIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12.122 10.571">
<g transform="translate(0 0.5)">
<path
style={{ fill: "none", stroke: "rgba(255,255,255,0.8)" }}
d="M4816.27,3755.205v-2.939h8.539v9.571h-8.539v-2.932"
transform="translate(-4813.187 -3752.266)"
/>
<path
style={{ fill: "none", stroke: "rgba(255,255,255,0.8)" }}
d="M4813.187,3757.052h8.081"
transform="translate(-4813.187 -3752.266)"
/>
<path
style={{ fill: "none", stroke: "rgba(255,255,255,0.8)" }}
d="M4806.5,3756.511l2.265,2.063-2.265,2.063"
transform="translate(-4800.808 -3753.863)"
/>
</g>
</svg>
</SvgIcon>
);
}
}
export default LogoutIcon;

View File

@@ -0,0 +1,33 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class RemoveIcon extends React.Component {
render() {
return (
<SvgIcon viewBox="0 0 11.656 3.101">
<path
fill="#081c42"
d="M-13157.172,1879.551h-11.656v-3.1h11.656v3.1Z"
transform="translate(13168.828 -1876.449)"
/>
</SvgIcon>
);
}
}
export default RemoveIcon;

View File

@@ -0,0 +1,41 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class UploadFile extends React.Component {
render() {
return (
<SvgIcon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12.996">
<g transform="translate(-63.686 -70.783)">
<path
className="a"
d="M74.736,79.879v1.95h-9.1v-1.95h-1.95v3.9h13v-3.9Z"
/>
<path
className="a"
d="M69.211,80.533h1.95V73.861h1.525l-2.5-3.078-2.5,3.078h1.525Z"
/>
</g>
</svg>
</SvgIcon>
);
}
}
export default UploadFile;

View File

@@ -0,0 +1,64 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import { SvgIcon } from "@material-ui/core";
class UsageIcon extends React.Component {
render() {
return (
<SvgIcon viewBox="0 0 16.172 17.187">
<defs>
<linearGradient
id="a"
y1="0.5"
x2="1"
y2="0.5"
gradientUnits="objectBoundingBox"
>
<stop offset="0.044" stopColor="#362585" />
<stop offset="0.301" stopColor="#281b6f" />
<stop offset="1" stopColor="#1e1560" />
</linearGradient>
</defs>
<path
style={{
fill: "none",
stroke: "#707070",
strokeMiterlimit: 10,
strokeWidth: "0.5px",
}}
d="M-4778.1,2239.582v6.425h6.425"
transform="translate(4787.594 -2239.582)"
/>
<path
fill={"#707070"}
d="M-4784.238,2247.532v-.581c0-.027.009-.054.012-.081.039-.313.055-.632.121-.939a6.744,6.744,0,0,1,3.064-4.441,6.514,6.514,0,0,1,3.293-1.032,6.923,6.923,0,0,1,2.667.423,6.793,6.793,0,0,1,4.119,4.333,6.053,6.053,0,0,1,.279,1.337c.006.083.014.164.021.247v.86c-.011.131-.018.261-.032.392a6.494,6.494,0,0,1-.626,2.147,6.807,6.807,0,0,1-4.044,3.528,6.052,6.052,0,0,1-1.663.3,6.576,6.576,0,0,1-2.565-.325,6.73,6.73,0,0,1-3.947-3.451,6.627,6.627,0,0,1-.658-2.288C-4784.212,2247.816-4784.225,2247.674-4784.238,2247.532Zm13.025-.306c-.024-.309-.021-.661-.082-1a6.206,6.206,0,0,0-1.658-3.293,6.153,6.153,0,0,0-4.1-1.9,5.984,5.984,0,0,0-2.476.355,6.188,6.188,0,0,0-4.134,5.708,6.453,6.453,0,0,0,.228,1.881,6.127,6.127,0,0,0,1.984,3.052,6.046,6.046,0,0,0,3.806,1.445,6.043,6.043,0,0,0,1.235-.065,6.249,6.249,0,0,0,3.783-2.2,6.2,6.2,0,0,0,1.352-3.048C-4771.228,2247.863-4771.233,2247.563-4771.212,2247.226Z"
transform="translate(4786.834 -2240.452)"
/>
<ellipse
style={{ opacity: 0.1, fill: "url(#a)" }}
cx="6.151"
cy="6.151"
rx="6.151"
ry="6.151"
transform="translate(0 4.886)"
/>
</SvgIcon>
);
}
}
export default UsageIcon;

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.879 23.119"><defs><style>.cls-1{fill:#1b1556;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M10.086,13.4,8.969,14.573a4.2,4.2,0,0,0-3.01-1.279,3.886,3.886,0,0,0-3.884,4.093,3.888,3.888,0,0,0,3.884,4.1A4.4,4.4,0,0,0,9,20.2l1.082,1.186A5.344,5.344,0,0,1,6,23.119a5.512,5.512,0,0,1-5.7-5.732A5.509,5.509,0,0,1,6,11.667,5.328,5.328,0,0,1,10.086,13.4Z"/><path class="cls-1" d="M23.608,17.387a5.637,5.637,0,0,1-5.8,5.732,5.628,5.628,0,0,1-5.791-5.732,5.626,5.626,0,0,1,5.791-5.72A5.635,5.635,0,0,1,23.608,17.387Zm-9.825,0a4.024,4.024,0,1,0,8.046,0,4.024,4.024,0,1,0-8.046,0Z"/><path class="cls-1" d="M36.862,16.073V22.9H35.129V16.643c0-2.093-1.163-3.325-3.174-3.325a3.24,3.24,0,0,0-3.371,3.372V22.9H26.839V11.888H28.56v1.569a4.354,4.354,0,0,1,3.709-1.79A4.261,4.261,0,0,1,36.862,16.073Z"/><path class="cls-1" d="M48.2,14.225a6.872,6.872,0,0,0-3.605-1.035c-1.569,0-2.6.663-2.6,1.732,0,.919.8,1.372,2.244,1.547l1.3.163c2.338.3,3.7,1.267,3.7,3.069,0,2.093-1.884,3.407-4.849,3.407A7.725,7.725,0,0,1,39.791,21.7l.8-1.3a5.8,5.8,0,0,0,3.815,1.2c1.86,0,3.034-.616,3.034-1.778,0-.884-.744-1.419-2.3-1.605l-1.314-.151c-2.477-.3-3.639-1.408-3.639-3.046,0-2.082,1.755-3.338,4.4-3.338a8.067,8.067,0,0,1,4.372,1.2Z"/><path class="cls-1" d="M63.033,17.387a5.8,5.8,0,0,1-11.593,0,5.8,5.8,0,0,1,11.593,0Zm-9.825,0a4.023,4.023,0,1,0,8.045,0,4.023,4.023,0,1,0-8.045,0Z"/><path class="cls-1" d="M68.008,22.9H66.264V6.155h1.744Z"/><path class="cls-1" d="M81.879,17.353a5.606,5.606,0,0,1-.035.65H73.019a3.743,3.743,0,0,0,3.9,3.593A5.1,5.1,0,0,0,80.4,20.213l.931,1.186a6.179,6.179,0,0,1-4.524,1.72A5.394,5.394,0,0,1,71.24,17.4a5.406,5.406,0,0,1,5.465-5.732C79.693,11.667,81.856,14,81.879,17.353ZM73.043,16.6h7.069a3.446,3.446,0,0,0-3.442-3.384A3.59,3.59,0,0,0,73.043,16.6Z"/><rect class="cls-1" x="13.484" y="0.12" width="2.328" height="6.875"/><path class="cls-1" d="M10.662.215,5.936,3.1a.21.21,0,0,1-.219,0L.992.215A.651.651,0,0,0,.654.12H.648A.648.648,0,0,0,0,.768v6.22H2.327V4.028a.233.233,0,0,1,.354-.2l2.648,1.62a.829.829,0,0,0,.853.008l2.8-1.639a.232.232,0,0,1,.35.2V6.988h2.327V.768A.648.648,0,0,0,11.006.12H11A.651.651,0,0,0,10.662.215Z"/><path class="cls-1" d="M27.422.12H25.061V3.25a.233.233,0,0,1-.342.205L18.6.2A.662.662,0,0,0,18.3.12h0a.648.648,0,0,0-.648.648v6.22h2.342V3.863a.233.233,0,0,1,.342-.206L26.47,6.915a.646.646,0,0,0,.3.076h0a.648.648,0,0,0,.648-.648Z"/><path class="cls-1" d="M29.252,7V.12h1.072V7Z"/><path class="cls-1" d="M36.629,7.119c-2.882,0-4.927-1.368-4.927-3.56S33.759,0,36.629,0s4.938,1.367,4.938,3.559S39.547,7.119,36.629,7.119Zm0-6.208c-2.143,0-3.794.936-3.794,2.648s1.651,2.648,3.794,2.648,3.805-.923,3.805-2.648S38.772.911,36.629.911Z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="121.755" height="29.822" viewBox="0 0 121.755 29.822"><defs><style>.a{fill:#fff;}</style></defs><g transform="translate(3016.56 -1037.757)"><path class="a" d="M-3000.913,1053.692l-1.772,1.194a6.088,6.088,0,0,0-5.135-2.652,6.348,6.348,0,0,0-6.522,6.654,6.348,6.348,0,0,0,6.522,6.654,6.031,6.031,0,0,0,5.124-2.64l1.735,1.266a8.126,8.126,0,0,1-6.859,3.411,8.422,8.422,0,0,1-8.74-8.691,8.422,8.422,0,0,1,8.74-8.691A7.963,7.963,0,0,1-3000.913,1053.692Z"/><path class="a" d="M-2980.919,1058.888a8.422,8.422,0,0,1-8.74,8.691,8.422,8.422,0,0,1-8.739-8.691,8.421,8.421,0,0,1,8.739-8.691A8.422,8.422,0,0,1-2980.919,1058.888Zm-15.261,0a6.347,6.347,0,0,0,6.521,6.654,6.347,6.347,0,0,0,6.521-6.654,6.347,6.347,0,0,0-6.521-6.654A6.347,6.347,0,0,0-2996.18,1058.888Z"/><path class="a" d="M-2962.831,1067.338h-1.917l-10.2-13.26-.012,13.248h-2.122v-16.888h1.917l10.21,13.26V1050.45h2.122Z"/><path class="a" d="M-2947.009,1053.777a8.835,8.835,0,0,0-5-1.555c-2.471,0-4.231,1.109-4.231,2.929,0,1.531,1.29,2.315,3.821,2.628l1.484.181c2.856.35,5.3,1.507,5.3,4.484,0,3.364-3.05,5.123-6.7,5.123a10.935,10.935,0,0,1-6.654-2.194l1.157-1.687a9.018,9.018,0,0,0,5.5,1.868c2.519,0,4.5-1.025,4.5-2.929,0-1.567-1.41-2.314-4.038-2.64l-1.567-.193c-2.784-.337-5-1.627-5-4.508,0-3.255,2.893-5.075,6.449-5.075a10.336,10.336,0,0,1,6.076,1.844Z"/><path class="a" d="M-2925.292,1058.888a8.422,8.422,0,0,1-8.74,8.691,8.422,8.422,0,0,1-8.739-8.691,8.421,8.421,0,0,1,8.739-8.691A8.422,8.422,0,0,1-2925.292,1058.888Zm-15.261,0a6.348,6.348,0,0,0,6.521,6.654,6.347,6.347,0,0,0,6.521-6.654,6.347,6.347,0,0,0-6.521-6.654A6.348,6.348,0,0,0-2940.553,1058.888Z"/><path class="a" d="M-2909.663,1067.326h-11.79V1050.45h2.122v14.863h9.668Z"/><path class="a" d="M-2894.8,1067.326h-11.982V1050.45h11.862v1.988h-9.74v5.389h9.427v2h-9.427v5.509h9.86Z"/><rect class="a" width="2.576" height="7.547" transform="translate(-3001.66 1037.924)"/><path class="a" d="M-3004.759,1037.995l-5.23,3.194a.229.229,0,0,1-.242,0l-5.23-3.194a.726.726,0,0,0-.374-.1h-.006a.717.717,0,0,0-.717.717v6.864h2.574v-3.257a.258.258,0,0,1,.392-.22l2.931,1.793a.919.919,0,0,0,.944.009l3.092-1.814a.258.258,0,0,1,.388.222v3.267h2.575v-6.864a.717.717,0,0,0-.717-.717h-.006A.723.723,0,0,0-3004.759,1037.995Z"/><path class="a" d="M-2986.212,1037.922h-2.613v3.463a.258.258,0,0,1-.379.228l-6.771-3.607a.723.723,0,0,0-.337-.084h0a.717.717,0,0,0-.717.717v6.832h2.592v-3.408a.258.258,0,0,1,.379-.227l6.8,3.606a.714.714,0,0,0,.336.083h0a.716.716,0,0,0,.717-.717v-6.886Z"/><path class="a" d="M-2984.121,1045.469v-7.547h1.2v7.547Z"/><path class="a" d="M-2976.024,1045.635c-3.189,0-5.451-1.513-5.451-3.939s2.276-3.939,5.451-3.939,5.466,1.513,5.466,3.939S-2972.794,1045.635-2976.024,1045.635Zm0-6.87c-2.371,0-4.2,1.036-4.2,2.931s1.826,2.93,4.2,2.93,4.212-1.022,4.212-2.93S-2973.652,1038.765-2976.024,1038.765Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1,4 +1,4 @@
// This file is part of MinIO Buckets Server
// 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
@@ -19,7 +19,7 @@ import {
createStyles,
StyledProps,
Theme,
withStyles
withStyles,
} from "@material-ui/core/styles";
import history from "../../../history";
@@ -28,7 +28,7 @@ import {
RouteComponentProps,
Router,
Switch,
withRouter
withRouter,
} from "react-router-dom";
import { connect } from "react-redux";
import { AppState } from "../../../store";
@@ -41,62 +41,62 @@ import ViewBucket from "./ViewBucket/ViewBucket";
const styles = (theme: Theme) =>
createStyles({
root: {
display: "flex"
display: "flex",
},
toolbar: {
background: theme.palette.background.default,
color: "black",
paddingRight: 24 // keep right padding when drawer closed
paddingRight: 24, // keep right padding when drawer closed
},
toolbarIcon: {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
padding: "0 8px",
...theme.mixins.toolbar
...theme.mixins.toolbar,
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(["width", "margin"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
duration: theme.transitions.duration.leavingScreen,
}),
},
menuButton: {
marginRight: 36
marginRight: 36,
},
menuButtonHidden: {
display: "none"
display: "none",
},
title: {
flexGrow: 1
flexGrow: 1,
},
appBarSpacer: {
height: "5px"
height: "5px",
},
content: {
flexGrow: 1,
height: "100vh",
overflow: "auto"
overflow: "auto",
},
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4)
paddingBottom: theme.spacing(4),
},
paper: {
padding: theme.spacing(2),
display: "flex",
overflow: "auto",
flexDirection: "column"
flexDirection: "column",
},
fixedHeight: {
minHeight: 240
}
minHeight: 240,
},
});
const mapState = (state: AppState) => ({
open: state.system.sidebarOpen
open: state.system.sidebarOpen,
});
const connector = connect(mapState, { setMenuOpen });

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import React, { useEffect, useState } from "react";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import { Button, LinearProgress } from "@material-ui/core";
@@ -23,6 +23,21 @@ import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import api from "../../../../common/api";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
import { factorForDropdown, getBytes } from "../../../../common/utils";
import { AppState } from "../../../../store";
import { connect } from "react-redux";
import {
addBucketName,
addBucketQuota,
addBucketQuotaSize,
addBucketQuotaType,
addBucketQuotaUnit,
addBucketVersioned,
} from "../actions";
import { useDebounce } from "use-debounce";
import { MakeBucketRequest } from "../types";
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
const styles = (theme: Theme) =>
createStyles({
@@ -32,126 +47,294 @@ const styles = (theme: Theme) =>
buttonContainer: {
textAlign: "right",
},
multiContainer: {
display: "flex",
alignItems: "center" as const,
justifyContent: "flex-start" as const,
},
quotaSizeContainer: {
flexGrow: 1,
},
sizeFactorContainer: {
flexGrow: 0,
maxWidth: 80,
marginLeft: 8,
alignSelf: "flex-start" as const,
},
...modalBasic,
});
interface IAddBucketProps {
classes: any;
open: boolean;
closeModalAndRefresh: () => void;
}
interface IAddBucketState {
addLoading: boolean;
addError: string;
closeModalAndRefresh: (refresh: boolean) => void;
addBucketName: typeof addBucketName;
addBucketVersioned: typeof addBucketVersioned;
addBucketQuota: typeof addBucketQuota;
addBucketQuotaType: typeof addBucketQuotaType;
addBucketQuotaSize: typeof addBucketQuotaSize;
addBucketQuotaUnit: typeof addBucketQuotaUnit;
bucketName: string;
versioned: boolean;
enableQuota: boolean;
quotaType: string;
quotaSize: string;
quotaUnit: string;
}
class AddBucket extends React.Component<IAddBucketProps, IAddBucketState> {
state: IAddBucketState = {
addLoading: false,
addError: "",
bucketName: "",
};
const AddBucket = ({
classes,
open,
closeModalAndRefresh,
addBucketName,
addBucketVersioned,
addBucketQuota,
addBucketQuotaType,
addBucketQuotaSize,
addBucketQuotaUnit,
bucketName,
versioned,
enableQuota,
quotaType,
quotaSize,
quotaUnit,
}: IAddBucketProps) => {
const [bName, setBName] = useState<string>(bucketName);
const [addLoading, setAddLoading] = useState<boolean>(false);
const [addError, setAddError] = useState<string>("");
const [sendEnabled, setSendEnabled] = useState<boolean>(false);
addRecord(event: React.FormEvent) {
const addRecord = (event: React.FormEvent) => {
event.preventDefault();
const { bucketName, addLoading } = this.state;
if (addLoading) {
return;
}
this.setState({ addLoading: true }, () => {
api
.invoke("POST", "/api/v1/buckets", {
name: bucketName,
})
.then((res) => {
this.setState(
{
addLoading: false,
addError: "",
},
() => {
this.props.closeModalAndRefresh();
}
);
})
.catch((err) => {
this.setState({
addLoading: false,
addError: err,
});
});
});
}
setAddLoading(true);
render() {
const { classes, open } = this.props;
const { addLoading, addError, bucketName } = this.state;
return (
<ModalWrapper
title="Create Bucket"
modalOpen={open}
onClose={() => {
this.setState({ addError: "" }, () => {
this.props.closeModalAndRefresh();
});
let request: MakeBucketRequest = {
name: bucketName,
versioning: versioned,
};
if (enableQuota) {
const amount = getBytes(quotaSize, quotaUnit, false);
request.quota = {
enabled: true,
quota_type: quotaType,
amount: parseInt(amount),
};
}
api
.invoke("POST", "/api/v1/buckets", request)
.then((res) => {
setAddLoading(false);
setAddError("");
closeModalAndRefresh(true);
})
.catch((err) => {
setAddLoading(false);
setAddError(err);
});
};
const [value] = useDebounce(bName, 1000);
useEffect(() => {
addBucketName(value);
}, [value, addBucketName]);
const resetForm = () => {
setBName("");
addBucketVersioned(false);
addBucketQuota(false);
addBucketQuotaType("hard");
addBucketQuotaSize("1");
addBucketQuotaUnit("TiB");
};
useEffect(() => {
let valid = false;
if (bName.trim() !== "") {
valid = true;
}
if (enableQuota && valid) {
if (quotaSize.trim() === "" || parseInt(quotaSize) === 0) {
valid = false;
}
}
setSendEnabled(valid);
}, [bName, versioned, quotaType, quotaSize, quotaUnit, enableQuota]);
return (
<ModalWrapper
title="Create Bucket"
modalOpen={open}
onClose={() => {
setAddError("");
closeModalAndRefresh(false);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
addRecord(e);
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.addRecord(e);
}}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
{addError !== "" && (
<Grid item xs={12}>
<InputBoxWrapper
id="bucket-name"
name="bucket-name"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ bucketName: e.target.value });
}}
label="Bucket Name"
value={bucketName}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<Grid item xs={12}>
<InputBoxWrapper
id="bucket-name"
name="bucket-name"
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setBName(event.target.value);
}}
label="Bucket Name"
value={bName}
/>
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
value="versioned"
id="versioned"
name="versioned"
checked={versioned}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
addBucketVersioned(event.target.checked);
}}
label={"Versioning"}
indicatorLabel={"On"}
/>
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
value="bucket_quota"
id="bucket_quota"
name="bucket_quota"
checked={enableQuota}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
addBucketQuota(event.target.checked);
}}
label={"Enable Bucket Quota"}
indicatorLabel={"On"}
/>
</Grid>
{enableQuota && (
<React.Fragment>
<Grid item xs={12}>
<SelectWrapper
value={quotaType}
label="Quota Type"
id="quota_type"
name="quota_type"
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
addBucketQuotaType(e.target.value as string);
}}
options={[
{ value: "hard", label: "Hard" },
{ value: "fifo", label: "FIFO" },
]}
/>
</Grid>
<Grid item xs={12}>
<div className={classes.multiContainer}>
<div className={classes.quotaSizeContainer}>
<InputBoxWrapper
type="number"
id="quota_size"
name="quota_size"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
addBucketQuotaSize(e.target.value);
}}
label="Quota"
value={quotaSize}
required
min="1"
/>
</div>
<div className={classes.sizeFactorContainer}>
<SelectWrapper
label="&nbsp;"
id="quota_unit"
name="quota_unit"
value={quotaUnit}
onChange={(
e: React.ChangeEvent<{ value: unknown }>
) => {
addBucketQuotaUnit(e.target.value as string);
}}
options={factorForDropdown()}
/>
</div>
</div>
</Grid>
</React.Fragment>
)}
</Grid>
</form>
</ModalWrapper>
);
}
}
<Grid item xs={12} className={classes.buttonContainer}>
<button
type="button"
color="primary"
className={classes.clearButton}
onClick={resetForm}
>
Clear
</button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading || !sendEnabled}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
};
export default withStyles(styles)(AddBucket);
const mapState = (state: AppState) => ({
addBucketModalOpen: state.buckets.open,
bucketName: state.buckets.addBucketName,
versioned: state.buckets.addBucketVersioning,
enableQuota: state.buckets.addBucketQuotaEnabled,
quotaType: state.buckets.addBucketQuotaType,
quotaSize: state.buckets.addBucketQuotaSize,
quotaUnit: state.buckets.addBucketQuotaUnit,
});
const connector = connect(mapState, {
addBucketName: addBucketName,
addBucketVersioned: addBucketVersioned,
addBucketQuota: addBucketQuota,
addBucketQuotaType: addBucketQuotaType,
addBucketQuotaSize: addBucketQuotaSize,
addBucketQuotaUnit: addBucketQuotaUnit,
});
export default connector(withStyles(styles)(AddBucket));

View File

@@ -14,11 +14,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import React, { useEffect, useState } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import { Button } from "@material-ui/core";
import Typography from "@material-ui/core/Typography";
import TextField from "@material-ui/core/TextField";
import InputAdornment from "@material-ui/core/InputAdornment";
import SearchIcon from "@material-ui/icons/Search";
@@ -31,6 +30,15 @@ import DeleteBucket from "./DeleteBucket";
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
import { CreateIcon } from "../../../../icons";
import { niceBytes } from "../../../../common/utils";
import { AppState } from "../../../../store";
import { connect } from "react-redux";
import { addBucketOpen, addBucketReset } from "../actions";
import {
actionsTray,
containerForHeader,
searchField,
} from "../../Common/FormComponents/common/styleLibrary";
import PageHeader from "../../Common/PageHeader/PageHeader";
const styles = (theme: Theme) =>
createStyles({
@@ -62,188 +70,156 @@ const styles = (theme: Theme) =>
},
},
},
actionsTray: {
textAlign: "right",
"& button": {
marginLeft: 10,
},
},
searchField: {
background: "#FFFFFF",
padding: 12,
borderRadius: 5,
boxShadow: "0px 3px 6px #00000012",
},
...actionsTray,
...searchField,
...containerForHeader(theme.spacing(4)),
});
interface IListBucketsProps {
classes: any;
addBucketOpen: typeof addBucketOpen;
addBucketModalOpen: boolean;
addBucketReset: typeof addBucketReset;
}
interface IListBucketsState {
records: Bucket[];
totalRecords: number;
loading: boolean;
error: string;
deleteError: string;
addScreenOpen: boolean;
page: number;
rowsPerPage: number;
deleteOpen: boolean;
selectedBucket: string;
filterBuckets: string;
}
const ListBuckets = ({
classes,
addBucketOpen,
addBucketModalOpen,
addBucketReset,
}: IListBucketsProps) => {
const [records, setRecords] = useState<Bucket[]>([]);
const [totalRecords, setTotalRecords] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string>("");
const [page, setPage] = useState<number>(0);
const [rowsPerPage, setRowsPerPage] = useState<number>(10);
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
const [selectedBucket, setSelectedBucket] = useState<string>("");
const [filterBuckets, setFilterBuckets] = useState<string>("");
class ListBuckets extends React.Component<
IListBucketsProps,
IListBucketsState
> {
state: IListBucketsState = {
records: [],
totalRecords: 0,
loading: false,
error: "",
deleteError: "",
addScreenOpen: false,
page: 0,
rowsPerPage: 10,
deleteOpen: false,
selectedBucket: "",
filterBuckets: "",
useEffect(() => {
if (loading) {
const fetchRecords = () => {
setLoading(true);
const offset = page * rowsPerPage;
api
.invoke(
"GET",
`/api/v1/buckets?offset=${offset}&limit=${rowsPerPage}`
)
.then((res: BucketList) => {
setLoading(false);
setRecords(res.buckets || []);
setTotalRecords(!res.buckets ? 0 : res.total);
setError("");
// if we get 0 results, and page > 0 , go down 1 page
if (
(res.buckets === undefined ||
res.buckets == null ||
res.buckets.length === 0) &&
page > 0
) {
const newPage = page - 1;
setPage(newPage);
setLoading(true);
}
})
.catch((err: any) => {
setLoading(false);
setError(err);
});
};
fetchRecords();
}
}, [loading, page, rowsPerPage]);
const closeAddModalAndRefresh = (refresh: boolean) => {
addBucketOpen(false);
addBucketReset();
if (refresh) {
setLoading(true);
}
};
fetchRecords() {
this.setState({ loading: true }, () => {
const { page, rowsPerPage } = this.state;
const offset = page * rowsPerPage;
api
.invoke("GET", `/api/v1/buckets?offset=${offset}&limit=${rowsPerPage}`)
.then((res: BucketList) => {
this.setState({
loading: false,
records: res.buckets || [],
totalRecords: !res.buckets ? 0 : res.total,
error: "",
});
// if we get 0 results, and page > 0 , go down 1 page
if (
(res.buckets === undefined ||
res.buckets == null ||
res.buckets.length === 0) &&
page > 0
) {
const newPage = page - 1;
this.setState({ page: newPage }, () => {
this.fetchRecords();
});
}
})
.catch((err: any) => {
this.setState({ loading: false, error: err });
});
});
}
const closeDeleteModalAndRefresh = (refresh: boolean) => {
setDeleteOpen(false);
if (refresh) {
setLoading(true);
}
};
closeAddModalAndRefresh() {
this.setState({ addScreenOpen: false }, () => {
this.fetchRecords();
});
}
useEffect(() => {
setLoading(true);
}, []);
closeDeleteModalAndRefresh(refresh: boolean) {
this.setState({ deleteOpen: false }, () => {
if (refresh) {
this.fetchRecords();
useEffect(() => {
setLoading(true);
}, [page, rowsPerPage]);
const confirmDeleteBucket = (bucket: string) => {
setDeleteOpen(true);
setSelectedBucket(bucket);
};
const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const rPP = parseInt(event.target.value, 10);
setPage(0);
setRowsPerPage(rPP);
};
const tableActions = [
{ type: "view", to: `/buckets`, sendOnlyId: true },
{ type: "delete", onClick: confirmDeleteBucket, sendOnlyId: true },
];
const offset = page * rowsPerPage;
const displayParsedDate = (date: string) => {
return <Moment>{date}</Moment>;
};
const filteredRecords = records.filter((b: Bucket) => {
if (filterBuckets === "") {
return true;
} else {
if (b.name.indexOf(filterBuckets) >= 0) {
return true;
} else {
return false;
}
});
}
}
});
componentDidMount(): void {
this.fetchRecords();
}
const showInPage = filteredRecords.slice(offset, offset + rowsPerPage);
bucketFilter(): void {}
render() {
const { classes } = this.props;
const {
records,
totalRecords,
addScreenOpen,
loading,
page,
rowsPerPage,
deleteOpen,
selectedBucket,
filterBuckets,
} = this.state;
const offset = page * rowsPerPage;
const handleChangePage = (event: unknown, newPage: number) => {
this.setState({ page: newPage });
};
const handleChangeRowsPerPage = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const rPP = parseInt(event.target.value, 10);
this.setState({ page: 0, rowsPerPage: rPP });
};
const confirmDeleteBucket = (bucket: string) => {
this.setState({ deleteOpen: true, selectedBucket: bucket });
};
const tableActions = [
{ type: "view", to: `/buckets`, sendOnlyId: true },
{ type: "delete", onClick: confirmDeleteBucket, sendOnlyId: true },
];
const displayParsedDate = (date: string) => {
return <Moment>{date}</Moment>;
};
const filteredRecords = records
.slice(offset, offset + rowsPerPage)
.filter((b: Bucket) => {
if (filterBuckets === "") {
return true;
} else {
if (b.name.indexOf(filterBuckets) >= 0) {
return true;
} else {
return false;
}
}
});
return (
<React.Fragment>
{addScreenOpen && (
<AddBucket
open={addScreenOpen}
closeModalAndRefresh={() => {
this.closeAddModalAndRefresh();
}}
/>
)}
{deleteOpen && (
<DeleteBucket
deleteOpen={deleteOpen}
selectedBucket={selectedBucket}
closeDeleteModalAndRefresh={(refresh: boolean) => {
this.closeDeleteModalAndRefresh(refresh);
}}
/>
)}
<Grid container>
<Grid item xs={12}>
<Typography variant="h6">Buckets</Typography>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
return (
<React.Fragment>
{addBucketModalOpen && (
<AddBucket
open={addBucketModalOpen}
closeModalAndRefresh={closeAddModalAndRefresh}
/>
)}
{deleteOpen && (
<DeleteBucket
deleteOpen={deleteOpen}
selectedBucket={selectedBucket}
closeDeleteModalAndRefresh={(refresh: boolean) => {
closeDeleteModalAndRefresh(refresh);
}}
/>
)}
<PageHeader label={"Buckets"} />
<Grid container>
{error !== "" && <span className={classes.error}>{error}</span>}
<Grid item xs={12} className={classes.container}>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Search Buckets"
@@ -251,9 +227,7 @@ class ListBuckets extends React.Component<
id="search-resource"
label=""
onChange={(val) => {
this.setState({
filterBuckets: val.target.value,
});
setFilterBuckets(val.target.value);
}}
InputProps={{
disableUnderline: true,
@@ -269,9 +243,7 @@ class ListBuckets extends React.Component<
color="primary"
startIcon={<CreateIcon />}
onClick={() => {
this.setState({
addScreenOpen: true,
});
addBucketOpen(true);
}}
>
Create Bucket
@@ -297,13 +269,13 @@ class ListBuckets extends React.Component<
},
]}
isLoading={loading}
records={filteredRecords}
records={showInPage}
entityName="Buckets"
idField="name"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
count: filteredRecords.length,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
@@ -317,9 +289,18 @@ class ListBuckets extends React.Component<
/>
</Grid>
</Grid>
</React.Fragment>
);
}
}
</Grid>
</React.Fragment>
);
};
export default withStyles(styles)(ListBuckets);
const mapState = (state: AppState) => ({
addBucketModalOpen: state.buckets.open,
});
const connector = connect(mapState, {
addBucketOpen: addBucketOpen,
addBucketReset: addBucketReset,
});
export default connector(withStyles(styles)(ListBuckets));

View File

@@ -0,0 +1,116 @@
// 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 <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
import { Button, Grid, LinearProgress } from "@material-ui/core";
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { modalBasic } from "../../../../Common/FormComponents/common/styleLibrary";
import { connect } from "react-redux";
import { createFolder } from "../../../../ObjectBrowser/actions";
interface ICreateFolder {
classes: any;
modalOpen: boolean;
folderName: string;
createFolder: (newFolder: string) => any;
onClose: () => any;
}
const styles = (theme: Theme) =>
createStyles({
buttonContainer: {
textAlign: "right",
},
pathLabel: {
marginTop: 0,
marginBottom: 32,
},
...modalBasic,
});
const CreateFolderModal = ({
modalOpen,
folderName,
onClose,
createFolder,
classes,
}: ICreateFolder) => {
const [pathUrl, setPathUrl] = useState("");
const resetForm = () => {
setPathUrl("");
};
const createProcess = () => {
createFolder(pathUrl);
onClose();
};
const folderTruncated = folderName.split("/").slice(2).join("/");
return (
<React.Fragment>
<ModalWrapper modalOpen={modalOpen} title="Add Folder" onClose={onClose}>
<Grid container>
<h3 className={classes.pathLabel}>
Current Path: {folderTruncated}/
</h3>
<Grid item xs={12}>
<InputBoxWrapper
value={pathUrl}
label={"Folder Path"}
id={"folderPath"}
name={"folderPath"}
placeholder={"Enter Folder Path"}
onChange={(e) => {
setPathUrl(e.target.value);
}}
/>
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<button
type="button"
color="primary"
className={classes.clearButton}
onClick={resetForm}
>
Clear
</button>
<Button
type="submit"
variant="contained"
color="primary"
disabled={pathUrl.trim() === ""}
onClick={createProcess}
>
Save
</Button>
</Grid>
</Grid>
</ModalWrapper>
</React.Fragment>
);
};
const mapDispatchToProps = {
createFolder,
};
const connector = connect(null, mapDispatchToProps);
export default connector(withStyles(styles)(CreateFolderModal));

View File

@@ -0,0 +1,160 @@
// 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 <http://www.gnu.org/licenses/>.
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import React from "react";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
} from "@material-ui/core";
import api from "../../../../../../common/api";
import Typography from "@material-ui/core/Typography";
const styles = (theme: Theme) =>
createStyles({
errorBlock: {
color: "red",
},
});
interface IDeleteObjectProps {
classes: any;
closeDeleteModalAndRefresh: (refresh: boolean) => void;
deleteOpen: boolean;
selectedObject: string;
selectedBucket: string;
}
interface IDeleteObjectState {
deleteLoading: boolean;
deleteError: string;
}
class DeleteObject extends React.Component<
IDeleteObjectProps,
IDeleteObjectState
> {
state: IDeleteObjectState = {
deleteLoading: false,
deleteError: "",
};
removeRecord() {
const { deleteLoading } = this.state;
const { selectedObject, selectedBucket } = this.props;
if (deleteLoading) {
return;
}
var recursive = false;
if (selectedObject.endsWith("/")) {
recursive = true;
}
this.setState({ deleteLoading: true }, () => {
api
.invoke(
"DELETE",
`/api/v1/buckets/${selectedBucket}/objects?path=${selectedObject}&recursive=${recursive}`
)
.then((res: any) => {
this.setState(
{
deleteLoading: false,
deleteError: "",
},
() => {
this.props.closeDeleteModalAndRefresh(true);
}
);
})
.catch((err) => {
this.setState({
deleteLoading: false,
deleteError: err,
});
});
});
}
render() {
const { classes, deleteOpen, selectedObject } = this.props;
const { deleteLoading, deleteError } = this.state;
return (
<Dialog
open={deleteOpen}
onClose={() => {
this.setState({ deleteError: "" }, () => {
this.props.closeDeleteModalAndRefresh(false);
});
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Delete</DialogTitle>
<DialogContent>
{deleteLoading && <LinearProgress />}
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete: <b>{selectedObject}</b>?{" "}
{deleteError !== "" && (
<React.Fragment>
<br />
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{deleteError}
</Typography>
</React.Fragment>
)}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
this.setState({ deleteError: "" }, () => {
this.props.closeDeleteModalAndRefresh(false);
});
}}
color="primary"
disabled={deleteLoading}
>
Cancel
</Button>
<Button
onClick={() => {
this.setState({ deleteError: "" }, () => {
this.removeRecord();
});
}}
color="secondary"
disabled={deleteLoading}
>
Delete
</Button>
</DialogActions>
</Dialog>
);
}
}
export default withStyles(styles)(DeleteObject);

View File

@@ -0,0 +1,514 @@
// 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 <http://www.gnu.org/licenses/>.
import React, { useState, useEffect } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import TextField from "@material-ui/core/TextField";
import InputAdornment from "@material-ui/core/InputAdornment";
import SearchIcon from "@material-ui/icons/Search";
import { BucketObject, BucketObjectsList } from "./types";
import api from "../../../../../../common/api";
import TableWrapper from "../../../../Common/TableWrapper/TableWrapper";
import { niceBytes } from "../../../../../../common/utils";
import DeleteObject from "./DeleteObject";
import {
actionsTray,
containerForHeader,
objectBrowserCommon,
searchField,
} from "../../../../Common/FormComponents/common/styleLibrary";
import PageHeader from "../../../../Common/PageHeader/PageHeader";
import storage from "local-storage-fallback";
import { isNullOrUndefined } from "util";
import { Button, Input } from "@material-ui/core";
import * as reactMoment from "react-moment";
import { CreateIcon } from "../../../../../../icons";
import Snackbar from "@material-ui/core/Snackbar";
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
import get from "lodash/get";
import { withRouter } from "react-router-dom";
import { addRoute, setAllRoutes } from "../../../../ObjectBrowser/actions";
import { connect } from "react-redux";
import { ObjectBrowserState, Route } from "../../../../ObjectBrowser/reducers";
import CreateFolderModal from "./CreateFolderModal";
import { create } from "domain";
import UploadFile from "../../../../../../icons/UploadFile";
const commonIcon = {
backgroundRepeat: "no-repeat",
backgroundPosition: "center center",
width: 16,
height: 40,
marginRight: 10,
};
const styles = (theme: Theme) =>
createStyles({
seeMore: {
marginTop: theme.spacing(3),
},
paper: {
display: "flex",
overflow: "auto",
flexDirection: "column",
},
addSideBar: {
width: "320px",
padding: "20px",
},
errorBlock: {
color: "red",
},
tableToolbar: {
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(0),
},
minTableHeader: {
color: "#393939",
"& tr": {
"& th": {
fontWeight: "bold",
},
},
},
fileName: {
display: "flex",
alignItems: "center",
},
iconFolder: {
backgroundImage: "url(/images/ob_folder_clear.svg)",
...commonIcon,
},
iconFile: {
backgroundImage: "url(/images/ob_file_clear.svg)",
...commonIcon,
},
buttonsContainer: {
"& .MuiButtonBase-root": {
marginLeft: 10,
},
},
"@global": {
".rowElementRaw:hover .iconFileElm": {
backgroundImage: "url(/images/ob_file_filled.svg)",
},
".rowElementRaw:hover .iconFolderElm": {
backgroundImage: "url(/images/ob_folder_filled.svg)",
},
},
...actionsTray,
...searchField,
...objectBrowserCommon,
...containerForHeader(theme.spacing(4)),
});
interface IListObjectsProps {
classes: any;
match: any;
addRoute: (param1: string, param2: string) => any;
setAllRoutes: (path: string) => any;
routesList: Route[];
}
interface ObjectBrowserReducer {
objectBrowser: ObjectBrowserState;
}
const ListObjects = ({
classes,
match,
addRoute,
setAllRoutes,
routesList,
}: IListObjectsProps) => {
const [records, setRecords] = useState<BucketObject[]>([]);
const [totalRecords, setTotalRecords] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string>("");
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
const [createFolderOpen, setCreateFolderOpen] = useState<boolean>(false);
const [deleteError, setDeleteError] = useState<string>("");
const [selectedObject, setSelectedObject] = useState<string>("");
const [selectedBucket, setSelectedBucket] = useState<string>("");
const [filterObjects, setFilterObjects] = useState<string>("");
const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
const [snackBarMessage, setSnackbarMessage] = useState<string>("");
useEffect(() => {
const bucketName = match.params["bucket"];
const internalPaths = match.params[0];
let extraPath = "";
if (internalPaths) {
extraPath = `?prefix=${internalPaths}/`;
}
api
.invoke("GET", `/api/v1/buckets/${bucketName}/objects${extraPath}`)
.then((res: BucketObjectsList) => {
setLoading(false);
setSelectedBucket(bucketName);
setRecords(res.objects || []);
setTotalRecords(!res.objects ? 0 : res.total);
setError("");
// TODO:
// if we get 0 results, and page > 0 , go down 1 page
})
.catch((err: any) => {
setLoading(false);
setError(err);
});
}, [loading, match]);
useEffect(() => {
const url = get(match, "url", "/object-browser");
if (url !== routesList[routesList.length - 1].route) {
setAllRoutes(url);
}
}, [match, routesList, setAllRoutes]);
const closeDeleteModalAndRefresh = (refresh: boolean) => {
setDeleteOpen(false);
if (refresh) {
setLoading(true);
}
};
const closeAddFolderModal = () => {
setCreateFolderOpen(false);
};
const showSnackBarMessage = (text: string) => {
setSnackbarMessage(text);
setOpenSnackbar(true);
};
const closeSnackBar = () => {
setSnackbarMessage("");
setOpenSnackbar(false);
};
const upload = (e: any, bucketName: string, path: string) => {
if (isNullOrUndefined(e) || isNullOrUndefined(e.target)) {
return;
}
const token: string = storage.getItem("token")!;
e.preventDefault();
let file = e.target.files[0];
const fileName = file.name;
const objectName = `${path}${fileName}`;
let uploadUrl = `/api/v1/buckets/${bucketName}/objects/upload?prefix=${objectName}`;
let xhr = new XMLHttpRequest();
xhr.open("POST", uploadUrl, true);
xhr.setRequestHeader("Authorization", `Bearer ${token}`);
xhr.withCredentials = false;
xhr.onload = function (event) {
// TODO: handle status
if (xhr.status === 401 || xhr.status === 403) {
showSnackBarMessage("An error occurred while uploading the file.");
}
if (xhr.status === 500) {
showSnackBarMessage("An error occurred while uploading the file.");
}
if (xhr.status === 200) {
showSnackBarMessage("Object uploaded successfully.");
setLoading(true);
}
};
xhr.upload.addEventListener("error", (event) => {
// TODO: handle error
showSnackBarMessage("An error occurred while uploading the file.");
});
xhr.upload.addEventListener("progress", (event) => {
// TODO: handle progress with event.loaded, event.total
});
xhr.onerror = () => {
showSnackBarMessage("An error occurred while uploading the file.");
};
const formData = new FormData();
const blobFile = new Blob([file]);
formData.append("upfile", blobFile);
xhr.send(formData);
e.target.value = null;
};
const download = (bucketName: string, objectName: string) => {
const anchor = document.createElement("a");
document.body.appendChild(anchor);
const token: string = storage.getItem("token")!;
const xhr = new XMLHttpRequest();
xhr.open(
"GET",
`/api/v1/buckets/${bucketName}/objects/download?prefix=${objectName}`,
true
);
xhr.setRequestHeader("Authorization", `Bearer ${token}`);
xhr.responseType = "blob";
xhr.onload = function (e) {
if (this.status === 200) {
const blob = new Blob([this.response], {
type: "octet/stream",
});
const blobUrl = window.URL.createObjectURL(blob);
anchor.href = blobUrl;
anchor.download = objectName;
anchor.click();
window.URL.revokeObjectURL(blobUrl);
anchor.remove();
}
};
xhr.send();
};
const displayParsedDate = (date: string) => {
return <reactMoment.default>{date}</reactMoment.default>;
};
const confirmDeleteObject = (object: string) => {
setDeleteOpen(true);
setSelectedObject(object);
};
const downloadObject = (object: string) => {
download(selectedBucket, object);
};
const openPath = (idElement: string) => {
const currentPath = get(match, "url", "/object-browser");
// Element is a folder, we redirect to it
if (idElement.endsWith("/")) {
const idElementClean = idElement
.substr(0, idElement.length - 1)
.split("/");
const lastIndex = idElementClean.length - 1;
const newPath = `${currentPath}/${idElementClean[lastIndex]}`;
addRoute(newPath, idElementClean[lastIndex]);
return;
}
// Element is a file. we open details here
// TODO: Add details open function here.
//console.log("object", idElementClean);
};
const uploadObject = (e: any): void => {
// Handle of deeper routes.
const currentPath = routesList[routesList.length - 1].route;
const splitPaths = currentPath
.split("/")
.filter((item) => item.trim() !== "");
let path = "";
if (splitPaths.length > 2) {
path = `${splitPaths.slice(2).join("/")}/`;
}
let file = e.target.files[0];
showSnackBarMessage(`Uploading: ${file.name}`);
upload(e, selectedBucket, path);
};
const snackBarAction = (
<Button
color="secondary"
size="small"
onClick={() => {
closeSnackBar();
}}
>
Dismiss
</Button>
);
const tableActions = [
{ type: "view", onClick: openPath, sendOnlyId: true },
{ type: "download", onClick: downloadObject, sendOnlyId: true },
{ type: "delete", onClick: confirmDeleteObject, sendOnlyId: true },
];
const displayName = (element: string) => {
let elementString = element;
let icon = `${classes.iconFile} iconFileElm`;
// Element is a folder
if (element.endsWith("/")) {
icon = `${classes.iconFolder} iconFolderElm`;
elementString = element.substr(0, element.length - 1);
}
const splitItem = elementString.split("/");
return (
<div className={classes.fileName}>
<div className={icon} />
<span>{splitItem[splitItem.length - 1]}</span>
</div>
);
};
const filteredRecords = records.filter((b: BucketObject) => {
if (filterObjects === "") {
return true;
} else {
if (b.name.indexOf(filterObjects) >= 0) {
return true;
} else {
return false;
}
}
});
return (
<React.Fragment>
{deleteOpen && (
<DeleteObject
deleteOpen={deleteOpen}
selectedBucket={selectedBucket}
selectedObject={selectedObject}
closeDeleteModalAndRefresh={closeDeleteModalAndRefresh}
/>
)}
{createFolderOpen && (
<CreateFolderModal
modalOpen={createFolderOpen}
folderName={routesList[routesList.length - 1].route}
onClose={closeAddFolderModal}
/>
)}
<Snackbar
open={openSnackbar}
message={snackBarMessage}
action={snackBarAction}
/>
<PageHeader label="Object Browser" />
<Grid container>
<Grid item xs={12} className={classes.container}>
<Grid item xs={12} className={classes.obTitleSection}>
<div>
<BrowserBreadcrumbs />
</div>
<div className={classes.buttonsContainer}>
<Button
variant="contained"
color="primary"
startIcon={<CreateIcon />}
component="label"
onClick={() => {
setCreateFolderOpen(true);
}}
>
Create Folder
</Button>
<Button
variant="contained"
color="primary"
startIcon={<UploadFile />}
component="label"
>
File
<Input
type="file"
onChange={(e) => uploadObject(e)}
id="file-input"
style={{ display: "none" }}
/>
</Button>
</div>
</Grid>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Search Objects"
className={classes.searchField}
id="search-resource"
label=""
onChange={(val) => {
setFilterObjects(val.target.value);
}}
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<TableWrapper
itemActions={tableActions}
columns={[
{
label: "Name",
elementKey: "name",
renderFunction: displayName,
},
{
label: "Last Modified",
elementKey: "last_modified",
renderFunction: displayParsedDate,
},
{
label: "Size",
elementKey: "size",
renderFunction: niceBytes,
},
]}
isLoading={loading}
entityName="Objects"
idField="name"
records={filteredRecords}
/>
</Grid>
</Grid>
</Grid>
</React.Fragment>
);
};
const mapStateToProps = ({ objectBrowser }: ObjectBrowserReducer) => ({
routesList: get(objectBrowser, "routesList", []),
});
const mapDispatchToProps = {
addRoute,
setAllRoutes,
};
const connector = connect(mapStateToProps, mapDispatchToProps);
export default withRouter(connector(withStyles(styles)(ListObjects)));

View File

@@ -0,0 +1,27 @@
// 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 <http://www.gnu.org/licenses/>.
export interface BucketObject {
name: string;
size: number;
last_modified: Date;
content_type: string;
}
export interface BucketObjectsList {
objects: BucketObject[];
total: number;
}

View File

@@ -0,0 +1,234 @@
// 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 <http://www.gnu.org/licenses/>.
import React, { useState } from "react";
import get from "lodash/get";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import { Button, LinearProgress } from "@material-ui/core";
import api from "../../../../common/api";
import { IRemoteBucket } from "../types";
interface IReplicationModal {
open: boolean;
closeModalAndRefresh: () => any;
classes: any;
bucketName: string;
}
const styles = (theme: Theme) =>
createStyles({
errorBlock: {
color: "red",
},
minTableHeader: {
color: "#393939",
"& tr": {
"& th": {
fontWeight: "bold",
},
},
},
buttonContainer: {
textAlign: "right",
},
...modalBasic,
});
const AddReplicationModal = ({
open,
closeModalAndRefresh,
classes,
bucketName,
}: IReplicationModal) => {
const [addError, setAddError] = useState("");
const [addLoading, setAddLoading] = useState(false);
const [accessKey, setAccessKey] = useState("");
const [secretKey, setSecretKey] = useState("");
const [targetURL, setTargetURL] = useState("");
const [targetBucket, setTargetBucket] = useState("");
const [region, setRegion] = useState("");
const addRecord = () => {
const remoteBucketInfo = {
accessKey: accessKey,
secretKey: secretKey,
sourceBucket: bucketName,
targetURL: targetURL,
targetBucket: targetBucket,
region: region,
};
api
.invoke("POST", "/api/v1/remote-buckets", remoteBucketInfo)
.then(() => {
api
.invoke("GET", "/api/v1/remote-buckets")
.then((res: any) => {
const remoteBuckets = get(res, "buckets", []);
const remoteBucket = remoteBuckets.find(
(itemRemote: IRemoteBucket) => {
return itemRemote.sourceBucket === bucketName;
}
);
if (remoteBucket && remoteBucket.remoteARN) {
const remoteARN = remoteBucket.remoteARN;
const replicationInfo = {
destination_bucket: targetBucket,
arn: remoteARN,
};
api
.invoke(
"POST",
`/api/v1/buckets/${bucketName}/replication`,
replicationInfo
)
.then(() => {
setAddLoading(false);
setAddError("");
closeModalAndRefresh();
})
.catch((err) => {
setAddLoading(false);
setAddError(err);
});
}
})
.catch((err) => {
setAddError(err);
});
})
.catch((err) => {
setAddLoading(false);
setAddError(err);
});
};
return (
<ModalWrapper
modalOpen={open}
onClose={() => {
setAddError("");
closeModalAndRefresh();
}}
title="Set Bucket Replication"
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setAddLoading(true);
addRecord();
}}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
{addError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{addError}
</Typography>
</Grid>
)}
<Grid item xs={12}>
<InputBoxWrapper
id="target"
name="target"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setAccessKey(e.target.value);
}}
label="Access Key"
value={accessKey}
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="target"
name="target"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setSecretKey(e.target.value);
}}
label="Secret Key"
value={secretKey}
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="target"
name="target"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTargetURL(e.target.value);
}}
placeholder="https://play.min.io:9000"
label="Target URL"
value={targetURL}
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="target"
name="target"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTargetBucket(e.target.value);
}}
label="Target Bucket"
value={targetBucket}
/>
</Grid>
<Grid item xs={12}>
<InputBoxWrapper
id="target"
name="target"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setRegion(e.target.value);
}}
label="Region"
value={region}
/>
</Grid>
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={addLoading}
>
Save
</Button>
</Grid>
{addLoading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
};
export default withStyles(styles)(AddReplicationModal);

View File

@@ -0,0 +1,199 @@
// 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 <http://www.gnu.org/licenses/>.
import React from "react";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import { Button, LinearProgress } from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import api from "../../../../common/api";
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
const styles = (theme: Theme) =>
createStyles({
errorBlock: {
color: "red",
},
minTableHeader: {
color: "#393939",
"& tr": {
"& th": {
fontWeight: "bold",
},
},
},
buttonContainer: {
textAlign: "right",
},
...modalBasic,
});
interface IEnableBucketEncryptionProps {
classes: any;
open: boolean;
selectedBucket: string;
closeModalAndRefresh: () => void;
}
interface IEnableBucketEncryptionState {
loading: boolean;
encryptionError: string;
kmsKeyID: string;
suffix: string;
encryptionType: string;
}
class EnableBucketEncryption extends React.Component<
IEnableBucketEncryptionProps,
IEnableBucketEncryptionState
> {
state: IEnableBucketEncryptionState = {
loading: false,
encryptionError: "",
kmsKeyID: "",
suffix: "",
encryptionType: "sse-s3",
};
enableBucketEncryption(event: React.FormEvent) {
event.preventDefault();
const { kmsKeyID, loading, encryptionType } = this.state;
const { selectedBucket } = this.props;
if (loading) {
return;
}
api
.invoke("POST", `/api/v1/buckets/${selectedBucket}/encryption/enable`, {
encType: encryptionType,
kmsKeyID: kmsKeyID,
})
.then(() => {
this.setState(
{
loading: false,
encryptionError: "",
},
() => {
this.props.closeModalAndRefresh();
}
);
})
.catch((err: any) => {
this.setState({ encryptionError: err });
});
}
render() {
const { classes, open } = this.props;
const { loading, encryptionError, kmsKeyID, encryptionType } = this.state;
return (
<ModalWrapper
modalOpen={open}
onClose={() => {
this.setState({ encryptionError: "" }, () => {
this.props.closeModalAndRefresh();
});
}}
title="Enable Bucket Encryption"
>
<form
noValidate
autoComplete="off"
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
this.enableBucketEncryption(e);
}}
>
<Grid container>
<Grid item xs={12} className={classes.formScrollable}>
{encryptionError !== "" && (
<Grid item xs={12}>
<Typography
component="p"
variant="body1"
className={classes.errorBlock}
>
{encryptionError}
</Typography>
</Grid>
)}
<Grid item xs={12}>
<SelectWrapper
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
this.setState({ encryptionType: e.target.value as string });
}}
id="select-encryption-type"
name="select-encryption-type"
label={"Encryption Type"}
value={encryptionType}
options={[
{
label: "SSE-S3",
value: "sse-s3",
},
{
label: "SSE-KMS",
value: "sse-kms",
},
]}
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
{encryptionType === "sse-kms" && (
<Grid item xs={12}>
<InputBoxWrapper
id="kms-key-id"
name="kms-key-id"
label="KMS Key ID"
value={kmsKeyID}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ kmsKeyID: e.target.value });
}}
/>
</Grid>
)}
<Grid item xs={12}>
<br />
</Grid>
</Grid>
<Grid item xs={12} className={classes.buttonContainer}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={loading}
>
Save
</Button>
</Grid>
{loading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
</Grid>
</form>
</ModalWrapper>
);
}
}
export default withStyles(styles)(EnableBucketEncryption);

View File

@@ -94,7 +94,7 @@ class SetAccessPolicy extends React.Component<
}
render() {
const { classes, open, actualPolicy } = this.props;
const { classes, open } = this.props;
const { addLoading, addError, accessPolicy } = this.state;
return (
<ModalWrapper

View File

@@ -23,9 +23,19 @@ import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import CircularProgress from "@material-ui/core/CircularProgress";
import api from "../../../../common/api";
import { BucketEvent, BucketEventList, BucketInfo, BucketList } from "../types";
import {
BucketEvent,
BucketEventList,
BucketInfo,
BucketEncryptionInfo,
BucketList,
BucketReplication,
BucketReplicationDestination,
BucketReplicationRule,
BucketReplicationRuleDeleteMarker,
BucketVersioning,
} from "../types";
import { Button } from "@material-ui/core";
import Typography from "@material-ui/core/Typography";
import SetAccessPolicy from "./SetAccessPolicy";
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
import { CreateIcon } from "../../../../icons";
@@ -33,6 +43,11 @@ import AddEvent from "./AddEvent";
import DeleteEvent from "./DeleteEvent";
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
import { niceBytes } from "../../../../common/utils";
import AddReplicationModal from "./AddReplicationModal";
import { containerForHeader } from "../../Common/FormComponents/common/styleLibrary";
import PageHeader from "../../Common/PageHeader/PageHeader";
import Checkbox from "@material-ui/core/Checkbox";
import EnableBucketEncryption from "./EnableBucketEncryption";
const styles = (theme: Theme) =>
createStyles({
@@ -117,6 +132,14 @@ const styles = (theme: Theme) =>
capitalizeFirst: {
textTransform: "capitalize",
},
doubleElement: {
display: "flex",
justifyContent: "space-between",
},
tabPan: {
marginTop: "5px",
},
...containerForHeader(theme.spacing(4)),
});
interface IViewBucketProps {
@@ -124,9 +147,40 @@ interface IViewBucketProps {
match: any;
}
interface TabPanelProps {
children?: React.ReactNode;
index: any;
value: any;
}
function TabPanel(props: TabPanelProps) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
style={{ marginTop: "5px" }}
{...other}
>
{value === index && <React.Fragment>{children}</React.Fragment>}
</div>
);
}
function a11yProps(index: any) {
return {
id: `simple-tab-${index}`,
"aria-controls": `simple-tabpanel-${index}`,
};
}
interface IViewBucketState {
info: BucketInfo | null;
records: BucketEvent[];
replicationRules: BucketReplicationRule[];
totalRecords: number;
loadingBucket: boolean;
loadingEvents: boolean;
@@ -137,18 +191,25 @@ interface IViewBucketState {
setAccessPolicyScreenOpen: boolean;
page: number;
rowsPerPage: number;
curTab: number;
addScreenOpen: boolean;
enableEncryptionScreenOpen: boolean;
deleteOpen: boolean;
selectedBucket: string;
selectedEvent: BucketEvent | null;
bucketSize: string;
errorSize: string;
replicationSet: boolean;
openSetReplication: boolean;
isVersioned: boolean;
encryptionEnabled: boolean;
}
class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
state: IViewBucketState = {
info: null,
records: [],
replicationRules: [],
totalRecords: 0,
loadingBucket: true,
loadingEvents: true,
@@ -158,13 +219,19 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
errBucket: "",
setAccessPolicyScreenOpen: false,
page: 0,
curTab: 0,
rowsPerPage: 10,
addScreenOpen: false,
enableEncryptionScreenOpen: false,
deleteOpen: false,
selectedBucket: "",
selectedEvent: null,
bucketSize: "0",
errorSize: "",
replicationSet: false,
openSetReplication: false,
isVersioned: false,
encryptionEnabled: false,
};
fetchEvents() {
@@ -195,6 +262,29 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
.catch((err: any) => {
this.setState({ loadingEvents: false, error: err });
});
api
.invoke("GET", `/api/v1/buckets/${bucketName}/versioning`)
.then((res: BucketVersioning) => {
this.setState({
isVersioned: res.is_versioned,
});
})
.catch((err: any) => {
this.setState({ error: err });
});
api
.invoke("GET", `/api/v1/buckets/${bucketName}/replication`)
.then((res: BucketReplication) => {
const r = res.rules ? res.rules : [];
this.setState({
replicationRules: r,
});
})
.catch((err: any) => {
this.setState({ error: err });
});
});
}
@@ -241,6 +331,21 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
});
}
fetchBucketEncryptionInfo() {
const { match } = this.props;
const bucketName = match.params["bucketName"];
api
.invoke("GET", `/api/v1/buckets/${bucketName}/encryption/info`)
.then((res: BucketEncryptionInfo) => {
if (res.algorithm) {
this.setState({ encryptionEnabled: true });
}
})
.catch((err) => {
console.log(err);
});
}
closeAddModalAndRefresh() {
this.setState({ setAccessPolicyScreenOpen: false }, () => {
this.loadInfo();
@@ -259,6 +364,7 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
this.loadInfo();
this.fetchEvents();
this.fetchBucketsSize();
this.fetchBucketEncryptionInfo();
}
bucketFilter(): void {}
@@ -276,9 +382,15 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
rowsPerPage,
deleteOpen,
addScreenOpen,
enableEncryptionScreenOpen,
selectedEvent,
bucketSize,
loadingSize,
openSetReplication,
isVersioned,
replicationRules,
curTab,
encryptionEnabled,
} = this.state;
const offset = page * rowsPerPage;
@@ -301,6 +413,7 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
};
let accessPolicy = "n/a";
if (info !== null) {
accessPolicy = info.access;
}
@@ -309,9 +422,43 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
return <React.Fragment>{events.join(", ")}</React.Fragment>;
};
const ruleDestDisplay = (events: BucketReplicationDestination) => {
return (
<React.Fragment>
{events.bucket.replace("arn:aws:s3:::", "")}
</React.Fragment>
);
};
const ruleDelDisplay = (events: BucketReplicationRuleDeleteMarker) => {
return <React.Fragment>{events.status}</React.Fragment>;
};
const setOpenReplicationOpen = (open = false) => {
this.setState({ openSetReplication: open });
};
const handleEncryptionCheckbox = (
event: React.ChangeEvent<HTMLInputElement>
) => {
if (event.target.checked) {
this.setState({ enableEncryptionScreenOpen: true });
} else {
api
.invoke("POST", `/api/v1/buckets/${bucketName}/encryption/disable`)
.then(() => {
this.setState({ encryptionEnabled: false });
})
.catch((err: any) => {
this.setState({ error: err });
});
}
};
const tableActions = [{ type: "delete", onClick: confirmDeleteEvent }];
const filteredRecords = records.slice(offset, offset + rowsPerPage);
const filteredRules = replicationRules.slice(offset, offset + rowsPerPage);
return (
<React.Fragment>
@@ -325,6 +472,16 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
}}
/>
)}
{enableEncryptionScreenOpen && (
<EnableBucketEncryption
open={enableEncryptionScreenOpen}
selectedBucket={bucketName}
closeModalAndRefresh={() => {
this.setState({ enableEncryptionScreenOpen: false });
this.fetchBucketEncryptionInfo();
}}
/>
)}
{setAccessPolicyScreenOpen && (
<SetAccessPolicy
bucketName={bucketName}
@@ -335,130 +492,214 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
}}
/>
)}
{openSetReplication && (
<AddReplicationModal
closeModalAndRefresh={() => {
setOpenReplicationOpen(false);
this.fetchEvents();
}}
open={openSetReplication}
bucketName={bucketName}
/>
)}
<PageHeader label={`Bucket > ${match.params["bucketName"]}`} />
<Grid container>
<Grid item xs={12}>
<Typography variant="h6">
{`Bucket > ${match.params["bucketName"]}`}
</Typography>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<div className={classes.headerContainer}>
<div>
<Paper className={classes.paperContainer}>
<div className={classes.gridContainer}>
<div>Access Policy:</div>
<div className={classes.capitalizeFirst}>
{loadingBucket ? (
<CircularProgress
color="primary"
size={16}
variant="indeterminate"
/>
) : (
accessPolicy.toLowerCase()
)}
</div>
<div>Reported Usage:</div>
<div>
{loadingSize ? (
<CircularProgress
color="primary"
size={16}
variant="indeterminate"
/>
) : (
niceBytes(bucketSize)
)}
</div>
</div>
</Paper>
</div>
<div className={classes.masterActions}>
<Grid item xs={12} className={classes.container}>
<Grid item xs={12}>
<div className={classes.headerContainer}>
<div>
<Paper className={classes.paperContainer}>
<div className={classes.gridContainer}>
<div>Access Policy:</div>
<div className={classes.capitalizeFirst}>
{loadingBucket ? (
<CircularProgress
color="primary"
size={16}
variant="indeterminate"
/>
) : (
accessPolicy.toLowerCase()
)}
</div>
<div>Reported Usage:</div>
<div>
{loadingSize ? (
<CircularProgress
color="primary"
size={16}
variant="indeterminate"
/>
) : (
niceBytes(bucketSize)
)}
</div>
<div>Replication:</div>
<div className={classes.doubleElement}>
<span>{replicationRules.length ? "Yes" : "No"}</span>
</div>
<div>Versioning:</div>
<div>{isVersioned ? "Yes" : "No"}&nbsp;</div>
<div>Encryption:</div>
<div>
<Checkbox
color="primary"
inputProps={{
"aria-label": "secondary checkbox",
}}
onChange={(event) => handleEncryptionCheckbox(event)}
checked={encryptionEnabled}
/>
</div>
</div>
</Paper>
</div>
<div className={classes.masterActions}>
<div>
<Button
variant="contained"
color="primary"
fullWidth
size="medium"
onClick={() => {
this.setState({
setAccessPolicyScreenOpen: true,
});
}}
>
Change Access Policy
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid container item xs={12}>
<Grid item xs={6}>
<Tabs
value={curTab}
onChange={(e: React.ChangeEvent<{}>, newValue: number) => {
this.setState({ curTab: newValue });
}}
indicatorColor="primary"
textColor="primary"
aria-label="cluster-tabs"
>
<Tab label="Events" {...a11yProps(0)} />
<Tab label="Replication" {...a11yProps(1)} />
</Tabs>
</Grid>
<Grid item xs={6} className={classes.actionsTray}>
{curTab === 0 && (
<Button
variant="contained"
color="primary"
fullWidth
startIcon={<CreateIcon />}
size="medium"
onClick={() => {
this.setState({
setAccessPolicyScreenOpen: true,
addScreenOpen: true,
});
}}
>
Change Access Policy
Subscribe to Event
</Button>
</div>
</div>
</div>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={6}>
<Tabs
value={0}
indicatorColor="primary"
textColor="primary"
aria-label="cluster-tabs"
>
<Tab label="Events" />
</Tabs>
</Grid>
<Grid item xs={6} className={classes.actionsTray}>
<Button
variant="contained"
color="primary"
startIcon={<CreateIcon />}
size="medium"
onClick={() => {
this.setState({
addScreenOpen: true,
});
}}
>
Subcribe to Event
</Button>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<TableWrapper
itemActions={tableActions}
columns={[
{ label: "SQS", elementKey: "arn" },
{
label: "Events",
elementKey: "events",
renderFunction: eventsDisplay,
},
{ label: "Prefix", elementKey: "prefix" },
{ label: "Suffix", elementKey: "suffix" },
]}
isLoading={loadingEvents}
records={filteredRecords}
entityName="Events"
idField="id"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true,
},
onChangePage: handleChangePage,
onChangeRowsPerPage: handleChangeRowsPerPage,
ActionsComponent: MinTablePaginationActions,
}}
/>
)}
{curTab === 1 && (
<Button
variant="contained"
color="primary"
startIcon={<CreateIcon />}
size="medium"
onClick={() => {
this.setState({
openSetReplication: true,
});
}}
>
Add Replication Rule
</Button>
)}
</Grid>
</Grid>
<Grid item xs={12}>
<TabPanel index={0} value={curTab}>
<TableWrapper
itemActions={tableActions}
columns={[
{ label: "SQS", elementKey: "arn" },
{
label: "Events",
elementKey: "events",
renderFunction: eventsDisplay,
},
{ label: "Prefix", elementKey: "prefix" },
{ label: "Suffix", elementKey: "suffix" },
]}
isLoading={loadingEvents}
records={filteredRecords}
entityName="Events"
idField="id"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true,
},
onChangePage: handleChangePage,
onChangeRowsPerPage: handleChangeRowsPerPage,
ActionsComponent: MinTablePaginationActions,
}}
/>
</TabPanel>
<TabPanel index={1} value={curTab}>
<TableWrapper
itemActions={tableActions}
columns={[
{ label: "ID", elementKey: "id" },
{
label: "Priority",
elementKey: "priority",
},
{
label: "Destination",
elementKey: "destination",
renderFunction: ruleDestDisplay,
},
{
label: "Delete Replication",
elementKey: "delete_marker_replication",
renderFunction: ruleDelDisplay,
},
{ label: "Status", elementKey: "status" },
]}
isLoading={loadingEvents}
records={filteredRules}
entityName="Replication Rules"
idField="id"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true,
},
onChangePage: handleChangePage,
onChangeRowsPerPage: handleChangeRowsPerPage,
ActionsComponent: MinTablePaginationActions,
}}
/>
</TabPanel>
</Grid>
</Grid>
</Grid>

View File

@@ -0,0 +1,126 @@
// 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 <http://www.gnu.org/licenses/>.
export const ADD_BUCKET_OPEN = "ADD_BUCKET_OPEN";
export const ADD_BUCKET_NAME = "ADD_BUCKET_NAME";
export const ADD_BUCKET_VERSIONED = "ADD_BUCKET_VERSIONED";
export const ADD_BUCKET_QUOTA = "ADD_BUCKET_QUOTA";
export const ADD_BUCKET_QUOTA_TYPE = "ADD_BUCKET_QUOTA_TYPE";
export const ADD_BUCKET_QUOTA_SIZE = "ADD_BUCKET_QUOTA_SIZE";
export const ADD_BUCKET_QUOTA_UNIT = "ADD_BUCKET_QUOTA_UNIT";
export const ADD_BUCKET_RESET = "ADD_BUCKET_RESET";
interface AddBucketOpenAction {
type: typeof ADD_BUCKET_OPEN;
open: boolean;
}
interface AddBucketNameAction {
type: typeof ADD_BUCKET_NAME;
name: string;
}
interface AddBucketVersionedAction {
type: typeof ADD_BUCKET_VERSIONED;
versioned: boolean;
}
interface AddBucketQuotaAction {
type: typeof ADD_BUCKET_QUOTA;
quota: boolean;
}
interface AddBucketQuotaTypeAction {
type: typeof ADD_BUCKET_QUOTA_TYPE;
quotaType: string;
}
interface AddBucketQuotaSizeAction {
type: typeof ADD_BUCKET_QUOTA_SIZE;
quotaSize: string;
}
interface AddBucketQuotaUnitAction {
type: typeof ADD_BUCKET_QUOTA_UNIT;
quotaUnit: string;
}
interface AddBucketResetAction {
type: typeof ADD_BUCKET_RESET;
}
export type BucketActionTypes =
| AddBucketOpenAction
| AddBucketNameAction
| AddBucketVersionedAction
| AddBucketQuotaAction
| AddBucketQuotaTypeAction
| AddBucketQuotaSizeAction
| AddBucketQuotaUnitAction
| AddBucketResetAction;
export function addBucketOpen(open: boolean) {
return {
type: ADD_BUCKET_OPEN,
open: open,
};
}
export function addBucketName(name: string) {
return {
type: ADD_BUCKET_NAME,
name: name,
};
}
export function addBucketVersioned(versioned: boolean) {
return {
type: ADD_BUCKET_VERSIONED,
versioned: versioned,
};
}
export function addBucketQuota(quota: boolean) {
return {
type: ADD_BUCKET_QUOTA,
quota: quota,
};
}
export function addBucketQuotaType(quotaType: string) {
return {
type: ADD_BUCKET_QUOTA_TYPE,
quotaType: quotaType,
};
}
export function addBucketQuotaSize(quotaSize: string) {
return {
type: ADD_BUCKET_QUOTA_SIZE,
quotaSize: quotaSize,
};
}
export function addBucketQuotaUnit(quotaUnit: string) {
return {
type: ADD_BUCKET_QUOTA_UNIT,
quotaUnit: quotaUnit,
};
}
export function addBucketReset() {
return {
type: ADD_BUCKET_RESET,
};
}

View File

@@ -0,0 +1,102 @@
// 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 <http://www.gnu.org/licenses/>.
import {
ADD_BUCKET_NAME,
ADD_BUCKET_OPEN,
ADD_BUCKET_QUOTA,
ADD_BUCKET_QUOTA_SIZE,
ADD_BUCKET_QUOTA_TYPE,
ADD_BUCKET_QUOTA_UNIT,
ADD_BUCKET_RESET,
ADD_BUCKET_VERSIONED,
BucketActionTypes,
} from "./actions";
export interface BucketsState {
open: boolean;
addBucketName: string;
addBucketVersioning: boolean;
addBucketQuotaEnabled: boolean;
addBucketQuotaType: string;
addBucketQuotaSize: string;
addBucketQuotaUnit: string;
}
const initialState: BucketsState = {
open: false,
addBucketName: "",
addBucketVersioning: false,
addBucketQuotaEnabled: false,
addBucketQuotaType: "hard",
addBucketQuotaSize: "1",
addBucketQuotaUnit: "TiB",
};
export function bucketsReducer(
state = initialState,
action: BucketActionTypes
): BucketsState {
switch (action.type) {
case ADD_BUCKET_OPEN:
return {
...state,
open: action.open,
};
case ADD_BUCKET_NAME:
return {
...state,
addBucketName: action.name,
};
case ADD_BUCKET_VERSIONED:
return {
...state,
addBucketVersioning: action.versioned,
};
case ADD_BUCKET_QUOTA:
return {
...state,
addBucketQuotaEnabled: action.quota,
};
case ADD_BUCKET_QUOTA_TYPE:
return {
...state,
addBucketQuotaType: action.quotaType,
};
case ADD_BUCKET_QUOTA_SIZE:
return {
...state,
addBucketQuotaSize: action.quotaSize,
};
case ADD_BUCKET_QUOTA_UNIT:
return {
...state,
addBucketQuotaUnit: action.quotaUnit,
};
case ADD_BUCKET_RESET:
return {
...state,
addBucketName: "",
addBucketVersioning: false,
addBucketQuotaEnabled: false,
addBucketQuotaType: "hard",
addBucketQuotaSize: "1",
addBucketQuotaUnit: "TiB",
};
default:
return state;
}
}

Some files were not shown because too many files have changed in this diff Show More