Going to work and add new code on tenant logs so i make this small refactor to keep things separated Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
456 lines
16 KiB
Go
456 lines
16 KiB
Go
package operatorapi
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
"github.com/go-openapi/runtime/middleware"
|
|
"github.com/go-openapi/swag"
|
|
"github.com/minio/console/cluster"
|
|
"github.com/minio/console/models"
|
|
"github.com/minio/console/operatorapi/operations"
|
|
"github.com/minio/console/operatorapi/operations/operator_api"
|
|
"github.com/minio/console/restapi"
|
|
miniov2 "github.com/minio/operator/pkg/apis/minio.min.io/v2"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
func registerTenantLogsHandlers(api *operations.OperatorAPI) {
|
|
api.OperatorAPIGetTenantLogsHandler = operator_api.GetTenantLogsHandlerFunc(func(params operator_api.GetTenantLogsParams, session *models.Principal) middleware.Responder {
|
|
payload, err := getTenantLogsResponse(session, params)
|
|
if err != nil {
|
|
return operator_api.NewGetTenantLogsDefault(int(err.Code)).WithPayload(err)
|
|
}
|
|
return operator_api.NewGetTenantLogsOK().WithPayload(payload)
|
|
})
|
|
|
|
api.OperatorAPISetTenantLogsHandler = operator_api.SetTenantLogsHandlerFunc(func(params operator_api.SetTenantLogsParams, session *models.Principal) middleware.Responder {
|
|
payload, err := setTenantLogsResponse(session, params)
|
|
if err != nil {
|
|
return operator_api.NewSetTenantLogsDefault(int(err.Code)).WithPayload(err)
|
|
}
|
|
return operator_api.NewSetTenantLogsOK().WithPayload(payload)
|
|
})
|
|
|
|
api.OperatorAPIEnableTenantLoggingHandler = operator_api.EnableTenantLoggingHandlerFunc(func(params operator_api.EnableTenantLoggingParams, session *models.Principal) middleware.Responder {
|
|
payload, err := enableTenantLoggingResponse(session, params)
|
|
if err != nil {
|
|
return operator_api.NewEnableTenantLoggingDefault(int(err.Code)).WithPayload(err)
|
|
}
|
|
return operator_api.NewEnableTenantLoggingOK().WithPayload(payload)
|
|
})
|
|
|
|
api.OperatorAPIDisableTenantLoggingHandler = operator_api.DisableTenantLoggingHandlerFunc(func(params operator_api.DisableTenantLoggingParams, session *models.Principal) middleware.Responder {
|
|
payload, err := disableTenantLoggingResponse(session, params)
|
|
if err != nil {
|
|
return operator_api.NewDisableTenantLoggingDefault(int(err.Code)).WithPayload(err)
|
|
}
|
|
return operator_api.NewDisableTenantLoggingOK().WithPayload(payload)
|
|
})
|
|
}
|
|
|
|
// getTenantLogsResponse returns the Audit Log and Log DB configuration of a tenant
|
|
func getTenantLogsResponse(session *models.Principal, params operator_api.GetTenantLogsParams) (*models.TenantLogs, *models.Error) {
|
|
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
|
defer cancel()
|
|
|
|
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
|
if err != nil {
|
|
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantLogs)
|
|
}
|
|
|
|
opClient := &operatorClient{
|
|
client: opClientClientSet,
|
|
}
|
|
|
|
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
|
if err != nil {
|
|
return nil, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantLogs)
|
|
}
|
|
if minTenant.Spec.Log == nil {
|
|
return &models.TenantLogs{
|
|
Disabled: true,
|
|
}, nil
|
|
}
|
|
annotations := []*models.Annotation{}
|
|
for k, v := range minTenant.Spec.Log.Annotations {
|
|
annotations = append(annotations, &models.Annotation{Key: k, Value: v})
|
|
}
|
|
labels := []*models.Label{}
|
|
for k, v := range minTenant.Spec.Log.Labels {
|
|
labels = append(labels, &models.Label{Key: k, Value: v})
|
|
}
|
|
nodeSelector := []*models.NodeSelector{}
|
|
for k, v := range minTenant.Spec.Log.NodeSelector {
|
|
nodeSelector = append(nodeSelector, &models.NodeSelector{Key: k, Value: v})
|
|
}
|
|
if minTenant.Spec.Log.Db == nil {
|
|
minTenant.Spec.Log.Db = &miniov2.LogDbConfig{}
|
|
}
|
|
dbAnnotations := []*models.Annotation{}
|
|
for k, v := range minTenant.Spec.Log.Db.Annotations {
|
|
dbAnnotations = append(dbAnnotations, &models.Annotation{Key: k, Value: v})
|
|
}
|
|
dbLabels := []*models.Label{}
|
|
for k, v := range minTenant.Spec.Log.Db.Labels {
|
|
dbLabels = append(dbLabels, &models.Label{Key: k, Value: v})
|
|
}
|
|
dbNodeSelector := []*models.NodeSelector{}
|
|
for k, v := range minTenant.Spec.Log.Db.NodeSelector {
|
|
dbNodeSelector = append(dbNodeSelector, &models.NodeSelector{Key: k, Value: v})
|
|
}
|
|
var logSecurityContext *models.SecurityContext
|
|
var logDBSecurityContext *models.SecurityContext
|
|
|
|
if minTenant.Spec.Log.SecurityContext != nil {
|
|
logSecurityContext = convertK8sSCToModelSC(minTenant.Spec.Log.SecurityContext)
|
|
}
|
|
if minTenant.Spec.Log.Db.SecurityContext != nil {
|
|
logDBSecurityContext = convertK8sSCToModelSC(minTenant.Spec.Log.Db.SecurityContext)
|
|
}
|
|
|
|
if minTenant.Spec.Log.Audit == nil || minTenant.Spec.Log.Audit.DiskCapacityGB == nil {
|
|
minTenant.Spec.Log.Audit = &miniov2.AuditConfig{DiskCapacityGB: swag.Int(0)}
|
|
}
|
|
|
|
tenantLoggingConfiguration := &models.TenantLogs{
|
|
Image: minTenant.Spec.Log.Image,
|
|
DiskCapacityGB: fmt.Sprintf("%d", *minTenant.Spec.Log.Audit.DiskCapacityGB),
|
|
Annotations: annotations,
|
|
Labels: labels,
|
|
NodeSelector: nodeSelector,
|
|
ServiceAccountName: minTenant.Spec.Log.ServiceAccountName,
|
|
SecurityContext: logSecurityContext,
|
|
DbImage: minTenant.Spec.Log.Db.Image,
|
|
DbInitImage: minTenant.Spec.Log.Db.InitImage,
|
|
DbAnnotations: dbAnnotations,
|
|
DbLabels: dbLabels,
|
|
DbNodeSelector: dbNodeSelector,
|
|
DbServiceAccountName: minTenant.Spec.Log.Db.ServiceAccountName,
|
|
DbSecurityContext: logDBSecurityContext,
|
|
Disabled: false,
|
|
}
|
|
|
|
var requestedCPU string
|
|
var requestedMem string
|
|
var requestedDBCPU string
|
|
var requestedDBMem string
|
|
|
|
if minTenant.Spec.Log.Resources.Requests != nil {
|
|
requestedCPUQ := minTenant.Spec.Log.Resources.Requests["cpu"]
|
|
requestedCPU = strconv.FormatInt(requestedCPUQ.Value(), 10)
|
|
requestedMemQ := minTenant.Spec.Log.Resources.Requests["memory"]
|
|
requestedMem = strconv.FormatInt(requestedMemQ.Value(), 10)
|
|
|
|
requestedDBCPUQ := minTenant.Spec.Log.Db.Resources.Requests["cpu"]
|
|
requestedDBCPU = strconv.FormatInt(requestedDBCPUQ.Value(), 10)
|
|
requestedDBMemQ := minTenant.Spec.Log.Db.Resources.Requests["memory"]
|
|
requestedDBMem = strconv.FormatInt(requestedDBMemQ.Value(), 10)
|
|
|
|
tenantLoggingConfiguration.LogCPURequest = requestedCPU
|
|
tenantLoggingConfiguration.LogMemRequest = requestedMem
|
|
tenantLoggingConfiguration.LogDBCPURequest = requestedDBCPU
|
|
tenantLoggingConfiguration.LogDBMemRequest = requestedDBMem
|
|
}
|
|
return tenantLoggingConfiguration, nil
|
|
}
|
|
|
|
// setTenantLogsResponse updates the Audit Log and Log DB configuration for the tenant
|
|
func setTenantLogsResponse(session *models.Principal, params operator_api.SetTenantLogsParams) (bool, *models.Error) {
|
|
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
|
defer cancel()
|
|
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
|
}
|
|
|
|
opClient := &operatorClient{
|
|
client: opClientClientSet,
|
|
}
|
|
|
|
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
|
}
|
|
|
|
labels := make(map[string]string)
|
|
if params.Data.Labels != nil {
|
|
for i := 0; i < len(params.Data.Labels); i++ {
|
|
if params.Data.Labels[i] != nil {
|
|
labels[params.Data.Labels[i].Key] = params.Data.Labels[i].Value
|
|
}
|
|
}
|
|
minTenant.Spec.Log.Labels = labels
|
|
}
|
|
|
|
if params.Data.Annotations != nil {
|
|
annotations := make(map[string]string)
|
|
for i := 0; i < len(params.Data.Annotations); i++ {
|
|
if params.Data.Annotations[i] != nil {
|
|
annotations[params.Data.Annotations[i].Key] = params.Data.Annotations[i].Value
|
|
}
|
|
}
|
|
minTenant.Spec.Log.Annotations = annotations
|
|
}
|
|
if params.Data.NodeSelector != nil {
|
|
nodeSelector := make(map[string]string)
|
|
for i := 0; i < len(params.Data.NodeSelector); i++ {
|
|
if params.Data.NodeSelector[i] != nil {
|
|
nodeSelector[params.Data.NodeSelector[i].Key] = params.Data.NodeSelector[i].Value
|
|
}
|
|
}
|
|
minTenant.Spec.Log.NodeSelector = nodeSelector
|
|
}
|
|
logResourceRequest := make(corev1.ResourceList)
|
|
if len(params.Data.LogCPURequest) > 0 {
|
|
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, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
logResourceRequest["cpu"] = cpuQuantity
|
|
minTenant.Spec.Log.Resources.Requests = logResourceRequest
|
|
}
|
|
}
|
|
if len(params.Data.LogMemRequest) > 0 {
|
|
if reflect.TypeOf(params.Data.LogMemRequest).Kind() == reflect.String && params.Data.LogMemRequest != "" {
|
|
memQuantity, err := resource.ParseQuantity(params.Data.LogMemRequest)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
|
|
logResourceRequest["memory"] = memQuantity
|
|
minTenant.Spec.Log.Resources.Requests = logResourceRequest
|
|
}
|
|
}
|
|
|
|
modified := false
|
|
if minTenant.Spec.Log.Db != nil {
|
|
modified = true
|
|
}
|
|
dbLabels := make(map[string]string)
|
|
if params.Data.DbLabels != nil {
|
|
for i := 0; i < len(params.Data.DbLabels); i++ {
|
|
if params.Data.DbLabels[i] != nil {
|
|
dbLabels[params.Data.DbLabels[i].Key] = params.Data.DbLabels[i].Value
|
|
}
|
|
modified = true
|
|
}
|
|
}
|
|
dbAnnotations := make(map[string]string)
|
|
if params.Data.DbAnnotations != nil {
|
|
for i := 0; i < len(params.Data.DbAnnotations); i++ {
|
|
if params.Data.DbAnnotations[i] != nil {
|
|
dbAnnotations[params.Data.DbAnnotations[i].Key] = params.Data.DbAnnotations[i].Value
|
|
}
|
|
modified = true
|
|
}
|
|
}
|
|
dbNodeSelector := make(map[string]string)
|
|
if params.Data.DbNodeSelector != nil {
|
|
for i := 0; i < len(params.Data.DbNodeSelector); i++ {
|
|
if params.Data.DbNodeSelector[i] != nil {
|
|
dbNodeSelector[params.Data.DbNodeSelector[i].Key] = params.Data.DbNodeSelector[i].Value
|
|
}
|
|
modified = true
|
|
}
|
|
}
|
|
logDBResourceRequest := make(corev1.ResourceList)
|
|
if len(params.Data.LogDBCPURequest) > 0 {
|
|
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, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
logDBResourceRequest["cpu"] = dbCPUQuantity
|
|
minTenant.Spec.Log.Db.Resources.Requests = logDBResourceRequest
|
|
}
|
|
}
|
|
if len(params.Data.LogDBMemRequest) > 0 {
|
|
if reflect.TypeOf(params.Data.LogDBMemRequest).Kind() == reflect.String && params.Data.LogDBMemRequest != "" {
|
|
dbMemQuantity, err := resource.ParseQuantity(params.Data.LogDBMemRequest)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
logDBResourceRequest["memory"] = dbMemQuantity
|
|
minTenant.Spec.Log.Db.Resources.Requests = logDBResourceRequest
|
|
}
|
|
}
|
|
if len(params.Data.Image) > 0 {
|
|
minTenant.Spec.Log.Image = params.Data.Image
|
|
}
|
|
if params.Data.SecurityContext != nil {
|
|
minTenant.Spec.Log.SecurityContext, err = convertModelSCToK8sSC(params.Data.SecurityContext)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
}
|
|
if len(params.Data.DiskCapacityGB) > 0 {
|
|
diskCapacityGB, err := strconv.Atoi(params.Data.DiskCapacityGB)
|
|
if err == nil {
|
|
if minTenant.Spec.Log.Audit != nil && minTenant.Spec.Log.Audit.DiskCapacityGB != nil {
|
|
*minTenant.Spec.Log.Audit.DiskCapacityGB = diskCapacityGB
|
|
} else {
|
|
minTenant.Spec.Log.Audit = &miniov2.AuditConfig{DiskCapacityGB: swag.Int(diskCapacityGB)}
|
|
}
|
|
}
|
|
}
|
|
if len(params.Data.ServiceAccountName) > 0 {
|
|
minTenant.Spec.Log.ServiceAccountName = params.Data.ServiceAccountName
|
|
}
|
|
if params.Data.DbLabels != nil {
|
|
|
|
if params.Data.DbImage != "" || params.Data.DbServiceAccountName != "" {
|
|
modified = true
|
|
}
|
|
if modified {
|
|
if minTenant.Spec.Log.Db == nil {
|
|
// Default class name for Log search
|
|
diskSpaceFromAPI := int64(5) * humanize.GiByte // Default is 5Gi
|
|
logSearchStorageClass := "standard"
|
|
|
|
logSearchDiskSpace := resource.NewQuantity(diskSpaceFromAPI, resource.DecimalExponent)
|
|
|
|
minTenant.Spec.Log.Db = &miniov2.LogDbConfig{
|
|
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: params.Tenant + "-log",
|
|
},
|
|
Spec: corev1.PersistentVolumeClaimSpec{
|
|
AccessModes: []corev1.PersistentVolumeAccessMode{
|
|
corev1.ReadWriteOnce,
|
|
},
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceStorage: *logSearchDiskSpace,
|
|
},
|
|
},
|
|
StorageClassName: &logSearchStorageClass,
|
|
},
|
|
},
|
|
Labels: dbLabels,
|
|
Annotations: dbAnnotations,
|
|
NodeSelector: dbNodeSelector,
|
|
Image: params.Data.DbImage,
|
|
ServiceAccountName: params.Data.DbServiceAccountName,
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: minTenant.Spec.Log.Db.Resources.Requests,
|
|
},
|
|
}
|
|
} else {
|
|
minTenant.Spec.Log.Db.Labels = dbLabels
|
|
minTenant.Spec.Log.Db.Annotations = dbAnnotations
|
|
minTenant.Spec.Log.Db.NodeSelector = dbNodeSelector
|
|
minTenant.Spec.Log.Db.Image = params.Data.DbImage
|
|
minTenant.Spec.Log.Db.InitImage = params.Data.DbInitImage
|
|
minTenant.Spec.Log.Db.ServiceAccountName = params.Data.DbServiceAccountName
|
|
minTenant.Spec.Log.Db.SecurityContext, err = convertModelSCToK8sSC(params.Data.DbSecurityContext)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
// enableTenantLoggingResponse enables Tenant Logging
|
|
func enableTenantLoggingResponse(session *models.Principal, params operator_api.EnableTenantLoggingParams) (bool, *models.Error) {
|
|
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
|
defer cancel()
|
|
|
|
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
|
}
|
|
|
|
opClient := &operatorClient{
|
|
client: opClientClientSet,
|
|
}
|
|
|
|
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
|
}
|
|
minTenant.EnsureDefaults()
|
|
// Default class name for Log search
|
|
diskSpaceFromAPI := int64(5) * humanize.GiByte // Default is 5Gi
|
|
logSearchStorageClass := "standard"
|
|
|
|
logSearchDiskSpace := resource.NewQuantity(diskSpaceFromAPI, resource.DecimalExponent)
|
|
|
|
auditMaxCap := 10
|
|
if (diskSpaceFromAPI / humanize.GiByte) < int64(auditMaxCap) {
|
|
auditMaxCap = int(diskSpaceFromAPI / humanize.GiByte)
|
|
}
|
|
|
|
minTenant.Spec.Log = &miniov2.LogConfig{
|
|
Audit: &miniov2.AuditConfig{DiskCapacityGB: swag.Int(auditMaxCap)},
|
|
Db: &miniov2.LogDbConfig{
|
|
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: params.Tenant + "-log",
|
|
},
|
|
Spec: corev1.PersistentVolumeClaimSpec{
|
|
AccessModes: []corev1.PersistentVolumeAccessMode{
|
|
corev1.ReadWriteOnce,
|
|
},
|
|
Resources: corev1.ResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
corev1.ResourceStorage: *logSearchDiskSpace,
|
|
},
|
|
},
|
|
StorageClassName: &logSearchStorageClass,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err = opClient.TenantUpdate(ctx, minTenant, metav1.UpdateOptions{})
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
// disableTenantLoggingResponse disables Tenant Logging
|
|
func disableTenantLoggingResponse(session *models.Principal, params operator_api.DisableTenantLoggingParams) (bool, *models.Error) {
|
|
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
|
|
defer cancel()
|
|
|
|
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
|
}
|
|
if err != nil {
|
|
return false, restapi.ErrorWithContext(ctx, err, restapi.ErrUnableToGetTenantUsage)
|
|
}
|
|
|
|
opClient := &operatorClient{
|
|
client: opClientClientSet,
|
|
}
|
|
|
|
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
|
|
if err != nil {
|
|
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, restapi.ErrorWithContext(ctx, err)
|
|
}
|
|
return true, nil
|
|
}
|