Refactor and tests for adding tenant (#2577)
This commit is contained in:
2
.github/workflows/jobs.yaml
vendored
2
.github/workflows/jobs.yaml
vendored
@@ -1542,7 +1542,7 @@ jobs:
|
||||
go tool cover -func=all.out | grep total > tmp2
|
||||
result=`cat tmp2 | awk 'END {print $3}'`
|
||||
result=${result%\%}
|
||||
threshold=62.0
|
||||
threshold=63.2
|
||||
echo "Result:"
|
||||
echo "$result%"
|
||||
if (( $(echo "$result >= $threshold" |bc -l) )); then
|
||||
|
||||
@@ -22,18 +22,17 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
|
||||
"github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/minio/console/cluster"
|
||||
"github.com/minio/console/models"
|
||||
miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
)
|
||||
@@ -56,7 +55,6 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
func createTenant(ctx context.Context, params operator_api.CreateTenantParams, clientSet K8sClientI, cv1 v1.CoreV1Interface, session *models.Principal) (response *models.CreateTenantResponse, mError *models.Error) {
|
||||
tenantReq := params.Body
|
||||
minioImage := getTenantMinIOImage(tenantReq.Image)
|
||||
imm := true
|
||||
|
||||
ns := *tenantReq.Namespace
|
||||
|
||||
@@ -64,6 +62,11 @@ func createTenant(ctx context.Context, params operator_api.CreateTenantParams, c
|
||||
tenantName := *tenantReq.Name
|
||||
var users []*corev1.LocalObjectReference
|
||||
|
||||
// delete secrets created if an errors occurred during tenant creation,
|
||||
defer func() {
|
||||
deleteSecretsIfTenantCreationFails(ctx, mError, tenantName, ns, clientSet)
|
||||
}()
|
||||
|
||||
err := createTenantCredentialsSecret(ctx, ns, tenantName, clientSet)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
@@ -74,11 +77,6 @@ func createTenant(ctx context.Context, params operator_api.CreateTenantParams, c
|
||||
tenantConfigurationENV["MINIO_ROOT_USER"] = accessKey
|
||||
tenantConfigurationENV["MINIO_ROOT_PASSWORD"] = secretKey
|
||||
|
||||
// delete secrets created if an errors occurred during tenant creation,
|
||||
defer func() {
|
||||
deleteSecretsIfTenantCreationFails(ctx, mError, tenantName, ns, clientSet)
|
||||
}()
|
||||
|
||||
// Check the Erasure Coding Parity for validity and pass it to Tenant
|
||||
if tenantReq.ErasureCodingParity > 0 {
|
||||
if tenantReq.ErasureCodingParity < 2 || tenantReq.ErasureCodingParity > 8 {
|
||||
@@ -115,44 +113,11 @@ func createTenant(ctx context.Context, params operator_api.CreateTenantParams, c
|
||||
minInst.Spec.Users = users
|
||||
case tenantReq.Idp.Oidc != nil:
|
||||
tenantExternalIDPConfigured = true
|
||||
// Enable IDP (OIDC) for MinIO
|
||||
configurationURL := *tenantReq.Idp.Oidc.ConfigurationURL
|
||||
clientID := *tenantReq.Idp.Oidc.ClientID
|
||||
secretID := *tenantReq.Idp.Oidc.SecretID
|
||||
claimName := *tenantReq.Idp.Oidc.ClaimName
|
||||
scopes := tenantReq.Idp.Oidc.Scopes
|
||||
callbackURL := tenantReq.Idp.Oidc.CallbackURL
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CONFIG_URL"] = configurationURL
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CLIENT_ID"] = clientID
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CLIENT_SECRET"] = secretID
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CLAIM_NAME"] = claimName
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_REDIRECT_URI"] = callbackURL
|
||||
if scopes == "" {
|
||||
scopes = "openid,profile,email"
|
||||
}
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_SCOPES"] = scopes
|
||||
tenantConfigurationENV = setTenantOIDCConfig(tenantReq, tenantConfigurationENV)
|
||||
case len(tenantReq.Idp.Keys) > 0:
|
||||
// Create the secret any built-in user passed if no external IDP was configured
|
||||
for i := 0; i < len(tenantReq.Idp.Keys); i++ {
|
||||
userSecretName := fmt.Sprintf("%s-user-%d", tenantName, i)
|
||||
users = append(users, &corev1.LocalObjectReference{Name: userSecretName})
|
||||
userSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: userSecretName,
|
||||
Labels: map[string]string{
|
||||
miniov2.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"CONSOLE_ACCESS_KEY": []byte(*tenantReq.Idp.Keys[i].AccessKey),
|
||||
"CONSOLE_SECRET_KEY": []byte(*tenantReq.Idp.Keys[i].SecretKey),
|
||||
},
|
||||
}
|
||||
_, err := clientSet.createSecret(ctx, ns, &userSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
users, err = setTenantBuiltInUsers(ctx, clientSet, tenantReq, users)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// attach the users to the tenant
|
||||
minInst.Spec.Users = users
|
||||
@@ -294,144 +259,18 @@ func createTenant(ctx context.Context, params operator_api.CreateTenantParams, c
|
||||
|
||||
// Is Log Search enabled? (present in the parameters) if so configure
|
||||
if tenantReq.LogSearchConfiguration != nil {
|
||||
|
||||
// Default class name for Log search
|
||||
diskSpaceFromAPI := int64(5) * humanize.GiByte // Default is 5Gi
|
||||
logSearchImage := ""
|
||||
logSearchPgImage := ""
|
||||
logSearchPgInitImage := ""
|
||||
var logSearchStorageClass *string // Nil means use default storage class
|
||||
var logSearchSecurityContext *corev1.PodSecurityContext
|
||||
var logSearchPgSecurityContext *corev1.PodSecurityContext
|
||||
|
||||
if tenantReq.LogSearchConfiguration.StorageSize != nil {
|
||||
diskSpaceFromAPI = int64(*tenantReq.LogSearchConfiguration.StorageSize) * humanize.GiByte
|
||||
minInst, err = setTenantLogSearchConfiguration(ctx, tenantReq, minInst)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.StorageClass != "" {
|
||||
logSearchStorageClass = stringPtr(tenantReq.LogSearchConfiguration.StorageClass)
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.Image != "" {
|
||||
logSearchImage = tenantReq.LogSearchConfiguration.Image
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.PostgresImage != "" {
|
||||
logSearchPgImage = tenantReq.LogSearchConfiguration.PostgresImage
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.PostgresInitImage != "" {
|
||||
logSearchPgInitImage = tenantReq.LogSearchConfiguration.PostgresInitImage
|
||||
}
|
||||
// if security context for logSearch is present, configure it.
|
||||
if tenantReq.LogSearchConfiguration.SecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.SecurityContext)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
logSearchSecurityContext = sc
|
||||
}
|
||||
// if security context for logSearch is present, configure it.
|
||||
if tenantReq.LogSearchConfiguration.PostgresSecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.PostgresSecurityContext)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
logSearchPgSecurityContext = sc
|
||||
}
|
||||
|
||||
logSearchDiskSpace := resource.NewQuantity(diskSpaceFromAPI, resource.DecimalExponent)
|
||||
|
||||
// the audit max cap cannot be larger than disk size on the DB, else it won't trim the data
|
||||
auditMaxCap := 10
|
||||
if (diskSpaceFromAPI / humanize.GiByte) < int64(auditMaxCap) {
|
||||
auditMaxCap = int(diskSpaceFromAPI / humanize.GiByte)
|
||||
}
|
||||
|
||||
// default activate lgo search and prometheus
|
||||
minInst.Spec.Log = &miniov2.LogConfig{
|
||||
Audit: &miniov2.AuditConfig{DiskCapacityGB: swag.Int(auditMaxCap)},
|
||||
Db: &miniov2.LogDbConfig{
|
||||
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: tenantName + "-log",
|
||||
},
|
||||
Spec: corev1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []corev1.PersistentVolumeAccessMode{
|
||||
corev1.ReadWriteOnce,
|
||||
},
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceStorage: *logSearchDiskSpace,
|
||||
},
|
||||
},
|
||||
StorageClassName: logSearchStorageClass,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// set log search images if any
|
||||
if logSearchImage != "" {
|
||||
minInst.Spec.Log.Image = logSearchImage
|
||||
}
|
||||
if logSearchPgImage != "" {
|
||||
minInst.Spec.Log.Db.Image = logSearchPgImage
|
||||
}
|
||||
if logSearchPgInitImage != "" {
|
||||
minInst.Spec.Log.Db.InitImage = logSearchPgInitImage
|
||||
}
|
||||
if logSearchSecurityContext != nil {
|
||||
minInst.Spec.Log.SecurityContext = logSearchSecurityContext
|
||||
}
|
||||
if logSearchPgSecurityContext != nil {
|
||||
minInst.Spec.Log.Db.SecurityContext = logSearchPgSecurityContext
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Is Prometheus/Monitoring enabled? (config present in the parameters) if so configure
|
||||
if tenantReq.PrometheusConfiguration != nil {
|
||||
prometheusDiskSpace := 5 // Default is 5 by API
|
||||
prometheusImage := "" // Default is ""
|
||||
prometheusSidecardImage := "" // Default is ""
|
||||
prometheusInitImage := "" // Default is ""
|
||||
|
||||
var prometheusStorageClass *string // Nil means default storage class
|
||||
|
||||
if tenantReq.PrometheusConfiguration.StorageSize != nil {
|
||||
prometheusDiskSpace = int(*tenantReq.PrometheusConfiguration.StorageSize)
|
||||
minInst, err = setTenantPrometheusConfig(ctx, tenantReq, minInst)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.StorageClass != "" {
|
||||
prometheusStorageClass = stringPtr(tenantReq.PrometheusConfiguration.StorageClass)
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.Image != "" {
|
||||
prometheusImage = tenantReq.PrometheusConfiguration.Image
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.SidecarImage != "" {
|
||||
prometheusSidecardImage = tenantReq.PrometheusConfiguration.SidecarImage
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.InitImage != "" {
|
||||
prometheusInitImage = tenantReq.PrometheusConfiguration.InitImage
|
||||
}
|
||||
|
||||
minInst.Spec.Prometheus = &miniov2.PrometheusConfig{
|
||||
DiskCapacityDB: swag.Int(prometheusDiskSpace),
|
||||
StorageClassName: prometheusStorageClass,
|
||||
}
|
||||
if prometheusImage != "" {
|
||||
minInst.Spec.Prometheus.Image = prometheusImage
|
||||
}
|
||||
if prometheusSidecardImage != "" {
|
||||
minInst.Spec.Prometheus.SideCarImage = prometheusSidecardImage
|
||||
}
|
||||
if prometheusInitImage != "" {
|
||||
minInst.Spec.Prometheus.InitImage = prometheusInitImage
|
||||
}
|
||||
// if security context for prometheus is present, configure it.
|
||||
if tenantReq.PrometheusConfiguration != nil && tenantReq.PrometheusConfiguration.SecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.PrometheusConfiguration.SecurityContext)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
minInst.Spec.Prometheus.SecurityContext = sc
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// expose services
|
||||
@@ -636,3 +475,186 @@ func setTenantActiveDirectoryConfig(ctx context.Context, clientSet K8sClientI, t
|
||||
}
|
||||
return tenantConfigurationENV, users, nil
|
||||
}
|
||||
|
||||
func setTenantOIDCConfig(tenantReq *models.CreateTenantRequest, tenantConfigurationENV map[string]string) map[string]string {
|
||||
configurationURL := *tenantReq.Idp.Oidc.ConfigurationURL
|
||||
clientID := *tenantReq.Idp.Oidc.ClientID
|
||||
secretID := *tenantReq.Idp.Oidc.SecretID
|
||||
claimName := *tenantReq.Idp.Oidc.ClaimName
|
||||
scopes := tenantReq.Idp.Oidc.Scopes
|
||||
callbackURL := tenantReq.Idp.Oidc.CallbackURL
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CONFIG_URL"] = configurationURL
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CLIENT_ID"] = clientID
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CLIENT_SECRET"] = secretID
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_CLAIM_NAME"] = claimName
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_REDIRECT_URI"] = callbackURL
|
||||
if scopes == "" {
|
||||
scopes = "openid,profile,email"
|
||||
}
|
||||
tenantConfigurationENV["MINIO_IDENTITY_OPENID_SCOPES"] = scopes
|
||||
return tenantConfigurationENV
|
||||
}
|
||||
|
||||
func setTenantBuiltInUsers(ctx context.Context, clientSet K8sClientI, tenantReq *models.CreateTenantRequest, users []*corev1.LocalObjectReference) ([]*corev1.LocalObjectReference, error) {
|
||||
imm := true
|
||||
for i := 0; i < len(tenantReq.Idp.Keys); i++ {
|
||||
userSecretName := fmt.Sprintf("%s-user-%d", *tenantReq.Name, i)
|
||||
users = append(users, &corev1.LocalObjectReference{Name: userSecretName})
|
||||
userSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: userSecretName,
|
||||
Labels: map[string]string{
|
||||
miniov2.TenantLabel: *tenantReq.Name,
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"CONSOLE_ACCESS_KEY": []byte(*tenantReq.Idp.Keys[i].AccessKey),
|
||||
"CONSOLE_SECRET_KEY": []byte(*tenantReq.Idp.Keys[i].SecretKey),
|
||||
},
|
||||
}
|
||||
_, err := clientSet.createSecret(ctx, *tenantReq.Namespace, &userSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return users, err
|
||||
}
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func setTenantLogSearchConfiguration(ctx context.Context, tenantReq *models.CreateTenantRequest, minInst miniov2.Tenant) (miniov2.Tenant, error) {
|
||||
diskSpaceFromAPI := int64(5) * humanize.GiByte // Default is 5Gi
|
||||
logSearchImage := ""
|
||||
logSearchPgImage := ""
|
||||
logSearchPgInitImage := ""
|
||||
var logSearchStorageClass *string // Nil means use default storage class
|
||||
var logSearchSecurityContext *corev1.PodSecurityContext
|
||||
var logSearchPgSecurityContext *corev1.PodSecurityContext
|
||||
|
||||
if tenantReq.LogSearchConfiguration.StorageSize != nil {
|
||||
diskSpaceFromAPI = int64(*tenantReq.LogSearchConfiguration.StorageSize) * humanize.GiByte
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.StorageClass != "" {
|
||||
logSearchStorageClass = stringPtr(tenantReq.LogSearchConfiguration.StorageClass)
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.Image != "" {
|
||||
logSearchImage = tenantReq.LogSearchConfiguration.Image
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.PostgresImage != "" {
|
||||
logSearchPgImage = tenantReq.LogSearchConfiguration.PostgresImage
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.PostgresInitImage != "" {
|
||||
logSearchPgInitImage = tenantReq.LogSearchConfiguration.PostgresInitImage
|
||||
}
|
||||
// if security context for logSearch is present, configure it.
|
||||
if tenantReq.LogSearchConfiguration.SecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.SecurityContext)
|
||||
if err != nil {
|
||||
return minInst, err
|
||||
}
|
||||
logSearchSecurityContext = sc
|
||||
}
|
||||
// if security context for logSearch is present, configure it.
|
||||
if tenantReq.LogSearchConfiguration.PostgresSecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.PostgresSecurityContext)
|
||||
if err != nil {
|
||||
return minInst, err
|
||||
}
|
||||
logSearchPgSecurityContext = sc
|
||||
}
|
||||
|
||||
logSearchDiskSpace := resource.NewQuantity(diskSpaceFromAPI, resource.DecimalExponent)
|
||||
|
||||
// the audit max cap cannot be larger than disk size on the DB, else it won't trim the data
|
||||
auditMaxCap := 10
|
||||
if (diskSpaceFromAPI / humanize.GiByte) < int64(auditMaxCap) {
|
||||
auditMaxCap = int(diskSpaceFromAPI / humanize.GiByte)
|
||||
}
|
||||
|
||||
// default activate lgo search and prometheus
|
||||
minInst.Spec.Log = &miniov2.LogConfig{
|
||||
Audit: &miniov2.AuditConfig{DiskCapacityGB: swag.Int(auditMaxCap)},
|
||||
Db: &miniov2.LogDbConfig{
|
||||
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: *tenantReq.Name + "-log",
|
||||
},
|
||||
Spec: corev1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []corev1.PersistentVolumeAccessMode{
|
||||
corev1.ReadWriteOnce,
|
||||
},
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceStorage: *logSearchDiskSpace,
|
||||
},
|
||||
},
|
||||
StorageClassName: logSearchStorageClass,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// set log search images if any
|
||||
if logSearchImage != "" {
|
||||
minInst.Spec.Log.Image = logSearchImage
|
||||
}
|
||||
if logSearchPgImage != "" {
|
||||
minInst.Spec.Log.Db.Image = logSearchPgImage
|
||||
}
|
||||
if logSearchPgInitImage != "" {
|
||||
minInst.Spec.Log.Db.InitImage = logSearchPgInitImage
|
||||
}
|
||||
if logSearchSecurityContext != nil {
|
||||
minInst.Spec.Log.SecurityContext = logSearchSecurityContext
|
||||
}
|
||||
if logSearchPgSecurityContext != nil {
|
||||
minInst.Spec.Log.Db.SecurityContext = logSearchPgSecurityContext
|
||||
}
|
||||
return minInst, nil
|
||||
}
|
||||
|
||||
func setTenantPrometheusConfig(ctx context.Context, tenantReq *models.CreateTenantRequest, minInst miniov2.Tenant) (miniov2.Tenant, error) {
|
||||
prometheusDiskSpace := 5 // Default is 5 by API
|
||||
prometheusImage := "" // Default is ""
|
||||
prometheusSidecardImage := "" // Default is ""
|
||||
prometheusInitImage := "" // Default is ""
|
||||
|
||||
var prometheusStorageClass *string // Nil means default storage class
|
||||
|
||||
if tenantReq.PrometheusConfiguration.StorageSize != nil {
|
||||
prometheusDiskSpace = int(*tenantReq.PrometheusConfiguration.StorageSize)
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.StorageClass != "" {
|
||||
prometheusStorageClass = stringPtr(tenantReq.PrometheusConfiguration.StorageClass)
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.Image != "" {
|
||||
prometheusImage = tenantReq.PrometheusConfiguration.Image
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.SidecarImage != "" {
|
||||
prometheusSidecardImage = tenantReq.PrometheusConfiguration.SidecarImage
|
||||
}
|
||||
if tenantReq.PrometheusConfiguration.InitImage != "" {
|
||||
prometheusInitImage = tenantReq.PrometheusConfiguration.InitImage
|
||||
}
|
||||
|
||||
minInst.Spec.Prometheus = &miniov2.PrometheusConfig{
|
||||
DiskCapacityDB: swag.Int(prometheusDiskSpace),
|
||||
StorageClassName: prometheusStorageClass,
|
||||
}
|
||||
if prometheusImage != "" {
|
||||
minInst.Spec.Prometheus.Image = prometheusImage
|
||||
}
|
||||
if prometheusSidecardImage != "" {
|
||||
minInst.Spec.Prometheus.SideCarImage = prometheusSidecardImage
|
||||
}
|
||||
if prometheusInitImage != "" {
|
||||
minInst.Spec.Prometheus.InitImage = prometheusInitImage
|
||||
}
|
||||
// if security context for prometheus is present, configure it.
|
||||
if tenantReq.PrometheusConfiguration != nil && tenantReq.PrometheusConfiguration.SecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.PrometheusConfiguration.SecurityContext)
|
||||
if err != nil {
|
||||
return minInst, err
|
||||
}
|
||||
minInst.Spec.Prometheus.SecurityContext = sc
|
||||
}
|
||||
return minInst, nil
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
package operatorapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
@@ -25,17 +29,24 @@ import (
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type TenantTestSuite struct {
|
||||
suite.Suite
|
||||
assert *assert.Assertions
|
||||
opClient opClientMock
|
||||
assert *assert.Assertions
|
||||
opClient opClientMock
|
||||
k8sclient k8sClientMock
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) SetupSuite() {
|
||||
suite.assert = assert.New(suite.T())
|
||||
suite.opClient = opClientMock{}
|
||||
suite.k8sclient = k8sClientMock{}
|
||||
k8sClientDeleteSecretsCollectionMock = func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) SetupTest() {
|
||||
@@ -129,6 +140,186 @@ func (suite *TenantTestSuite) TestCreateTenantHandlerWithError() {
|
||||
suite.assert.True(ok)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongECP() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
params.Body.ErasureCodingParity = 1
|
||||
k8sClientCreateSecretMock = func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return nil, nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongActiveDirectoryConfig() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
params.Body.ErasureCodingParity = 2
|
||||
url := "mock-url"
|
||||
lookup := "mock-lookup"
|
||||
params.Body.Idp = &models.IdpConfiguration{
|
||||
ActiveDirectory: &models.IdpConfigurationActiveDirectory{
|
||||
SkipTLSVerification: true,
|
||||
ServerInsecure: true,
|
||||
ServerStartTLS: true,
|
||||
UserDNS: []string{"mock-user"},
|
||||
URL: &url,
|
||||
LookupBindDn: &lookup,
|
||||
},
|
||||
}
|
||||
k8sClientCreateSecretMock = func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
if strings.HasPrefix(secret.Name, fmt.Sprintf("%s-user-", *params.Body.Name)) {
|
||||
return nil, errors.New("mock-error")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongBuiltInUsers() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
accessKey := "mock-access-key"
|
||||
secretKey := "mock-secret-key"
|
||||
params.Body.Idp = &models.IdpConfiguration{
|
||||
Keys: []*models.IdpConfigurationKeysItems0{
|
||||
{
|
||||
AccessKey: &accessKey,
|
||||
SecretKey: &secretKey,
|
||||
},
|
||||
},
|
||||
}
|
||||
k8sClientCreateSecretMock = func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
if strings.HasPrefix(secret.Name, fmt.Sprintf("%s-user-", *params.Body.Name)) {
|
||||
return nil, errors.New("mock-error")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithOIDCAndWrongServerCertificates() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
url := "mock-url"
|
||||
clientID := "mock-client-id"
|
||||
clientSecret := "mock-client-secret"
|
||||
claimName := "mock-claim-name"
|
||||
crt := "mock-crt"
|
||||
key := "mock-key"
|
||||
params.Body.Idp = &models.IdpConfiguration{
|
||||
Oidc: &models.IdpConfigurationOidc{
|
||||
ClientID: &clientID,
|
||||
SecretID: &clientSecret,
|
||||
ClaimName: &claimName,
|
||||
ConfigurationURL: &url,
|
||||
},
|
||||
}
|
||||
params.Body.TLS = &models.TLSConfiguration{
|
||||
MinioServerCertificates: []*models.KeyPairConfiguration{
|
||||
{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
},
|
||||
}
|
||||
k8sClientDeleteSecretMock = func(ctx context.Context, namespace, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongClientCertificates() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
crt := "mock-crt"
|
||||
key := "mock-key"
|
||||
params.Body.TLS = &models.TLSConfiguration{
|
||||
MinioClientCertificates: []*models.KeyPairConfiguration{
|
||||
{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
},
|
||||
}
|
||||
k8sClientDeleteSecretMock = func(ctx context.Context, namespace, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongCAsCertificates() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
params.Body.TLS = &models.TLSConfiguration{
|
||||
MinioCAsCertificates: []string{"bW9jay1jcnQ="},
|
||||
}
|
||||
k8sClientDeleteSecretMock = func(ctx context.Context, namespace, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
}
|
||||
k8sClientCreateSecretMock = func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
if strings.HasPrefix(secret.Name, fmt.Sprintf("%s-ca-certificate-", *params.Body.Name)) {
|
||||
return nil, errors.New("mock-error")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongMtlsCertificates() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
crt := "mock-crt"
|
||||
key := "mock-key"
|
||||
enableTLS := true
|
||||
params.Body.EnableTLS = &enableTLS
|
||||
params.Body.Encryption = &models.EncryptionConfiguration{
|
||||
MinioMtls: &models.KeyPairConfiguration{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
}
|
||||
k8sClientDeleteSecretMock = func(ctx context.Context, namespace, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongKESConfig() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
crt := "mock-crt"
|
||||
key := "mock-key"
|
||||
enableTLS := true
|
||||
params.Body.EnableTLS = &enableTLS
|
||||
params.Body.Encryption = &models.EncryptionConfiguration{
|
||||
ServerTLS: &models.KeyPairConfiguration{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
Image: "mock-image",
|
||||
Replicas: "1",
|
||||
}
|
||||
k8sClientDeleteSecretMock = func(ctx context.Context, namespace, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) TestCreateTenantWithWrongPool() {
|
||||
params, _ := suite.initCreateTenantRequest()
|
||||
params.Body.Annotations = map[string]string{"mock": "mock"}
|
||||
params.Body.Pools = []*models.Pool{{}}
|
||||
k8sClientCreateSecretMock = func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return nil, nil
|
||||
}
|
||||
k8sClientDeleteSecretMock = func(ctx context.Context, namespace, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
}
|
||||
_, err := createTenant(context.Background(), params, suite.k8sclient, nil, &models.Principal{})
|
||||
suite.assert.NotNil(err)
|
||||
}
|
||||
|
||||
func (suite *TenantTestSuite) initCreateTenantRequest() (params operator_api.CreateTenantParams, api operations.OperatorAPI) {
|
||||
registerTenantHandlers(&api)
|
||||
params.HTTPRequest = &http.Request{}
|
||||
|
||||
Reference in New Issue
Block a user