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:
Lenin Alevski
2022-04-28 12:55:06 -07:00
committed by GitHub
parent 8c18829089
commit 566fb27fc1
100 changed files with 4959 additions and 1738 deletions

View File

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

View File

@@ -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(),

View File

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

View File

@@ -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{

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,

View File

@@ -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{

View File

@@ -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"

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,

View File

@@ -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++ {