Error and Audit logger webhooks (#1855)
Similar to MinIO now it's possible to configure webhooks to log all triggered errors and incomming requests via env variables: ``` CONSOLE_LOGGER_WEBHOOK_ENABLE_<ID> CONSOLE_LOGGER_WEBHOOK_ENDPOINT_<ID> CONSOLE_LOGGER_WEBHOOK_AUTH_TOKEN_<ID> CONSOLE_LOGGER_WEBHOOK_CLIENT_CERT_<ID> CONSOLE_LOGGER_WEBHOOK_CLIENT_KEY_<ID> CONSOLE_LOGGER_WEBHOOK_QUEUE_SIZE_<ID> CONSOLE_AUDIT_WEBHOOK_ENABLE_<ID> CONSOLE_AUDIT_WEBHOOK_ENDPOINT_<ID> CONSOLE_AUDIT_WEBHOOK_AUTH_TOKEN_<ID> CONSOLE_AUDIT_WEBHOOK_CLIENT_CERT_<ID> CONSOLE_AUDIT_WEBHOOK_QUEUE_SIZE_<ID> ``` Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
This commit is contained in:
@@ -18,15 +18,14 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
errors "github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/console/cluster"
|
||||
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||
operatorClientset "github.com/minio/operator/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
var errInvalidCredentials = errors.New("invalid Login")
|
||||
|
||||
// operatorCredentialsProvider is an struct to hold the JWT (service account token)
|
||||
type operatorCredentialsProvider struct {
|
||||
serviceAccountJWT string
|
||||
@@ -86,7 +85,7 @@ func GetConsoleCredentialsForOperator(jwt string) (*credentials.Credentials, err
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err = checkServiceAccountTokenValid(ctx, opClient); err != nil {
|
||||
return nil, errInvalidCredentials
|
||||
return nil, errors.ErrInvalidLogin
|
||||
}
|
||||
return credentials.New(operatorCredentialsProvider{serviceAccountJWT: jwt}), nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/klauspost/compress/gzhttp"
|
||||
|
||||
"github.com/minio/console/restapi"
|
||||
"github.com/unrolled/secure"
|
||||
|
||||
@@ -58,7 +57,7 @@ func configureAPI(api *operations.OperatorAPI) http.Handler {
|
||||
api.KeyAuth = func(token string, scopes []string) (*models.Principal, error) {
|
||||
// we are validating the session token by decrypting the claims inside, if the operation succeed that means the jwt
|
||||
// was generated and signed by us in the first place
|
||||
claims, err := auth.SessionTokenAuthenticate(token)
|
||||
claims, err := auth.ParseClaimsFromToken(token)
|
||||
if err != nil {
|
||||
api.Logger("Unable to validate the session token %s: %v", token, err)
|
||||
return nil, errors.New(401, "incorrect api key auth")
|
||||
@@ -101,8 +100,8 @@ func configureAPI(api *operations.OperatorAPI) http.Handler {
|
||||
|
||||
// The TLS configuration before HTTPS server starts.
|
||||
func configureTLS(tlsConfig *tls.Config) {
|
||||
tlsConfig.RootCAs = GlobalRootCAs
|
||||
tlsConfig.GetCertificate = GlobalTLSCertsManager.GetCertificate
|
||||
tlsConfig.RootCAs = restapi.GlobalRootCAs
|
||||
tlsConfig.GetCertificate = restapi.GlobalTLSCertsManager.GetCertificate
|
||||
}
|
||||
|
||||
// As soon as server is initialized but not run yet, this function will be called.
|
||||
@@ -118,24 +117,6 @@ func setupMiddlewares(handler http.Handler) http.Handler {
|
||||
return handler
|
||||
}
|
||||
|
||||
func AuthenticationMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token, err := auth.GetTokenFromRequest(r)
|
||||
if err != nil && err != auth.ErrNoAuthToken {
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
// All handlers handle appropriately to return errors
|
||||
// based on their swagger rules, we do not need to
|
||||
// additionally return error here, let the next ServeHTTPs
|
||||
// handle it appropriately.
|
||||
if token != "" {
|
||||
r.Header.Add("Authorization", "Bearer "+token)
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// proxyMiddleware adds the proxy capability
|
||||
func proxyMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -150,19 +131,23 @@ func proxyMiddleware(next http.Handler) http.Handler {
|
||||
// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
|
||||
// So this is a good place to plug in a panic handling middleware, logging and metrics.
|
||||
func setupGlobalMiddleware(handler http.Handler) http.Handler {
|
||||
// handle cookie or authorization header for session
|
||||
next := AuthenticationMiddleware(handler)
|
||||
// proxy requests
|
||||
next = proxyMiddleware(next)
|
||||
next := proxyMiddleware(handler)
|
||||
// if audit-log is enabled console will log all incoming request
|
||||
next = restapi.AuditLogMiddleware(next)
|
||||
// serve static files
|
||||
next = restapi.FileServerMiddleware(next)
|
||||
// add information to request context
|
||||
next = restapi.ContextMiddleware(next)
|
||||
// handle cookie or authorization header for session
|
||||
next = restapi.AuthenticationMiddleware(next)
|
||||
// Secure middleware, this middleware wrap all the previous handlers and add
|
||||
// HTTP security headers
|
||||
secureOptions := secure.Options{
|
||||
AllowedHosts: restapi.GetSecureAllowedHosts(),
|
||||
AllowedHostsAreRegex: restapi.GetSecureAllowedHostsAreRegex(),
|
||||
HostsProxyHeaders: restapi.GetSecureHostsProxyHeaders(),
|
||||
SSLRedirect: restapi.GetTLSRedirect() == "on" && len(GlobalPublicCerts) > 0,
|
||||
SSLRedirect: restapi.GetTLSRedirect() == "on" && len(restapi.GlobalPublicCerts) > 0,
|
||||
SSLHost: restapi.GetSecureTLSHost(),
|
||||
STSSeconds: restapi.GetSecureSTSSeconds(),
|
||||
STSIncludeSubdomains: restapi.GetSecureSTSIncludeSubdomains(),
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 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 operatorapi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/madmin-go"
|
||||
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// Generic error messages
|
||||
errorGeneric = errors.New("an error occurred, please try again")
|
||||
errInvalidCredentials = errors.New("invalid Login")
|
||||
errorGenericInvalidSession = errors.New("invalid session")
|
||||
errorGenericUnauthorized = errors.New("unauthorized")
|
||||
errorGenericForbidden = errors.New("forbidden")
|
||||
// ErrorGenericNotFound Generic error for not found
|
||||
ErrorGenericNotFound = errors.New("not found")
|
||||
// Explicit error messages
|
||||
errorInvalidErasureCodingValue = errors.New("invalid Erasure Coding Value")
|
||||
errorUnableToGetTenantUsage = errors.New("unable to get tenant usage")
|
||||
errorUnableToGetTenantLogs = errors.New("unable to get tenant logs")
|
||||
errorUnableToUpdateTenantCertificates = errors.New("unable to update tenant certificates")
|
||||
errorUpdatingEncryptionConfig = errors.New("unable to update encryption configuration")
|
||||
errorDeletingEncryptionConfig = errors.New("error disabling tenant encryption")
|
||||
errorEncryptionConfigNotFound = errors.New("encryption configuration not found")
|
||||
errBucketBodyNotInRequest = errors.New("error bucket body not in request")
|
||||
errBucketNameNotInRequest = errors.New("error bucket name not in request")
|
||||
errGroupBodyNotInRequest = errors.New("error group body not in request")
|
||||
errGroupNameNotInRequest = errors.New("error group name not in request")
|
||||
errPolicyNameNotInRequest = errors.New("error policy name not in request")
|
||||
errPolicyBodyNotInRequest = errors.New("error policy body not in request")
|
||||
errSSENotConfigured = errors.New("error server side encryption configuration not found")
|
||||
errBucketLifeCycleNotConfigured = errors.New("error bucket life cycle configuration not found")
|
||||
errChangePassword = errors.New("error please check your current password")
|
||||
errInvalidLicense = errors.New("invalid license key")
|
||||
errLicenseNotFound = errors.New("license not found")
|
||||
errAvoidSelfAccountDelete = errors.New("logged in user cannot be deleted by itself")
|
||||
errAccessDenied = errors.New("access denied")
|
||||
errTooManyNodes = errors.New("cannot request more nodes than what is available in the cluster")
|
||||
errTooFewNodes = errors.New("there are not enough nodes in the cluster to support this tenant")
|
||||
errTooFewSchedulableNodes = errors.New("there is not enough schedulable nodes to satisfy this requirement")
|
||||
errFewerThanFourNodes = errors.New("at least 4 nodes are required for a tenant")
|
||||
)
|
||||
|
||||
// prepareError receives an error object and parse it against k8sErrors, returns the right error code paired with a generic error message
|
||||
func prepareError(err ...error) *models.Error {
|
||||
errorCode := int32(500)
|
||||
errorMessage := errorGeneric.Error()
|
||||
if len(err) > 0 {
|
||||
frame := getFrame(2)
|
||||
fileParts := strings.Split(frame.File, "/")
|
||||
LogError("original error -> (%s:%d: %v)", fileParts[len(fileParts)-1], frame.Line, err[0])
|
||||
if k8sErrors.IsUnauthorized(err[0]) {
|
||||
errorCode = 401
|
||||
errorMessage = errorGenericUnauthorized.Error()
|
||||
}
|
||||
if k8sErrors.IsForbidden(err[0]) {
|
||||
errorCode = 403
|
||||
errorMessage = errorGenericForbidden.Error()
|
||||
}
|
||||
if k8sErrors.IsNotFound(err[0]) {
|
||||
errorCode = 404
|
||||
errorMessage = ErrorGenericNotFound.Error()
|
||||
}
|
||||
if err[0] == ErrorGenericNotFound {
|
||||
errorCode = 404
|
||||
errorMessage = ErrorGenericNotFound.Error()
|
||||
}
|
||||
if errors.Is(err[0], errInvalidCredentials) {
|
||||
errorCode = 401
|
||||
errorMessage = errInvalidCredentials.Error()
|
||||
}
|
||||
// console invalid erasure coding value
|
||||
if errors.Is(err[0], errorInvalidErasureCodingValue) {
|
||||
errorCode = 400
|
||||
errorMessage = errorInvalidErasureCodingValue.Error()
|
||||
}
|
||||
if errors.Is(err[0], errBucketBodyNotInRequest) {
|
||||
errorCode = 400
|
||||
errorMessage = errBucketBodyNotInRequest.Error()
|
||||
}
|
||||
if errors.Is(err[0], errBucketNameNotInRequest) {
|
||||
errorCode = 400
|
||||
errorMessage = errBucketNameNotInRequest.Error()
|
||||
}
|
||||
if errors.Is(err[0], errGroupBodyNotInRequest) {
|
||||
errorCode = 400
|
||||
errorMessage = errGroupBodyNotInRequest.Error()
|
||||
}
|
||||
if errors.Is(err[0], errGroupNameNotInRequest) {
|
||||
errorCode = 400
|
||||
errorMessage = errGroupNameNotInRequest.Error()
|
||||
}
|
||||
if errors.Is(err[0], errPolicyNameNotInRequest) {
|
||||
errorCode = 400
|
||||
errorMessage = errPolicyNameNotInRequest.Error()
|
||||
}
|
||||
if errors.Is(err[0], errPolicyBodyNotInRequest) {
|
||||
errorCode = 400
|
||||
errorMessage = errPolicyBodyNotInRequest.Error()
|
||||
}
|
||||
// console invalid session error
|
||||
if errors.Is(err[0], errorGenericInvalidSession) {
|
||||
errorCode = 401
|
||||
errorMessage = errorGenericInvalidSession.Error()
|
||||
}
|
||||
// Bucket life cycle not configured
|
||||
if errors.Is(err[0], errBucketLifeCycleNotConfigured) {
|
||||
errorCode = 404
|
||||
errorMessage = errBucketLifeCycleNotConfigured.Error()
|
||||
}
|
||||
// Encryption not configured
|
||||
if errors.Is(err[0], errSSENotConfigured) {
|
||||
errorCode = 404
|
||||
errorMessage = errSSENotConfigured.Error()
|
||||
}
|
||||
// account change password
|
||||
if madmin.ToErrorResponse(err[0]).Code == "SignatureDoesNotMatch" {
|
||||
errorCode = 403
|
||||
errorMessage = errChangePassword.Error()
|
||||
}
|
||||
if errors.Is(err[0], errLicenseNotFound) {
|
||||
errorCode = 404
|
||||
errorMessage = errLicenseNotFound.Error()
|
||||
}
|
||||
if errors.Is(err[0], errInvalidLicense) {
|
||||
errorCode = 404
|
||||
errorMessage = errInvalidLicense.Error()
|
||||
}
|
||||
if errors.Is(err[0], errAvoidSelfAccountDelete) {
|
||||
errorCode = 403
|
||||
errorMessage = errAvoidSelfAccountDelete.Error()
|
||||
}
|
||||
if madmin.ToErrorResponse(err[0]).Code == "AccessDenied" {
|
||||
errorCode = 403
|
||||
errorMessage = errAccessDenied.Error()
|
||||
}
|
||||
if madmin.ToErrorResponse(err[0]).Code == "InvalidAccessKeyId" {
|
||||
errorCode = 401
|
||||
errorMessage = errorGenericInvalidSession.Error()
|
||||
}
|
||||
// console invalid session error
|
||||
if madmin.ToErrorResponse(err[0]).Code == "XMinioAdminNoSuchUser" {
|
||||
errorCode = 401
|
||||
errorMessage = errorGenericInvalidSession.Error()
|
||||
}
|
||||
// if we received a second error take that as friendly message but dont override the code
|
||||
if len(err) > 1 && err[1] != nil {
|
||||
LogError("friendly error: %v", err[1].Error())
|
||||
errorMessage = err[1].Error()
|
||||
}
|
||||
// if we receive third error we just print that as debugging
|
||||
if len(err) > 2 && err[2] != nil {
|
||||
LogError("debugging error: %v", err[2].Error())
|
||||
}
|
||||
|
||||
errRemoteTierExists := errors.New("Specified remote tier already exists") //nolint
|
||||
if errors.Is(err[0], errRemoteTierExists) {
|
||||
errorMessage = err[0].Error()
|
||||
}
|
||||
if errors.Is(err[0], errTooFewNodes) {
|
||||
errorCode = 507
|
||||
errorMessage = errTooFewNodes.Error()
|
||||
}
|
||||
if errors.Is(err[0], errTooFewSchedulableNodes) {
|
||||
errorCode = 507
|
||||
errorMessage = errTooFewSchedulableNodes.Error()
|
||||
}
|
||||
if errors.Is(err[0], errFewerThanFourNodes) {
|
||||
errorCode = 507
|
||||
errorMessage = errFewerThanFourNodes.Error()
|
||||
}
|
||||
}
|
||||
return &models.Error{Code: errorCode, Message: swag.String(errorMessage), DetailedMessage: swag.String(err[0].Error())}
|
||||
}
|
||||
|
||||
func getFrame(skipFrames int) runtime.Frame {
|
||||
// We need the frame at index skipFrames+2, since we never want runtime.Callers and getFrame
|
||||
targetFrameIndex := skipFrames + 2
|
||||
|
||||
// Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need
|
||||
programCounters := make([]uintptr, targetFrameIndex+2)
|
||||
n := runtime.Callers(0, programCounters)
|
||||
|
||||
frame := runtime.Frame{Function: "unknown"}
|
||||
if n > 0 {
|
||||
frames := runtime.CallersFrames(programCounters[:n])
|
||||
for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
|
||||
var frameCandidate runtime.Frame
|
||||
frameCandidate, more = frames.Next()
|
||||
if frameIndex == targetFrameIndex {
|
||||
frame = frameCandidate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frame
|
||||
}
|
||||
@@ -42,7 +42,7 @@ import (
|
||||
func registerLoginHandlers(api *operations.OperatorAPI) {
|
||||
// GET login strategy
|
||||
api.AuthLoginDetailHandler = authApi.LoginDetailHandlerFunc(func(params authApi.LoginDetailParams) middleware.Responder {
|
||||
loginDetails, err := getLoginDetailsResponse(params.HTTPRequest)
|
||||
loginDetails, err := getLoginDetailsResponse(params)
|
||||
if err != nil {
|
||||
return authApi.NewLoginDetailDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func registerLoginHandlers(api *operations.OperatorAPI) {
|
||||
})
|
||||
// POST login using k8s service account token
|
||||
api.AuthLoginOperatorHandler = authApi.LoginOperatorHandlerFunc(func(params authApi.LoginOperatorParams) middleware.Responder {
|
||||
loginResponse, err := getLoginOperatorResponse(params.Body)
|
||||
loginResponse, err := getLoginOperatorResponse(params)
|
||||
if err != nil {
|
||||
return authApi.NewLoginOperatorDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func registerLoginHandlers(api *operations.OperatorAPI) {
|
||||
})
|
||||
// POST login using external IDP
|
||||
api.AuthLoginOauth2AuthHandler = authApi.LoginOauth2AuthHandlerFunc(func(params authApi.LoginOauth2AuthParams) middleware.Responder {
|
||||
loginResponse, err := getLoginOauth2AuthResponse(params.HTTPRequest, params.Body)
|
||||
loginResponse, err := getLoginOauth2AuthResponse(params)
|
||||
if err != nil {
|
||||
return authApi.NewLoginOauth2AuthDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
@@ -87,14 +87,19 @@ func login(credentials restapi.ConsoleCredentialsI) (*string, error) {
|
||||
// if we made it here, the consoleCredentials work, generate a jwt with claims
|
||||
token, err := auth.NewEncryptedTokenForClient(&tokens, credentials.GetAccountAccessKey(), nil)
|
||||
if err != nil {
|
||||
LogError("error authenticating user: %v", err)
|
||||
return nil, errInvalidCredentials
|
||||
restapi.LogError("error authenticating user: %v", err)
|
||||
return nil, restapi.ErrInvalidLogin
|
||||
}
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// getLoginDetailsResponse returns information regarding the Console authentication mechanism.
|
||||
func getLoginDetailsResponse(r *http.Request) (*models.LoginDetails, *models.Error) {
|
||||
func getLoginDetailsResponse(params authApi.LoginDetailParams) (*models.LoginDetails, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
r := params.HTTPRequest
|
||||
|
||||
loginStrategy := models.LoginDetailsLoginStrategyServiceDashAccount
|
||||
redirectURL := ""
|
||||
|
||||
@@ -103,7 +108,7 @@ func getLoginDetailsResponse(r *http.Request) (*models.LoginDetails, *models.Err
|
||||
// initialize new oauth2 client
|
||||
oauth2Client, err := oauth2.NewOauth2ProviderClient(nil, r, restapi.GetConsoleHTTPClient())
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// Validate user against IDP
|
||||
identityProvider := &auth.IdentityProvider{Client: oauth2Client}
|
||||
@@ -126,31 +131,35 @@ func verifyUserAgainstIDP(ctx context.Context, provider auth.IdentityProviderI,
|
||||
return oauth2Token, nil
|
||||
}
|
||||
|
||||
func getLoginOauth2AuthResponse(r *http.Request, lr *models.LoginOauth2AuthRequest) (*models.LoginResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
func getLoginOauth2AuthResponse(params authApi.LoginOauth2AuthParams) (*models.LoginResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
r := params.HTTPRequest
|
||||
lr := params.Body
|
||||
|
||||
if oauth2.IsIDPEnabled() {
|
||||
// initialize new oauth2 client
|
||||
oauth2Client, err := oauth2.NewOauth2ProviderClient(nil, r, restapi.GetConsoleHTTPClient())
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// initialize new identity provider
|
||||
identityProvider := auth.IdentityProvider{Client: oauth2Client}
|
||||
// Validate user against IDP
|
||||
_, err = verifyUserAgainstIDP(ctx, identityProvider, *lr.Code, *lr.State)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// If we pass here that means the IDP correctly authenticate the user with the operator resource
|
||||
// we proceed to use the service account token configured in the operator-console pod
|
||||
creds, err := newConsoleCredentials(getK8sSAToken())
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
token, err := login(restapi.ConsoleCredentials{ConsoleCredentials: creds})
|
||||
if err != nil {
|
||||
return nil, prepareError(errInvalidCredentials, nil, err)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrInvalidLogin, nil, err)
|
||||
}
|
||||
// serialize output
|
||||
loginResponse := &models.LoginResponse{
|
||||
@@ -158,7 +167,7 @@ func getLoginOauth2AuthResponse(r *http.Request, lr *models.LoginOauth2AuthReque
|
||||
}
|
||||
return loginResponse, nil
|
||||
}
|
||||
return nil, prepareError(errorGeneric)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrDefault)
|
||||
}
|
||||
|
||||
func newConsoleCredentials(secretKey string) (*credentials.Credentials, error) {
|
||||
@@ -170,17 +179,22 @@ func newConsoleCredentials(secretKey string) (*credentials.Credentials, error) {
|
||||
}
|
||||
|
||||
// getLoginOperatorResponse validate the provided service account token against k8s api
|
||||
func getLoginOperatorResponse(lmr *models.LoginOperatorRequest) (*models.LoginResponse, *models.Error) {
|
||||
func getLoginOperatorResponse(params authApi.LoginOperatorParams) (*models.LoginResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
lmr := params.Body
|
||||
|
||||
creds, err := newConsoleCredentials(*lmr.Jwt)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
consoleCreds := restapi.ConsoleCredentials{ConsoleCredentials: creds}
|
||||
// Set a random as access key as session identifier
|
||||
consoleCreds.AccountAccessKey = fmt.Sprintf("%d", rand.Intn(100000-10000)+10000)
|
||||
token, err := login(consoleCreds)
|
||||
if err != nil {
|
||||
return nil, prepareError(errInvalidCredentials, nil, err)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrInvalidLogin, nil, err)
|
||||
}
|
||||
// serialize output
|
||||
loginResponse := &models.LoginResponse{
|
||||
|
||||
@@ -20,12 +20,13 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
xerrors "github.com/minio/console/restapi"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/cluster"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/operatorapi/operations"
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
@@ -44,12 +45,12 @@ func registerNamespaceHandlers(api *operations.OperatorAPI) {
|
||||
}
|
||||
|
||||
func getNamespaceCreatedResponse(session *models.Principal, params operator_api.CreateNamespaceParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
namespace := *params.Body.Name
|
||||
@@ -57,7 +58,7 @@ func getNamespaceCreatedResponse(session *models.Principal, params operator_api.
|
||||
errCreation := getNamespaceCreated(ctx, clientset.CoreV1(), namespace)
|
||||
|
||||
if errCreation != nil {
|
||||
return prepareError(errCreation)
|
||||
return xerrors.ErrorWithContext(ctx, errCreation)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
xerrors "github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/minio-go/v7/pkg/set"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
@@ -52,8 +54,8 @@ func registerNodesHandlers(api *operations.OperatorAPI) {
|
||||
return operator_api.NewListNodeLabelsOK().WithPayload(*resp)
|
||||
})
|
||||
|
||||
api.OperatorAPIGetAllocatableResourcesHandler = operator_api.GetAllocatableResourcesHandlerFunc(func(params operator_api.GetAllocatableResourcesParams, principal *models.Principal) middleware.Responder {
|
||||
resp, err := getAllocatableResourcesResponse(params.NumNodes, principal)
|
||||
api.OperatorAPIGetAllocatableResourcesHandler = operator_api.GetAllocatableResourcesHandlerFunc(func(params operator_api.GetAllocatableResourcesParams, session *models.Principal) middleware.Responder {
|
||||
resp, err := getAllocatableResourcesResponse(session, params)
|
||||
if err != nil {
|
||||
return operator_api.NewGetAllocatableResourcesDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
@@ -71,7 +73,7 @@ type NodeResourceInfo struct {
|
||||
func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface, numNodes int32) (*models.MaxAllocatableMemResponse, error) {
|
||||
// can't request less than 4 nodes
|
||||
if numNodes < 4 {
|
||||
return nil, errFewerThanFourNodes
|
||||
return nil, xerrors.ErrFewerThanFourNodes
|
||||
}
|
||||
|
||||
// get all nodes from cluster
|
||||
@@ -97,15 +99,15 @@ func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface,
|
||||
}
|
||||
// requesting more nodes than schedulable and less than total number of workers
|
||||
if int(numNodes) > schedulableNodes && int(numNodes) < nonMasterNodes {
|
||||
return nil, errTooManyNodes
|
||||
return nil, xerrors.ErrTooManyNodes
|
||||
}
|
||||
if nonMasterNodes < int(numNodes) {
|
||||
return nil, errTooFewNodes
|
||||
return nil, xerrors.ErrTooFewNodes
|
||||
}
|
||||
|
||||
// not enough schedulable nodes
|
||||
if schedulableNodes < int(numNodes) {
|
||||
return nil, errTooFewSchedulableNodes
|
||||
return nil, xerrors.ErrTooFewAvailableNodes
|
||||
}
|
||||
|
||||
availableMemSizes := []int64{}
|
||||
@@ -177,12 +179,12 @@ func min(x, y int64) int64 {
|
||||
func getMaxAllocatableMemoryResponse(ctx context.Context, session *models.Principal, numNodes int32) (*models.MaxAllocatableMemResponse, *models.Error) {
|
||||
client, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
clusterResources, err := getMaxAllocatableMemory(ctx, client.CoreV1(), numNodes)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return clusterResources, nil
|
||||
}
|
||||
@@ -217,12 +219,12 @@ func getNodeLabels(ctx context.Context, clientset v1.CoreV1Interface) (*models.N
|
||||
func getNodeLabelsResponse(ctx context.Context, session *models.Principal) (*models.NodeLabels, *models.Error) {
|
||||
client, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
clusterResources, err := getNodeLabels(ctx, client.CoreV1())
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return clusterResources, nil
|
||||
}
|
||||
@@ -357,17 +359,16 @@ OUTER:
|
||||
|
||||
// Get allocatable resources response
|
||||
|
||||
func getAllocatableResourcesResponse(numNodes int32, session *models.Principal) (*models.AllocatableResourcesResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
func getAllocatableResourcesResponse(session *models.Principal, params operator_api.GetAllocatableResourcesParams) (*models.AllocatableResourcesResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
client, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
clusterResources, err := getAllocatableResources(ctx, client.CoreV1(), numNodes)
|
||||
clusterResources, err := getAllocatableResources(ctx, client.CoreV1(), params.NumNodes)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return clusterResources, nil
|
||||
}
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
package operatorapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/minio/console/restapi"
|
||||
errors "github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/console/pkg/utils"
|
||||
|
||||
@@ -50,14 +51,14 @@ func GetParityInfo(nodes int64, disksPerNode int64) (models.ParityResponse, erro
|
||||
}
|
||||
|
||||
func getParityResponse(params operator_api.GetParityParams) (models.ParityResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
nodes := params.Nodes
|
||||
disksPerNode := params.DisksPerNode
|
||||
|
||||
parityValues, err := GetParityInfo(nodes, disksPerNode)
|
||||
if err != nil {
|
||||
restapi.LogError("error getting parity info: %v", err)
|
||||
return nil, prepareError(err)
|
||||
errors.LogError("error getting parity info: %v", err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
return parityValues, nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
xerrors "github.com/minio/console/restapi"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/minio/console/cluster"
|
||||
@@ -94,18 +96,18 @@ func getResourceQuota(ctx context.Context, client K8sClientI, namespace, resourc
|
||||
}
|
||||
|
||||
func getResourceQuotaResponse(session *models.Principal, params operator_api.GetResourceQuotaParams) (*models.ResourceQuota, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
client, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
k8sClient := &k8sClient{
|
||||
client: client,
|
||||
}
|
||||
resourceQuota, err := getResourceQuota(ctx, k8sClient, params.Namespace, params.ResourceQuotaName)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return resourceQuota, nil
|
||||
}
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
package operatorapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
errors "github.com/minio/console/restapi"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/operatorapi/operations"
|
||||
@@ -28,7 +31,7 @@ import (
|
||||
func registerSessionHandlers(api *operations.OperatorAPI) {
|
||||
// session check
|
||||
api.AuthSessionCheckHandler = authApi.SessionCheckHandlerFunc(func(params authApi.SessionCheckParams, session *models.Principal) middleware.Responder {
|
||||
sessionResp, err := getSessionResponse(session)
|
||||
sessionResp, err := getSessionResponse(session, params)
|
||||
if err != nil {
|
||||
return authApi.NewSessionCheckDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
@@ -37,10 +40,12 @@ func registerSessionHandlers(api *operations.OperatorAPI) {
|
||||
}
|
||||
|
||||
// getSessionResponse parse the token of the current session and returns a list of allowed actions to render in the UI
|
||||
func getSessionResponse(session *models.Principal) (*models.OperatorSessionResponse, *models.Error) {
|
||||
func getSessionResponse(session *models.Principal, params authApi.SessionCheckParams) (*models.OperatorSessionResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// serialize output
|
||||
if session == nil {
|
||||
return nil, prepareError(errorGenericInvalidSession)
|
||||
return nil, errors.ErrorWithContext(ctx, errors.ErrInvalidSession)
|
||||
}
|
||||
sessionResp := &models.OperatorSessionResponse{
|
||||
Status: models.OperatorSessionResponseStatusOk,
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
func getTenantCreatedResponse(session *models.Principal, params operator_api.CreateTenantParams) (response *models.CreateTenantResponse, mError *models.Error) {
|
||||
tenantReq := params.Body
|
||||
minioImage := tenantReq.Image
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
if minioImage == "" {
|
||||
minImg, err := cluster.GetMinioImage()
|
||||
@@ -56,7 +56,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
client: clientSet,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
ns := *tenantReq.Namespace
|
||||
@@ -98,7 +98,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
// Enable/Disable console object browser for MinIO tenant (default is on)
|
||||
@@ -110,7 +110,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
tenantConfigurationENV["MINIO_ROOT_USER"] = accessKey
|
||||
tenantConfigurationENV["MINIO_ROOT_PASSWORD"] = secretKey
|
||||
|
||||
// delete secrets created if an error occurred during tenant creation,
|
||||
// delete secrets created if an errors occurred during tenant creation,
|
||||
defer func() {
|
||||
if mError != nil {
|
||||
restapi.LogError("deleting secrets created for failed tenant: %s if any: %v", tenantName, mError)
|
||||
@@ -127,7 +127,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
// Check the Erasure Coding Parity for validity and pass it to Tenant
|
||||
if tenantReq.ErasureCodingParity > 0 {
|
||||
if tenantReq.ErasureCodingParity < 2 || tenantReq.ErasureCodingParity > 8 {
|
||||
return nil, prepareError(errorInvalidErasureCodingValue)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrInvalidErasureCodingValue)
|
||||
}
|
||||
tenantConfigurationENV["MINIO_STORAGE_CLASS_STANDARD"] = fmt.Sprintf("EC:%d", tenantReq.ErasureCodingParity)
|
||||
}
|
||||
@@ -204,7 +204,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
}
|
||||
_, err := clientSet.CoreV1().Secrets(ns).Create(ctx, &userSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
}
|
||||
// attach the users to the tenant
|
||||
@@ -248,7 +248,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
}
|
||||
_, err := clientSet.CoreV1().Secrets(ns).Create(ctx, &userSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
}
|
||||
// attach the users to the tenant
|
||||
@@ -274,7 +274,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
externalCertSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
||||
externalCertSecret, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, tenantReq.TLS.Minio, externalCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
minInst.Spec.ExternalCertSecret = externalCertSecret
|
||||
}
|
||||
@@ -286,7 +286,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
certificates := []*models.KeyPairConfiguration{tenantReq.Encryption.Client}
|
||||
certificateSecrets, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, certificates, tenantExternalClientCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(restapi.ErrorGeneric)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrDefault)
|
||||
}
|
||||
if len(certificateSecrets) > 0 {
|
||||
minInst.Spec.ExternalClientCertSecret = certificateSecrets[0]
|
||||
@@ -296,7 +296,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
// KES configuration for Tenant instance
|
||||
minInst.Spec.KES, err = getKESConfiguration(ctx, &k8sClient, ns, tenantReq.Encryption, secretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(restapi.ErrorGeneric)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrDefault)
|
||||
}
|
||||
// Set Labels, Annotations and Node Selector for KES
|
||||
minInst.Spec.KES.Labels = tenantReq.Encryption.Labels
|
||||
@@ -306,7 +306,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if tenantReq.Encryption.SecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.Encryption.SecurityContext)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
minInst.Spec.KES.SecurityContext = sc
|
||||
}
|
||||
@@ -317,7 +317,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
for i, caCertificate := range tenantReq.TLS.CaCertificates {
|
||||
certificateContent, err := base64.StdEncoding.DecodeString(caCertificate)
|
||||
if err != nil {
|
||||
return nil, prepareError(restapi.ErrorGeneric, nil, err)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrDefault, nil, err)
|
||||
}
|
||||
caCertificates = append(caCertificates, tenantSecret{
|
||||
Name: fmt.Sprintf("ca-certificate-%d", i),
|
||||
@@ -329,7 +329,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if len(caCertificates) > 0 {
|
||||
certificateSecrets, err := createOrReplaceSecrets(ctx, &k8sClient, ns, caCertificates, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(restapi.ErrorGeneric, nil, err)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrDefault, nil, err)
|
||||
}
|
||||
minInst.Spec.ExternalCaCertSecret = certificateSecrets
|
||||
}
|
||||
@@ -347,7 +347,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
pool, err := parseTenantPoolRequest(pool)
|
||||
if err != nil {
|
||||
restapi.LogError("parseTenantPoolRequest failed: %v", err)
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
minInst.Spec.Pools = append(minInst.Spec.Pools, *pool)
|
||||
}
|
||||
@@ -363,7 +363,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if tenantReq.ImagePullSecret != "" {
|
||||
imagePullSecret = tenantReq.ImagePullSecret
|
||||
} else if imagePullSecret, err = setImageRegistry(ctx, tenantReq.ImageRegistry, clientSet.CoreV1(), ns, tenantName); err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// pass the image pull secret to the Tenant
|
||||
if imagePullSecret != "" {
|
||||
@@ -410,7 +410,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if tenantReq.LogSearchConfiguration.SecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.SecurityContext)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
logSearchSecurityContext = sc
|
||||
}
|
||||
@@ -418,7 +418,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if tenantReq.LogSearchConfiguration.PostgresSecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.PostgresSecurityContext)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
logSearchPgSecurityContext = sc
|
||||
}
|
||||
@@ -514,7 +514,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if tenantReq.PrometheusConfiguration != nil && tenantReq.PrometheusConfiguration.SecurityContext != nil {
|
||||
sc, err := convertModelSCToK8sSC(tenantReq.PrometheusConfiguration.SecurityContext)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
minInst.Spec.Prometheus.SecurityContext = sc
|
||||
}
|
||||
@@ -538,7 +538,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
},
|
||||
}, tenantName)
|
||||
if err != nil {
|
||||
return nil, prepareError(restapi.ErrorGeneric, nil, err)
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrDefault, nil, err)
|
||||
}
|
||||
minInst.Spec.Configuration = &corev1.LocalObjectReference{Name: tenantConfigurationName}
|
||||
|
||||
@@ -562,20 +562,20 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
|
||||
opClient, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
_, err = opClient.MinioV2().Tenants(ns).Create(context.Background(), &minInst, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
restapi.LogError("Creating new tenant failed with: %v", err)
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
// Integrations
|
||||
if os.Getenv("GKE_INTEGRATION") != "" {
|
||||
err := gkeIntegration(clientSet, tenantName, ns, session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
}
|
||||
response = &models.CreateTenantResponse{
|
||||
|
||||
@@ -20,20 +20,21 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
errors "github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/console/cluster"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
"github.com/minio/console/restapi"
|
||||
miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func getTenantDetailsResponse(session *models.Principal, params operator_api.TenantDetailsParams) (*models.Tenant, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -42,7 +43,7 @@ func getTenantDetailsResponse(session *models.Principal, params operator_api.Ten
|
||||
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
info := getTenantInfo(minTenant)
|
||||
@@ -50,7 +51,7 @@ func getTenantDetailsResponse(session *models.Principal, params operator_api.Ten
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
k8sClient := k8sClient{
|
||||
@@ -59,7 +60,7 @@ func getTenantDetailsResponse(session *models.Principal, params operator_api.Ten
|
||||
|
||||
tenantConfiguration, err := GetTenantConfiguration(ctx, &k8sClient, minTenant)
|
||||
if err != nil {
|
||||
restapi.LogError("unable to fetch configuration for tenant %s: %v", minTenant.Name, err)
|
||||
errors.LogError("unable to fetch configuration for tenant %s: %v", minTenant.Name, err)
|
||||
}
|
||||
|
||||
// detect if AD/LDAP is enabled
|
||||
@@ -105,14 +106,14 @@ func getTenantDetailsResponse(session *models.Principal, params operator_api.Ten
|
||||
//minio service
|
||||
minSvc, err := k8sClient.getService(ctx, minTenant.Namespace, minTenant.MinIOCIServiceName(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
// we can tolerate this error
|
||||
restapi.LogError("Unable to get MinIO service name: %v, continuing", err)
|
||||
// we can tolerate this errors
|
||||
errors.LogError("Unable to get MinIO service name: %v, continuing", err)
|
||||
}
|
||||
//console service
|
||||
conSvc, err := k8sClient.getService(ctx, minTenant.Namespace, minTenant.ConsoleCIServiceName(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
// we can tolerate this error
|
||||
restapi.LogError("Unable to get MinIO console service name: %v, continuing", err)
|
||||
// we can tolerate this errors
|
||||
errors.LogError("Unable to get MinIO console service name: %v, continuing", err)
|
||||
}
|
||||
|
||||
schema := "http"
|
||||
|
||||
@@ -22,9 +22,12 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/console/pkg/http"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
utils2 "github.com/minio/console/pkg/utils"
|
||||
"github.com/minio/console/restapi"
|
||||
miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -32,7 +35,7 @@ import (
|
||||
)
|
||||
|
||||
// updateTenantAction does an update on the minioTenant by patching the desired changes
|
||||
func updateTenantAction(ctx context.Context, operatorClient OperatorClientI, clientset v1.CoreV1Interface, httpCl utils2.HTTPClientI, namespace string, params operator_api.UpdateTenantParams) error {
|
||||
func updateTenantAction(ctx context.Context, operatorClient OperatorClientI, clientset v1.CoreV1Interface, httpCl http.ClientI, namespace string, params operator_api.UpdateTenantParams) error {
|
||||
imageToUpdate := params.Body.Image
|
||||
imageRegistryReq := params.Body.ImageRegistry
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
utils2 "github.com/minio/console/pkg/http"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/minio/madmin-go"
|
||||
|
||||
utils2 "github.com/minio/console/pkg/utils"
|
||||
|
||||
"github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
@@ -354,14 +354,16 @@ func registerTenantHandlers(api *operations.OperatorAPI) {
|
||||
|
||||
// getDeleteTenantResponse gets the output of deleting a minio instance
|
||||
func getDeleteTenantResponse(session *models.Principal, params operator_api.DeleteTenantParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// get Kubernetes Client
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
opClient := &operatorClient{
|
||||
client: opClientClientSet,
|
||||
@@ -373,12 +375,12 @@ func getDeleteTenantResponse(session *models.Principal, params operator_api.Dele
|
||||
|
||||
tenant, err := opClient.TenantGet(params.HTTPRequest.Context(), params.Namespace, params.Tenant, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
tenant.EnsureDefaults()
|
||||
|
||||
if err = deleteTenantAction(params.HTTPRequest.Context(), opClient, clientset.CoreV1(), tenant, deleteTenantPVCs); err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -396,7 +398,7 @@ func deleteTenantAction(
|
||||
err := operatorClient.TenantDelete(ctx, tenant.Namespace, tenant.Name, 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
|
||||
// else, we return the errors
|
||||
if (deletePvcs && !k8sErrors.IsNotFound(err)) || !deletePvcs {
|
||||
return err
|
||||
}
|
||||
@@ -440,19 +442,19 @@ func deleteTenantAction(
|
||||
|
||||
// getDeleteTenantResponse gets the output of deleting a minio instance
|
||||
func getDeletePodResponse(session *models.Principal, params operator_api.DeletePodParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// get Kubernetes Client
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
listOpts := metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("v1.min.io/tenant=%s", params.Tenant),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s%s", params.Tenant, params.PodName[len(params.Tenant):]),
|
||||
}
|
||||
if err = clientset.CoreV1().Pods(params.Namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, listOpts); err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -494,12 +496,12 @@ func getTenantCreds(ctx context.Context, client K8sClientI, tenant *miniov2.Tena
|
||||
tenantAccessKey, ok := tenantConfiguration["accesskey"]
|
||||
if !ok {
|
||||
restapi.LogError("tenant's secret doesn't contain accesskey")
|
||||
return nil, restapi.ErrorGeneric
|
||||
return nil, restapi.ErrDefault
|
||||
}
|
||||
tenantSecretKey, ok := tenantConfiguration["secretkey"]
|
||||
if !ok {
|
||||
restapi.LogError("tenant's secret doesn't contain secretkey")
|
||||
return nil, restapi.ErrorGeneric
|
||||
return nil, restapi.ErrDefault
|
||||
}
|
||||
return &tenantKeys{accessKey: tenantAccessKey, secretKey: tenantSecretKey}, nil
|
||||
}
|
||||
@@ -842,19 +844,19 @@ func updateTenantIdentityProvider(ctx context.Context, operatorClient OperatorCl
|
||||
|
||||
func getTenantIdentityProviderResponse(session *models.Principal, params operator_api.TenantIdentityProviderParams) (*models.IdpConfiguration, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
opClient := &operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
@@ -862,27 +864,27 @@ func getTenantIdentityProviderResponse(session *models.Principal, params operato
|
||||
client: clientSet,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
info, err := getTenantIdentityProvider(ctx, &k8sClient, minTenant)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func getUpdateTenantIdentityProviderResponse(session *models.Principal, params operator_api.UpdateTenantIdentityProviderParams) *models.Error {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
@@ -891,25 +893,25 @@ func getUpdateTenantIdentityProviderResponse(session *models.Principal, params o
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := updateTenantIdentityProvider(ctx, opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||
return prepareError(err, errors.New("unable to update tenant"))
|
||||
return restapi.ErrorWithContext(ctx, err, errors.New("unable to update tenant"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTenantSecurityResponse(session *models.Principal, params operator_api.TenantSecurityParams) (*models.TenantSecurityResponse, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
opClient := &operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
@@ -917,27 +919,27 @@ func getTenantSecurityResponse(session *models.Principal, params operator_api.Te
|
||||
client: clientSet,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
info, err := getTenantSecurity(ctx, &k8sClient, minTenant)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func getUpdateTenantSecurityResponse(session *models.Principal, params operator_api.UpdateTenantSecurityParams) *models.Error {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
@@ -946,7 +948,7 @@ func getUpdateTenantSecurityResponse(session *models.Principal, params operator_
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := updateTenantSecurity(ctx, opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||
return prepareError(err, errors.New("unable to update tenant"))
|
||||
return restapi.ErrorWithContext(ctx, err, errors.New("unable to update tenant"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1117,36 +1119,36 @@ func listTenants(ctx context.Context, operatorClient OperatorClientI, namespace
|
||||
}
|
||||
|
||||
func getListAllTenantsResponse(session *models.Principal, params operator_api.ListAllTenantsParams) (*models.ListTenantsResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
opClient := &operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
listT, err := listTenants(ctx, opClient, "", params.Limit)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return listT, nil
|
||||
}
|
||||
|
||||
// getListTenantsResponse list tenants by namespace
|
||||
func getListTenantsResponse(session *models.Principal, params operator_api.ListTenantsParams) (*models.ListTenantsResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
opClient := &operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
listT, err := listTenants(ctx, opClient, params.Namespace, params.Limit)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return listT, nil
|
||||
}
|
||||
@@ -1233,27 +1235,27 @@ func removeAnnotations(annotationsOne, annotationsTwo map[string]string) map[str
|
||||
}
|
||||
|
||||
func getUpdateTenantResponse(session *models.Principal, params operator_api.UpdateTenantParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
opClient := &operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
httpC := &utils2.HTTPClient{
|
||||
httpC := &utils2.Client{
|
||||
Client: &http.Client{
|
||||
Timeout: 4 * time.Second,
|
||||
},
|
||||
}
|
||||
if err := updateTenantAction(ctx, opClient, clientSet.CoreV1(), httpC, params.Namespace, params); err != nil {
|
||||
return prepareError(err, errors.New("unable to update tenant"))
|
||||
return restapi.ErrorWithContext(ctx, err, errors.New("unable to update tenant"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1284,17 +1286,17 @@ func addTenantPool(ctx context.Context, operatorClient OperatorClientI, params o
|
||||
}
|
||||
|
||||
func getTenantAddPoolResponse(session *models.Principal, params operator_api.TenantAddPoolParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
opClient := &operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := addTenantPool(ctx, opClient, params); err != nil {
|
||||
return prepareError(err, errors.New("unable to add pool"))
|
||||
return restapi.ErrorWithContext(ctx, err, errors.New("unable to add pool"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1302,16 +1304,16 @@ func getTenantAddPoolResponse(session *models.Principal, params operator_api.Ten
|
||||
// getTenantUsageResponse returns the usage of a tenant
|
||||
func getTenantUsageResponse(session *models.Principal, params operator_api.GetTenantUsageParams) (*models.TenantUsage, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -1323,7 +1325,7 @@ func getTenantUsageResponse(session *models.Principal, params operator_api.GetTe
|
||||
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
minTenant.EnsureDefaults()
|
||||
|
||||
@@ -1336,7 +1338,7 @@ func getTenantUsageResponse(session *models.Principal, params operator_api.GetTe
|
||||
svcURL,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
// create a minioClient interface implementation
|
||||
// defining the client to be used
|
||||
@@ -1344,7 +1346,7 @@ func getTenantUsageResponse(session *models.Principal, params operator_api.GetTe
|
||||
// serialize output
|
||||
adminInfo, err := restapi.GetAdminInfo(ctx, adminClient)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
info := &models.TenantUsage{Used: adminInfo.Usage, DiskUsed: adminInfo.DisksUsage}
|
||||
return info, nil
|
||||
@@ -1353,12 +1355,12 @@ func getTenantUsageResponse(session *models.Principal, params operator_api.GetTe
|
||||
// getTenantLogsResponse returns the logs of a tenant
|
||||
func getTenantLogsResponse(session *models.Principal, params operator_api.GetTenantLogsParams) (*models.TenantLogs, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorUnableToGetTenantLogs)
|
||||
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantLogs)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -1367,7 +1369,7 @@ func getTenantLogsResponse(session *models.Principal, params operator_api.GetTen
|
||||
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorUnableToGetTenantLogs)
|
||||
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantLogs)
|
||||
}
|
||||
if minTenant.Spec.Log == nil {
|
||||
retval := &models.TenantLogs{
|
||||
@@ -1450,12 +1452,12 @@ func getTenantLogsResponse(session *models.Principal, params operator_api.GetTen
|
||||
// setTenantLogsResponse returns the logs of a tenant
|
||||
func setTenantLogsResponse(session *models.Principal, params operator_api.SetTenantLogsParams) (bool, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -1464,7 +1466,7 @@ func setTenantLogsResponse(session *models.Principal, params operator_api.SetTen
|
||||
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
|
||||
var labels = make(map[string]string)
|
||||
@@ -1493,7 +1495,7 @@ func setTenantLogsResponse(session *models.Principal, params operator_api.SetTen
|
||||
if reflect.TypeOf(params.Data.LogCPURequest).Kind() == reflect.String && params.Data.LogCPURequest != "0Gi" && params.Data.LogCPURequest != "" {
|
||||
cpuQuantity, err := resource.ParseQuantity(params.Data.LogCPURequest)
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
logResourceRequest["cpu"] = cpuQuantity
|
||||
minTenant.Spec.Log.Resources.Requests = logResourceRequest
|
||||
@@ -1501,7 +1503,7 @@ func setTenantLogsResponse(session *models.Principal, params operator_api.SetTen
|
||||
if reflect.TypeOf(params.Data.LogMemRequest).Kind() == reflect.String {
|
||||
memQuantity, err := resource.ParseQuantity(params.Data.LogMemRequest)
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
logResourceRequest["memory"] = memQuantity
|
||||
@@ -1538,7 +1540,7 @@ func setTenantLogsResponse(session *models.Principal, params operator_api.SetTen
|
||||
if reflect.TypeOf(params.Data.LogDBCPURequest).Kind() == reflect.String && params.Data.LogDBCPURequest != "0Gi" && params.Data.LogDBCPURequest != "" {
|
||||
dbCPUQuantity, err := resource.ParseQuantity(params.Data.LogDBCPURequest)
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
logDBResourceRequest["cpu"] = dbCPUQuantity
|
||||
minTenant.Spec.Log.Db.Resources.Requests = logDBResourceRequest
|
||||
@@ -1546,7 +1548,7 @@ func setTenantLogsResponse(session *models.Principal, params operator_api.SetTen
|
||||
if reflect.TypeOf(params.Data.LogDBMemRequest).Kind() == reflect.String {
|
||||
dbMemQuantity, err := resource.ParseQuantity(params.Data.LogDBMemRequest)
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
logDBResourceRequest["memory"] = dbMemQuantity
|
||||
minTenant.Spec.Log.Db.Resources.Requests = logDBResourceRequest
|
||||
@@ -1609,7 +1611,7 @@ func setTenantLogsResponse(session *models.Principal, params operator_api.SetTen
|
||||
|
||||
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@@ -1617,12 +1619,12 @@ func setTenantLogsResponse(session *models.Principal, params operator_api.SetTen
|
||||
// enableTenantLoggingResponse enables Tenant Logging
|
||||
func enableTenantLoggingResponse(session *models.Principal, params operator_api.EnableTenantLoggingParams) (bool, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -1631,7 +1633,7 @@ func enableTenantLoggingResponse(session *models.Principal, params operator_api.
|
||||
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
minTenant.EnsureDefaults()
|
||||
|
||||
@@ -1670,7 +1672,7 @@ func enableTenantLoggingResponse(session *models.Principal, params operator_api.
|
||||
|
||||
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@@ -1678,15 +1680,15 @@ func enableTenantLoggingResponse(session *models.Principal, params operator_api.
|
||||
// disableTenantLoggingResponse disables Tenant Logging
|
||||
func disableTenantLoggingResponse(session *models.Principal, params operator_api.DisableTenantLoggingParams) (bool, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -1695,31 +1697,31 @@ func disableTenantLoggingResponse(session *models.Principal, params operator_api
|
||||
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
minTenant.EnsureDefaults()
|
||||
minTenant.Spec.Log = nil
|
||||
|
||||
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func getTenantPodsResponse(session *models.Principal, params operator_api.GetTenantPodsParams) ([]*models.TenantPod, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
listOpts := metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", miniov2.TenantLabel, params.Tenant),
|
||||
}
|
||||
pods, err := clientset.CoreV1().Pods(params.Namespace).List(ctx, listOpts)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
retval := []*models.TenantPod{}
|
||||
for _, pod := range pods.Items {
|
||||
@@ -1743,35 +1745,35 @@ func getTenantPodsResponse(session *models.Principal, params operator_api.GetTen
|
||||
}
|
||||
|
||||
func getPodLogsResponse(session *models.Principal, params operator_api.GetPodLogsParams) (string, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return "", prepareError(err)
|
||||
return "", restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
listOpts := &corev1.PodLogOptions{}
|
||||
logs := clientset.CoreV1().Pods(params.Namespace).GetLogs(params.PodName, listOpts)
|
||||
buff, err := logs.DoRaw(ctx)
|
||||
if err != nil {
|
||||
return "", prepareError(err)
|
||||
return "", restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return string(buff), nil
|
||||
}
|
||||
|
||||
func getPodEventsResponse(session *models.Principal, params operator_api.GetPodEventsParams) (models.EventListWrapper, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
pod, err := clientset.CoreV1().Pods(params.Namespace).Get(ctx, params.PodName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
events, err := clientset.CoreV1().Events(params.Namespace).List(ctx, metav1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.uid=%s", pod.UID)})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
retval := models.EventListWrapper{}
|
||||
for i := 0; i < len(events.Items); i++ {
|
||||
@@ -1791,12 +1793,12 @@ func getPodEventsResponse(session *models.Principal, params operator_api.GetPodE
|
||||
|
||||
//get values for prometheus metrics
|
||||
func getTenantMonitoringResponse(session *models.Principal, params operator_api.GetTenantMonitoringParams) (*models.TenantMonitoringInfo, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -1805,7 +1807,7 @@ func getTenantMonitoringResponse(session *models.Principal, params operator_api.
|
||||
|
||||
minInst, err := opClient.TenantGet(ctx, params.Namespace, params.Tenant, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
monitoringInfo := &models.TenantMonitoringInfo{}
|
||||
@@ -1886,12 +1888,12 @@ func getTenantMonitoringResponse(session *models.Principal, params operator_api.
|
||||
//sets tenant Prometheus monitoring cofiguration fields to values provided
|
||||
func setTenantMonitoringResponse(session *models.Principal, params operator_api.SetTenantMonitoringParams) (bool, *models.Error) {
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -1900,7 +1902,7 @@ func setTenantMonitoringResponse(session *models.Principal, params operator_api.
|
||||
|
||||
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
||||
if err != nil {
|
||||
return false, prepareError(err, errorUnableToGetTenantUsage)
|
||||
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
||||
}
|
||||
|
||||
if params.Data.Toggle {
|
||||
@@ -1916,7 +1918,7 @@ func setTenantMonitoringResponse(session *models.Principal, params operator_api.
|
||||
}
|
||||
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@@ -1944,7 +1946,7 @@ func setTenantMonitoringResponse(session *models.Principal, params operator_api.
|
||||
if params.Data.MonitoringCPURequest != "" {
|
||||
cpuQuantity, err := resource.ParseQuantity(params.Data.MonitoringCPURequest)
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
monitoringResourceRequest["cpu"] = cpuQuantity
|
||||
}
|
||||
@@ -1952,7 +1954,7 @@ func setTenantMonitoringResponse(session *models.Principal, params operator_api.
|
||||
if params.Data.MonitoringMemRequest != "" {
|
||||
memQuantity, err := resource.ParseQuantity(params.Data.MonitoringMemRequest)
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
monitoringResourceRequest["memory"] = memQuantity
|
||||
}
|
||||
@@ -1977,7 +1979,7 @@ func setTenantMonitoringResponse(session *models.Principal, params operator_api.
|
||||
minTenant.Spec.Prometheus.ServiceAccountName = params.Data.ServiceAccountName
|
||||
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return false, prepareError(err)
|
||||
return false, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
@@ -2422,11 +2424,11 @@ func parseNodeSelectorTerm(term *corev1.NodeSelectorTerm) *models.NodeSelectorTe
|
||||
}
|
||||
|
||||
func getTenantUpdatePoolResponse(session *models.Principal, params operator_api.TenantUpdatePoolsParams) (*models.Tenant, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -2436,7 +2438,7 @@ func getTenantUpdatePoolResponse(session *models.Principal, params operator_api.
|
||||
t, err := updateTenantPools(ctx, opClient, params.Namespace, params.Tenant, params.Body.Pools)
|
||||
if err != nil {
|
||||
restapi.LogError("error updating Tenant's pools: %v", err)
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
// parse it to models.Tenant
|
||||
@@ -2487,20 +2489,19 @@ func updateTenantPools(
|
||||
}
|
||||
|
||||
func getTenantYAML(session *models.Principal, params operator_api.GetTenantYAMLParams) (*models.TenantYAML, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// get Kubernetes Client
|
||||
|
||||
opClient, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
tenant, err := opClient.MinioV2().Tenants(params.Namespace).Get(params.HTTPRequest.Context(), params.Tenant, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
// remove managed fields
|
||||
tenant.ManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
|
||||
//yb, err := yaml.Marshal(tenant)
|
||||
j8sJSONSerializer := k8sJson.NewSerializerWithOptions(
|
||||
k8sJson.DefaultMetaFactory, nil, nil,
|
||||
@@ -2514,7 +2515,7 @@ func getTenantYAML(session *models.Principal, params operator_api.GetTenantYAMLP
|
||||
|
||||
err = j8sJSONSerializer.Encode(tenant, buf)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
yb := buf.String()
|
||||
@@ -2523,6 +2524,8 @@ func getTenantYAML(session *models.Principal, params operator_api.GetTenantYAMLP
|
||||
}
|
||||
|
||||
func getUpdateTenantYAML(session *models.Principal, params operator_api.PutTenantYAMLParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// https://godoc.org/k8s.io/apimachinery/pkg/runtime#Scheme
|
||||
scheme := runtime.NewScheme()
|
||||
|
||||
@@ -2540,12 +2543,12 @@ func getUpdateTenantYAML(session *models.Principal, params operator_api.PutTenan
|
||||
// get Kubernetes Client
|
||||
opClient, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
tenant, err := opClient.MinioV2().Tenants(params.Namespace).Get(params.HTTPRequest.Context(), params.Tenant, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
upTenant := tenant.DeepCopy()
|
||||
// only update safe fields: spec, metadata.finalizers, metadata.labels and metadata.annotations
|
||||
@@ -2563,23 +2566,23 @@ func getUpdateTenantYAML(session *models.Principal, params operator_api.PutTenan
|
||||
}
|
||||
|
||||
func getTenantEventsResponse(session *models.Principal, params operator_api.GetTenantEventsParams) (models.EventListWrapper, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
client, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
tenant, err := client.MinioV2().Tenants(params.Namespace).Get(ctx, params.Tenant, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
events, err := clientset.CoreV1().Events(params.Namespace).List(ctx, metav1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.uid=%s", tenant.UID)})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
retval := models.EventListWrapper{}
|
||||
for _, event := range events.Items {
|
||||
@@ -2603,7 +2606,7 @@ func getUpdateDomainsResponse(session *models.Principal, params operator_api.Upd
|
||||
|
||||
operatorCli, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
opClient := &operatorClient{
|
||||
@@ -2613,7 +2616,7 @@ func getUpdateDomainsResponse(session *models.Principal, params operator_api.Upd
|
||||
err = updateTenantDomains(ctx, opClient, params.Namespace, params.Tenant, params.Body.Domains)
|
||||
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -27,6 +27,8 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
xerrors "github.com/minio/console/restapi"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
|
||||
"errors"
|
||||
@@ -108,25 +110,25 @@ func tenantUpdateCertificates(ctx context.Context, operatorClient OperatorClient
|
||||
|
||||
// getTenantUpdateCertificatesResponse wrapper of tenantUpdateCertificates
|
||||
func getTenantUpdateCertificatesResponse(session *models.Principal, params operator_api.TenantUpdateCertificateParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err, errorUnableToUpdateTenantCertificates)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrUnableToUpdateTenantCertificates)
|
||||
}
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
}
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err, errorUnableToUpdateTenantCertificates)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrUnableToUpdateTenantCertificates)
|
||||
}
|
||||
opClient := operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := tenantUpdateCertificates(ctx, &opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||
return prepareError(err, errorUnableToUpdateTenantCertificates)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrUnableToUpdateTenantCertificates)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -239,42 +241,42 @@ func tenantUpdateEncryption(ctx context.Context, operatorClient OperatorClientI,
|
||||
|
||||
// getTenantDeleteEncryptionResponse is a wrapper for tenantDeleteEncryption
|
||||
func getTenantDeleteEncryptionResponse(session *models.Principal, params operator_api.TenantDeleteEncryptionParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err, errorDeletingEncryptionConfig)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrDeletingEncryptionConfig)
|
||||
}
|
||||
opClient := operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := tenantDeleteEncryption(ctx, &opClient, params.Namespace, params); err != nil {
|
||||
return prepareError(err, errorDeletingEncryptionConfig)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrDeletingEncryptionConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getTenantUpdateEncryptionResponse is a wrapper for tenantUpdateEncryption
|
||||
func getTenantUpdateEncryptionResponse(session *models.Principal, params operator_api.TenantUpdateEncryptionParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err, errorUpdatingEncryptionConfig)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrUpdatingEncryptionConfig)
|
||||
}
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
}
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err, errorUpdatingEncryptionConfig)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrUpdatingEncryptionConfig)
|
||||
}
|
||||
opClient := operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := tenantUpdateEncryption(ctx, &opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||
return prepareError(err, errorUpdatingEncryptionConfig)
|
||||
return xerrors.ErrorWithContext(ctx, err, xerrors.ErrUpdatingEncryptionConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -453,26 +455,26 @@ func tenantEncryptionInfo(ctx context.Context, operatorClient OperatorClientI, c
|
||||
|
||||
// getTenantEncryptionResponse is a wrapper for tenantEncryptionInfo
|
||||
func getTenantEncryptionInfoResponse(session *models.Principal, params operator_api.TenantEncryptionInfoParams) (*models.EncryptionConfigurationResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorEncryptionConfigNotFound)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err, xerrors.ErrEncryptionConfigNotFound)
|
||||
}
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
}
|
||||
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorEncryptionConfigNotFound)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err, xerrors.ErrEncryptionConfigNotFound)
|
||||
}
|
||||
opClient := operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
configuration, err := tenantEncryptionInfo(ctx, &opClient, &k8sClient, params.Namespace, params)
|
||||
if err != nil {
|
||||
return nil, prepareError(err, errorEncryptionConfigNotFound)
|
||||
return nil, xerrors.ErrorWithContext(ctx, err, xerrors.ErrEncryptionConfigNotFound)
|
||||
}
|
||||
return configuration, nil
|
||||
}
|
||||
@@ -541,8 +543,8 @@ func createOrReplaceSecrets(ctx context.Context, clientSet K8sClientI, ns string
|
||||
// delete secret with same name if exists
|
||||
err := clientSet.deleteSecret(ctx, ns, secret.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
// log the error if any and continue
|
||||
LogError("deleting secret name %s failed: %v, continuing..", secret.Name, err)
|
||||
// log the errors if any and continue
|
||||
xerrors.LogError("deleting secret name %s failed: %v, continuing..", secret.Name, err)
|
||||
}
|
||||
k8sSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -579,8 +581,8 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient
|
||||
// delete secret with same name if exists
|
||||
err := clientSet.deleteSecret(ctx, ns, keyPairSecretName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
// log the error if any and continue
|
||||
LogError("deleting secret name %s failed: %v, continuing..", keyPairSecretName, err)
|
||||
// log the errors if any and continue
|
||||
xerrors.LogError("deleting secret name %s failed: %v, continuing..", keyPairSecretName, err)
|
||||
}
|
||||
imm := true
|
||||
tlsCrt, err := base64.StdEncoding.DecodeString(*keyPair.Crt)
|
||||
@@ -625,13 +627,13 @@ func createOrReplaceExternalCertSecrets(ctx context.Context, clientSet K8sClient
|
||||
func createOrReplaceKesConfigurationSecrets(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, kesConfigurationSecretName, kesClientCertSecretName, tenantName string) (*corev1.LocalObjectReference, *miniov2.LocalCertificateReference, error) {
|
||||
// delete KES configuration secret if exists
|
||||
if err := clientSet.deleteSecret(ctx, ns, kesConfigurationSecretName, metav1.DeleteOptions{}); err != nil {
|
||||
// log the error if any and continue
|
||||
LogError("deleting secret name %s failed: %v, continuing..", kesConfigurationSecretName, err)
|
||||
// log the errors if any and continue
|
||||
xerrors.LogError("deleting secret name %s failed: %v, continuing..", kesConfigurationSecretName, err)
|
||||
}
|
||||
// delete KES client cert secret if exists
|
||||
if err := clientSet.deleteSecret(ctx, ns, kesClientCertSecretName, metav1.DeleteOptions{}); err != nil {
|
||||
// log the error if any and continue
|
||||
LogError("deleting secret name %s failed: %v, continuing..", kesClientCertSecretName, err)
|
||||
// log the errors if any and continue
|
||||
xerrors.LogError("deleting secret name %s failed: %v, continuing..", kesClientCertSecretName, err)
|
||||
}
|
||||
// if autoCert is enabled then Operator will generate the client certificates, calculate the client cert identity
|
||||
// and pass it to KES via the ${MINIO_KES_IDENTITY} variable
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/minio/console/pkg/utils"
|
||||
xhttp "github.com/minio/console/pkg/http"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
|
||||
@@ -897,7 +897,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
operatorClient OperatorClientI
|
||||
httpCl utils.HTTPClientI
|
||||
httpCl xhttp.ClientI
|
||||
nameSpace string
|
||||
tenantName string
|
||||
mockTenantPatch func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*miniov2.Tenant, error)
|
||||
|
||||
@@ -17,20 +17,24 @@
|
||||
package operatorapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
errors "github.com/minio/console/restapi"
|
||||
|
||||
xhttp "github.com/minio/console/pkg/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/operatorapi/operations"
|
||||
"github.com/minio/console/operatorapi/operations/user_api"
|
||||
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/minio/console/pkg/utils"
|
||||
)
|
||||
|
||||
func registerVersionHandlers(api *operations.OperatorAPI) {
|
||||
api.UserAPICheckMinIOVersionHandler = user_api.CheckMinIOVersionHandlerFunc(func(params user_api.CheckMinIOVersionParams) middleware.Responder {
|
||||
versionResponse, err := getVersionResponse()
|
||||
versionResponse, err := getVersionResponse(params)
|
||||
if err != nil {
|
||||
return user_api.NewCheckMinIOVersionDefault(int(err.Code)).WithPayload(err)
|
||||
}
|
||||
@@ -39,13 +43,15 @@ func registerVersionHandlers(api *operations.OperatorAPI) {
|
||||
}
|
||||
|
||||
// getSessionResponse parse the token of the current session and returns a list of allowed actions to render in the UI
|
||||
func getVersionResponse() (*models.CheckOperatorVersionResponse, *models.Error) {
|
||||
ver, err := utils.GetLatestMinIOImage(&utils.HTTPClient{
|
||||
func getVersionResponse(params user_api.CheckMinIOVersionParams) (*models.CheckOperatorVersionResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
ver, err := utils.GetLatestMinIOImage(&xhttp.Client{
|
||||
Client: &http.Client{
|
||||
Timeout: 15 * time.Second,
|
||||
}})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return &models.CheckOperatorVersionResponse{
|
||||
LatestVersion: *ver,
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
errors "github.com/minio/console/restapi"
|
||||
|
||||
miniov1 "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
@@ -33,7 +35,7 @@ import (
|
||||
|
||||
func registerVolumesHandlers(api *operations.OperatorAPI) {
|
||||
api.OperatorAPIListPVCsHandler = operator_api.ListPVCsHandlerFunc(func(params operator_api.ListPVCsParams, session *models.Principal) middleware.Responder {
|
||||
payload, err := getPVCsResponse(session)
|
||||
payload, err := getPVCsResponse(session, params)
|
||||
|
||||
if err != nil {
|
||||
return operator_api.NewListPVCsDefault(int(err.Code)).WithPayload(err)
|
||||
@@ -72,13 +74,13 @@ func registerVolumesHandlers(api *operations.OperatorAPI) {
|
||||
|
||||
}
|
||||
|
||||
func getPVCsResponse(session *models.Principal) (*models.ListPVCsResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
func getPVCsResponse(session *models.Principal, params operator_api.ListPVCsParams) (*models.ListPVCsResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
// Filter Tenant PVCs. They keep their v1 tenant annotation
|
||||
@@ -90,7 +92,7 @@ func getPVCsResponse(session *models.Principal) (*models.ListPVCsResponse, *mode
|
||||
listAllPvcs, err2 := clientset.CoreV1().PersistentVolumeClaims("").List(ctx, listOpts)
|
||||
|
||||
if err2 != nil {
|
||||
return nil, prepareError(err2)
|
||||
return nil, errors.ErrorWithContext(ctx, err2)
|
||||
}
|
||||
|
||||
var ListPVCs []*models.PvcsListResponse
|
||||
@@ -121,12 +123,12 @@ func getPVCsResponse(session *models.Principal) (*models.ListPVCsResponse, *mode
|
||||
}
|
||||
|
||||
func getPVCsForTenantResponse(session *models.Principal, params operator_api.ListPVCsForTenantParams) (*models.ListPVCsResponse, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
|
||||
// Filter Tenant PVCs. They keep their v1 tenant annotation
|
||||
@@ -138,7 +140,7 @@ func getPVCsForTenantResponse(session *models.Principal, params operator_api.Lis
|
||||
listAllPvcs, err2 := clientset.CoreV1().PersistentVolumeClaims(params.Namespace).List(ctx, listOpts)
|
||||
|
||||
if err2 != nil {
|
||||
return nil, prepareError(err2)
|
||||
return nil, errors.ErrorWithContext(ctx, err2)
|
||||
}
|
||||
|
||||
var ListPVCs []*models.PvcsListResponse
|
||||
@@ -169,37 +171,37 @@ func getPVCsForTenantResponse(session *models.Principal, params operator_api.Lis
|
||||
}
|
||||
|
||||
func getDeletePVCResponse(session *models.Principal, params operator_api.DeletePVCParams) *models.Error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
// get Kubernetes Client
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return prepareError(err)
|
||||
return errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
listOpts := metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("v1.min.io/tenant=%s", params.Tenant),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s", params.PVCName),
|
||||
}
|
||||
if err = clientset.CoreV1().PersistentVolumeClaims(params.Namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, listOpts); err != nil {
|
||||
return prepareError(err)
|
||||
return errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPVCEventsResponse(session *models.Principal, params operator_api.GetPVCEventsParams) (models.EventListWrapper, *models.Error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
||||
defer cancel()
|
||||
clientset, err := cluster.K8sClient(session.STSSessionToken)
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
PVC, err := clientset.CoreV1().PersistentVolumeClaims(params.Namespace).Get(ctx, params.PVCName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
events, err := clientset.CoreV1().Events(params.Namespace).List(ctx, metav1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.uid=%s", PVC.UID)})
|
||||
if err != nil {
|
||||
return nil, prepareError(err)
|
||||
return nil, errors.ErrorWithContext(ctx, err)
|
||||
}
|
||||
retval := models.EventListWrapper{}
|
||||
for i := 0; i < len(events.Items); i++ {
|
||||
|
||||
Reference in New Issue
Block a user