Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c59737a71d | ||
|
|
7c2ba707eb | ||
|
|
545a890c45 | ||
|
|
4b42308484 | ||
|
|
5a95fed35b | ||
|
|
f880e3976f | ||
|
|
25fa2f3275 | ||
|
|
9f005b7537 | ||
|
|
1ad6e977f2 | ||
|
|
e9a64c5479 | ||
|
|
a2e7259ccb | ||
|
|
d28e66a353 | ||
|
|
e0ff6623bb | ||
|
|
3d59e9ac30 | ||
|
|
cff712f071 |
@@ -47,12 +47,12 @@ var serverCmd = cli.Command{
|
|||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "tls-host",
|
Name: "tls-host",
|
||||||
Value: restapi.GetSSLHostname(),
|
Value: restapi.GetTLSHostname(),
|
||||||
Usage: "HTTPS server hostname",
|
Usage: "HTTPS server hostname",
|
||||||
},
|
},
|
||||||
cli.IntFlag{
|
cli.IntFlag{
|
||||||
Name: "tls-port",
|
Name: "tls-port",
|
||||||
Value: restapi.GetSSLPort(),
|
Value: restapi.GetTLSPort(),
|
||||||
Usage: "HTTPS server port",
|
Usage: "HTTPS server port",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -21,6 +21,7 @@ require (
|
|||||||
github.com/minio/minio-go/v7 v7.0.5-0.20200807085956-d7db33ea7618
|
github.com/minio/minio-go/v7 v7.0.5-0.20200807085956-d7db33ea7618
|
||||||
github.com/minio/operator v0.0.0-20200806194125-c2ff646f4af1
|
github.com/minio/operator v0.0.0-20200806194125-c2ff646f4af1
|
||||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
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/stretchr/testify v1.6.1
|
||||||
github.com/unrolled/secure v1.0.7
|
github.com/unrolled/secure v1.0.7
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
|
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ spec:
|
|||||||
serviceAccountName: console-sa
|
serviceAccountName: console-sa
|
||||||
containers:
|
containers:
|
||||||
- name: console
|
- name: console
|
||||||
image: minio/console:v0.3.10
|
image: minio/console:v0.3.15
|
||||||
imagePullPolicy: "IfNotPresent"
|
imagePullPolicy: "IfNotPresent"
|
||||||
args:
|
args:
|
||||||
- server
|
- server
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ resources:
|
|||||||
- console-configmap.yaml
|
- console-configmap.yaml
|
||||||
- console-service.yaml
|
- console-service.yaml
|
||||||
- console-deployment.yaml
|
- console-deployment.yaml
|
||||||
- minio-operator.yaml
|
- https://github.com/minio/operator/?ref=v3.0.10
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ rules:
|
|||||||
- list
|
- list
|
||||||
- patch
|
- patch
|
||||||
- update
|
- update
|
||||||
|
- deletecollection
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
@@ -22,12 +23,21 @@ rules:
|
|||||||
- services
|
- services
|
||||||
- events
|
- events
|
||||||
- resourcequotas
|
- resourcequotas
|
||||||
|
- nodes
|
||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
- watch
|
- watch
|
||||||
- create
|
- create
|
||||||
- list
|
- list
|
||||||
- patch
|
- patch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- persistentvolumeclaims
|
||||||
|
verbs:
|
||||||
|
- deletecollection
|
||||||
|
- list
|
||||||
|
- get
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- "storage.k8s.io"
|
- "storage.k8s.io"
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ spec:
|
|||||||
serviceAccountName: console-sa
|
serviceAccountName: console-sa
|
||||||
containers:
|
containers:
|
||||||
- name: console
|
- name: console
|
||||||
image: minio/console:v0.3.10
|
image: minio/console:v0.3.15
|
||||||
imagePullPolicy: "IfNotPresent"
|
imagePullPolicy: "IfNotPresent"
|
||||||
env:
|
env:
|
||||||
- name: CONSOLE_OPERATOR_MODE
|
- name: CONSOLE_OPERATOR_MODE
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ resources:
|
|||||||
- console-configmap.yaml
|
- console-configmap.yaml
|
||||||
- console-service.yaml
|
- console-service.yaml
|
||||||
- console-deployment.yaml
|
- console-deployment.yaml
|
||||||
- minio-operator.yaml
|
- https://github.com/minio/operator/?ref=v3.0.10
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,9 @@ type CreateTenantRequest struct {
|
|||||||
// annotations
|
// annotations
|
||||||
Annotations map[string]string `json:"annotations,omitempty"`
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
|
||||||
|
// console image
|
||||||
|
ConsoleImage string `json:"console_image,omitempty"`
|
||||||
|
|
||||||
// enable console
|
// enable console
|
||||||
EnableConsole *bool `json:"enable_console,omitempty"`
|
EnableConsole *bool `json:"enable_console,omitempty"`
|
||||||
|
|
||||||
@@ -60,6 +63,9 @@ type CreateTenantRequest struct {
|
|||||||
// image
|
// image
|
||||||
Image string `json:"image,omitempty"`
|
Image string `json:"image,omitempty"`
|
||||||
|
|
||||||
|
// image pull secret
|
||||||
|
ImagePullSecret string `json:"image_pull_secret,omitempty"`
|
||||||
|
|
||||||
// image registry
|
// image registry
|
||||||
ImageRegistry *ImageRegistry `json:"image_registry,omitempty"`
|
ImageRegistry *ImageRegistry `json:"image_registry,omitempty"`
|
||||||
|
|
||||||
|
|||||||
60
models/delete_tenant_request.go
Normal file
60
models/delete_tenant_request.go
Normal 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeleteTenantRequest delete tenant request
|
||||||
|
//
|
||||||
|
// swagger:model deleteTenantRequest
|
||||||
|
type DeleteTenantRequest struct {
|
||||||
|
|
||||||
|
// delete pvcs
|
||||||
|
DeletePvcs bool `json:"delete_pvcs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates this delete tenant request
|
||||||
|
func (m *DeleteTenantRequest) Validate(formats strfmt.Registry) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary interface implementation
|
||||||
|
func (m *DeleteTenantRequest) MarshalBinary() ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return swag.WriteJSON(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary interface implementation
|
||||||
|
func (m *DeleteTenantRequest) UnmarshalBinary(b []byte) error {
|
||||||
|
var res DeleteTenantRequest
|
||||||
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = res
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -130,8 +130,8 @@ type IdpConfigurationActiveDirectory struct {
|
|||||||
// server insecure
|
// server insecure
|
||||||
ServerInsecure bool `json:"server_insecure,omitempty"`
|
ServerInsecure bool `json:"server_insecure,omitempty"`
|
||||||
|
|
||||||
// skip ssl verification
|
// skip tls verification
|
||||||
SkipSslVerification bool `json:"skip_ssl_verification,omitempty"`
|
SkipTLSVerification bool `json:"skip_tls_verification,omitempty"`
|
||||||
|
|
||||||
// url
|
// url
|
||||||
// Required: true
|
// Required: true
|
||||||
|
|||||||
@@ -34,10 +34,17 @@ import (
|
|||||||
// swagger:model updateTenantRequest
|
// swagger:model updateTenantRequest
|
||||||
type UpdateTenantRequest struct {
|
type UpdateTenantRequest struct {
|
||||||
|
|
||||||
|
// console image
|
||||||
|
// Pattern: ^((.*?)/(.*?):(.+))$
|
||||||
|
ConsoleImage string `json:"console_image,omitempty"`
|
||||||
|
|
||||||
// image
|
// image
|
||||||
// Pattern: ^((.*?)/(.*?):(.+))$
|
// Pattern: ^((.*?)/(.*?):(.+))$
|
||||||
Image string `json:"image,omitempty"`
|
Image string `json:"image,omitempty"`
|
||||||
|
|
||||||
|
// image pull secret
|
||||||
|
ImagePullSecret string `json:"image_pull_secret,omitempty"`
|
||||||
|
|
||||||
// image registry
|
// image registry
|
||||||
ImageRegistry *ImageRegistry `json:"image_registry,omitempty"`
|
ImageRegistry *ImageRegistry `json:"image_registry,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -46,6 +53,10 @@ type UpdateTenantRequest struct {
|
|||||||
func (m *UpdateTenantRequest) Validate(formats strfmt.Registry) error {
|
func (m *UpdateTenantRequest) Validate(formats strfmt.Registry) error {
|
||||||
var res []error
|
var res []error
|
||||||
|
|
||||||
|
if err := m.validateConsoleImage(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := m.validateImage(formats); err != nil {
|
if err := m.validateImage(formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
@@ -60,6 +71,19 @@ func (m *UpdateTenantRequest) Validate(formats strfmt.Registry) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *UpdateTenantRequest) validateConsoleImage(formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if swag.IsZero(m.ConsoleImage) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Pattern("console_image", "body", string(m.ConsoleImage), `^((.*?)/(.*?):(.+))$`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *UpdateTenantRequest) validateImage(formats strfmt.Registry) error {
|
func (m *UpdateTenantRequest) validateImage(formats strfmt.Registry) error {
|
||||||
|
|
||||||
if swag.IsZero(m.Image) { // not required
|
if swag.IsZero(m.Image) { // not required
|
||||||
|
|||||||
@@ -17,14 +17,17 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/hmac"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -33,6 +36,9 @@ import (
|
|||||||
"github.com/minio/console/models"
|
"github.com/minio/console/models"
|
||||||
"github.com/minio/console/pkg/auth/token"
|
"github.com/minio/console/pkg/auth/token"
|
||||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||||
|
"github.com/secure-io/sio-go/sioutil"
|
||||||
|
"golang.org/x/crypto/chacha20"
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,6 +46,7 @@ var (
|
|||||||
errNoAuthToken = errors.New("session token missing")
|
errNoAuthToken = errors.New("session token missing")
|
||||||
errReadingToken = errors.New("session token internal data is malformed")
|
errReadingToken = errors.New("session token internal data is malformed")
|
||||||
errClaimsFormat = errors.New("encrypted session token claims not in the right format")
|
errClaimsFormat = errors.New("encrypted session token claims not in the right format")
|
||||||
|
errorGeneric = errors.New("an error has occurred")
|
||||||
)
|
)
|
||||||
|
|
||||||
// derivedKey is the key used to encrypt the session token claims, its derived using pbkdf on CONSOLE_PBKDF_PASSPHRASE with CONSOLE_PBKDF_SALT
|
// derivedKey is the key used to encrypt the session token claims, its derived using pbkdf on CONSOLE_PBKDF_PASSPHRASE with CONSOLE_PBKDF_SALT
|
||||||
@@ -102,9 +109,10 @@ func NewEncryptedTokenForClient(credentials *credentials.Value, actions []string
|
|||||||
// returns a base64 encoded ciphertext
|
// returns a base64 encoded ciphertext
|
||||||
func encryptClaims(accessKeyID, secretAccessKey, sessionToken string, actions []string) (string, error) {
|
func encryptClaims(accessKeyID, secretAccessKey, sessionToken string, actions []string) (string, error) {
|
||||||
payload := []byte(fmt.Sprintf("%s#%s#%s#%s", accessKeyID, secretAccessKey, sessionToken, strings.Join(actions, ",")))
|
payload := []byte(fmt.Sprintf("%s#%s#%s#%s", accessKeyID, secretAccessKey, sessionToken, strings.Join(actions, ",")))
|
||||||
ciphertext, err := encrypt(payload)
|
ciphertext, err := encrypt(payload, []byte{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
log.Println(err)
|
||||||
|
return "", errorGeneric
|
||||||
}
|
}
|
||||||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||||
}
|
}
|
||||||
@@ -116,7 +124,7 @@ func decryptClaims(ciphertext string) (*DecryptedClaims, error) {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return nil, errClaimsFormat
|
return nil, errClaimsFormat
|
||||||
}
|
}
|
||||||
plaintext, err := decrypt(decoded)
|
plaintext, err := decrypt(decoded, []byte{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return nil, errClaimsFormat
|
return nil, errClaimsFormat
|
||||||
@@ -136,37 +144,137 @@ func decryptClaims(ciphertext string) (*DecryptedClaims, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
|
const (
|
||||||
func encrypt(plaintext []byte) ([]byte, error) {
|
aesGcm = 0x00
|
||||||
block, _ := aes.NewCipher(derivedKey)
|
c20p1305 = 0x01
|
||||||
gcm, err := cipher.NewGCM(block)
|
)
|
||||||
|
|
||||||
|
// Encrypt a blob of data using AEAD scheme, AES-GCM if the executing CPU
|
||||||
|
// provides AES hardware support, otherwise will use ChaCha20-Poly1305
|
||||||
|
// with a pbkdf2 derived key, this function should be used to encrypt a session
|
||||||
|
// or data key provided as plaintext.
|
||||||
|
//
|
||||||
|
// The returned ciphertext data consists of:
|
||||||
|
// iv | AEAD ID | nonce | encrypted data
|
||||||
|
// 32 1 12 ~ len(data)
|
||||||
|
func encrypt(plaintext, associatedData []byte) ([]byte, error) {
|
||||||
|
iv, err := sioutil.Random(32) // 32 bit IV
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
nonce := make([]byte, gcm.NonceSize())
|
var algorithm byte
|
||||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
if sioutil.NativeAES() {
|
||||||
|
algorithm = aesGcm
|
||||||
|
} else {
|
||||||
|
algorithm = c20p1305
|
||||||
|
}
|
||||||
|
var aead cipher.AEAD
|
||||||
|
switch algorithm {
|
||||||
|
case aesGcm:
|
||||||
|
mac := hmac.New(sha256.New, derivedKey)
|
||||||
|
mac.Write(iv)
|
||||||
|
sealingKey := mac.Sum(nil)
|
||||||
|
|
||||||
|
var block cipher.Block
|
||||||
|
block, err = aes.NewCipher(sealingKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
aead, err = cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case c20p1305:
|
||||||
|
var sealingKey []byte
|
||||||
|
sealingKey, err = chacha20.HChaCha20(derivedKey, iv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
aead, err = chacha20poly1305.New(sealingKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nonce, err := sioutil.Random(aead.NonceSize())
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cipherText := gcm.Seal(nonce, nonce, plaintext, nil)
|
|
||||||
return cipherText, nil
|
sealedBytes := aead.Seal(nil, nonce, plaintext, associatedData)
|
||||||
|
|
||||||
|
// ciphertext = iv | AEAD ID | nonce | sealed bytes
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.Write(iv)
|
||||||
|
buf.WriteByte(algorithm)
|
||||||
|
buf.Write(nonce)
|
||||||
|
buf.Write(sealedBytes)
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypts a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
|
// Decrypts a blob of data using AEAD scheme AES-GCM if the executing CPU
|
||||||
func decrypt(data []byte) ([]byte, error) {
|
// provides AES hardware support, otherwise will use ChaCha20-Poly1305with
|
||||||
block, err := aes.NewCipher(derivedKey)
|
// and a pbkdf2 derived key
|
||||||
|
func decrypt(ciphertext []byte, associatedData []byte) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
iv [32]byte
|
||||||
|
algorithm [1]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 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := io.ReadFull(r, algorithm[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := io.ReadFull(r, nonce[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var aead cipher.AEAD
|
||||||
|
switch algorithm[0] {
|
||||||
|
case aesGcm:
|
||||||
|
mac := hmac.New(sha256.New, derivedKey)
|
||||||
|
mac.Write(iv[:])
|
||||||
|
sealingKey := mac.Sum(nil)
|
||||||
|
block, err := aes.NewCipher(sealingKey[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
aead, err = cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case c20p1305:
|
||||||
|
sealingKey, err := chacha20.HChaCha20(derivedKey, iv[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
aead, err = chacha20poly1305.New(sealingKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid algorithm: %v", algorithm)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nonce) != aead.NonceSize() {
|
||||||
|
return nil, fmt.Errorf("invalid nonce size %d, expected %d", len(nonce), aead.NonceSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
sealedBytes, err := ioutil.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
gcm, err := cipher.NewGCM(block)
|
|
||||||
if err != nil {
|
plaintext, err := aead.Open(nil, nonce[:], sealedBytes, associatedData)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nonceSize := gcm.NonceSize()
|
|
||||||
nonce, cipherText := data[:nonceSize], data[nonceSize:]
|
|
||||||
plaintext, err := gcm.Open(nil, nonce, cipherText, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return plaintext, nil
|
return plaintext, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,12 +36,12 @@ func TestNewJWTWithClaimsForClient(t *testing.T) {
|
|||||||
funcAssert := assert.New(t)
|
funcAssert := assert.New(t)
|
||||||
// Test-1 : NewEncryptedTokenForClient() is generated correctly without errors
|
// Test-1 : NewEncryptedTokenForClient() is generated correctly without errors
|
||||||
function := "NewEncryptedTokenForClient()"
|
function := "NewEncryptedTokenForClient()"
|
||||||
jwt, err := NewEncryptedTokenForClient(creds, []string{""})
|
token, err := NewEncryptedTokenForClient(creds, []string{""})
|
||||||
if err != nil || jwt == "" {
|
if err != nil || token == "" {
|
||||||
t.Errorf("Failed on %s:, error occurred: %s", function, err)
|
t.Errorf("Failed on %s:, error occurred: %s", function, err)
|
||||||
}
|
}
|
||||||
// saving jwt for future tests
|
// saving token for future tests
|
||||||
goodToken = jwt
|
goodToken = token
|
||||||
// Test-2 : NewEncryptedTokenForClient() throws error because of empty credentials
|
// Test-2 : NewEncryptedTokenForClient() throws error because of empty credentials
|
||||||
if _, err = NewEncryptedTokenForClient(nil, []string{""}); err != nil {
|
if _, err = NewEncryptedTokenForClient(nil, []string{""}); err != nil {
|
||||||
funcAssert.Equal("provided credentials are empty", err.Error())
|
funcAssert.Equal("provided credentials are empty", err.Error())
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -111,7 +111,7 @@ const AddTenant = ({
|
|||||||
const [accessKey, setAccessKey] = useState<string>("");
|
const [accessKey, setAccessKey] = useState<string>("");
|
||||||
const [secretKey, setSecretKey] = useState<string>("");
|
const [secretKey, setSecretKey] = useState<string>("");
|
||||||
const [enableConsole, setEnableConsole] = useState<boolean>(true);
|
const [enableConsole, setEnableConsole] = useState<boolean>(true);
|
||||||
const [enableSSL, setEnableSSL] = useState<boolean>(false);
|
const [enableTLS, setEnableTLS] = useState<boolean>(false);
|
||||||
const [sizeFactor, setSizeFactor] = useState<string>("Gi");
|
const [sizeFactor, setSizeFactor] = useState<string>("Gi");
|
||||||
const [storageClasses, setStorageClassesList] = useState<Opts[]>([]);
|
const [storageClasses, setStorageClassesList] = useState<Opts[]>([]);
|
||||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||||
@@ -274,7 +274,7 @@ const AddTenant = ({
|
|||||||
name: tenantName,
|
name: tenantName,
|
||||||
service_name: tenantName,
|
service_name: tenantName,
|
||||||
image: imageName,
|
image: imageName,
|
||||||
enable_ssl: enableSSL,
|
enable_tls: enableTLS,
|
||||||
enable_console: enableConsole,
|
enable_console: enableConsole,
|
||||||
access_key: accessKey,
|
access_key: accessKey,
|
||||||
secret_key: secretKey,
|
secret_key: secretKey,
|
||||||
@@ -750,17 +750,17 @@ const AddTenant = ({
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<CheckboxWrapper
|
<CheckboxWrapper
|
||||||
value="enable_ssl"
|
value="enable_tls"
|
||||||
id="enable_ssl"
|
id="enable_tls"
|
||||||
name="enable_ssl"
|
name="enable_tls"
|
||||||
checked={enableSSL}
|
checked={enableTLS}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const targetD = e.target;
|
const targetD = e.target;
|
||||||
const checked = targetD.checked;
|
const checked = targetD.checked;
|
||||||
|
|
||||||
setEnableSSL(checked);
|
setEnableTLS(checked);
|
||||||
}}
|
}}
|
||||||
label={"Enable SSL"}
|
label={"Enable TLS"}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@@ -882,9 +882,9 @@ const AddTenant = ({
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell align="right" className={classes.tableTitle}>
|
<TableCell align="right" className={classes.tableTitle}>
|
||||||
Enable SSL
|
Enable TLS
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>{enableSSL ? "Enabled" : "Disabled"}</TableCell>
|
<TableCell>{enableTLS ? "Enabled" : "Disabled"}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell align="right" className={classes.tableTitle}>
|
<TableCell align="right" className={classes.tableTitle}>
|
||||||
|
|||||||
2635
portal-ui/yarn.lock
2635
portal-ui/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -54,10 +54,6 @@ import (
|
|||||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
minioRegCred = "minio-regcred-secret"
|
|
||||||
)
|
|
||||||
|
|
||||||
type imageRegistry struct {
|
type imageRegistry struct {
|
||||||
Auths map[string]imageRegistryCredentials `json:"auths"`
|
Auths map[string]imageRegistryCredentials `json:"auths"`
|
||||||
}
|
}
|
||||||
@@ -114,7 +110,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
|||||||
err := getDeleteTenantResponse(session, params)
|
err := getDeleteTenantResponse(session, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return admin_api.NewTenantInfoDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to delete tenant")})
|
return admin_api.NewTenantInfoDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
|
||||||
}
|
}
|
||||||
return admin_api.NewTenantInfoOK()
|
return admin_api.NewTenantInfoOK()
|
||||||
|
|
||||||
@@ -149,25 +145,58 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteTenantAction performs the actions of deleting a tenant
|
|
||||||
func deleteTenantAction(ctx context.Context, operatorClient OperatorClient, nameSpace, instanceName string) error {
|
|
||||||
err := operatorClient.TenantDelete(ctx, nameSpace, instanceName, metav1.DeleteOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDeleteTenantResponse gets the output of deleting a minio instance
|
// getDeleteTenantResponse gets the output of deleting a minio instance
|
||||||
func getDeleteTenantResponse(session *models.Principal, params admin_api.DeleteTenantParams) error {
|
func getDeleteTenantResponse(session *models.Principal, params admin_api.DeleteTenantParams) error {
|
||||||
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// get Kubernetes Client
|
||||||
|
clientset, err := cluster.K8sClient(session.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
opClient := &operatorClient{
|
opClient := &operatorClient{
|
||||||
client: opClientClientSet,
|
client: opClientClientSet,
|
||||||
}
|
}
|
||||||
return deleteTenantAction(context.Background(), opClient, params.Namespace, params.Tenant)
|
deleteTenantPVCs := false
|
||||||
|
if params.Body != nil {
|
||||||
|
deleteTenantPVCs = params.Body.DeletePvcs
|
||||||
|
}
|
||||||
|
return deleteTenantAction(context.Background(), opClient, clientset.CoreV1(), params.Namespace, params.Tenant, deleteTenantPVCs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteTenantAction performs the actions of deleting a tenant
|
||||||
|
//
|
||||||
|
// It also adds the option of deleting the tenant's underlying pvcs if deletePvcs set
|
||||||
|
func deleteTenantAction(
|
||||||
|
ctx context.Context,
|
||||||
|
operatorClient OperatorClient,
|
||||||
|
clientset v1.CoreV1Interface,
|
||||||
|
namespace, tenantName string,
|
||||||
|
deletePvcs bool) error {
|
||||||
|
|
||||||
|
err := operatorClient.TenantDelete(ctx, namespace, tenantName, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
// try to delete pvc even if the tenant doesn't exist anymore but only if deletePvcs is set to true,
|
||||||
|
// else, we return the error
|
||||||
|
if (deletePvcs && !k8sErrors.IsNotFound(err)) || !deletePvcs {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if deletePvcs {
|
||||||
|
opts := metav1.ListOptions{
|
||||||
|
LabelSelector: fmt.Sprintf("%s=%s", operator.TenantLabel, tenantName),
|
||||||
|
}
|
||||||
|
err = clientset.PersistentVolumeClaims(namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// delete all tenant's secrets only if deletePvcs = true
|
||||||
|
return clientset.Secrets(namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, opts)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTenantScheme(mi *operator.Tenant) string {
|
func getTenantScheme(mi *operator.Tenant) string {
|
||||||
@@ -345,10 +374,10 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
|
|
||||||
if minioImage == "" {
|
if minioImage == "" {
|
||||||
minImg, err := cluster.GetMinioImage()
|
minImg, err := cluster.GetMinioImage()
|
||||||
if err != nil {
|
// we can live without figuring out the latest version of MinIO, Operator will use a hardcoded value
|
||||||
return nil, err
|
if err == nil {
|
||||||
|
minioImage = *minImg
|
||||||
}
|
}
|
||||||
minioImage = *minImg
|
|
||||||
}
|
}
|
||||||
// get Kubernetes Client
|
// get Kubernetes Client
|
||||||
clientset, err := cluster.K8sClient(session.SessionToken)
|
clientset, err := cluster.K8sClient(session.SessionToken)
|
||||||
@@ -369,12 +398,16 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
secretKey = tenantReq.SecretKey
|
secretKey = tenantReq.SecretKey
|
||||||
}
|
}
|
||||||
|
|
||||||
secretName := fmt.Sprintf("%s-secret", *tenantReq.Name)
|
tenantName := *tenantReq.Name
|
||||||
|
secretName := fmt.Sprintf("%s-secret", tenantName)
|
||||||
imm := true
|
imm := true
|
||||||
|
|
||||||
instanceSecret := corev1.Secret{
|
instanceSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: secretName,
|
Name: secretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
@@ -403,7 +436,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
//Construct a MinIO Instance with everything we are getting from parameters
|
//Construct a MinIO Instance with everything we are getting from parameters
|
||||||
minInst := operator.Tenant{
|
minInst := operator.Tenant{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: *tenantReq.Name,
|
Name: tenantName,
|
||||||
},
|
},
|
||||||
Spec: operator.TenantSpec{
|
Spec: operator.TenantSpec{
|
||||||
Image: minioImage,
|
Image: minioImage,
|
||||||
@@ -420,7 +453,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
url := *tenantReq.Idp.ActiveDirectory.URL
|
url := *tenantReq.Idp.ActiveDirectory.URL
|
||||||
userNameFormat := *tenantReq.Idp.ActiveDirectory.UsernameFormat
|
userNameFormat := *tenantReq.Idp.ActiveDirectory.UsernameFormat
|
||||||
userSearchFilter := *tenantReq.Idp.ActiveDirectory.UserSearchFilter
|
userSearchFilter := *tenantReq.Idp.ActiveDirectory.UserSearchFilter
|
||||||
tlsSkipVerify := tenantReq.Idp.ActiveDirectory.SkipSslVerification
|
tlsSkipVerify := tenantReq.Idp.ActiveDirectory.SkipTLSVerification
|
||||||
serverInsecure := tenantReq.Idp.ActiveDirectory.ServerInsecure
|
serverInsecure := tenantReq.Idp.ActiveDirectory.ServerInsecure
|
||||||
groupSearchDN := tenantReq.Idp.ActiveDirectory.GroupSearchBaseDn
|
groupSearchDN := tenantReq.Idp.ActiveDirectory.GroupSearchBaseDn
|
||||||
groupSearchFilter := tenantReq.Idp.ActiveDirectory.GroupSearchFilter
|
groupSearchFilter := tenantReq.Idp.ActiveDirectory.GroupSearchFilter
|
||||||
@@ -467,7 +500,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
}
|
}
|
||||||
|
|
||||||
isEncryptionAvailable := false
|
isEncryptionAvailable := false
|
||||||
if *tenantReq.EnableTLS {
|
if tenantReq.EnableTLS != nil && *tenantReq.EnableTLS {
|
||||||
// If user request autoCert, Operator will generate certificate keypair for MinIO (server), Console (server) and KES (server and app mTLS)
|
// If user request autoCert, Operator will generate certificate keypair for MinIO (server), Console (server) and KES (server and app mTLS)
|
||||||
isEncryptionAvailable = true
|
isEncryptionAvailable = true
|
||||||
minInst.Spec.RequestAutoCert = *tenantReq.EnableTLS
|
minInst.Spec.RequestAutoCert = *tenantReq.EnableTLS
|
||||||
@@ -493,6 +526,9 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
externalTLSCertificateSecret := corev1.Secret{
|
externalTLSCertificateSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: externalTLSCertificateSecretName,
|
Name: externalTLSCertificateSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Type: corev1.SecretTypeTLS,
|
Type: corev1.SecretTypeTLS,
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
@@ -520,13 +556,13 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
})
|
})
|
||||||
// KES client mTLSCertificates used by MinIO instance, only if autoCert is not enabled
|
// KES client mTLSCertificates used by MinIO instance, only if autoCert is not enabled
|
||||||
if !minInst.Spec.RequestAutoCert {
|
if !minInst.Spec.RequestAutoCert {
|
||||||
minInst.Spec.ExternalClientCertSecret, err = getTenantExternalClientCertificates(ctx, clientset, ns, tenantReq.Encryption, secretName)
|
minInst.Spec.ExternalClientCertSecret, err = getTenantExternalClientCertificates(ctx, clientset, ns, tenantReq.Encryption, secretName, tenantName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// KES configuration for Tenant instance
|
// KES configuration for Tenant instance
|
||||||
minInst.Spec.KES, err = getKESConfiguration(ctx, clientset, ns, tenantReq.Encryption, secretName, minInst.Spec.RequestAutoCert)
|
minInst.Spec.KES, err = getKESConfiguration(ctx, clientset, ns, tenantReq.Encryption, secretName, tenantName, minInst.Spec.RequestAutoCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -536,11 +572,13 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
var consoleAccess string
|
var consoleAccess string
|
||||||
var consoleSecret string
|
var consoleSecret string
|
||||||
|
|
||||||
//enableConsole := true
|
enableConsole := true
|
||||||
enableConsole := *tenantReq.EnableConsole
|
if tenantReq.EnableConsole != nil && *tenantReq.EnableConsole {
|
||||||
|
enableConsole = *tenantReq.EnableConsole
|
||||||
|
}
|
||||||
|
|
||||||
if enableConsole {
|
if enableConsole {
|
||||||
consoleSelector := fmt.Sprintf("%s-console", *tenantReq.Name)
|
consoleSelector := fmt.Sprintf("%s-console", tenantName)
|
||||||
consoleSecretName := fmt.Sprintf("%s-secret", consoleSelector)
|
consoleSecretName := fmt.Sprintf("%s-secret", consoleSelector)
|
||||||
consoleAccess = RandomCharString(16)
|
consoleAccess = RandomCharString(16)
|
||||||
consoleSecret = RandomCharString(32)
|
consoleSecret = RandomCharString(32)
|
||||||
@@ -548,6 +586,9 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
instanceSecret := corev1.Secret{
|
instanceSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: consoleSecretName,
|
Name: consoleSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
@@ -585,9 +626,9 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const consoleVersion = "minio/console:v0.3.10"
|
const consoleVersion = "minio/console:v0.3.15"
|
||||||
minInst.Spec.Console = &operator.ConsoleConfiguration{
|
minInst.Spec.Console = &operator.ConsoleConfiguration{
|
||||||
Replicas: 2,
|
Replicas: 1,
|
||||||
Image: consoleVersion,
|
Image: consoleVersion,
|
||||||
ConsoleSecret: &corev1.LocalObjectReference{Name: consoleSecretName},
|
ConsoleSecret: &corev1.LocalObjectReference{Name: consoleSecretName},
|
||||||
Resources: corev1.ResourceRequirements{
|
Resources: corev1.ResourceRequirements{
|
||||||
@@ -597,7 +638,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !minInst.Spec.RequestAutoCert && tenantReq.TLS.Console != nil {
|
if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Console != nil {
|
||||||
consoleExternalTLSCertificateSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
consoleExternalTLSCertificateSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
||||||
tlsCrt, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Console.Crt)
|
tlsCrt, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Console.Crt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -610,6 +651,9 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
consoleExternalTLSCertificateSecret := corev1.Secret{
|
consoleExternalTLSCertificateSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: consoleExternalTLSCertificateSecretName,
|
Name: consoleExternalTLSCertificateSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Type: corev1.SecretTypeTLS,
|
Type: corev1.SecretTypeTLS,
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
@@ -658,13 +702,25 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
minInst.Spec.Mountpath = tenantReq.MounthPath
|
minInst.Spec.Mountpath = tenantReq.MounthPath
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := setImageRegistry(ctx, tenantReq.ImageRegistry, clientset.CoreV1(), ns); err != nil {
|
// We accept either `image_pull_secret` or the individual details of the `image_registry` but not both
|
||||||
|
var imagePullSecret string
|
||||||
|
|
||||||
|
if tenantReq.ImagePullSecret != "" {
|
||||||
|
imagePullSecret = tenantReq.ImagePullSecret
|
||||||
|
} else if imagePullSecret, err = setImageRegistry(ctx, tenantName, tenantReq.ImageRegistry, clientset.CoreV1(), ns); err != nil {
|
||||||
log.Println("error setting image registry secret:", err)
|
log.Println("error setting image registry secret:", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// pass the image pull secret to the Tenant
|
||||||
|
if imagePullSecret != "" {
|
||||||
|
minInst.Spec.ImagePullSecret = corev1.LocalObjectReference{
|
||||||
|
Name: imagePullSecret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
minInst.Spec.ImagePullSecret = corev1.LocalObjectReference{
|
// set console image if provided
|
||||||
Name: minioRegCred,
|
if tenantReq.ConsoleImage != "" {
|
||||||
|
minInst.Spec.Console.Image = tenantReq.ConsoleImage
|
||||||
}
|
}
|
||||||
|
|
||||||
opClient, err := cluster.OperatorClient(session.SessionToken)
|
opClient, err := cluster.OperatorClient(session.SessionToken)
|
||||||
@@ -679,7 +735,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
|
|
||||||
// Integratrions
|
// Integratrions
|
||||||
if os.Getenv("GKE_INTEGRATION") != "" {
|
if os.Getenv("GKE_INTEGRATION") != "" {
|
||||||
err := gkeIntegration(clientset, *tenantReq.Name, ns, session.SessionToken)
|
err := gkeIntegration(clientset, tenantName, ns, session.SessionToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -698,9 +754,11 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setImageRegistry(ctx context.Context, req *models.ImageRegistry, clientset v1.CoreV1Interface, namespace string) error {
|
// setImageRegistry creates a secret to store the private registry credentials, if one exist it updates the existing one
|
||||||
|
// returns the name of the secret created/updated
|
||||||
|
func setImageRegistry(ctx context.Context, tenantName string, req *models.ImageRegistry, clientset v1.CoreV1Interface, namespace string) (string, error) {
|
||||||
if req == nil || req.Registry == nil || req.Username == nil || req.Password == nil {
|
if req == nil || req.Registry == nil || req.Username == nil || req.Password == nil {
|
||||||
return nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
credentials := make(map[string]imageRegistryCredentials)
|
credentials := make(map[string]imageRegistryCredentials)
|
||||||
@@ -718,12 +776,17 @@ func setImageRegistry(ctx context.Context, req *models.ImageRegistry, clientset
|
|||||||
}
|
}
|
||||||
imRegistryJSON, err := json.Marshal(imRegistry)
|
imRegistryJSON, err := json.Marshal(imRegistry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pullSecretName := fmt.Sprintf("%s-regcred", tenantName)
|
||||||
|
|
||||||
instanceSecret := corev1.Secret{
|
instanceSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: minioRegCred,
|
Name: pullSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
corev1.DockerConfigJsonKey: []byte(string(imRegistryJSON)),
|
corev1.DockerConfigJsonKey: []byte(string(imRegistryJSON)),
|
||||||
@@ -732,22 +795,22 @@ func setImageRegistry(ctx context.Context, req *models.ImageRegistry, clientset
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get or Create secret if it doesn't exist
|
// Get or Create secret if it doesn't exist
|
||||||
_, err = clientset.Secrets(namespace).Get(ctx, minioRegCred, metav1.GetOptions{})
|
_, err = clientset.Secrets(namespace).Get(ctx, pullSecretName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if k8sErrors.IsNotFound(err) {
|
if k8sErrors.IsNotFound(err) {
|
||||||
_, err = clientset.Secrets(namespace).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
_, err = clientset.Secrets(namespace).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
return nil
|
return "", nil
|
||||||
}
|
}
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
_, err = clientset.Secrets(namespace).Update(ctx, &instanceSecret, metav1.UpdateOptions{})
|
_, err = clientset.Secrets(namespace).Update(ctx, &instanceSecret, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
return nil
|
return pullSecretName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateTenantAction does an update on the minioTenant by patching the desired changes
|
// updateTenantAction does an update on the minioTenant by patching the desired changes
|
||||||
@@ -755,25 +818,35 @@ func updateTenantAction(ctx context.Context, operatorClient OperatorClient, clie
|
|||||||
imageToUpdate := params.Body.Image
|
imageToUpdate := params.Body.Image
|
||||||
imageRegistryReq := params.Body.ImageRegistry
|
imageRegistryReq := params.Body.ImageRegistry
|
||||||
|
|
||||||
if err := setImageRegistry(ctx, imageRegistryReq, clientset, namespace); err != nil {
|
|
||||||
log.Println("error setting image registry secret:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
minInst, err := operatorClient.TenantGet(ctx, namespace, params.Tenant, metav1.GetOptions{})
|
minInst, err := operatorClient.TenantGet(ctx, namespace, params.Tenant, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// we can take either the `image_pull_secret` of the `image_registry` but not both
|
||||||
|
if params.Body.ImagePullSecret != "" {
|
||||||
|
minInst.Spec.ImagePullSecret.Name = params.Body.ImagePullSecret
|
||||||
|
} else {
|
||||||
|
// update the image pull secret content
|
||||||
|
if _, err := setImageRegistry(ctx, params.Tenant, imageRegistryReq, clientset, namespace); err != nil {
|
||||||
|
log.Println("error setting image registry secret:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the console image
|
||||||
|
if strings.TrimSpace(params.Body.ConsoleImage) != "" && minInst.Spec.Console != nil {
|
||||||
|
minInst.Spec.Console.Image = params.Body.ConsoleImage
|
||||||
|
}
|
||||||
|
|
||||||
// if image to update is empty we'll use the latest image by default
|
// if image to update is empty we'll use the latest image by default
|
||||||
if strings.TrimSpace(imageToUpdate) != "" {
|
if strings.TrimSpace(imageToUpdate) != "" {
|
||||||
minInst.Spec.Image = imageToUpdate
|
minInst.Spec.Image = imageToUpdate
|
||||||
} else {
|
} else {
|
||||||
im, err := cluster.GetLatestMinioImage(httpCl)
|
im, err := cluster.GetLatestMinioImage(httpCl)
|
||||||
if err != nil {
|
// if we can't get the MinIO image, we won' auto-update it unless it's explicit by name
|
||||||
return err
|
if err == nil {
|
||||||
|
minInst.Spec.Image = *im
|
||||||
}
|
}
|
||||||
minInst.Spec.Image = *im
|
|
||||||
}
|
}
|
||||||
|
|
||||||
payloadBytes, err := json.Marshal(minInst)
|
payloadBytes, err := json.Marshal(minInst)
|
||||||
@@ -1331,7 +1404,7 @@ func parseNodeSelectorTerm(term *corev1.NodeSelectorTerm) *models.NodeSelectorTe
|
|||||||
return &t
|
return &t
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTenantExternalClientCertificates(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName string) (clientCertificates *operator.LocalCertificateReference, err error) {
|
func getTenantExternalClientCertificates(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string) (clientCertificates *operator.LocalCertificateReference, err error) {
|
||||||
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
||||||
// If there's an error during this process we delete all KES configuration secrets
|
// If there's an error during this process we delete all KES configuration secrets
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -1356,6 +1429,9 @@ func getTenantExternalClientCertificates(ctx context.Context, clientSet *kuberne
|
|||||||
instanceExternalClientCertificateSecret := corev1.Secret{
|
instanceExternalClientCertificateSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: instanceExternalClientCertificateSecretName,
|
Name: instanceExternalClientCertificateSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Type: corev1.SecretTypeTLS,
|
Type: corev1.SecretTypeTLS,
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
@@ -1376,7 +1452,7 @@ func getTenantExternalClientCertificates(ctx context.Context, clientSet *kuberne
|
|||||||
return clientCertificates, nil
|
return clientCertificates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKESConfiguration(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName string, autoCert bool) (kesConfiguration *operator.KESConfig, err error) {
|
func getKESConfiguration(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string, autoCert bool) (kesConfiguration *operator.KESConfig, err error) {
|
||||||
// secrets used by the KES configuration
|
// secrets used by the KES configuration
|
||||||
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
||||||
kesExternalCertificateSecretName := fmt.Sprintf("%s-kes-external-mtls-certificates", secretName)
|
kesExternalCertificateSecretName := fmt.Sprintf("%s-kes-external-mtls-certificates", secretName)
|
||||||
@@ -1432,6 +1508,9 @@ func getKESConfiguration(ctx context.Context, clientSet *kubernetes.Clientset, n
|
|||||||
kesExternalCertificateSecret := corev1.Secret{
|
kesExternalCertificateSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: kesExternalCertificateSecretName,
|
Name: kesExternalCertificateSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Type: corev1.SecretTypeTLS,
|
Type: corev1.SecretTypeTLS,
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
@@ -1617,6 +1696,9 @@ func getKESConfiguration(ctx context.Context, clientSet *kubernetes.Clientset, n
|
|||||||
kesClientCertSecret := corev1.Secret{
|
kesClientCertSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: kesClientCertSecretName,
|
Name: kesClientCertSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
Data: mTLSCertificates,
|
Data: mTLSCertificates,
|
||||||
@@ -1640,6 +1722,9 @@ func getKESConfiguration(ctx context.Context, clientSet *kubernetes.Clientset, n
|
|||||||
kesConfigurationSecret := corev1.Secret{
|
kesConfigurationSecret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: kesConfigurationSecretName,
|
Name: kesConfigurationSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Immutable: &imm,
|
Immutable: &imm,
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
|
|||||||
@@ -33,9 +33,11 @@ import (
|
|||||||
operator "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
operator "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
||||||
v1 "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
v1 "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
types "k8s.io/apimachinery/pkg/types"
|
types "k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
)
|
)
|
||||||
@@ -335,12 +337,13 @@ func Test_TenantInfo(t *testing.T) {
|
|||||||
|
|
||||||
func Test_deleteTenantAction(t *testing.T) {
|
func Test_deleteTenantAction(t *testing.T) {
|
||||||
opClient := opClientMock{}
|
opClient := opClientMock{}
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
operatorClient OperatorClient
|
operatorClient OperatorClient
|
||||||
nameSpace string
|
nameSpace string
|
||||||
tenantName string
|
tenantName string
|
||||||
|
deletePvcs bool
|
||||||
|
objs []runtime.Object
|
||||||
mockTenantDelete func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error
|
mockTenantDelete func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -355,6 +358,7 @@ func Test_deleteTenantAction(t *testing.T) {
|
|||||||
operatorClient: opClient,
|
operatorClient: opClient,
|
||||||
nameSpace: "default",
|
nameSpace: "default",
|
||||||
tenantName: "minio-tenant",
|
tenantName: "minio-tenant",
|
||||||
|
deletePvcs: false,
|
||||||
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@@ -368,17 +372,155 @@ func Test_deleteTenantAction(t *testing.T) {
|
|||||||
operatorClient: opClient,
|
operatorClient: opClient,
|
||||||
nameSpace: "default",
|
nameSpace: "default",
|
||||||
tenantName: "minio-tenant",
|
tenantName: "minio-tenant",
|
||||||
|
deletePvcs: false,
|
||||||
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
||||||
return errors.New("something happened")
|
return errors.New("something happened")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Delete only PVCs of the defined tenant on the specific namespace
|
||||||
|
name: "Delete PVCs on Tenant Deletion",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
operatorClient: opClient,
|
||||||
|
nameSpace: "minio-tenant",
|
||||||
|
tenantName: "tenant1",
|
||||||
|
deletePvcs: true,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "PVC1",
|
||||||
|
Namespace: "minio-tenant",
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: "tenant1",
|
||||||
|
operator.ZoneLabel: "zone-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Do not delete underlying pvcs
|
||||||
|
name: "Don't Delete PVCs on Tenant Deletion",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
operatorClient: opClient,
|
||||||
|
nameSpace: "minio-tenant",
|
||||||
|
tenantName: "tenant1",
|
||||||
|
deletePvcs: false,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "PVC1",
|
||||||
|
Namespace: "minio-tenant",
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: "tenant1",
|
||||||
|
operator.ZoneLabel: "zone-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// If error is different than NotFound, PVC deletion should not continue
|
||||||
|
name: "Don't delete pvcs if error Deleting Tenant, return",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
operatorClient: opClient,
|
||||||
|
nameSpace: "minio-tenant",
|
||||||
|
tenantName: "tenant1",
|
||||||
|
deletePvcs: true,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "PVC1",
|
||||||
|
Namespace: "minio-tenant",
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: "tenant1",
|
||||||
|
operator.ZoneLabel: "zone-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
||||||
|
return errors.New("error returned")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// If error is NotFound while trying to Delete Tenant, PVC deletion should continue
|
||||||
|
name: "Delete pvcs if tenant not found",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
operatorClient: opClient,
|
||||||
|
nameSpace: "minio-tenant",
|
||||||
|
tenantName: "tenant1",
|
||||||
|
deletePvcs: true,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "PVC1",
|
||||||
|
Namespace: "minio-tenant",
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: "tenant1",
|
||||||
|
operator.ZoneLabel: "zone-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
||||||
|
return k8sErrors.NewNotFound(schema.GroupResource{}, "tenant1")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// If error is NotFound while trying to Delete Tenant and pvcdeletion=false,
|
||||||
|
// error should be returned
|
||||||
|
name: "Don't delete pvcs and return error if tenant not found",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
operatorClient: opClient,
|
||||||
|
nameSpace: "minio-tenant",
|
||||||
|
tenantName: "tenant1",
|
||||||
|
deletePvcs: false,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "PVC1",
|
||||||
|
Namespace: "minio-tenant",
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: "tenant1",
|
||||||
|
operator.ZoneLabel: "zone-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantDelete: func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error {
|
||||||
|
return k8sErrors.NewNotFound(schema.GroupResource{}, "tenant1")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
opClientTenantDeleteMock = tt.args.mockTenantDelete
|
opClientTenantDeleteMock = tt.args.mockTenantDelete
|
||||||
|
kubeClient := fake.NewSimpleClientset(tt.args.objs...)
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := deleteTenantAction(tt.args.ctx, tt.args.operatorClient, tt.args.nameSpace, tt.args.tenantName); (err != nil) != tt.wantErr {
|
if err := deleteTenantAction(tt.args.ctx, tt.args.operatorClient, kubeClient.CoreV1(), tt.args.nameSpace, tt.args.tenantName, tt.args.deletePvcs); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("deleteTenantAction() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("deleteTenantAction() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -647,6 +789,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
|||||||
return &http.Response{}, nil
|
return &http.Response{}, nil
|
||||||
},
|
},
|
||||||
params: admin_api.UpdateTenantParams{
|
params: admin_api.UpdateTenantParams{
|
||||||
|
Tenant: "minio-tenant",
|
||||||
Body: &models.UpdateTenantRequest{
|
Body: &models.UpdateTenantRequest{
|
||||||
Image: "minio/minio:RELEASE.2020-06-03T22-13-49Z",
|
Image: "minio/minio:RELEASE.2020-06-03T22-13-49Z",
|
||||||
},
|
},
|
||||||
@@ -675,6 +818,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
|||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
params: admin_api.UpdateTenantParams{
|
params: admin_api.UpdateTenantParams{
|
||||||
|
Tenant: "minio-tenant",
|
||||||
Body: &models.UpdateTenantRequest{
|
Body: &models.UpdateTenantRequest{
|
||||||
Image: "",
|
Image: "",
|
||||||
},
|
},
|
||||||
@@ -683,7 +827,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
|||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Empty image input Error retrieving latest image",
|
name: "Empty image input Error retrieving latest image, nothing happens",
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
operatorClient: opClient,
|
operatorClient: opClient,
|
||||||
@@ -700,12 +844,63 @@ func Test_UpdateTenantAction(t *testing.T) {
|
|||||||
return nil, errors.New("error")
|
return nil, errors.New("error")
|
||||||
},
|
},
|
||||||
params: admin_api.UpdateTenantParams{
|
params: admin_api.UpdateTenantParams{
|
||||||
|
Tenant: "minio-tenant",
|
||||||
Body: &models.UpdateTenantRequest{
|
Body: &models.UpdateTenantRequest{
|
||||||
Image: "",
|
Image: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update minio console version no errors",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
operatorClient: opClient,
|
||||||
|
httpCl: httpClientM,
|
||||||
|
nameSpace: "default",
|
||||||
|
tenantName: "minio-tenant",
|
||||||
|
mockTenantPatch: func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error) {
|
||||||
|
return &v1.Tenant{}, nil
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error) {
|
||||||
|
return &v1.Tenant{}, nil
|
||||||
|
},
|
||||||
|
mockHTTPClientGet: func(url string) (resp *http.Response, err error) {
|
||||||
|
return nil, errors.New("use default minio")
|
||||||
|
},
|
||||||
|
params: admin_api.UpdateTenantParams{
|
||||||
|
Body: &models.UpdateTenantRequest{
|
||||||
|
ConsoleImage: "minio/console:v0.3.15",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update minio image pull secrets no errors",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
operatorClient: opClient,
|
||||||
|
httpCl: httpClientM,
|
||||||
|
nameSpace: "default",
|
||||||
|
tenantName: "minio-tenant",
|
||||||
|
mockTenantPatch: func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error) {
|
||||||
|
return &v1.Tenant{}, nil
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error) {
|
||||||
|
return &v1.Tenant{}, nil
|
||||||
|
},
|
||||||
|
mockHTTPClientGet: func(url string) (resp *http.Response, err error) {
|
||||||
|
return nil, errors.New("use default minio")
|
||||||
|
},
|
||||||
|
params: admin_api.UpdateTenantParams{
|
||||||
|
Body: &models.UpdateTenantRequest{
|
||||||
|
ImagePullSecret: "minio-regcred",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -715,7 +910,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
|||||||
cnsClient := fake.NewSimpleClientset(tt.objs...)
|
cnsClient := fake.NewSimpleClientset(tt.objs...)
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := updateTenantAction(tt.args.ctx, tt.args.operatorClient, cnsClient.CoreV1(), tt.args.httpCl, tt.args.nameSpace, tt.args.params); (err != nil) != tt.wantErr {
|
if err := updateTenantAction(tt.args.ctx, tt.args.operatorClient, cnsClient.CoreV1(), tt.args.httpCl, tt.args.nameSpace, tt.args.params); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("deleteTenantAction() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("updateTenantAction() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ func newMinioClient(claims *models.Principal) (*minio.Client, error) {
|
|||||||
// newS3BucketClient creates a new mc S3Client to talk to the server based on a bucket
|
// newS3BucketClient creates a new mc S3Client to talk to the server based on a bucket
|
||||||
func newS3BucketClient(claims *models.Principal, bucketName string) (*mc.S3Client, error) {
|
func newS3BucketClient(claims *models.Principal, bucketName string) (*mc.S3Client, error) {
|
||||||
endpoint := getMinIOServer()
|
endpoint := getMinIOServer()
|
||||||
useSSL := getMinIOEndpointIsSecure()
|
useTLS := getMinIOEndpointIsSecure()
|
||||||
|
|
||||||
if strings.TrimSpace(bucketName) != "" {
|
if strings.TrimSpace(bucketName) != "" {
|
||||||
endpoint += fmt.Sprintf("/%s", bucketName)
|
endpoint += fmt.Sprintf("/%s", bucketName)
|
||||||
@@ -259,7 +259,7 @@ func newS3BucketClient(claims *models.Principal, bucketName string) (*mc.S3Clien
|
|||||||
return nil, fmt.Errorf("the provided credentials are invalid")
|
return nil, fmt.Errorf("the provided credentials are invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
s3Config := newS3Config(endpoint, claims.AccessKeyID, claims.SecretAccessKey, claims.SessionToken, !useSSL)
|
s3Config := newS3Config(endpoint, claims.AccessKeyID, claims.SecretAccessKey, claims.SessionToken, !useTLS)
|
||||||
client, pErr := mc.S3New(s3Config)
|
client, pErr := mc.S3New(s3Config)
|
||||||
if pErr != nil {
|
if pErr != nil {
|
||||||
return nil, pErr.Cause
|
return nil, pErr.Cause
|
||||||
|
|||||||
@@ -105,15 +105,15 @@ func GetPort() int {
|
|||||||
return port
|
return port
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSSLHostname gets console ssl hostname set on env variable
|
// GetTLSHostname gets console tls hostname set on env variable
|
||||||
// or default one
|
// or default one
|
||||||
func GetSSLHostname() string {
|
func GetTLSHostname() string {
|
||||||
return strings.ToLower(env.Get(ConsoleTLSHostname, TLSHostname))
|
return strings.ToLower(env.Get(ConsoleTLSHostname, TLSHostname))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSSLPort gets console ssl port set on env variable
|
// GetTLSPort gets console tls port set on env variable
|
||||||
// or default one
|
// or default one
|
||||||
func GetSSLPort() int {
|
func GetTLSPort() int {
|
||||||
port, err := strconv.Atoi(env.Get(ConsoleTLSPort, TLSPort))
|
port, err := strconv.Atoi(env.Get(ConsoleTLSPort, TLSPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
port = 9443
|
port = 9443
|
||||||
@@ -171,14 +171,14 @@ func getSecureHostsProxyHeaders() []string {
|
|||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If SSLRedirect is set to true, then only allow HTTPS requests. Default is true.
|
// If TLSRedirect is set to true, then only allow HTTPS requests. Default is true.
|
||||||
func getSSLRedirect() bool {
|
func getTLSRedirect() bool {
|
||||||
return strings.ToLower(env.Get(ConsoleSecureSSLRedirect, TLSRedirect)) == "on"
|
return strings.ToLower(env.Get(ConsoleSecureTLSRedirect, TLSRedirect)) == "on"
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSLHost is the host name that is used to redirect HTTP requests to HTTPS. Default is "", which indicates to use the same host.
|
// TLSHost is the host name that is used to redirect HTTP requests to HTTPS. Default is "", which indicates to use the same host.
|
||||||
func getSecureSSLHost() string {
|
func getSecureTLSHost() string {
|
||||||
return env.Get(ConsoleSecureSSLHost, fmt.Sprintf("%s:%s", TLSHostname, TLSPort))
|
return env.Get(ConsoleSecureTLSHost, fmt.Sprintf("%s:%s", TLSHostname, TLSPort))
|
||||||
}
|
}
|
||||||
|
|
||||||
// STSSeconds is the max-age of the Strict-Transport-Security header. Default is 0, which would NOT include the header.
|
// STSSeconds is the max-age of the Strict-Transport-Security header. Default is 0, which would NOT include the header.
|
||||||
@@ -200,9 +200,9 @@ func getSecureSTSPreload() bool {
|
|||||||
return strings.ToLower(env.Get(ConsoleSecureSTSPreload, "off")) == "on"
|
return strings.ToLower(env.Get(ConsoleSecureSTSPreload, "off")) == "on"
|
||||||
}
|
}
|
||||||
|
|
||||||
// If SSLTemporaryRedirect is true, the a 302 will be used while redirecting. Default is false (301).
|
// If TLSTemporaryRedirect is true, the a 302 will be used while redirecting. Default is false (301).
|
||||||
func getSecureSSLTemporaryRedirect() bool {
|
func getSecureTLSTemporaryRedirect() bool {
|
||||||
return strings.ToLower(env.Get(ConsoleSecureSSLTemporaryRedirect, "off")) == "on"
|
return strings.ToLower(env.Get(ConsoleSecureTLSTemporaryRedirect, "off")) == "on"
|
||||||
}
|
}
|
||||||
|
|
||||||
// STS header is only included when the connection is HTTPS.
|
// STS header is only included when the connection is HTTPS.
|
||||||
|
|||||||
@@ -149,12 +149,12 @@ func setupGlobalMiddleware(handler http.Handler) http.Handler {
|
|||||||
AllowedHosts: getSecureAllowedHosts(),
|
AllowedHosts: getSecureAllowedHosts(),
|
||||||
AllowedHostsAreRegex: getSecureAllowedHostsAreRegex(),
|
AllowedHostsAreRegex: getSecureAllowedHostsAreRegex(),
|
||||||
HostsProxyHeaders: getSecureHostsProxyHeaders(),
|
HostsProxyHeaders: getSecureHostsProxyHeaders(),
|
||||||
SSLRedirect: getSSLRedirect(),
|
SSLRedirect: getTLSRedirect(),
|
||||||
SSLHost: getSecureSSLHost(),
|
SSLHost: getSecureTLSHost(),
|
||||||
STSSeconds: getSecureSTSSeconds(),
|
STSSeconds: getSecureSTSSeconds(),
|
||||||
STSIncludeSubdomains: getSecureSTSIncludeSubdomains(),
|
STSIncludeSubdomains: getSecureSTSIncludeSubdomains(),
|
||||||
STSPreload: getSecureSTSPreload(),
|
STSPreload: getSecureSTSPreload(),
|
||||||
SSLTemporaryRedirect: getSecureSSLTemporaryRedirect(),
|
SSLTemporaryRedirect: getSecureTLSTemporaryRedirect(),
|
||||||
SSLHostFunc: nil,
|
SSLHostFunc: nil,
|
||||||
ForceSTSHeader: getSecureForceSTSHeader(),
|
ForceSTSHeader: getSecureForceSTSHeader(),
|
||||||
FrameDeny: getSecureFrameDeny(),
|
FrameDeny: getSecureFrameDeny(),
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ const (
|
|||||||
ConsoleSecureSTSSeconds = "CONSOLE_SECURE_STS_SECONDS"
|
ConsoleSecureSTSSeconds = "CONSOLE_SECURE_STS_SECONDS"
|
||||||
ConsoleSecureSTSIncludeSubdomains = "CONSOLE_SECURE_STS_INCLUDE_SUB_DOMAINS"
|
ConsoleSecureSTSIncludeSubdomains = "CONSOLE_SECURE_STS_INCLUDE_SUB_DOMAINS"
|
||||||
ConsoleSecureSTSPreload = "CONSOLE_SECURE_STS_PRELOAD"
|
ConsoleSecureSTSPreload = "CONSOLE_SECURE_STS_PRELOAD"
|
||||||
ConsoleSecureSSLRedirect = "CONSOLE_SECURE_SSL_REDIRECT"
|
ConsoleSecureTLSRedirect = "CONSOLE_SECURE_TLS_REDIRECT"
|
||||||
ConsoleSecureSSLHost = "CONSOLE_SECURE_SSL_HOST"
|
ConsoleSecureTLSHost = "CONSOLE_SECURE_TLS_HOST"
|
||||||
ConsoleSecureSSLTemporaryRedirect = "CONSOLE_SECURE_SSL_TEMPORARY_REDIRECT"
|
ConsoleSecureTLSTemporaryRedirect = "CONSOLE_SECURE_TLS_TEMPORARY_REDIRECT"
|
||||||
ConsoleSecureForceSTSHeader = "CONSOLE_SECURE_FORCE_STS_HEADER"
|
ConsoleSecureForceSTSHeader = "CONSOLE_SECURE_FORCE_STS_HEADER"
|
||||||
ConsoleSecurePublicKey = "CONSOLE_SECURE_PUBLIC_KEY"
|
ConsoleSecurePublicKey = "CONSOLE_SECURE_PUBLIC_KEY"
|
||||||
ConsoleSecureReferrerPolicy = "CONSOLE_SECURE_REFERRER_POLICY"
|
ConsoleSecureReferrerPolicy = "CONSOLE_SECURE_REFERRER_POLICY"
|
||||||
|
|||||||
@@ -1007,7 +1007,7 @@ func init() {
|
|||||||
"tags": [
|
"tags": [
|
||||||
"AdminAPI"
|
"AdminAPI"
|
||||||
],
|
],
|
||||||
"summary": "Delete Tenant",
|
"summary": "Delete tenant and underlying pvcs",
|
||||||
"operationId": "DeleteTenant",
|
"operationId": "DeleteTenant",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -1021,6 +1021,13 @@ func init() {
|
|||||||
"name": "tenant",
|
"name": "tenant",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/deleteTenantRequest"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -2024,6 +2031,9 @@ func init() {
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"console_image": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"enable_console": {
|
"enable_console": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true
|
"default": true
|
||||||
@@ -2046,6 +2056,9 @@ func init() {
|
|||||||
"image": {
|
"image": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"image_pull_secret": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"image_registry": {
|
"image_registry": {
|
||||||
"$ref": "#/definitions/imageRegistry"
|
"$ref": "#/definitions/imageRegistry"
|
||||||
},
|
},
|
||||||
@@ -2099,6 +2112,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"deleteTenantRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"delete_pvcs": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"encryptionConfiguration": {
|
"encryptionConfiguration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -2235,7 +2256,7 @@ func init() {
|
|||||||
"server_insecure": {
|
"server_insecure": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"skip_ssl_verification": {
|
"skip_tls_verification": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
@@ -3059,10 +3080,17 @@ func init() {
|
|||||||
"updateTenantRequest": {
|
"updateTenantRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"console_image": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^((.*?)/(.*?):(.+))$"
|
||||||
|
},
|
||||||
"image": {
|
"image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^((.*?)/(.*?):(.+))$"
|
"pattern": "^((.*?)/(.*?):(.+))$"
|
||||||
},
|
},
|
||||||
|
"image_pull_secret": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"image_registry": {
|
"image_registry": {
|
||||||
"$ref": "#/definitions/imageRegistry"
|
"$ref": "#/definitions/imageRegistry"
|
||||||
}
|
}
|
||||||
@@ -4410,7 +4438,7 @@ func init() {
|
|||||||
"tags": [
|
"tags": [
|
||||||
"AdminAPI"
|
"AdminAPI"
|
||||||
],
|
],
|
||||||
"summary": "Delete Tenant",
|
"summary": "Delete tenant and underlying pvcs",
|
||||||
"operationId": "DeleteTenant",
|
"operationId": "DeleteTenant",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -4424,6 +4452,13 @@ func init() {
|
|||||||
"name": "tenant",
|
"name": "tenant",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/deleteTenantRequest"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -5341,7 +5376,7 @@ func init() {
|
|||||||
"server_insecure": {
|
"server_insecure": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"skip_ssl_verification": {
|
"skip_tls_verification": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
@@ -5938,6 +5973,9 @@ func init() {
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"console_image": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"enable_console": {
|
"enable_console": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true
|
"default": true
|
||||||
@@ -5960,6 +5998,9 @@ func init() {
|
|||||||
"image": {
|
"image": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"image_pull_secret": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"image_registry": {
|
"image_registry": {
|
||||||
"$ref": "#/definitions/imageRegistry"
|
"$ref": "#/definitions/imageRegistry"
|
||||||
},
|
},
|
||||||
@@ -6013,6 +6054,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"deleteTenantRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"delete_pvcs": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"encryptionConfiguration": {
|
"encryptionConfiguration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -6149,7 +6198,7 @@ func init() {
|
|||||||
"server_insecure": {
|
"server_insecure": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"skip_ssl_verification": {
|
"skip_tls_verification": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
@@ -6907,10 +6956,17 @@ func init() {
|
|||||||
"updateTenantRequest": {
|
"updateTenantRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"console_image": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^((.*?)/(.*?):(.+))$"
|
||||||
|
},
|
||||||
"image": {
|
"image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^((.*?)/(.*?):(.+))$"
|
"pattern": "^((.*?)/(.*?):(.+))$"
|
||||||
},
|
},
|
||||||
|
"image_pull_secret": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"image_registry": {
|
"image_registry": {
|
||||||
"$ref": "#/definitions/imageRegistry"
|
"$ref": "#/definitions/imageRegistry"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func NewDeleteTenant(ctx *middleware.Context, handler DeleteTenantHandler) *Dele
|
|||||||
|
|
||||||
/*DeleteTenant swagger:route DELETE /namespaces/{namespace}/tenants/{tenant} AdminAPI deleteTenant
|
/*DeleteTenant swagger:route DELETE /namespaces/{namespace}/tenants/{tenant} AdminAPI deleteTenant
|
||||||
|
|
||||||
Delete Tenant
|
Delete tenant and underlying pvcs
|
||||||
|
|
||||||
*/
|
*/
|
||||||
type DeleteTenant struct {
|
type DeleteTenant struct {
|
||||||
|
|||||||
@@ -26,8 +26,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-openapi/errors"
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
"github.com/go-openapi/runtime/middleware"
|
"github.com/go-openapi/runtime/middleware"
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDeleteTenantParams creates a new DeleteTenantParams object
|
// NewDeleteTenantParams creates a new DeleteTenantParams object
|
||||||
@@ -46,6 +49,10 @@ type DeleteTenantParams struct {
|
|||||||
// HTTP Request Object
|
// HTTP Request Object
|
||||||
HTTPRequest *http.Request `json:"-"`
|
HTTPRequest *http.Request `json:"-"`
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: body
|
||||||
|
*/
|
||||||
|
Body *models.DeleteTenantRequest
|
||||||
/*
|
/*
|
||||||
Required: true
|
Required: true
|
||||||
In: path
|
In: path
|
||||||
@@ -67,6 +74,22 @@ func (o *DeleteTenantParams) BindRequest(r *http.Request, route *middleware.Matc
|
|||||||
|
|
||||||
o.HTTPRequest = r
|
o.HTTPRequest = r
|
||||||
|
|
||||||
|
if runtime.HasBody(r) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
var body models.DeleteTenantRequest
|
||||||
|
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
||||||
|
res = append(res, errors.NewParseError("body", "body", "", err))
|
||||||
|
} else {
|
||||||
|
// validate body object
|
||||||
|
if err := body.Validate(route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) == 0 {
|
||||||
|
o.Body = &body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
|
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
|
||||||
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
|
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
|
|||||||
@@ -19,16 +19,30 @@ package restapi
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func getCertPool() *x509.CertPool {
|
||||||
certDontExists = "File certificate doesn't exists: %s"
|
caCertFileNames := getMinioServerTLSRootCAs()
|
||||||
)
|
// If CAs certificates are configured we save them to the http.Client RootCAs store
|
||||||
|
certs := x509.NewCertPool()
|
||||||
|
for _, caCert := range caCertFileNames {
|
||||||
|
pemData, err := ioutil.ReadFile(caCert)
|
||||||
|
if err != nil {
|
||||||
|
// logging this error
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
certs.AppendCertsFromPEM(pemData)
|
||||||
|
}
|
||||||
|
return certs
|
||||||
|
}
|
||||||
|
|
||||||
|
var certPool = getCertPool()
|
||||||
|
|
||||||
func prepareSTSClientTransport(insecure bool) *http.Transport {
|
func prepareSTSClientTransport(insecure bool) *http.Transport {
|
||||||
// This takes github.com/minio/minio/pkg/madmin/transport.go as an example
|
// This takes github.com/minio/minio/pkg/madmin/transport.go as an example
|
||||||
@@ -36,18 +50,6 @@ func prepareSTSClientTransport(insecure bool) *http.Transport {
|
|||||||
// DefaultTransport - this default transport is similar to
|
// DefaultTransport - this default transport is similar to
|
||||||
// http.DefaultTransport but with additional param DisableCompression
|
// http.DefaultTransport but with additional param DisableCompression
|
||||||
// is set to true to avoid decompressing content with 'gzip' encoding.
|
// is set to true to avoid decompressing content with 'gzip' encoding.
|
||||||
|
|
||||||
// Keep TLS config.
|
|
||||||
tlsConfig := &tls.Config{
|
|
||||||
// Can't use SSLv3 because of POODLE and BEAST
|
|
||||||
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
|
||||||
// Can't use TLSv1.1 because of RC4 cipher usage
|
|
||||||
MinVersion: tls.VersionTLS12,
|
|
||||||
}
|
|
||||||
if insecure {
|
|
||||||
tlsConfig.InsecureSkipVerify = true
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultTransport := &http.Transport{
|
DefaultTransport := &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
DialContext: (&net.Dialer{
|
DialContext: (&net.Dialer{
|
||||||
@@ -61,38 +63,14 @@ func prepareSTSClientTransport(insecure bool) *http.Transport {
|
|||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
DisableCompression: true,
|
DisableCompression: true,
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: &tls.Config{
|
||||||
}
|
|
||||||
// If Minio instance is running with TLS enabled and it's using a self-signed certificate
|
|
||||||
// or a certificate issued by a custom certificate authority we prepare a new custom *http.Transport
|
|
||||||
if getMinIOEndpointIsSecure() {
|
|
||||||
caCertFileNames := getMinioServerTLSRootCAs()
|
|
||||||
tlsConfig := &tls.Config{
|
|
||||||
// Can't use SSLv3 because of POODLE and BEAST
|
// Can't use SSLv3 because of POODLE and BEAST
|
||||||
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
|
||||||
// Can't use TLSv1.1 because of RC4 cipher usage
|
// Can't use TLSv1.1 because of RC4 cipher usage
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
}
|
InsecureSkipVerify: insecure,
|
||||||
// If CAs certificates are configured we save them to the http.Client RootCAs store
|
RootCAs: certPool,
|
||||||
if len(caCertFileNames) > 0 {
|
},
|
||||||
certs := x509.NewCertPool()
|
|
||||||
for _, caCert := range caCertFileNames {
|
|
||||||
// Validate certificate exists
|
|
||||||
if FileExists(caCert) {
|
|
||||||
pemData, err := ioutil.ReadFile(caCert)
|
|
||||||
if err != nil {
|
|
||||||
// if there was an error reading pem file stop console
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
certs.AppendCertsFromPEM(pemData)
|
|
||||||
} else {
|
|
||||||
// if provided cert filename doesn't exists stop console
|
|
||||||
panic(fmt.Sprintf(certDontExists, caCert))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tlsConfig.RootCAs = certs
|
|
||||||
}
|
|
||||||
DefaultTransport.TLSClientConfig = tlsConfig
|
|
||||||
}
|
}
|
||||||
return DefaultTransport
|
return DefaultTransport
|
||||||
}
|
}
|
||||||
|
|||||||
24
swagger.yml
24
swagger.yml
@@ -1069,7 +1069,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- AdminAPI
|
- AdminAPI
|
||||||
delete:
|
delete:
|
||||||
summary: Delete Tenant
|
summary: Delete tenant and underlying pvcs
|
||||||
operationId: DeleteTenant
|
operationId: DeleteTenant
|
||||||
parameters:
|
parameters:
|
||||||
- name: namespace
|
- name: namespace
|
||||||
@@ -1080,6 +1080,11 @@ paths:
|
|||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
- name: body
|
||||||
|
in: body
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/deleteTenantRequest"
|
||||||
responses:
|
responses:
|
||||||
204:
|
204:
|
||||||
description: A successful response.
|
description: A successful response.
|
||||||
@@ -1778,8 +1783,13 @@ definitions:
|
|||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
pattern: "^((.*?)/(.*?):(.+))$"
|
pattern: "^((.*?)/(.*?):(.+))$"
|
||||||
|
console_image:
|
||||||
|
type: string
|
||||||
|
pattern: "^((.*?)/(.*?):(.+))$"
|
||||||
image_registry:
|
image_registry:
|
||||||
$ref: "#/definitions/imageRegistry"
|
$ref: "#/definitions/imageRegistry"
|
||||||
|
image_pull_secret:
|
||||||
|
type: string
|
||||||
|
|
||||||
imageRegistry:
|
imageRegistry:
|
||||||
type: object
|
type: object
|
||||||
@@ -1807,6 +1817,8 @@ definitions:
|
|||||||
pattern: "^[a-z0-9-]{3,63}$"
|
pattern: "^[a-z0-9-]{3,63}$"
|
||||||
image:
|
image:
|
||||||
type: string
|
type: string
|
||||||
|
console_image:
|
||||||
|
type: string
|
||||||
service_name:
|
service_name:
|
||||||
type: string
|
type: string
|
||||||
zones:
|
zones:
|
||||||
@@ -1835,6 +1847,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
image_registry:
|
image_registry:
|
||||||
$ref: "#/definitions/imageRegistry"
|
$ref: "#/definitions/imageRegistry"
|
||||||
|
image_pull_secret:
|
||||||
|
type: string
|
||||||
idp:
|
idp:
|
||||||
type: object
|
type: object
|
||||||
$ref: "#/definitions/idpConfiguration"
|
$ref: "#/definitions/idpConfiguration"
|
||||||
@@ -1901,7 +1915,7 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
group_name_attribute:
|
group_name_attribute:
|
||||||
type: string
|
type: string
|
||||||
skip_ssl_verification:
|
skip_tls_verification:
|
||||||
type: boolean
|
type: boolean
|
||||||
server_insecure:
|
server_insecure:
|
||||||
type: boolean
|
type: boolean
|
||||||
@@ -2507,3 +2521,9 @@ definitions:
|
|||||||
used:
|
used:
|
||||||
type: integer
|
type: integer
|
||||||
format: int64
|
format: int64
|
||||||
|
|
||||||
|
deleteTenantRequest:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
delete_pvcs:
|
||||||
|
type: boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user