Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c59387c2b4 | ||
|
|
c5a3eff745 | ||
|
|
624891ae1f |
@@ -15,7 +15,7 @@ spec:
|
|||||||
serviceAccountName: console-sa
|
serviceAccountName: console-sa
|
||||||
containers:
|
containers:
|
||||||
- name: console
|
- name: console
|
||||||
image: minio/console:v0.3.18
|
image: minio/console:v0.3.19
|
||||||
imagePullPolicy: "IfNotPresent"
|
imagePullPolicy: "IfNotPresent"
|
||||||
args:
|
args:
|
||||||
- server
|
- server
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ spec:
|
|||||||
serviceAccountName: console-sa
|
serviceAccountName: console-sa
|
||||||
containers:
|
containers:
|
||||||
- name: console
|
- name: console
|
||||||
image: minio/console:v0.3.18
|
image: minio/console:v0.3.19
|
||||||
imagePullPolicy: "IfNotPresent"
|
imagePullPolicy: "IfNotPresent"
|
||||||
env:
|
env:
|
||||||
- name: CONSOLE_OPERATOR_MODE
|
- name: CONSOLE_OPERATOR_MODE
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
// Code generated by go-swagger; DO NOT EDIT.
|
|
||||||
|
|
||||||
// This file is part of MinIO Console Server
|
|
||||||
// Copyright (c) 2020 MinIO, Inc.
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
package models
|
|
||||||
|
|
||||||
// This file was generated by the swagger tool.
|
|
||||||
// Editing this file might prove futile when you re-run the swagger generate command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/go-openapi/errors"
|
|
||||||
"github.com/go-openapi/strfmt"
|
|
||||||
"github.com/go-openapi/swag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ClusterResources cluster resources
|
|
||||||
//
|
|
||||||
// swagger:model clusterResources
|
|
||||||
type ClusterResources struct {
|
|
||||||
|
|
||||||
// nodes
|
|
||||||
Nodes []*NodeInfo `json:"nodes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate validates this cluster resources
|
|
||||||
func (m *ClusterResources) Validate(formats strfmt.Registry) error {
|
|
||||||
var res []error
|
|
||||||
|
|
||||||
if err := m.validateNodes(formats); err != nil {
|
|
||||||
res = append(res, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(res) > 0 {
|
|
||||||
return errors.CompositeValidationError(res...)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ClusterResources) validateNodes(formats strfmt.Registry) error {
|
|
||||||
|
|
||||||
if swag.IsZero(m.Nodes) { // not required
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(m.Nodes); i++ {
|
|
||||||
if swag.IsZero(m.Nodes[i]) { // not required
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Nodes[i] != nil {
|
|
||||||
if err := m.Nodes[i].Validate(formats); err != nil {
|
|
||||||
if ve, ok := err.(*errors.Validation); ok {
|
|
||||||
return ve.ValidateName("nodes" + "." + strconv.Itoa(i))
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalBinary interface implementation
|
|
||||||
func (m *ClusterResources) MarshalBinary() ([]byte, error) {
|
|
||||||
if m == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return swag.WriteJSON(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary interface implementation
|
|
||||||
func (m *ClusterResources) UnmarshalBinary(b []byte) error {
|
|
||||||
var res ClusterResources
|
|
||||||
if err := swag.ReadJSON(b, &res); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*m = res
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -27,28 +27,22 @@ import (
|
|||||||
"github.com/go-openapi/swag"
|
"github.com/go-openapi/swag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeTaints node taints
|
// MaxAllocatableMemResponse max allocatable mem response
|
||||||
//
|
//
|
||||||
// swagger:model nodeTaints
|
// swagger:model maxAllocatableMemResponse
|
||||||
type NodeTaints struct {
|
type MaxAllocatableMemResponse struct {
|
||||||
|
|
||||||
// no execute
|
// max memory
|
||||||
NoExecute []string `json:"no_execute"`
|
MaxMemory int64 `json:"max_memory,omitempty"`
|
||||||
|
|
||||||
// no schedule
|
|
||||||
NoSchedule []string `json:"no_schedule"`
|
|
||||||
|
|
||||||
// prefer no schedule
|
|
||||||
PreferNoSchedule []string `json:"prefer_no_schedule"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates this node taints
|
// Validate validates this max allocatable mem response
|
||||||
func (m *NodeTaints) Validate(formats strfmt.Registry) error {
|
func (m *MaxAllocatableMemResponse) Validate(formats strfmt.Registry) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalBinary interface implementation
|
// MarshalBinary interface implementation
|
||||||
func (m *NodeTaints) MarshalBinary() ([]byte, error) {
|
func (m *MaxAllocatableMemResponse) MarshalBinary() ([]byte, error) {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -56,8 +50,8 @@ func (m *NodeTaints) MarshalBinary() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalBinary interface implementation
|
// UnmarshalBinary interface implementation
|
||||||
func (m *NodeTaints) UnmarshalBinary(b []byte) error {
|
func (m *MaxAllocatableMemResponse) UnmarshalBinary(b []byte) error {
|
||||||
var res NodeTaints
|
var res MaxAllocatableMemResponse
|
||||||
if err := swag.ReadJSON(b, &res); err != nil {
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -28,29 +28,27 @@ import (
|
|||||||
"github.com/go-openapi/swag"
|
"github.com/go-openapi/swag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeInfo node info
|
// UpdateCertificatesRequest update certificates request
|
||||||
//
|
//
|
||||||
// swagger:model nodeInfo
|
// swagger:model updateCertificatesRequest
|
||||||
type NodeInfo struct {
|
type UpdateCertificatesRequest struct {
|
||||||
|
|
||||||
// Represents the resources of a node that are available for scheduling.
|
// console
|
||||||
AllocatableResources map[string]int64 `json:"allocatable_resources,omitempty"`
|
Console *KeyPairConfiguration `json:"console,omitempty"`
|
||||||
|
|
||||||
// name
|
// minio
|
||||||
Name string `json:"name,omitempty"`
|
Minio *KeyPairConfiguration `json:"minio,omitempty"`
|
||||||
|
|
||||||
// taints
|
|
||||||
Taints *NodeTaints `json:"taints,omitempty"`
|
|
||||||
|
|
||||||
// Represents the total resources of a node.
|
|
||||||
TotalResources map[string]int64 `json:"total_resources,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates this node info
|
// Validate validates this update certificates request
|
||||||
func (m *NodeInfo) Validate(formats strfmt.Registry) error {
|
func (m *UpdateCertificatesRequest) Validate(formats strfmt.Registry) error {
|
||||||
var res []error
|
var res []error
|
||||||
|
|
||||||
if err := m.validateTaints(formats); err != nil {
|
if err := m.validateConsole(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.validateMinio(formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,16 +58,34 @@ func (m *NodeInfo) Validate(formats strfmt.Registry) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *NodeInfo) validateTaints(formats strfmt.Registry) error {
|
func (m *UpdateCertificatesRequest) validateConsole(formats strfmt.Registry) error {
|
||||||
|
|
||||||
if swag.IsZero(m.Taints) { // not required
|
if swag.IsZero(m.Console) { // not required
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Taints != nil {
|
if m.Console != nil {
|
||||||
if err := m.Taints.Validate(formats); err != nil {
|
if err := m.Console.Validate(formats); err != nil {
|
||||||
if ve, ok := err.(*errors.Validation); ok {
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
return ve.ValidateName("taints")
|
return ve.ValidateName("console")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UpdateCertificatesRequest) validateMinio(formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if swag.IsZero(m.Minio) { // not required
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Minio != nil {
|
||||||
|
if err := m.Minio.Validate(formats); err != nil {
|
||||||
|
if ve, ok := err.(*errors.Validation); ok {
|
||||||
|
return ve.ValidateName("minio")
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -79,7 +95,7 @@ func (m *NodeInfo) validateTaints(formats strfmt.Registry) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshalBinary interface implementation
|
// MarshalBinary interface implementation
|
||||||
func (m *NodeInfo) MarshalBinary() ([]byte, error) {
|
func (m *UpdateCertificatesRequest) MarshalBinary() ([]byte, error) {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -87,8 +103,8 @@ func (m *NodeInfo) MarshalBinary() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalBinary interface implementation
|
// UnmarshalBinary interface implementation
|
||||||
func (m *NodeInfo) UnmarshalBinary(b []byte) error {
|
func (m *UpdateCertificatesRequest) UnmarshalBinary(b []byte) error {
|
||||||
var res NodeInfo
|
var res UpdateCertificatesRequest
|
||||||
if err := swag.ReadJSON(b, &res); err != nil {
|
if err := swag.ReadJSON(b, &res); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -18,12 +18,13 @@ package restapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"sort"
|
||||||
|
|
||||||
"github.com/minio/console/cluster"
|
"github.com/minio/console/cluster"
|
||||||
|
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/go-openapi/runtime/middleware"
|
"github.com/go-openapi/runtime/middleware"
|
||||||
"github.com/go-openapi/swag"
|
"github.com/go-openapi/swag"
|
||||||
"github.com/minio/console/models"
|
"github.com/minio/console/models"
|
||||||
@@ -35,73 +36,94 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func registerNodesHandlers(api *operations.ConsoleAPI) {
|
func registerNodesHandlers(api *operations.ConsoleAPI) {
|
||||||
api.AdminAPIGetClusterResourcesHandler = admin_api.GetClusterResourcesHandlerFunc(func(params admin_api.GetClusterResourcesParams, session *models.Principal) middleware.Responder {
|
api.AdminAPIGetMaxAllocatableMemHandler = admin_api.GetMaxAllocatableMemHandlerFunc(func(params admin_api.GetMaxAllocatableMemParams, principal *models.Principal) middleware.Responder {
|
||||||
resp, err := getClusterResourcesResponse(session)
|
resp, err := getMaxAllocatableMemoryResponse(principal, params.NumNodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return admin_api.NewGetClusterResourcesDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
|
return admin_api.NewGetMaxAllocatableMemDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
|
||||||
}
|
}
|
||||||
return admin_api.NewGetClusterResourcesOK().WithPayload(resp)
|
return admin_api.NewGetMaxAllocatableMemOK().WithPayload(resp)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getClusterResources get cluster nodes and collects taints, available and allocatable resources of the node
|
// getMaxAllocatableMemory get max allocatable memory given a desired number of nodes
|
||||||
func getClusterResources(ctx context.Context, clientset v1.CoreV1Interface) (*models.ClusterResources, error) {
|
func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface, numNodes int32) (*models.MaxAllocatableMemResponse, error) {
|
||||||
|
if numNodes == 0 {
|
||||||
|
return nil, errors.New("error NumNodes must be greated than 0")
|
||||||
|
}
|
||||||
|
|
||||||
// get all nodes from cluster
|
// get all nodes from cluster
|
||||||
nodes, err := clientset.Nodes().List(ctx, metav1.ListOptions{})
|
nodes, err := clientset.Nodes().List(ctx, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// construct ClusterResources response
|
|
||||||
res := &models.ClusterResources{}
|
|
||||||
|
|
||||||
|
availableMemSizes := []int64{}
|
||||||
|
OUTER:
|
||||||
for _, n := range nodes.Items {
|
for _, n := range nodes.Items {
|
||||||
// Get Total Resources
|
// Don't consider node if it has a NoSchedule or NoExecute Taint
|
||||||
totalResources := make(map[string]int64)
|
|
||||||
for resource, quantity := range n.Status.Capacity {
|
|
||||||
totalResources[string(resource)] = quantity.Value()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Allocatable Resources
|
|
||||||
allocatableResources := make(map[string]int64)
|
|
||||||
for resource, quantity := range n.Status.Allocatable {
|
|
||||||
allocatableResources[string(resource)] = quantity.Value()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Node taints and split them by effect
|
|
||||||
taints := &models.NodeTaints{}
|
|
||||||
for _, t := range n.Spec.Taints {
|
for _, t := range n.Spec.Taints {
|
||||||
var taint string
|
|
||||||
// when value is not defined the taint string is created without `=`
|
|
||||||
if strings.TrimSpace(t.Value) != "" {
|
|
||||||
taint = fmt.Sprintf("%s=%s:%s", t.Key, t.Value, t.Effect)
|
|
||||||
} else {
|
|
||||||
taint = fmt.Sprintf("%s:%s", t.Key, t.Effect)
|
|
||||||
}
|
|
||||||
switch t.Effect {
|
switch t.Effect {
|
||||||
case corev1.TaintEffectNoSchedule:
|
case corev1.TaintEffectNoSchedule:
|
||||||
taints.NoSchedule = append(taints.NoSchedule, taint)
|
continue OUTER
|
||||||
case corev1.TaintEffectNoExecute:
|
case corev1.TaintEffectNoExecute:
|
||||||
taints.NoExecute = append(taints.NoExecute, taint)
|
continue OUTER
|
||||||
case corev1.TaintEffectPreferNoSchedule:
|
|
||||||
taints.PreferNoSchedule = append(taints.PreferNoSchedule, taint)
|
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if quantity, ok := n.Status.Allocatable[corev1.ResourceMemory]; ok {
|
||||||
// create node object an add it to the nodes list
|
availableMemSizes = append(availableMemSizes, quantity.Value())
|
||||||
nodeInfo := &models.NodeInfo{
|
|
||||||
Name: n.Name,
|
|
||||||
Taints: taints,
|
|
||||||
AllocatableResources: allocatableResources,
|
|
||||||
TotalResources: totalResources,
|
|
||||||
}
|
}
|
||||||
res.Nodes = append(res.Nodes, nodeInfo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maxAllocatableMemory := getMaxClusterMemory(numNodes, availableMemSizes)
|
||||||
|
|
||||||
|
res := &models.MaxAllocatableMemResponse{
|
||||||
|
MaxMemory: maxAllocatableMemory,
|
||||||
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClusterResourcesResponse(session *models.Principal) (*models.ClusterResources, error) {
|
// getMaxClusterMemory returns the maximum memory size that can be used
|
||||||
|
// across numNodes (number of nodes)
|
||||||
|
func getMaxClusterMemory(numNodes int32, nodesMemorySizes []int64) int64 {
|
||||||
|
if int32(len(nodesMemorySizes)) < numNodes || numNodes == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort nodesMemorySizes int64 array
|
||||||
|
sort.Slice(nodesMemorySizes, func(i, j int) bool { return nodesMemorySizes[i] < nodesMemorySizes[j] })
|
||||||
|
maxIndex := 0
|
||||||
|
maxAllocatableMemory := nodesMemorySizes[maxIndex]
|
||||||
|
|
||||||
|
for i, size := range nodesMemorySizes {
|
||||||
|
// maxAllocatableMemory is the minimum value of nodesMemorySizes array
|
||||||
|
// only within the size of numNodes, if more nodes are available
|
||||||
|
// then the maxAllocatableMemory is equal to the next minimum value
|
||||||
|
// on the sorted nodesMemorySizes array.
|
||||||
|
// e.g. with numNodes = 4;
|
||||||
|
// maxAllocatableMemory of [2,4,8,8] => 2
|
||||||
|
// maxAllocatableMemory of [2,4,8,8,16] => 4
|
||||||
|
if int32(i) < numNodes {
|
||||||
|
maxAllocatableMemory = min(maxAllocatableMemory, size)
|
||||||
|
} else {
|
||||||
|
maxIndex++
|
||||||
|
maxAllocatableMemory = nodesMemorySizes[maxIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxAllocatableMemory
|
||||||
|
}
|
||||||
|
|
||||||
|
// min returns the smaller of x or y.
|
||||||
|
func min(x, y int64) int64 {
|
||||||
|
if x > y {
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMaxAllocatableMemoryResponse(session *models.Principal, numNodes int32) (*models.MaxAllocatableMemResponse, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client, err := cluster.K8sClient(session.SessionToken)
|
client, err := cluster.K8sClient(session.SessionToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -109,7 +131,7 @@ func getClusterResourcesResponse(session *models.Principal) (*models.ClusterReso
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterResources, err := getClusterResources(ctx, client.CoreV1())
|
clusterResources, err := getMaxAllocatableMemory(ctx, client.CoreV1(), numNodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error getting cluster's resources:", err)
|
log.Println("error getting cluster's resources:", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package restapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -31,45 +30,68 @@ import (
|
|||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_GetClusterResources(t *testing.T) {
|
func Test_MaxAllocatableMemory(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
objs []runtime.Object
|
numNodes int32
|
||||||
|
objs []runtime.Object
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
expected *models.ClusterResources
|
expected *models.MaxAllocatableMemResponse
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Get Nodes Taints and Resources",
|
name: "Get Max Ram No Taints",
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
|
numNodes: 2,
|
||||||
objs: []runtime.Object{
|
objs: []runtime.Object{
|
||||||
&corev1.Node{
|
&corev1.Node{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "node1",
|
Name: "node1",
|
||||||
},
|
},
|
||||||
Spec: corev1.NodeSpec{
|
Status: corev1.NodeStatus{
|
||||||
Taints: []corev1.Taint{
|
Allocatable: corev1.ResourceList{
|
||||||
corev1.Taint{
|
corev1.ResourceMemory: resource.MustParse("2Ki"),
|
||||||
Key: "node.kubernetes.io/unreachable",
|
corev1.ResourceCPU: resource.MustParse("4Ki"),
|
||||||
Effect: corev1.TaintEffectNoSchedule,
|
|
||||||
},
|
|
||||||
corev1.Taint{
|
|
||||||
Key: "own.minio.io/taint",
|
|
||||||
Effect: corev1.TaintEffectNoExecute,
|
|
||||||
Value: "val",
|
|
||||||
},
|
|
||||||
corev1.Taint{
|
|
||||||
Key: "node.kubernetes.io/unschedulable",
|
|
||||||
Effect: corev1.TaintEffectPreferNoSchedule,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
&corev1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node2",
|
||||||
|
},
|
||||||
Status: corev1.NodeStatus{
|
Status: corev1.NodeStatus{
|
||||||
Capacity: corev1.ResourceList{
|
Allocatable: corev1.ResourceList{
|
||||||
|
corev1.ResourceMemory: resource.MustParse("512"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &models.MaxAllocatableMemResponse{
|
||||||
|
MaxMemory: int64(512),
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Description: if there are more nodes than the amount
|
||||||
|
// of nodes we want to use, but one has taints of NoSchedule
|
||||||
|
// node should not be considered for max memory
|
||||||
|
name: "Get Max Ram on nodes with NoSchedule",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
numNodes: 2,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node1",
|
||||||
|
},
|
||||||
|
Status: corev1.NodeStatus{
|
||||||
|
Allocatable: corev1.ResourceList{
|
||||||
corev1.ResourceMemory: resource.MustParse("2Ki"),
|
corev1.ResourceMemory: resource.MustParse("2Ki"),
|
||||||
corev1.ResourceCPU: resource.MustParse("4Ki"),
|
corev1.ResourceCPU: resource.MustParse("4Ki"),
|
||||||
},
|
},
|
||||||
@@ -88,71 +110,256 @@ func Test_GetClusterResources(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Status: corev1.NodeStatus{
|
Status: corev1.NodeStatus{
|
||||||
Capacity: corev1.ResourceList{
|
|
||||||
corev1.ResourceMemory: resource.MustParse("1Ki"),
|
|
||||||
corev1.ResourceCPU: resource.MustParse("2Ki"),
|
|
||||||
},
|
|
||||||
Allocatable: corev1.ResourceList{
|
Allocatable: corev1.ResourceList{
|
||||||
corev1.ResourceMemory: resource.MustParse("512"),
|
corev1.ResourceMemory: resource.MustParse("6Ki"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&corev1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node3",
|
||||||
|
},
|
||||||
|
Status: corev1.NodeStatus{
|
||||||
|
Allocatable: corev1.ResourceList{
|
||||||
|
corev1.ResourceMemory: resource.MustParse("4Ki"),
|
||||||
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: &models.ClusterResources{
|
expected: &models.MaxAllocatableMemResponse{
|
||||||
Nodes: []*models.NodeInfo{
|
MaxMemory: int64(2048),
|
||||||
&models.NodeInfo{
|
},
|
||||||
Name: "node1",
|
wantErr: false,
|
||||||
Taints: &models.NodeTaints{
|
},
|
||||||
NoExecute: []string{
|
{
|
||||||
"own.minio.io/taint=val:NoExecute",
|
// Description: if there are more nodes than the amount
|
||||||
},
|
// of nodes we want to use, but one has taints of NoExecute
|
||||||
NoSchedule: []string{
|
// node should not be considered for max memory
|
||||||
"node.kubernetes.io/unreachable:NoSchedule",
|
// if one node has PreferNoSchedule that should be considered.
|
||||||
},
|
name: "Get Max Ram on nodes with NoExecute",
|
||||||
PreferNoSchedule: []string{
|
args: args{
|
||||||
"node.kubernetes.io/unschedulable:PreferNoSchedule",
|
ctx: context.Background(),
|
||||||
|
numNodes: 2,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node1",
|
||||||
|
},
|
||||||
|
Status: corev1.NodeStatus{
|
||||||
|
Allocatable: corev1.ResourceList{
|
||||||
|
corev1.ResourceMemory: resource.MustParse("2Ki"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("4Ki"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TotalResources: map[string]int64{
|
|
||||||
"memory": int64(2048),
|
|
||||||
"cpu": int64(4096),
|
|
||||||
},
|
|
||||||
AllocatableResources: map[string]int64{},
|
|
||||||
},
|
},
|
||||||
&models.NodeInfo{
|
&corev1.Node{
|
||||||
Name: "node2",
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Taints: &models.NodeTaints{
|
Name: "node2",
|
||||||
NoSchedule: []string{
|
},
|
||||||
"node.kubernetes.io/unreachable:NoSchedule",
|
Spec: corev1.NodeSpec{
|
||||||
|
Taints: []corev1.Taint{
|
||||||
|
corev1.Taint{
|
||||||
|
Key: "node.kubernetes.io/unreachable",
|
||||||
|
Effect: corev1.TaintEffectNoExecute,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TotalResources: map[string]int64{
|
Status: corev1.NodeStatus{
|
||||||
"memory": int64(1024),
|
Allocatable: corev1.ResourceList{
|
||||||
"cpu": int64(2048),
|
corev1.ResourceMemory: resource.MustParse("6Ki"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
AllocatableResources: map[string]int64{
|
},
|
||||||
"memory": int64(512),
|
&corev1.Node{
|
||||||
"cpu": int64(1024),
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node3",
|
||||||
|
},
|
||||||
|
Spec: corev1.NodeSpec{
|
||||||
|
Taints: []corev1.Taint{
|
||||||
|
corev1.Taint{
|
||||||
|
Key: "node.kubernetes.io/unreachable",
|
||||||
|
Effect: corev1.TaintEffectPreferNoSchedule,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: corev1.NodeStatus{
|
||||||
|
Allocatable: corev1.ResourceList{
|
||||||
|
corev1.ResourceMemory: resource.MustParse("4Ki"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
expected: &models.MaxAllocatableMemResponse{
|
||||||
|
MaxMemory: int64(2048),
|
||||||
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Description: if there are more nodes than the amount
|
||||||
|
// of nodes we want to use, max allocatable memory should
|
||||||
|
// be the minimum ram on the n nodes requested
|
||||||
|
name: "Get Max Ram, several nodes available",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
numNodes: 2,
|
||||||
|
objs: []runtime.Object{
|
||||||
|
&corev1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node1",
|
||||||
|
},
|
||||||
|
Status: corev1.NodeStatus{
|
||||||
|
Allocatable: corev1.ResourceList{
|
||||||
|
corev1.ResourceMemory: resource.MustParse("2Ki"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("4Ki"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&corev1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node2",
|
||||||
|
},
|
||||||
|
Status: corev1.NodeStatus{
|
||||||
|
Allocatable: corev1.ResourceList{
|
||||||
|
corev1.ResourceMemory: resource.MustParse("6Ki"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&corev1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "node3",
|
||||||
|
},
|
||||||
|
Status: corev1.NodeStatus{
|
||||||
|
Allocatable: corev1.ResourceList{
|
||||||
|
corev1.ResourceMemory: resource.MustParse("4Ki"),
|
||||||
|
corev1.ResourceCPU: resource.MustParse("1Ki"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &models.MaxAllocatableMemResponse{
|
||||||
|
MaxMemory: int64(4096),
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Description: if request has nil as request, expect error
|
||||||
|
name: "Nil nodes should be greater than 0",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
numNodes: 0,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
kubeClient := fake.NewSimpleClientset(tt.args.objs...)
|
kubeClient := fake.NewSimpleClientset(tt.args.objs...)
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := getClusterResources(tt.args.ctx, kubeClient.CoreV1())
|
got, err := getMaxAllocatableMemory(tt.args.ctx, kubeClient.CoreV1(), tt.args.numNodes)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("deleteTenantAction() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("getMaxAllocatableMemory() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, tt.expected) {
|
if !reflect.DeepEqual(got, tt.expected) {
|
||||||
ji, _ := json.Marshal(got)
|
t.Errorf("\ngot: %d \nwant: %d", got, tt.expected)
|
||||||
vi, _ := json.Marshal(tt.expected)
|
}
|
||||||
t.Errorf("\ngot: %s \nwant: %s", ji, vi)
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MaxMemoryFunc(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
numNodes int32
|
||||||
|
nodesMemorySizes []int64
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
expected int64
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get Max memory",
|
||||||
|
args: args{
|
||||||
|
numNodes: int32(4),
|
||||||
|
nodesMemorySizes: []int64{4294967296, 8589934592, 8589934592, 17179869184, 17179869184, 17179869184, 25769803776, 25769803776, 68719476736},
|
||||||
|
},
|
||||||
|
expected: int64(17179869184),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Description, if not enough nodes return 0
|
||||||
|
name: "Get Max memory Not enough nodes",
|
||||||
|
args: args{
|
||||||
|
numNodes: int32(4),
|
||||||
|
nodesMemorySizes: []int64{4294967296, 8589934592, 68719476736},
|
||||||
|
},
|
||||||
|
expected: int64(0),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Description, if not enough nodes return 0
|
||||||
|
name: "Get Max memory no nodes",
|
||||||
|
args: args{
|
||||||
|
numNodes: int32(4),
|
||||||
|
nodesMemorySizes: []int64{},
|
||||||
|
},
|
||||||
|
expected: int64(0),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Description, if not enough nodes return 0
|
||||||
|
name: "Get Max memory no nodes, no request",
|
||||||
|
args: args{
|
||||||
|
numNodes: int32(0),
|
||||||
|
nodesMemorySizes: []int64{},
|
||||||
|
},
|
||||||
|
expected: int64(0),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Description, if there are multiple nodes
|
||||||
|
// and required nodes is only 1, max should be equal to max memory
|
||||||
|
name: "Get Max memory one node",
|
||||||
|
args: args{
|
||||||
|
numNodes: int32(1),
|
||||||
|
nodesMemorySizes: []int64{4294967296, 8589934592, 68719476736},
|
||||||
|
},
|
||||||
|
expected: int64(68719476736),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Description: if more nodes max memory should be the minimum
|
||||||
|
// value across pairs of numNodes
|
||||||
|
name: "Get Max memory two nodes",
|
||||||
|
args: args{
|
||||||
|
numNodes: int32(2),
|
||||||
|
nodesMemorySizes: []int64{8589934592, 68719476736, 4294967296},
|
||||||
|
},
|
||||||
|
expected: int64(8589934592),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get Max Multiple Memory Sizes",
|
||||||
|
args: args{
|
||||||
|
numNodes: int32(4),
|
||||||
|
nodesMemorySizes: []int64{0, 0, 0, 0, 4294967296, 8589934592, 8589934592, 17179869184, 17179869184, 17179869184, 25769803776, 25769803776, 68719476736, 34359738368, 34359738368, 34359738368, 34359738368},
|
||||||
|
},
|
||||||
|
expected: int64(34359738368),
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := getMaxClusterMemory(tt.args.numNodes, tt.args.nodesMemorySizes)
|
||||||
|
if !reflect.DeepEqual(got, tt.expected) {
|
||||||
|
t.Errorf("\ngot: %d \nwant: %d", got, tt.expected)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ package restapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -32,11 +30,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/minio/console/pkg/kes"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
@@ -126,6 +121,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
|||||||
return admin_api.NewUpdateTenantCreated()
|
return admin_api.NewUpdateTenantCreated()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Add Tenant Zones
|
||||||
api.AdminAPITenantAddZoneHandler = admin_api.TenantAddZoneHandlerFunc(func(params admin_api.TenantAddZoneParams, session *models.Principal) middleware.Responder {
|
api.AdminAPITenantAddZoneHandler = admin_api.TenantAddZoneHandlerFunc(func(params admin_api.TenantAddZoneParams, session *models.Principal) middleware.Responder {
|
||||||
err := getTenantAddZoneResponse(session, params)
|
err := getTenantAddZoneResponse(session, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -135,6 +131,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
|||||||
return admin_api.NewTenantAddZoneCreated()
|
return admin_api.NewTenantAddZoneCreated()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Get Tenant Usage
|
||||||
api.AdminAPIGetTenantUsageHandler = admin_api.GetTenantUsageHandlerFunc(func(params admin_api.GetTenantUsageParams, session *models.Principal) middleware.Responder {
|
api.AdminAPIGetTenantUsageHandler = admin_api.GetTenantUsageHandlerFunc(func(params admin_api.GetTenantUsageParams, session *models.Principal) middleware.Responder {
|
||||||
payload, err := getTenantUsageResponse(session, params)
|
payload, err := getTenantUsageResponse(session, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -144,6 +141,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
|||||||
return admin_api.NewGetTenantUsageOK().WithPayload(payload)
|
return admin_api.NewGetTenantUsageOK().WithPayload(payload)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Update Tenant Zones
|
||||||
api.AdminAPITenantUpdateZonesHandler = admin_api.TenantUpdateZonesHandlerFunc(func(params admin_api.TenantUpdateZonesParams, session *models.Principal) middleware.Responder {
|
api.AdminAPITenantUpdateZonesHandler = admin_api.TenantUpdateZonesHandlerFunc(func(params admin_api.TenantUpdateZonesParams, session *models.Principal) middleware.Responder {
|
||||||
resp, err := getTenantUpdateZoneResponse(session, params)
|
resp, err := getTenantUpdateZoneResponse(session, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -152,6 +150,26 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
|||||||
}
|
}
|
||||||
return admin_api.NewTenantUpdateZonesOK().WithPayload(resp)
|
return admin_api.NewTenantUpdateZonesOK().WithPayload(resp)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Update Tenant Certificates
|
||||||
|
api.AdminAPITenantUpdateCertificateHandler = admin_api.TenantUpdateCertificateHandlerFunc(func(params admin_api.TenantUpdateCertificateParams, session *models.Principal) middleware.Responder {
|
||||||
|
err := getTenantUpdateCertificatesResponse(session, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return admin_api.NewGetTenantUsageDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to update tenant certificates")})
|
||||||
|
}
|
||||||
|
return admin_api.NewTenantUpdateCertificateCreated()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Update Tenant Encryption Configuration
|
||||||
|
api.AdminAPITenantUpdateEncryptionHandler = admin_api.TenantUpdateEncryptionHandlerFunc(func(params admin_api.TenantUpdateEncryptionParams, session *models.Principal) middleware.Responder {
|
||||||
|
err := getTenantUpdateEncryptionResponse(session, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return admin_api.NewGetTenantUsageDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to update encryption configuration")})
|
||||||
|
}
|
||||||
|
return admin_api.NewTenantUpdateCertificateCreated()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDeleteTenantResponse gets the output of deleting a minio instance
|
// getDeleteTenantResponse gets the output of deleting a minio instance
|
||||||
@@ -180,7 +198,7 @@ func getDeleteTenantResponse(session *models.Principal, params admin_api.DeleteT
|
|||||||
// It also adds the option of deleting the tenant's underlying pvcs if deletePvcs set
|
// It also adds the option of deleting the tenant's underlying pvcs if deletePvcs set
|
||||||
func deleteTenantAction(
|
func deleteTenantAction(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
operatorClient OperatorClient,
|
operatorClient OperatorClientI,
|
||||||
clientset v1.CoreV1Interface,
|
clientset v1.CoreV1Interface,
|
||||||
namespace, tenantName string,
|
namespace, tenantName string,
|
||||||
deletePvcs bool) error {
|
deletePvcs bool) error {
|
||||||
@@ -216,7 +234,7 @@ func getTenantScheme(mi *operator.Tenant) string {
|
|||||||
return scheme
|
return scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTenantAdminClient(ctx context.Context, client K8sClient, namespace, tenantName, serviceName, scheme string, insecure bool) (*madmin.AdminClient, error) {
|
func getTenantAdminClient(ctx context.Context, client K8sClientI, namespace, tenantName, serviceName, scheme string, insecure bool) (*madmin.AdminClient, error) {
|
||||||
// get admin credentials from secret
|
// get admin credentials from secret
|
||||||
creds, err := client.getSecret(ctx, namespace, fmt.Sprintf("%s-secret", tenantName), metav1.GetOptions{})
|
creds, err := client.getSecret(ctx, namespace, fmt.Sprintf("%s-secret", tenantName), metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -239,7 +257,7 @@ func getTenantAdminClient(ctx context.Context, client K8sClient, namespace, tena
|
|||||||
return mAdmin, nil
|
return mAdmin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTenant(ctx context.Context, operatorClient OperatorClient, namespace, tenantName string) (*operator.Tenant, error) {
|
func getTenant(ctx context.Context, operatorClient OperatorClientI, namespace, tenantName string) (*operator.Tenant, error) {
|
||||||
minInst, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
|
minInst, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -292,7 +310,7 @@ func getTenantInfoResponse(session *models.Principal, params admin_api.TenantInf
|
|||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func listTenants(ctx context.Context, operatorClient OperatorClient, namespace string, limit *int32) (*models.ListTenantsResponse, error) {
|
func listTenants(ctx context.Context, operatorClient OperatorClientI, namespace string, limit *int32) (*models.ListTenantsResponse, error) {
|
||||||
listOpts := metav1.ListOptions{
|
listOpts := metav1.ListOptions{
|
||||||
Limit: 10,
|
Limit: 10,
|
||||||
}
|
}
|
||||||
@@ -389,7 +407,10 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get Kubernetes Client
|
// get Kubernetes Client
|
||||||
clientset, err := cluster.K8sClient(session.SessionToken)
|
clientSet, err := cluster.K8sClient(session.SessionToken)
|
||||||
|
k8sClient := k8sClient{
|
||||||
|
client: clientSet,
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -425,7 +446,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -518,43 +539,15 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Minio != nil {
|
if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Minio != nil {
|
||||||
// User provided TLS certificates for MinIO
|
// User provided TLS certificates for MinIO
|
||||||
isEncryptionAvailable = true
|
isEncryptionAvailable = true
|
||||||
externalTLSCertificateSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
|
||||||
// disable autoCert
|
// disable autoCert
|
||||||
minInst.Spec.RequestAutoCert = false
|
minInst.Spec.RequestAutoCert = false
|
||||||
|
// Certificates used by the MinIO instance
|
||||||
tlsCrt, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Minio.Crt)
|
externalCertSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
||||||
|
externalCertSecret, err := createOrReplaceExternalCertSecret(ctx, &k8sClient, ns, tenantReq.TLS.Minio, externalCertSecretName, tenantName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
minInst.Spec.ExternalCertSecret = externalCertSecret
|
||||||
tlsKey, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Minio.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
externalTLSCertificateSecret := corev1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: externalTLSCertificateSecretName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
operator.TenantLabel: tenantName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Type: corev1.SecretTypeTLS,
|
|
||||||
Immutable: &imm,
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"tls.crt": tlsCrt,
|
|
||||||
"tls.key": tlsKey,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &externalTLSCertificateSecret, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Certificates used by the minio instance
|
|
||||||
minInst.Spec.ExternalCertSecret = &operator.LocalCertificateReference{
|
|
||||||
Name: externalTLSCertificateSecretName,
|
|
||||||
Type: "kubernetes.io/tls",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tenantReq.Encryption != nil && isEncryptionAvailable {
|
if tenantReq.Encryption != nil && isEncryptionAvailable {
|
||||||
@@ -565,13 +558,14 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
})
|
})
|
||||||
// KES client mTLSCertificates used by MinIO instance, only if autoCert is not enabled
|
// KES client mTLSCertificates used by MinIO instance, only if autoCert is not enabled
|
||||||
if !minInst.Spec.RequestAutoCert {
|
if !minInst.Spec.RequestAutoCert {
|
||||||
minInst.Spec.ExternalClientCertSecret, err = getTenantExternalClientCertificates(ctx, clientset, ns, tenantReq.Encryption, secretName, tenantName)
|
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
|
||||||
|
minInst.Spec.ExternalClientCertSecret, err = createOrReplaceExternalCertSecret(ctx, &k8sClient, ns, tenantReq.Encryption.Client, tenantExternalClientCertSecretName, tenantName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// KES configuration for Tenant instance
|
// KES configuration for Tenant instance
|
||||||
minInst.Spec.KES, err = getKESConfiguration(ctx, clientset, ns, tenantReq.Encryption, secretName, tenantName, minInst.Spec.RequestAutoCert)
|
minInst.Spec.KES, err = getKESConfiguration(ctx, &k8sClient, ns, tenantReq.Encryption, secretName, tenantName, minInst.Spec.RequestAutoCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -630,12 +624,12 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const consoleVersion = "minio/console:v0.3.18"
|
const consoleVersion = "minio/console:v0.3.19"
|
||||||
minInst.Spec.Console = &operator.ConsoleConfiguration{
|
minInst.Spec.Console = &operator.ConsoleConfiguration{
|
||||||
Replicas: 1,
|
Replicas: 1,
|
||||||
Image: consoleVersion,
|
Image: consoleVersion,
|
||||||
@@ -646,42 +640,15 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Console != nil {
|
if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Console != nil {
|
||||||
consoleExternalTLSCertificateSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
// Certificates used by the console instance
|
||||||
tlsCrt, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Console.Crt)
|
externalCertSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
||||||
|
externalCertSecret, err := createOrReplaceExternalCertSecret(ctx, &k8sClient, ns, tenantReq.TLS.Console, externalCertSecretName, tenantName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tlsKey, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Console.Key)
|
minInst.Spec.Console.ExternalCertSecret = externalCertSecret
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
consoleExternalTLSCertificateSecret := corev1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: consoleExternalTLSCertificateSecretName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
operator.TenantLabel: tenantName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Type: corev1.SecretTypeTLS,
|
|
||||||
Immutable: &imm,
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"tls.crt": tlsCrt,
|
|
||||||
"tls.key": tlsKey,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &consoleExternalTLSCertificateSecret, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Certificates used by the minio instance
|
|
||||||
minInst.Spec.Console.ExternalCertSecret = &operator.LocalCertificateReference{
|
|
||||||
Name: consoleExternalTLSCertificateSecretName,
|
|
||||||
Type: "kubernetes.io/tls",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the service name if provided
|
// set the service name if provided
|
||||||
@@ -718,7 +685,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
|
|
||||||
if tenantReq.ImagePullSecret != "" {
|
if tenantReq.ImagePullSecret != "" {
|
||||||
imagePullSecret = tenantReq.ImagePullSecret
|
imagePullSecret = tenantReq.ImagePullSecret
|
||||||
} else if imagePullSecret, err = setImageRegistry(ctx, tenantName, tenantReq.ImageRegistry, clientset.CoreV1(), ns); err != nil {
|
} else if imagePullSecret, err = setImageRegistry(ctx, tenantName, tenantReq.ImageRegistry, clientSet.CoreV1(), ns); err != nil {
|
||||||
log.Println("error setting image registry secret:", err)
|
log.Println("error setting image registry secret:", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -753,7 +720,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
|||||||
|
|
||||||
// Integratrions
|
// Integratrions
|
||||||
if os.Getenv("GKE_INTEGRATION") != "" {
|
if os.Getenv("GKE_INTEGRATION") != "" {
|
||||||
err := gkeIntegration(clientset, tenantName, ns, session.SessionToken)
|
err := gkeIntegration(clientSet, tenantName, ns, session.SessionToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -832,7 +799,7 @@ func setImageRegistry(ctx context.Context, tenantName string, req *models.ImageR
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateTenantAction does an update on the minioTenant by patching the desired changes
|
// updateTenantAction does an update on the minioTenant by patching the desired changes
|
||||||
func updateTenantAction(ctx context.Context, operatorClient OperatorClient, clientset v1.CoreV1Interface, httpCl cluster.HTTPClientI, namespace string, params admin_api.UpdateTenantParams) error {
|
func updateTenantAction(ctx context.Context, operatorClient OperatorClientI, clientset v1.CoreV1Interface, httpCl cluster.HTTPClientI, namespace string, params admin_api.UpdateTenantParams) error {
|
||||||
imageToUpdate := params.Body.Image
|
imageToUpdate := params.Body.Image
|
||||||
imageRegistryReq := params.Body.ImageRegistry
|
imageRegistryReq := params.Body.ImageRegistry
|
||||||
|
|
||||||
@@ -908,7 +875,7 @@ func getUpdateTenantResponse(session *models.Principal, params admin_api.UpdateT
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addTenantZone creates a zone to a defined tenant
|
// addTenantZone creates a zone to a defined tenant
|
||||||
func addTenantZone(ctx context.Context, operatorClient OperatorClient, params admin_api.TenantAddZoneParams) error {
|
func addTenantZone(ctx context.Context, operatorClient OperatorClientI, params admin_api.TenantAddZoneParams) error {
|
||||||
tenant, err := operatorClient.TenantGet(ctx, params.Namespace, params.Tenant, metav1.GetOptions{})
|
tenant, err := operatorClient.TenantGet(ctx, params.Namespace, params.Tenant, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1423,344 +1390,6 @@ func parseNodeSelectorTerm(term *corev1.NodeSelectorTerm) *models.NodeSelectorTe
|
|||||||
return &t
|
return &t
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTenantExternalClientCertificates(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string) (clientCertificates *operator.LocalCertificateReference, err error) {
|
|
||||||
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
|
||||||
// If there's an error during this process we delete all KES configuration secrets
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
errDelete := clientSet.CoreV1().Secrets(ns).Delete(ctx, instanceExternalClientCertificateSecretName, metav1.DeleteOptions{})
|
|
||||||
if errDelete != nil {
|
|
||||||
log.Print(errDelete)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
imm := true
|
|
||||||
// Secret to store KES clients TLS mTLSCertificates (mTLS authentication)
|
|
||||||
clientTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Crt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
clientTLSKey, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
instanceExternalClientCertificateSecret := corev1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: instanceExternalClientCertificateSecretName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
operator.TenantLabel: tenantName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Type: corev1.SecretTypeTLS,
|
|
||||||
Immutable: &imm,
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"tls.crt": clientTLSCrt,
|
|
||||||
"tls.key": clientTLSKey,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceExternalClientCertificateSecret, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// KES client mTLSCertificates used by MinIO instance
|
|
||||||
clientCertificates = &operator.LocalCertificateReference{
|
|
||||||
Name: instanceExternalClientCertificateSecretName,
|
|
||||||
Type: "kubernetes.io/tls",
|
|
||||||
}
|
|
||||||
return clientCertificates, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getKESConfiguration(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string, autoCert bool) (kesConfiguration *operator.KESConfig, err error) {
|
|
||||||
// secrets used by the KES configuration
|
|
||||||
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
|
||||||
kesExternalCertificateSecretName := fmt.Sprintf("%s-kes-external-mtls-certificates", secretName)
|
|
||||||
kesClientCertSecretName := fmt.Sprintf("%s-kes-mtls-certificates", secretName)
|
|
||||||
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
|
|
||||||
// If there's an error during this process we delete all KES configuration secrets
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
errDelete := clientSet.CoreV1().Secrets(ns).Delete(ctx, instanceExternalClientCertificateSecretName, metav1.DeleteOptions{})
|
|
||||||
if errDelete != nil {
|
|
||||||
log.Print(errDelete)
|
|
||||||
}
|
|
||||||
errDelete = clientSet.CoreV1().Secrets(ns).Delete(ctx, kesExternalCertificateSecretName, metav1.DeleteOptions{})
|
|
||||||
if errDelete != nil {
|
|
||||||
log.Print(errDelete)
|
|
||||||
}
|
|
||||||
errDelete = clientSet.CoreV1().Secrets(ns).Delete(ctx, kesClientCertSecretName, metav1.DeleteOptions{})
|
|
||||||
if errDelete != nil {
|
|
||||||
log.Print(errDelete)
|
|
||||||
}
|
|
||||||
errDelete = clientSet.CoreV1().Secrets(ns).Delete(ctx, kesConfigurationSecretName, metav1.DeleteOptions{})
|
|
||||||
if errDelete != nil {
|
|
||||||
log.Print(errDelete)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
imm := true
|
|
||||||
kesConfiguration = &operator.KESConfig{
|
|
||||||
Image: "minio/kes:v0.11.0",
|
|
||||||
Replicas: 1,
|
|
||||||
Metadata: nil,
|
|
||||||
}
|
|
||||||
// Using custom image for KES
|
|
||||||
if encryptionCfg.Image != "" {
|
|
||||||
kesConfiguration.Image = encryptionCfg.Image
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
clientCrtIdentity := "$MINIO_KES_IDENTITY"
|
|
||||||
// Generate server certificates for KES only if autoCert is disabled
|
|
||||||
if !autoCert {
|
|
||||||
serverTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Server.Crt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
serverTLSKey, err := base64.StdEncoding.DecodeString(*encryptionCfg.Server.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Secret to store KES server TLS mTLSCertificates
|
|
||||||
kesExternalCertificateSecret := corev1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: kesExternalCertificateSecretName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
operator.TenantLabel: tenantName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Type: corev1.SecretTypeTLS,
|
|
||||||
Immutable: &imm,
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"tls.crt": serverTLSCrt,
|
|
||||||
"tls.key": serverTLSKey,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &kesExternalCertificateSecret, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// External mTLSCertificates used by KES
|
|
||||||
kesConfiguration.ExternalCertSecret = &operator.LocalCertificateReference{
|
|
||||||
Name: kesExternalCertificateSecretName,
|
|
||||||
Type: "kubernetes.io/tls",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client certificate for KES used by Minio to mTLS
|
|
||||||
clientTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Crt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Calculate the client cert identity based on the clientTLSCrt
|
|
||||||
h := crypto.SHA256.New()
|
|
||||||
certificate, err := kes.ParseCertificate(clientTLSCrt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
h.Write(certificate.RawSubjectPublicKeyInfo)
|
|
||||||
clientCrtIdentity = hex.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default kesConfiguration for KES
|
|
||||||
kesConfig := kes.ServerConfig{
|
|
||||||
Addr: "0.0.0.0:7373",
|
|
||||||
Root: "disabled",
|
|
||||||
TLS: kes.TLS{
|
|
||||||
KeyPath: "/tmp/kes/server.key",
|
|
||||||
CertPath: "/tmp/kes/server.crt",
|
|
||||||
},
|
|
||||||
Policies: map[string]kes.Policy{
|
|
||||||
"default-policy": {
|
|
||||||
Paths: []string{
|
|
||||||
"/v1/key/create/my-minio-key",
|
|
||||||
"/v1/key/generate/my-minio-key",
|
|
||||||
"/v1/key/decrypt/my-minio-key",
|
|
||||||
},
|
|
||||||
Identities: []kes.Identity{
|
|
||||||
kes.Identity(clientCrtIdentity),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Cache: kes.Cache{
|
|
||||||
Expiry: &kes.Expiry{
|
|
||||||
Any: 5 * time.Minute,
|
|
||||||
Unused: 20 * time.Second,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Log: kes.Log{
|
|
||||||
Error: "on",
|
|
||||||
Audit: "off",
|
|
||||||
},
|
|
||||||
Keys: kes.Keys{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// operator will mount the mTLSCertificates in the following paths
|
|
||||||
// therefore we set these values in the KES yaml kesConfiguration
|
|
||||||
var mTLSClientCrtPath = "/tmp/kes/client.crt"
|
|
||||||
var mTLSClientKeyPath = "/tmp/kes/client.key"
|
|
||||||
var mTLSClientCaPath = "/tmp/kes/ca.crt"
|
|
||||||
// map to hold mTLSCertificates for KES mTLS against Vault
|
|
||||||
mTLSCertificates := map[string][]byte{}
|
|
||||||
|
|
||||||
// if encryption is enabled and encryption is configured to use Vault
|
|
||||||
if encryptionCfg.Vault != nil {
|
|
||||||
// Initialize Vault Config
|
|
||||||
|
|
||||||
kesConfig.Keys.Vault = &kes.Vault{
|
|
||||||
Endpoint: *encryptionCfg.Vault.Endpoint,
|
|
||||||
EnginePath: encryptionCfg.Vault.Engine,
|
|
||||||
Namespace: encryptionCfg.Vault.Namespace,
|
|
||||||
Prefix: encryptionCfg.Vault.Prefix,
|
|
||||||
Status: &kes.VaultStatus{
|
|
||||||
Ping: 10 * time.Second,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// Vault AppRole credentials
|
|
||||||
if encryptionCfg.Vault.Approle != nil {
|
|
||||||
kesConfig.Keys.Vault.AppRole = &kes.AppRole{
|
|
||||||
EnginePath: encryptionCfg.Vault.Approle.Engine,
|
|
||||||
ID: *encryptionCfg.Vault.Approle.ID,
|
|
||||||
Secret: *encryptionCfg.Vault.Approle.Secret,
|
|
||||||
Retry: 15 * time.Second,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, errors.New("approle credentials missing for kes")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vault mTLS kesConfiguration
|
|
||||||
if encryptionCfg.Vault.TLS != nil {
|
|
||||||
vaultTLSConfig := encryptionCfg.Vault.TLS
|
|
||||||
kesConfig.Keys.Vault.TLS = &kes.VaultTLS{}
|
|
||||||
if vaultTLSConfig.Crt != "" {
|
|
||||||
clientCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Crt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mTLSCertificates["client.crt"] = clientCrt
|
|
||||||
kesConfig.Keys.Vault.TLS.CertPath = mTLSClientCrtPath
|
|
||||||
}
|
|
||||||
if vaultTLSConfig.Key != "" {
|
|
||||||
clientKey, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mTLSCertificates["client.key"] = clientKey
|
|
||||||
kesConfig.Keys.Vault.TLS.KeyPath = mTLSClientKeyPath
|
|
||||||
}
|
|
||||||
if vaultTLSConfig.Ca != "" {
|
|
||||||
caCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Ca)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mTLSCertificates["ca.crt"] = caCrt
|
|
||||||
kesConfig.Keys.Vault.TLS.CAPath = mTLSClientCaPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if encryptionCfg.Aws != nil {
|
|
||||||
// Initialize AWS
|
|
||||||
kesConfig.Keys.Aws = &kes.Aws{
|
|
||||||
SecretsManager: &kes.AwsSecretManager{},
|
|
||||||
}
|
|
||||||
// AWS basic kesConfiguration
|
|
||||||
if encryptionCfg.Aws.Secretsmanager != nil {
|
|
||||||
kesConfig.Keys.Aws.SecretsManager.Endpoint = *encryptionCfg.Aws.Secretsmanager.Endpoint
|
|
||||||
kesConfig.Keys.Aws.SecretsManager.Region = *encryptionCfg.Aws.Secretsmanager.Region
|
|
||||||
kesConfig.Keys.Aws.SecretsManager.KmsKey = encryptionCfg.Aws.Secretsmanager.Kmskey
|
|
||||||
// AWS credentials
|
|
||||||
if encryptionCfg.Aws.Secretsmanager.Credentials != nil {
|
|
||||||
kesConfig.Keys.Aws.SecretsManager.Login = &kes.AwsSecretManagerLogin{
|
|
||||||
AccessKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Accesskey,
|
|
||||||
SecretKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Secretkey,
|
|
||||||
SessionToken: encryptionCfg.Aws.Secretsmanager.Credentials.Token,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if encryptionCfg.Gemalto != nil {
|
|
||||||
// Initialize Gemalto
|
|
||||||
kesConfig.Keys.Gemalto = &kes.Gemalto{
|
|
||||||
KeySecure: &kes.GemaltoKeySecure{},
|
|
||||||
}
|
|
||||||
// Gemalto Configuration
|
|
||||||
if encryptionCfg.Gemalto.Keysecure != nil {
|
|
||||||
kesConfig.Keys.Gemalto.KeySecure.Endpoint = *encryptionCfg.Gemalto.Keysecure.Endpoint
|
|
||||||
// Gemalto TLS kesConfiguration
|
|
||||||
if encryptionCfg.Gemalto.Keysecure.TLS != nil {
|
|
||||||
if encryptionCfg.Gemalto.Keysecure.TLS.Ca != nil {
|
|
||||||
caCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Gemalto.Keysecure.TLS.Ca)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mTLSCertificates["ca.crt"] = caCrt
|
|
||||||
kesConfig.Keys.Gemalto.KeySecure.TLS = &kes.GemaltoTLS{
|
|
||||||
CAPath: mTLSClientCaPath,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Gemalto Login
|
|
||||||
if encryptionCfg.Gemalto.Keysecure.Credentials != nil {
|
|
||||||
kesConfig.Keys.Gemalto.KeySecure.Credentials = &kes.GemaltoCredentials{
|
|
||||||
Token: *encryptionCfg.Gemalto.Keysecure.Credentials.Token,
|
|
||||||
Domain: *encryptionCfg.Gemalto.Keysecure.Credentials.Domain,
|
|
||||||
Retry: 15 * time.Second,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if mTLSCertificates contains elements we create the kubernetes secret
|
|
||||||
if len(mTLSCertificates) > 0 {
|
|
||||||
// Secret to store KES mTLS kesConfiguration
|
|
||||||
kesClientCertSecret := corev1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: kesClientCertSecretName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
operator.TenantLabel: tenantName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Immutable: &imm,
|
|
||||||
Data: mTLSCertificates,
|
|
||||||
}
|
|
||||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &kesClientCertSecret, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// kubernetes generic secret
|
|
||||||
kesConfiguration.ClientCertSecret = &operator.LocalCertificateReference{
|
|
||||||
Name: kesClientCertSecretName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate Yaml kesConfiguration for KES
|
|
||||||
serverConfigYaml, err := yaml.Marshal(kesConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Secret to store KES server kesConfiguration
|
|
||||||
kesConfigurationSecret := corev1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: kesConfigurationSecretName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
operator.TenantLabel: tenantName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Immutable: &imm,
|
|
||||||
Data: map[string][]byte{
|
|
||||||
"server-config.yaml": serverConfigYaml,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &kesConfigurationSecret, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Configuration used by KES
|
|
||||||
kesConfiguration.Configuration = &corev1.LocalObjectReference{
|
|
||||||
Name: kesConfigurationSecretName,
|
|
||||||
}
|
|
||||||
return kesConfiguration, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTenantUpdateZoneResponse(session *models.Principal, params admin_api.TenantUpdateZonesParams) (*models.Tenant, error) {
|
func getTenantUpdateZoneResponse(session *models.Principal, params admin_api.TenantUpdateZonesParams) (*models.Tenant, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
||||||
@@ -1789,7 +1418,7 @@ func getTenantUpdateZoneResponse(session *models.Principal, params admin_api.Ten
|
|||||||
// It does the equivalent to a PUT request on Tenant's zones
|
// It does the equivalent to a PUT request on Tenant's zones
|
||||||
func updateTenantZones(
|
func updateTenantZones(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
operatorClient OperatorClient,
|
operatorClient OperatorClientI,
|
||||||
namespace string,
|
namespace string,
|
||||||
tenantName string,
|
tenantName string,
|
||||||
zonesReq []*models.Zone) (*operator.Tenant, error) {
|
zonesReq []*models.Zone) (*operator.Tenant, error) {
|
||||||
|
|||||||
516
restapi/admin_tenants_helper.go
Normal file
516
restapi/admin_tenants_helper.go
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
// This file is part of MinIO Kubernetes Cloud
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package restapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/minio/console/cluster"
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
"github.com/minio/console/pkg/kes"
|
||||||
|
"github.com/minio/console/restapi/operations/admin_api"
|
||||||
|
operator "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tenantUpdateCertificates receives the keyPair certificates (public and private keys) for Minio and Console and will try
|
||||||
|
// to replace the existing kubernetes secrets with the new values, then will restart the affected pods so the new volumes can be mounted
|
||||||
|
func tenantUpdateCertificates(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params admin_api.TenantUpdateCertificateParams) error {
|
||||||
|
tenantName := params.Tenant
|
||||||
|
tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
secretName := fmt.Sprintf("%s-secret", tenantName)
|
||||||
|
body := params.Body
|
||||||
|
// check if MinIO is deployed with external certs and user provided new MinIO keypair
|
||||||
|
if tenant.ExternalCert() && body.Minio != nil {
|
||||||
|
minioCertSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
||||||
|
// update certificates
|
||||||
|
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Minio, minioCertSecretName, tenantName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// restart MinIO pods
|
||||||
|
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||||
|
LabelSelector: fmt.Sprintf("%s=%s", operator.TenantLabel, tenantName),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if Console is deployed with external certs and user provided new Console keypair
|
||||||
|
if tenant.ConsoleExternalCert() && tenant.HasConsoleEnabled() && body.Console != nil {
|
||||||
|
consoleCertSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
||||||
|
// update certificates
|
||||||
|
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Console, consoleCertSecretName, tenantName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// restart Console pods
|
||||||
|
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||||
|
LabelSelector: fmt.Sprintf("%s=%s", operator.ConsoleTenantLabel, fmt.Sprintf("%s-console", tenantName)),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTenantUpdateCertificatesResponse wrapper of tenantUpdateCertificates
|
||||||
|
func getTenantUpdateCertificatesResponse(session *models.Principal, params admin_api.TenantUpdateCertificateParams) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
// get Kubernetes Client
|
||||||
|
clientSet, err := cluster.K8sClient(session.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
k8sClient := k8sClient{
|
||||||
|
client: clientSet,
|
||||||
|
}
|
||||||
|
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
opClient := operatorClient{
|
||||||
|
client: opClientClientSet,
|
||||||
|
}
|
||||||
|
if err := tenantUpdateCertificates(ctx, &opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tenantUpdateEncryption allow user to update KES server certificates, KES client certificates (used by MinIO for mTLS) and KES configuration (KMS configuration, credentials, etc)
|
||||||
|
func tenantUpdateEncryption(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params admin_api.TenantUpdateEncryptionParams) error {
|
||||||
|
tenantName := params.Tenant
|
||||||
|
secretName := fmt.Sprintf("%s-secret", tenantName)
|
||||||
|
tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
|
||||||
|
body := params.Body
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Check if encryption is enabled for MinIO via KES
|
||||||
|
if tenant.HasKESEnabled() {
|
||||||
|
// check if KES is deployed with external certificates and user provided new server keypair
|
||||||
|
if tenant.KESExternalCert() && body.Server != nil {
|
||||||
|
kesExternalCertSecretName := fmt.Sprintf("%s-kes-external-cert", secretName)
|
||||||
|
// update certificates
|
||||||
|
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Server, kesExternalCertSecretName, tenantName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if Tenant is deployed with external client certificates and user provided new client keypaiir
|
||||||
|
if tenant.ExternalClientCert() && body.Client != nil {
|
||||||
|
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
|
||||||
|
// Update certificates
|
||||||
|
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Client, tenantExternalClientCertSecretName, tenantName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Restart MinIO pods to mount the new client secrets
|
||||||
|
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||||
|
LabelSelector: fmt.Sprintf("%s=%s", operator.TenantLabel, tenantName),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update KES identities in kes-configuration.yaml secret
|
||||||
|
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
|
||||||
|
kesClientCertSecretName := fmt.Sprintf("%s-kes-client-cert", secretName)
|
||||||
|
_, _, err := createOrReplaceKesConfigurationSecrets(ctx, clientSet, namespace, body, kesConfigurationSecretName, kesClientCertSecretName, tenantName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Restart KES pods to mount the new configuration
|
||||||
|
err = clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||||
|
LabelSelector: fmt.Sprintf("%s=%s", operator.KESInstanceLabel, fmt.Sprintf("%s-kes", tenantName)),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTenantUpdateEncryptionResponse is a wrapper for tenantUpdateEncryption
|
||||||
|
func getTenantUpdateEncryptionResponse(session *models.Principal, params admin_api.TenantUpdateEncryptionParams) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
// get Kubernetes Client
|
||||||
|
clientSet, err := cluster.K8sClient(session.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
k8sClient := k8sClient{
|
||||||
|
client: clientSet,
|
||||||
|
}
|
||||||
|
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
opClient := operatorClient{
|
||||||
|
client: opClientClientSet,
|
||||||
|
}
|
||||||
|
if err := tenantUpdateEncryption(ctx, &opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getKESConfiguration will generate the KES server certificate secrets, the tenant client secrets for mTLS authentication between MinIO and KES and the
|
||||||
|
// kes-configuration.yaml file used by the KES service (how to connect to the external KMS, eg: Vault, AWS, Gemalto, etc)
|
||||||
|
func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string, autoCert bool) (kesConfiguration *operator.KESConfig, err error) {
|
||||||
|
// Secrets used by the MiniO tenant service
|
||||||
|
//
|
||||||
|
// tenantExternalClientCertSecretName is the name of the secret that will store the certificates for mTLS between MinIO and the KES, eg: app.key and app.crt
|
||||||
|
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
|
||||||
|
// Secrets used by the KES service
|
||||||
|
//
|
||||||
|
// kesExternalCertSecretName is the name of the secret that will store the certificates for TLS in the KES server, eg: server.key and server.crt
|
||||||
|
kesExternalCertSecretName := fmt.Sprintf("%s-kes-external-cert", secretName)
|
||||||
|
// kesClientCertSecretName is the name of the secret that will store the certificates for mTLS between KES and the KMS, eg: mTLS with Vault or Gemalto KMS
|
||||||
|
kesClientCertSecretName := fmt.Sprintf("%s-kes-client-cert", secretName)
|
||||||
|
// kesConfigurationSecretName is the name of the secret that will store the configuration file, eg: kes-configuration.yaml
|
||||||
|
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
|
||||||
|
// if there's an error during this process we delete all KES configuration secrets
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
errDelete := clientSet.deleteSecret(ctx, ns, tenantExternalClientCertSecretName, metav1.DeleteOptions{})
|
||||||
|
if errDelete != nil {
|
||||||
|
log.Print(errDelete)
|
||||||
|
}
|
||||||
|
errDelete = clientSet.deleteSecret(ctx, ns, kesExternalCertSecretName, metav1.DeleteOptions{})
|
||||||
|
if errDelete != nil {
|
||||||
|
log.Print(errDelete)
|
||||||
|
}
|
||||||
|
errDelete = clientSet.deleteSecret(ctx, ns, kesClientCertSecretName, metav1.DeleteOptions{})
|
||||||
|
if errDelete != nil {
|
||||||
|
log.Print(errDelete)
|
||||||
|
}
|
||||||
|
errDelete = clientSet.deleteSecret(ctx, ns, kesConfigurationSecretName, metav1.DeleteOptions{})
|
||||||
|
if errDelete != nil {
|
||||||
|
log.Print(errDelete)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
kesConfiguration = &operator.KESConfig{
|
||||||
|
Image: "minio/kes:v0.11.0",
|
||||||
|
Replicas: 1,
|
||||||
|
Metadata: nil,
|
||||||
|
}
|
||||||
|
// Using custom image for KES
|
||||||
|
if encryptionCfg.Image != "" {
|
||||||
|
kesConfiguration.Image = encryptionCfg.Image
|
||||||
|
}
|
||||||
|
// Generate server certificates for KES only if autoCert is disabled
|
||||||
|
if !autoCert {
|
||||||
|
kesExternalCertSecret, err := createOrReplaceExternalCertSecret(ctx, clientSet, ns, encryptionCfg.Server, kesExternalCertSecretName, tenantName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// External TLS certificates used by KES
|
||||||
|
kesConfiguration.ExternalCertSecret = kesExternalCertSecret
|
||||||
|
}
|
||||||
|
// Prepare kesConfiguration for KES
|
||||||
|
serverConfigSecret, clientCertSecret, err := createOrReplaceKesConfigurationSecrets(ctx, clientSet, ns, encryptionCfg, kesConfigurationSecretName, kesClientCertSecretName, tenantName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Configuration used by KES
|
||||||
|
kesConfiguration.Configuration = serverConfigSecret
|
||||||
|
kesConfiguration.ClientCertSecret = clientCertSecret
|
||||||
|
|
||||||
|
return kesConfiguration, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createOrReplaceExternalCertSecret receives a keypair, public and private key, encoded in base64, decode it and generate a new kubernetes secret
|
||||||
|
// to be used by the operator for TLS encryption
|
||||||
|
func createOrReplaceExternalCertSecret(ctx context.Context, clientSet K8sClientI, ns string, keyPair *models.KeyPairConfiguration, secretName, tenantName string) (*operator.LocalCertificateReference, error) {
|
||||||
|
if keyPair == nil || keyPair.Crt == nil || keyPair.Key == nil || *keyPair.Crt == "" || *keyPair.Key == "" {
|
||||||
|
return nil, errors.New("certificate files must not be empty")
|
||||||
|
}
|
||||||
|
// delete secret with same name if exists
|
||||||
|
err := clientSet.deleteSecret(ctx, ns, secretName, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
// log the error if any and continue
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
imm := true
|
||||||
|
tlsCrt, err := base64.StdEncoding.DecodeString(*keyPair.Crt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tlsKey, err := base64.StdEncoding.DecodeString(*keyPair.Key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
externalTLSCertificateSecret := &corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: secretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: corev1.SecretTypeTLS,
|
||||||
|
Immutable: &imm,
|
||||||
|
Data: map[string][]byte{
|
||||||
|
"tls.crt": tlsCrt,
|
||||||
|
"tls.key": tlsKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err = clientSet.createSecret(ctx, ns, externalTLSCertificateSecret, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Certificates used by the minio instance
|
||||||
|
return &operator.LocalCertificateReference{
|
||||||
|
Name: secretName,
|
||||||
|
Type: "kubernetes.io/tls",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createOrReplaceKesConfigurationSecrets(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, kesConfigurationSecretName, kesClientCertSecretName, tenantName string) (*corev1.LocalObjectReference, *operator.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
|
||||||
|
log.Println(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
|
||||||
|
log.Println(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
|
||||||
|
clientCrtIdentity := "$MINIO_KES_IDENTITY"
|
||||||
|
// If a client certificate is provided proceed to calculate the identity
|
||||||
|
if encryptionCfg.Client != nil {
|
||||||
|
// Client certificate for KES used by Minio to mTLS
|
||||||
|
clientTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Crt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// Calculate the client cert identity based on the clientTLSCrt
|
||||||
|
h := crypto.SHA256.New()
|
||||||
|
certificate, err := kes.ParseCertificate(clientTLSCrt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
h.Write(certificate.RawSubjectPublicKeyInfo)
|
||||||
|
clientCrtIdentity = hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
// Default kesConfiguration for KES
|
||||||
|
kesConfig := &kes.ServerConfig{
|
||||||
|
Addr: "0.0.0.0:7373",
|
||||||
|
Root: "disabled",
|
||||||
|
TLS: kes.TLS{
|
||||||
|
KeyPath: "/tmp/kes/server.key",
|
||||||
|
CertPath: "/tmp/kes/server.crt",
|
||||||
|
},
|
||||||
|
Policies: map[string]kes.Policy{
|
||||||
|
"default-policy": {
|
||||||
|
Paths: []string{
|
||||||
|
"/v1/key/create/my-minio-key",
|
||||||
|
"/v1/key/generate/my-minio-key",
|
||||||
|
"/v1/key/decrypt/my-minio-key",
|
||||||
|
},
|
||||||
|
Identities: []kes.Identity{
|
||||||
|
kes.Identity(clientCrtIdentity),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Cache: kes.Cache{
|
||||||
|
Expiry: &kes.Expiry{
|
||||||
|
Any: 5 * time.Minute,
|
||||||
|
Unused: 20 * time.Second,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Log: kes.Log{
|
||||||
|
Error: "on",
|
||||||
|
Audit: "off",
|
||||||
|
},
|
||||||
|
Keys: kes.Keys{},
|
||||||
|
}
|
||||||
|
// operator will mount the mTLSCertificates in the following paths
|
||||||
|
// therefore we set these values in the KES yaml kesConfiguration
|
||||||
|
var mTLSClientCrtPath = "/tmp/kes/client.crt"
|
||||||
|
var mTLSClientKeyPath = "/tmp/kes/client.key"
|
||||||
|
var mTLSClientCaPath = "/tmp/kes/ca.crt"
|
||||||
|
// map to hold mTLSCertificates for KES mTLS against Vault
|
||||||
|
mTLSCertificates := map[string][]byte{}
|
||||||
|
// if encryption is enabled and encryption is configured to use Vault
|
||||||
|
if encryptionCfg.Vault != nil {
|
||||||
|
// Initialize Vault Config
|
||||||
|
kesConfig.Keys.Vault = &kes.Vault{
|
||||||
|
Endpoint: *encryptionCfg.Vault.Endpoint,
|
||||||
|
EnginePath: encryptionCfg.Vault.Engine,
|
||||||
|
Namespace: encryptionCfg.Vault.Namespace,
|
||||||
|
Prefix: encryptionCfg.Vault.Prefix,
|
||||||
|
Status: &kes.VaultStatus{
|
||||||
|
Ping: 10 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Vault AppRole credentials
|
||||||
|
if encryptionCfg.Vault.Approle != nil {
|
||||||
|
kesConfig.Keys.Vault.AppRole = &kes.AppRole{
|
||||||
|
EnginePath: encryptionCfg.Vault.Approle.Engine,
|
||||||
|
ID: *encryptionCfg.Vault.Approle.ID,
|
||||||
|
Secret: *encryptionCfg.Vault.Approle.Secret,
|
||||||
|
Retry: 15 * time.Second,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, nil, errors.New("approle credentials missing for kes")
|
||||||
|
}
|
||||||
|
// Vault mTLS kesConfiguration
|
||||||
|
if encryptionCfg.Vault.TLS != nil {
|
||||||
|
vaultTLSConfig := encryptionCfg.Vault.TLS
|
||||||
|
kesConfig.Keys.Vault.TLS = &kes.VaultTLS{}
|
||||||
|
if vaultTLSConfig.Crt != "" {
|
||||||
|
clientCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Crt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
mTLSCertificates["client.crt"] = clientCrt
|
||||||
|
kesConfig.Keys.Vault.TLS.CertPath = mTLSClientCrtPath
|
||||||
|
}
|
||||||
|
if vaultTLSConfig.Key != "" {
|
||||||
|
clientKey, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
mTLSCertificates["client.key"] = clientKey
|
||||||
|
kesConfig.Keys.Vault.TLS.KeyPath = mTLSClientKeyPath
|
||||||
|
}
|
||||||
|
if vaultTLSConfig.Ca != "" {
|
||||||
|
caCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Ca)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
mTLSCertificates["ca.crt"] = caCrt
|
||||||
|
kesConfig.Keys.Vault.TLS.CAPath = mTLSClientCaPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if encryptionCfg.Aws != nil {
|
||||||
|
// Initialize AWS
|
||||||
|
kesConfig.Keys.Aws = &kes.Aws{
|
||||||
|
SecretsManager: &kes.AwsSecretManager{},
|
||||||
|
}
|
||||||
|
// AWS basic kesConfiguration
|
||||||
|
if encryptionCfg.Aws.Secretsmanager != nil {
|
||||||
|
kesConfig.Keys.Aws.SecretsManager.Endpoint = *encryptionCfg.Aws.Secretsmanager.Endpoint
|
||||||
|
kesConfig.Keys.Aws.SecretsManager.Region = *encryptionCfg.Aws.Secretsmanager.Region
|
||||||
|
kesConfig.Keys.Aws.SecretsManager.KmsKey = encryptionCfg.Aws.Secretsmanager.Kmskey
|
||||||
|
// AWS credentials
|
||||||
|
if encryptionCfg.Aws.Secretsmanager.Credentials != nil {
|
||||||
|
kesConfig.Keys.Aws.SecretsManager.Login = &kes.AwsSecretManagerLogin{
|
||||||
|
AccessKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Accesskey,
|
||||||
|
SecretKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Secretkey,
|
||||||
|
SessionToken: encryptionCfg.Aws.Secretsmanager.Credentials.Token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if encryptionCfg.Gemalto != nil {
|
||||||
|
// Initialize Gemalto
|
||||||
|
kesConfig.Keys.Gemalto = &kes.Gemalto{
|
||||||
|
KeySecure: &kes.GemaltoKeySecure{},
|
||||||
|
}
|
||||||
|
// Gemalto Configuration
|
||||||
|
if encryptionCfg.Gemalto.Keysecure != nil {
|
||||||
|
kesConfig.Keys.Gemalto.KeySecure.Endpoint = *encryptionCfg.Gemalto.Keysecure.Endpoint
|
||||||
|
// Gemalto TLS kesConfiguration
|
||||||
|
if encryptionCfg.Gemalto.Keysecure.TLS != nil {
|
||||||
|
if encryptionCfg.Gemalto.Keysecure.TLS.Ca != nil {
|
||||||
|
caCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Gemalto.Keysecure.TLS.Ca)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
mTLSCertificates["ca.crt"] = caCrt
|
||||||
|
kesConfig.Keys.Gemalto.KeySecure.TLS = &kes.GemaltoTLS{
|
||||||
|
CAPath: mTLSClientCaPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Gemalto Login
|
||||||
|
if encryptionCfg.Gemalto.Keysecure.Credentials != nil {
|
||||||
|
kesConfig.Keys.Gemalto.KeySecure.Credentials = &kes.GemaltoCredentials{
|
||||||
|
Token: *encryptionCfg.Gemalto.Keysecure.Credentials.Token,
|
||||||
|
Domain: *encryptionCfg.Gemalto.Keysecure.Credentials.Domain,
|
||||||
|
Retry: 15 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imm := true
|
||||||
|
// if mTLSCertificates contains elements we create the kubernetes secret
|
||||||
|
var clientCertSecretReference *operator.LocalCertificateReference
|
||||||
|
if len(mTLSCertificates) > 0 {
|
||||||
|
// Secret to store KES mTLS kesConfiguration to authenticate against a KMS
|
||||||
|
kesClientCertSecret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: kesClientCertSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Immutable: &imm,
|
||||||
|
Data: mTLSCertificates,
|
||||||
|
}
|
||||||
|
_, err := clientSet.createSecret(ctx, ns, &kesClientCertSecret, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// kubernetes generic secret
|
||||||
|
clientCertSecretReference = &operator.LocalCertificateReference{
|
||||||
|
Name: kesClientCertSecretName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generate Yaml kesConfiguration for KES
|
||||||
|
serverConfigYaml, err := yaml.Marshal(kesConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// Secret to store KES server kesConfiguration
|
||||||
|
kesConfigurationSecret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: kesConfigurationSecretName,
|
||||||
|
Labels: map[string]string{
|
||||||
|
operator.TenantLabel: tenantName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Immutable: &imm,
|
||||||
|
Data: map[string][]byte{
|
||||||
|
"server-config.yaml": serverConfigYaml,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err = clientSet.createSecret(ctx, ns, &kesConfigurationSecret, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return &corev1.LocalObjectReference{
|
||||||
|
Name: kesConfigurationSecretName,
|
||||||
|
}, clientCertSecretReference, nil
|
||||||
|
}
|
||||||
456
restapi/admin_tenants_helper_test.go
Normal file
456
restapi/admin_tenants_helper_test.go
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
package restapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
"github.com/minio/console/restapi/operations/admin_api"
|
||||||
|
operator "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DeletePodCollectionMock func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||||
|
var DeleteSecretMock func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||||
|
var CreateSecretMock func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||||
|
|
||||||
|
func (c k8sClientMock) deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||||
|
return DeletePodCollectionMock(ctx, namespace, opts, listOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c k8sClientMock) deleteSecret(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return DeleteSecretMock(ctx, namespace, name, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c k8sClientMock) createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||||
|
return CreateSecretMock(ctx, namespace, secret, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_tenantUpdateCertificates(t *testing.T) {
|
||||||
|
k8sClient := k8sClientMock{}
|
||||||
|
opClient := opClientMock{}
|
||||||
|
crt := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUzRENDQTBTZ0F3SUJBZ0lRS0pDalNyK0xaMnJrYVo5ODAvZnV5akFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKdFRFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNVVV3UXdZRFZRUUxERHhoYkdWMgpjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3RVSEp2TG14dlkyRnNJQ2hNWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowCllTQkJjbWxoY3lreFREQktCZ05WQkFNTVEyMXJZMlZ5ZENCaGJHVjJjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3QKVUhKdkxteHZZMkZzSUNoTVpXNXBiaUJCYkdWMmMydHBJRWgxWlhKMFlTQkJjbWxoY3lrd0hoY05NVGt3TmpBeApNREF3TURBd1doY05NekF3T0RBeU1ERTFNekEzV2pCaU1TY3dKUVlEVlFRS0V4NXRhMk5sY25RZ1pHVjJaV3h2CmNHMWxiblFnWTJWeWRHbG1hV05oZEdVeE56QTFCZ05WQkFzTUxtRnNaWFp6YTBCMGFXWmhMbXh2WTJGc0lDaE0KWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowWVNCQmNtbGhjeWt3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQgpEd0F3Z2dFS0FvSUJBUUM2dlhLVyswWmhJQUNycmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhCm1rVlcxSkhBS3VTc0I1UHE0QnFSRXFueUhYT0ZROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFQKdVMxTFNtcHU5VjhFU2Q0Q3BiOGRvUkcvUW8vRTF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLTwp0NFVlcEt6d2dFQ2NKRVg4MVFoem1ZT25ELysyazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rCmEwTzQyRVl2NVNUT1N0dzI2TzMwTVRrcEg0dzRRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1USsKU0NlaDdqTVlVUThYV1JkbXVHbzFRT0g5cjdDKy82L1JhMlZIQWdNQkFBR2pnYmt3Z2JZd0RnWURWUjBQQVFILwpCQVFEQWdXZ01CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUJNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqCkJCZ3dGb0FVNHg4NUIyeGVlQzg0UEdvM1dZVWwxRGVvZlFNd1lBWURWUjBSQkZrd1Y0SWpLaTV0YVc1cGJ5MWgKYkdWMmMyc3Ribk11YzNaakxtTnNkWE4wWlhJdWJHOWpZV3lDTUNvdWFHOXVaWGwzWld4c0xXaHNMbTFwYm1sdgpMV0ZzWlhaemF5MXVjeTV6ZG1NdVkyeDFjM1JsY2k1c2IyTmhiREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBWUVBCnZnMFlIVGtzd3Z4NEE5ZXl0b1V3eTBOSFVjQXpuNy9BVCt3WEt6d3Fqa0RiS3hVYlFTMFNQVVI4SkVDMkpuUUgKU3pTNGFCNXRURVRYZUcrbHJZVU02b0RNcXlIalpUN1NJaW83OUNxOFloWWxORU9qMkhvaXdxalczZm10UU9kVApoVG1tS01lRnZleHo2cnRxbHp0cVdKa3kvOGd1MkMrMWw5UDFFUmhFNDZZY0puVmJ5REFTSGNvV2tiZVhFUGErCjNpNFd4bU1yMDlNZXFTNkFUb2NKanFBeEtYcURYWmlFZjRUVEp1ZTRBQ2s4WmhqaEtUUEV6RnQ3WllVaHY3dVoKdlZCOXhla2FqRzdMRU5kSHZncXVMRUxUV3czWkpBaXpSTU5KUUpzZU11LzdQN1NIeXRKTVJYdlVwd2R2dWhDOApKNm54aGRmUS91QVlQY1lHdlU5NUZPZ1NjWVZqNW1WQktXM0ZHbkl2YzZuamQ1OFhBSTE3dlk0K0ZZTnY4M2UxCm9mOGlxRFdWNTFyT1FlbG9FZFdmdHkvZTI2bXVWUUQzQlVjY2Z5SWpGYy9SeGNHdm5maUEwUm1uRDNkWFcyZ0oKUHFTd01ZZ3hxQndqMm1Qck5jdkFWY3BOeWRjTWJKOTFIOHRWY0ttRHMrY1NiV0tnblpmKzUvZm5yaTdmU3FLUQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
|
||||||
|
key := "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQzZ2WEtXKzBaaElBQ3IKcmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhbWtWVzFKSEFLdVNzQjVQcTRCcVJFcW55SFhPRgpROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFR1UzFMU21wdTlWOEVTZDRDcGI4ZG9SRy9Rby9FCjF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLT3Q0VWVwS3p3Z0VDY0pFWDgxUWh6bVlPbkQvKzIKazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rYTBPNDJFWXY1U1RPU3R3MjZPMzBNVGtwSDR3NApRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1UStTQ2VoN2pNWVVROFhXUmRtdUdvMVFPSDlyN0MrCi82L1JhMlZIQWdNQkFBRUNnZ0VCQUlyTlVFUnJSM2ZmK3IraGhJRS93ekZhbGNUMUZWaDh3aXpUWXJQcnZCMFkKYlZvcVJzZ2xUVTdxTjkvM3dmc2dzdEROZk5IQ1pySEJOR0drK0orMDZMV2tnakhycjdXeFBUaE16ZDRvUGN4RwpRdTBMOGE5ZVlBMXJwY3NOOVc5Um5JU3BRSEk4aTkxM0V6Z0RoOWk2WCt0bFQyNjNNK0JYaDhlM1Z5cDNSTmhpCjZZUTQwcWJsNlQ0TUlyLzRSMGJmcFExZWVMNVNnbHB6Z1d6ZGs4WGtmc0E5YnRiU1RoMjZKRlBPUU1tMm5adkcKbjBlZm85TDZtaktwRW9rRWpTY1hWYTRZNHJaREZFYTVIbkpUSDBHblByQzU1cDhBb3BFN1c1M2RDT3lxd29CcQo4SWtZb2grcm1qTUZrOGc5VlRVYlcwVE9YVTFSY1E1Z0gxWS9jam5uVTRrQ2dZRUE4amw5ZEQyN2JaQ2ZaTW9jCjJYRThiYkJTaFVXTjRvaklKc1lHY2xyTjJDUEtUNmExaVhvS3BrTXdGNUdsODEzQURGR1pTbWtUSUFVQXRXQU8KNzZCcEpGUlVCZ1hmUXhSU0gyS1RaRldxbE5yekZPQjNsT3h2bFJ1amw5eE9ueStyWUhJWC9BOWNqQlp3a2orSAo3MDZRTExvS1ZFL2lMYy9DMlI5VzRLRVI3R3NDZ1lFQXhWd3FyM1JnUXhHUmpueG1zbDZtUW5DQ3k2MXFoUzUxCkJicDJzWldraFNTV0w0YzFDY0NDMnZ2ektPSmJkZ2NZQU43L05sTHgzWjlCZUFjTVZMUEVoc2NPalB6YUlneEMKczJ2UkdwQUFtYnRjWi9MVlpKaERWTjIrSHowRHhnRUtCa1JzQU5XTG51cGRoUWJBdlZuTkVsY29YVlo1cC9qcwp3U1BCelFoSklaVUNnWUJqTUlHY0dTOW9SWUhRRHlmVEx4aVV2bEI4ZktnR2JRYXhRZ1FmemVsZktnRE5yekhGCnN6RXJOblk2SUkxNVpCbWhzY1I1QVNBd3kzdW55a2N6ZjFldTVjMW1qZjhJQkFsQkN1ZmFmVzRWK0xiMEJKdFQKWTZLcHg2Q3RMaTBQNk1CZ0JUaW5JazgrbW0zTXBiRnZvSmRQaVh0elhTYjhwWWhmeXdLVGg4SEVNd0tCZ1FDUwpvR0VPTFpYKy9pUjRDYkI2d0pzaExWbmZYSjJSQ096a0xwNVVYV3IzaURFVWFvMWJDMjJzcUJjRnZ2WllmL2l6ClhQbWJNSkNGS1BhSTZDT2ZJbGZXRWptYlFaZ0dSN21lZDNISkhFZDE3NTg5azBvN0RHeXB0bnl6MUs3akFvNmkKRFY5NFZ5NytCLzBuQWRkY1ZrVm5aTjJXU3RMam1xcTY2NGZtZmt0bTZRS0JnQzBsMk5OVlFWK2N0OFFRRFpINQpBRFIrSGM3Qk0wNDhURGhNTmhoR3JHc2tWNngwMCtMZTdISGdpT3h2NXJudkNlTlY2M001YUZHdFVWbllTN1VoCkE1NndaNVlZeFFnQ0xzNi9PRmZhK3NiTngrSjdnSjRjNXdMZVlJMXVPMTlzZHBHa2VHZ25vK3dXVmxDSzFCbW0KRGM0TXA2STRiUTVtdy93YVpLQnpjRTJLCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
|
||||||
|
badCrt := "ASD"
|
||||||
|
badKey := "ASD"
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
opClient OperatorClientI
|
||||||
|
clientSet K8sClientI
|
||||||
|
namespace string
|
||||||
|
params admin_api.TenantUpdateCertificateParams
|
||||||
|
mockTenantGet func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error)
|
||||||
|
mockDeleteSecret func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||||
|
mockCreateSecret func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||||
|
mockDeletePodCollection func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "error getting tenant information",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateCertificateParams{},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return nil, errors.New("invalid tenant")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error replacing external certs for tenant because of missing keypair",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateCertificateParams{
|
||||||
|
Body: &models.TLSConfiguration{
|
||||||
|
Minio: &models.KeyPairConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return &operator.Tenant{
|
||||||
|
Spec: operator.TenantSpec{
|
||||||
|
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||||
|
Name: "secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error replacing external certs for tenant because of malformed encoded certs",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateCertificateParams{
|
||||||
|
Body: &models.TLSConfiguration{
|
||||||
|
Minio: &models.KeyPairConfiguration{
|
||||||
|
Crt: &badCrt,
|
||||||
|
Key: &badKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return &operator.Tenant{
|
||||||
|
Spec: operator.TenantSpec{
|
||||||
|
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||||
|
Name: "secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error replacing external certs for tenant because of error during secret creation",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateCertificateParams{
|
||||||
|
Body: &models.TLSConfiguration{
|
||||||
|
Minio: &models.KeyPairConfiguration{
|
||||||
|
Crt: &crt,
|
||||||
|
Key: &key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return &operator.Tenant{
|
||||||
|
Spec: operator.TenantSpec{
|
||||||
|
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||||
|
Name: "secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||||
|
return nil, errors.New("error creating secret")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "certificates replaced but error during deleting existing tenant pods",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateCertificateParams{
|
||||||
|
Body: &models.TLSConfiguration{
|
||||||
|
Minio: &models.KeyPairConfiguration{
|
||||||
|
Crt: &crt,
|
||||||
|
Key: &key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return &operator.Tenant{
|
||||||
|
Spec: operator.TenantSpec{
|
||||||
|
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||||
|
Name: "secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||||
|
return &v1.Secret{}, nil
|
||||||
|
},
|
||||||
|
mockDeletePodCollection: func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||||
|
return errors.New("error deleting minio pods")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error replacing external certs for console because of missing keypair",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateCertificateParams{
|
||||||
|
Body: &models.TLSConfiguration{
|
||||||
|
Console: &models.KeyPairConfiguration{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return &operator.Tenant{
|
||||||
|
Spec: operator.TenantSpec{
|
||||||
|
Console: &operator.ConsoleConfiguration{
|
||||||
|
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||||
|
Name: "secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "certificates replaced but error during deleting existing tenant pods",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateCertificateParams{
|
||||||
|
Body: &models.TLSConfiguration{
|
||||||
|
Console: &models.KeyPairConfiguration{
|
||||||
|
Crt: &crt,
|
||||||
|
Key: &key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return &operator.Tenant{
|
||||||
|
Spec: operator.TenantSpec{
|
||||||
|
Console: &operator.ConsoleConfiguration{
|
||||||
|
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||||
|
Name: "secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||||
|
return &v1.Secret{}, nil
|
||||||
|
},
|
||||||
|
mockDeletePodCollection: func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||||
|
return errors.New("error deleting console pods")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
opClientTenantGetMock = tt.args.mockTenantGet
|
||||||
|
DeleteSecretMock = tt.args.mockDeleteSecret
|
||||||
|
CreateSecretMock = tt.args.mockCreateSecret
|
||||||
|
DeletePodCollectionMock = tt.args.mockDeletePodCollection
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := tenantUpdateCertificates(tt.args.ctx, tt.args.opClient, tt.args.clientSet, tt.args.namespace, tt.args.params); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("tenantUpdateCertificates() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_tenantUpdateEncryption(t *testing.T) {
|
||||||
|
k8sClient := k8sClientMock{}
|
||||||
|
opClient := opClientMock{}
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
opClient OperatorClientI
|
||||||
|
clientSet K8sClientI
|
||||||
|
namespace string
|
||||||
|
params admin_api.TenantUpdateEncryptionParams
|
||||||
|
mockTenantGet func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error)
|
||||||
|
mockDeleteSecret func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||||
|
mockCreateSecret func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||||
|
mockDeletePodCollection func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "error updating encryption configuration because of error getting tenant",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
opClient: opClient,
|
||||||
|
clientSet: k8sClient,
|
||||||
|
namespace: "",
|
||||||
|
params: admin_api.TenantUpdateEncryptionParams{},
|
||||||
|
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||||
|
return nil, errors.New("invalid tenant")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
opClientTenantGetMock = tt.args.mockTenantGet
|
||||||
|
DeleteSecretMock = tt.args.mockDeleteSecret
|
||||||
|
CreateSecretMock = tt.args.mockCreateSecret
|
||||||
|
DeletePodCollectionMock = tt.args.mockDeletePodCollection
|
||||||
|
if err := tenantUpdateEncryption(tt.args.ctx, tt.args.opClient, tt.args.clientSet, tt.args.namespace, tt.args.params); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("tenantUpdateEncryption() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_createOrReplaceKesConfigurationSecrets(t *testing.T) {
|
||||||
|
k8sClient := k8sClientMock{}
|
||||||
|
crt := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUzRENDQTBTZ0F3SUJBZ0lRS0pDalNyK0xaMnJrYVo5ODAvZnV5akFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKdFRFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNVVV3UXdZRFZRUUxERHhoYkdWMgpjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3RVSEp2TG14dlkyRnNJQ2hNWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowCllTQkJjbWxoY3lreFREQktCZ05WQkFNTVEyMXJZMlZ5ZENCaGJHVjJjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3QKVUhKdkxteHZZMkZzSUNoTVpXNXBiaUJCYkdWMmMydHBJRWgxWlhKMFlTQkJjbWxoY3lrd0hoY05NVGt3TmpBeApNREF3TURBd1doY05NekF3T0RBeU1ERTFNekEzV2pCaU1TY3dKUVlEVlFRS0V4NXRhMk5sY25RZ1pHVjJaV3h2CmNHMWxiblFnWTJWeWRHbG1hV05oZEdVeE56QTFCZ05WQkFzTUxtRnNaWFp6YTBCMGFXWmhMbXh2WTJGc0lDaE0KWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowWVNCQmNtbGhjeWt3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQgpEd0F3Z2dFS0FvSUJBUUM2dlhLVyswWmhJQUNycmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhCm1rVlcxSkhBS3VTc0I1UHE0QnFSRXFueUhYT0ZROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFQKdVMxTFNtcHU5VjhFU2Q0Q3BiOGRvUkcvUW8vRTF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLTwp0NFVlcEt6d2dFQ2NKRVg4MVFoem1ZT25ELysyazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rCmEwTzQyRVl2NVNUT1N0dzI2TzMwTVRrcEg0dzRRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1USsKU0NlaDdqTVlVUThYV1JkbXVHbzFRT0g5cjdDKy82L1JhMlZIQWdNQkFBR2pnYmt3Z2JZd0RnWURWUjBQQVFILwpCQVFEQWdXZ01CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUJNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqCkJCZ3dGb0FVNHg4NUIyeGVlQzg0UEdvM1dZVWwxRGVvZlFNd1lBWURWUjBSQkZrd1Y0SWpLaTV0YVc1cGJ5MWgKYkdWMmMyc3Ribk11YzNaakxtTnNkWE4wWlhJdWJHOWpZV3lDTUNvdWFHOXVaWGwzWld4c0xXaHNMbTFwYm1sdgpMV0ZzWlhaemF5MXVjeTV6ZG1NdVkyeDFjM1JsY2k1c2IyTmhiREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBWUVBCnZnMFlIVGtzd3Z4NEE5ZXl0b1V3eTBOSFVjQXpuNy9BVCt3WEt6d3Fqa0RiS3hVYlFTMFNQVVI4SkVDMkpuUUgKU3pTNGFCNXRURVRYZUcrbHJZVU02b0RNcXlIalpUN1NJaW83OUNxOFloWWxORU9qMkhvaXdxalczZm10UU9kVApoVG1tS01lRnZleHo2cnRxbHp0cVdKa3kvOGd1MkMrMWw5UDFFUmhFNDZZY0puVmJ5REFTSGNvV2tiZVhFUGErCjNpNFd4bU1yMDlNZXFTNkFUb2NKanFBeEtYcURYWmlFZjRUVEp1ZTRBQ2s4WmhqaEtUUEV6RnQ3WllVaHY3dVoKdlZCOXhla2FqRzdMRU5kSHZncXVMRUxUV3czWkpBaXpSTU5KUUpzZU11LzdQN1NIeXRKTVJYdlVwd2R2dWhDOApKNm54aGRmUS91QVlQY1lHdlU5NUZPZ1NjWVZqNW1WQktXM0ZHbkl2YzZuamQ1OFhBSTE3dlk0K0ZZTnY4M2UxCm9mOGlxRFdWNTFyT1FlbG9FZFdmdHkvZTI2bXVWUUQzQlVjY2Z5SWpGYy9SeGNHdm5maUEwUm1uRDNkWFcyZ0oKUHFTd01ZZ3hxQndqMm1Qck5jdkFWY3BOeWRjTWJKOTFIOHRWY0ttRHMrY1NiV0tnblpmKzUvZm5yaTdmU3FLUQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
|
||||||
|
key := "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQzZ2WEtXKzBaaElBQ3IKcmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhbWtWVzFKSEFLdVNzQjVQcTRCcVJFcW55SFhPRgpROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFR1UzFMU21wdTlWOEVTZDRDcGI4ZG9SRy9Rby9FCjF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLT3Q0VWVwS3p3Z0VDY0pFWDgxUWh6bVlPbkQvKzIKazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rYTBPNDJFWXY1U1RPU3R3MjZPMzBNVGtwSDR3NApRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1UStTQ2VoN2pNWVVROFhXUmRtdUdvMVFPSDlyN0MrCi82L1JhMlZIQWdNQkFBRUNnZ0VCQUlyTlVFUnJSM2ZmK3IraGhJRS93ekZhbGNUMUZWaDh3aXpUWXJQcnZCMFkKYlZvcVJzZ2xUVTdxTjkvM3dmc2dzdEROZk5IQ1pySEJOR0drK0orMDZMV2tnakhycjdXeFBUaE16ZDRvUGN4RwpRdTBMOGE5ZVlBMXJwY3NOOVc5Um5JU3BRSEk4aTkxM0V6Z0RoOWk2WCt0bFQyNjNNK0JYaDhlM1Z5cDNSTmhpCjZZUTQwcWJsNlQ0TUlyLzRSMGJmcFExZWVMNVNnbHB6Z1d6ZGs4WGtmc0E5YnRiU1RoMjZKRlBPUU1tMm5adkcKbjBlZm85TDZtaktwRW9rRWpTY1hWYTRZNHJaREZFYTVIbkpUSDBHblByQzU1cDhBb3BFN1c1M2RDT3lxd29CcQo4SWtZb2grcm1qTUZrOGc5VlRVYlcwVE9YVTFSY1E1Z0gxWS9jam5uVTRrQ2dZRUE4amw5ZEQyN2JaQ2ZaTW9jCjJYRThiYkJTaFVXTjRvaklKc1lHY2xyTjJDUEtUNmExaVhvS3BrTXdGNUdsODEzQURGR1pTbWtUSUFVQXRXQU8KNzZCcEpGUlVCZ1hmUXhSU0gyS1RaRldxbE5yekZPQjNsT3h2bFJ1amw5eE9ueStyWUhJWC9BOWNqQlp3a2orSAo3MDZRTExvS1ZFL2lMYy9DMlI5VzRLRVI3R3NDZ1lFQXhWd3FyM1JnUXhHUmpueG1zbDZtUW5DQ3k2MXFoUzUxCkJicDJzWldraFNTV0w0YzFDY0NDMnZ2ektPSmJkZ2NZQU43L05sTHgzWjlCZUFjTVZMUEVoc2NPalB6YUlneEMKczJ2UkdwQUFtYnRjWi9MVlpKaERWTjIrSHowRHhnRUtCa1JzQU5XTG51cGRoUWJBdlZuTkVsY29YVlo1cC9qcwp3U1BCelFoSklaVUNnWUJqTUlHY0dTOW9SWUhRRHlmVEx4aVV2bEI4ZktnR2JRYXhRZ1FmemVsZktnRE5yekhGCnN6RXJOblk2SUkxNVpCbWhzY1I1QVNBd3kzdW55a2N6ZjFldTVjMW1qZjhJQkFsQkN1ZmFmVzRWK0xiMEJKdFQKWTZLcHg2Q3RMaTBQNk1CZ0JUaW5JazgrbW0zTXBiRnZvSmRQaVh0elhTYjhwWWhmeXdLVGg4SEVNd0tCZ1FDUwpvR0VPTFpYKy9pUjRDYkI2d0pzaExWbmZYSjJSQ096a0xwNVVYV3IzaURFVWFvMWJDMjJzcUJjRnZ2WllmL2l6ClhQbWJNSkNGS1BhSTZDT2ZJbGZXRWptYlFaZ0dSN21lZDNISkhFZDE3NTg5azBvN0RHeXB0bnl6MUs3akFvNmkKRFY5NFZ5NytCLzBuQWRkY1ZrVm5aTjJXU3RMam1xcTY2NGZtZmt0bTZRS0JnQzBsMk5OVlFWK2N0OFFRRFpINQpBRFIrSGM3Qk0wNDhURGhNTmhoR3JHc2tWNngwMCtMZTdISGdpT3h2NXJudkNlTlY2M001YUZHdFVWbllTN1VoCkE1NndaNVlZeFFnQ0xzNi9PRmZhK3NiTngrSjdnSjRjNXdMZVlJMXVPMTlzZHBHa2VHZ25vK3dXVmxDSzFCbW0KRGM0TXA2STRiUTVtdy93YVpLQnpjRTJLCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
|
||||||
|
badCrt := "ASD"
|
||||||
|
badKey := "ASD"
|
||||||
|
appRole := "ASD"
|
||||||
|
appSecret := "ASD"
|
||||||
|
endpoint := "ASD"
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
clientSet K8sClientI
|
||||||
|
ns string
|
||||||
|
encryptionCfg *models.EncryptionConfiguration
|
||||||
|
kesConfigurationSecretName string
|
||||||
|
kesClientCertSecretName string
|
||||||
|
tenantName string
|
||||||
|
mockDeleteSecret func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||||
|
mockCreateSecret func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *v1.LocalObjectReference
|
||||||
|
want1 *operator.LocalCertificateReference
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "error decoding the client certificate",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
clientSet: k8sClient,
|
||||||
|
encryptionCfg: &models.EncryptionConfiguration{
|
||||||
|
Client: &models.KeyPairConfiguration{
|
||||||
|
Crt: &badCrt,
|
||||||
|
Key: &badKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ns: "default",
|
||||||
|
kesConfigurationSecretName: "test-secret",
|
||||||
|
kesClientCertSecretName: "test-client-secret",
|
||||||
|
tenantName: "test",
|
||||||
|
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
want1: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error because of malformed decoded certificate",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
clientSet: k8sClient,
|
||||||
|
encryptionCfg: &models.EncryptionConfiguration{
|
||||||
|
Client: &models.KeyPairConfiguration{
|
||||||
|
Crt: &key, // will cause an error because we are passing a private key as the public key
|
||||||
|
Key: &key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ns: "default",
|
||||||
|
kesConfigurationSecretName: "test-secret",
|
||||||
|
kesClientCertSecretName: "test-client-secret",
|
||||||
|
tenantName: "test",
|
||||||
|
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
want1: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error because of malformed decoded certificate",
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
clientSet: k8sClient,
|
||||||
|
encryptionCfg: &models.EncryptionConfiguration{
|
||||||
|
Client: &models.KeyPairConfiguration{
|
||||||
|
Crt: &crt,
|
||||||
|
Key: &key,
|
||||||
|
},
|
||||||
|
Vault: &models.VaultConfiguration{
|
||||||
|
Approle: &models.VaultConfigurationApprole{
|
||||||
|
Engine: "",
|
||||||
|
ID: &appRole,
|
||||||
|
Retry: 0,
|
||||||
|
Secret: &appSecret,
|
||||||
|
},
|
||||||
|
Endpoint: &endpoint,
|
||||||
|
Engine: "",
|
||||||
|
Namespace: "",
|
||||||
|
Prefix: "",
|
||||||
|
Status: nil,
|
||||||
|
TLS: &models.VaultConfigurationTLS{
|
||||||
|
Ca: crt,
|
||||||
|
Crt: crt,
|
||||||
|
Key: key,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ns: "default",
|
||||||
|
kesConfigurationSecretName: "test-secret",
|
||||||
|
kesClientCertSecretName: "test-client-secret",
|
||||||
|
tenantName: "test",
|
||||||
|
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||||
|
return &v1.Secret{}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &v1.LocalObjectReference{
|
||||||
|
Name: "test-secret",
|
||||||
|
},
|
||||||
|
want1: &operator.LocalCertificateReference{
|
||||||
|
Name: "test-client-secret",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
DeleteSecretMock = tt.args.mockDeleteSecret
|
||||||
|
CreateSecretMock = tt.args.mockCreateSecret
|
||||||
|
got, got1, err := createOrReplaceKesConfigurationSecrets(tt.args.ctx, tt.args.clientSet, tt.args.ns, tt.args.encryptionCfg, tt.args.kesConfigurationSecretName, tt.args.kesClientCertSecretName, tt.args.tenantName)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("createOrReplaceKesConfigurationSecrets() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("createOrReplaceKesConfigurationSecrets() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got1, tt.want1) {
|
||||||
|
t.Errorf("createOrReplaceKesConfigurationSecrets() got1 = %v, want %v", got1, tt.want1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,7 +88,7 @@ func Test_TenantInfoTenantAdminClient(t *testing.T) {
|
|||||||
kClient := k8sClientMock{}
|
kClient := k8sClientMock{}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
client K8sClient
|
client K8sClientI
|
||||||
namespace string
|
namespace string
|
||||||
tenantName string
|
tenantName string
|
||||||
serviceName string
|
serviceName string
|
||||||
@@ -339,7 +339,7 @@ func Test_deleteTenantAction(t *testing.T) {
|
|||||||
opClient := opClientMock{}
|
opClient := opClientMock{}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
operatorClient OperatorClient
|
operatorClient OperatorClientI
|
||||||
nameSpace string
|
nameSpace string
|
||||||
tenantName string
|
tenantName string
|
||||||
deletePvcs bool
|
deletePvcs bool
|
||||||
@@ -532,7 +532,7 @@ func Test_TenantAddZone(t *testing.T) {
|
|||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
operatorClient OperatorClient
|
operatorClient OperatorClientI
|
||||||
nameSpace string
|
nameSpace string
|
||||||
mockTenantPatch func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error)
|
mockTenantPatch func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error)
|
||||||
mockTenantGet func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error)
|
mockTenantGet func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error)
|
||||||
@@ -706,7 +706,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
|||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
operatorClient OperatorClient
|
operatorClient OperatorClientI
|
||||||
httpCl cluster.HTTPClientI
|
httpCl cluster.HTTPClientI
|
||||||
nameSpace string
|
nameSpace string
|
||||||
tenantName string
|
tenantName string
|
||||||
@@ -871,7 +871,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
|||||||
},
|
},
|
||||||
params: admin_api.UpdateTenantParams{
|
params: admin_api.UpdateTenantParams{
|
||||||
Body: &models.UpdateTenantRequest{
|
Body: &models.UpdateTenantRequest{
|
||||||
ConsoleImage: "minio/console:v0.3.18",
|
ConsoleImage: "minio/console:v0.3.19",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -437,18 +437,28 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/cluster/resources": {
|
"/cluster/max-allocatable-memory": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"AdminAPI"
|
"AdminAPI"
|
||||||
],
|
],
|
||||||
"summary": "Get Cluster Resources",
|
"summary": "Get maximum allocatable memory for given number of nodes",
|
||||||
"operationId": "GetClusterResources",
|
"operationId": "GetMaxAllocatableMem",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"name": "num_nodes",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/clusterResources"
|
"$ref": "#/definitions/maxAllocatableMemResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
@@ -1066,6 +1076,90 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/namespaces/{namespace}/tenants/{tenant}/certificates": {
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"AdminAPI"
|
||||||
|
],
|
||||||
|
"summary": "Tenant Update Certificates",
|
||||||
|
"operationId": "TenantUpdateCertificate",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "namespace",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "tenant",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/tlsConfiguration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "A successful response."
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Generic error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/namespaces/{namespace}/tenants/{tenant}/encryption": {
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"AdminAPI"
|
||||||
|
],
|
||||||
|
"summary": "Tenant Update Encryption",
|
||||||
|
"operationId": "TenantUpdateEncryption",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "namespace",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "tenant",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/encryptionConfiguration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "A successful response."
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Generic error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/namespaces/{namespace}/tenants/{tenant}/usage": {
|
"/namespaces/{namespace}/tenants/{tenant}/usage": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -2044,17 +2138,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"clusterResources": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"nodes": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/nodeInfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"configDescription": {
|
"configDescription": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -2594,30 +2677,12 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nodeInfo": {
|
"maxAllocatableMemResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"allocatable_resources": {
|
"max_memory": {
|
||||||
"description": "Represents the resources of a node that are available for scheduling.",
|
"type": "integer",
|
||||||
"type": "object",
|
"format": "int64"
|
||||||
"additionalProperties": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"taints": {
|
|
||||||
"$ref": "#/definitions/nodeTaints"
|
|
||||||
},
|
|
||||||
"total_resources": {
|
|
||||||
"description": "Represents the total resources of a node.",
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2685,29 +2750,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nodeTaints": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"no_execute": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"no_schedule": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"prefer_no_schedule": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nofiticationService": {
|
"nofiticationService": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
@@ -4019,18 +4061,28 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/cluster/resources": {
|
"/cluster/max-allocatable-memory": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"AdminAPI"
|
"AdminAPI"
|
||||||
],
|
],
|
||||||
"summary": "Get Cluster Resources",
|
"summary": "Get maximum allocatable memory for given number of nodes",
|
||||||
"operationId": "GetClusterResources",
|
"operationId": "GetMaxAllocatableMem",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32",
|
||||||
|
"name": "num_nodes",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/clusterResources"
|
"$ref": "#/definitions/maxAllocatableMemResponse"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default": {
|
"default": {
|
||||||
@@ -4648,6 +4700,90 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/namespaces/{namespace}/tenants/{tenant}/certificates": {
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"AdminAPI"
|
||||||
|
],
|
||||||
|
"summary": "Tenant Update Certificates",
|
||||||
|
"operationId": "TenantUpdateCertificate",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "namespace",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "tenant",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/tlsConfiguration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "A successful response."
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Generic error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/namespaces/{namespace}/tenants/{tenant}/encryption": {
|
||||||
|
"put": {
|
||||||
|
"tags": [
|
||||||
|
"AdminAPI"
|
||||||
|
],
|
||||||
|
"summary": "Tenant Update Encryption",
|
||||||
|
"operationId": "TenantUpdateEncryption",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "namespace",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "tenant",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/encryptionConfiguration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "A successful response."
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Generic error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/namespaces/{namespace}/tenants/{tenant}/usage": {
|
"/namespaces/{namespace}/tenants/{tenant}/usage": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -6143,17 +6279,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"clusterResources": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"nodes": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/nodeInfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"configDescription": {
|
"configDescription": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -6693,30 +6818,12 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nodeInfo": {
|
"maxAllocatableMemResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"allocatable_resources": {
|
"max_memory": {
|
||||||
"description": "Represents the resources of a node that are available for scheduling.",
|
"type": "integer",
|
||||||
"type": "object",
|
"format": "int64"
|
||||||
"additionalProperties": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"taints": {
|
|
||||||
"$ref": "#/definitions/nodeTaints"
|
|
||||||
},
|
|
||||||
"total_resources": {
|
|
||||||
"description": "Represents the total resources of a node.",
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "int64"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -6740,29 +6847,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nodeTaints": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"no_execute": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"no_schedule": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"prefer_no_schedule": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nofiticationService": {
|
"nofiticationService": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|||||||
@@ -24,13 +24,16 @@ import (
|
|||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// K8sClient interface with all functions to be implemented
|
// K8sClientI interface with all functions to be implemented
|
||||||
// by mock when testing, it should include all K8sClient respective api calls
|
// by mock when testing, it should include all K8sClientI respective api calls
|
||||||
// that are used within this project.
|
// that are used within this project.
|
||||||
type K8sClient interface {
|
type K8sClientI interface {
|
||||||
getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error)
|
getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error)
|
||||||
getSecret(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*v1.Secret, error)
|
getSecret(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*v1.Secret, error)
|
||||||
getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error)
|
getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error)
|
||||||
|
deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||||
|
deleteSecret(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||||
|
createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface implementation
|
// Interface implementation
|
||||||
@@ -51,3 +54,15 @@ func (c *k8sClient) getSecret(ctx context.Context, namespace, secretName string,
|
|||||||
func (c *k8sClient) getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error) {
|
func (c *k8sClient) getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error) {
|
||||||
return c.client.CoreV1().Services(namespace).Get(ctx, serviceName, opts)
|
return c.client.CoreV1().Services(namespace).Get(ctx, serviceName, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *k8sClient) deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||||
|
return c.client.CoreV1().Pods(namespace).DeleteCollection(ctx, opts, listOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *k8sClient) deleteSecret(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||||
|
return c.client.CoreV1().Secrets(namespace).Delete(ctx, name, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *k8sClient) createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||||
|
return c.client.CoreV1().Secrets(namespace).Create(ctx, secret, opts)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
// Code generated by go-swagger; DO NOT EDIT.
|
|
||||||
|
|
||||||
// This file is part of MinIO Console Server
|
|
||||||
// Copyright (c) 2020 MinIO, Inc.
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
package admin_api
|
|
||||||
|
|
||||||
// This file was generated by the swagger tool.
|
|
||||||
// Editing this file might prove futile when you re-run the swagger generate command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/go-openapi/errors"
|
|
||||||
"github.com/go-openapi/runtime/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewGetClusterResourcesParams creates a new GetClusterResourcesParams object
|
|
||||||
// no default values defined in spec.
|
|
||||||
func NewGetClusterResourcesParams() GetClusterResourcesParams {
|
|
||||||
|
|
||||||
return GetClusterResourcesParams{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetClusterResourcesParams contains all the bound params for the get cluster resources operation
|
|
||||||
// typically these are obtained from a http.Request
|
|
||||||
//
|
|
||||||
// swagger:parameters GetClusterResources
|
|
||||||
type GetClusterResourcesParams struct {
|
|
||||||
|
|
||||||
// HTTP Request Object
|
|
||||||
HTTPRequest *http.Request `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
|
||||||
// for simple values it will use straight method calls.
|
|
||||||
//
|
|
||||||
// To ensure default values, the struct must have been initialized with NewGetClusterResourcesParams() beforehand.
|
|
||||||
func (o *GetClusterResourcesParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
|
||||||
var res []error
|
|
||||||
|
|
||||||
o.HTTPRequest = r
|
|
||||||
|
|
||||||
if len(res) > 0 {
|
|
||||||
return errors.CompositeValidationError(res...)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// Code generated by go-swagger; DO NOT EDIT.
|
|
||||||
|
|
||||||
// This file is part of MinIO Console Server
|
|
||||||
// Copyright (c) 2020 MinIO, Inc.
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
package admin_api
|
|
||||||
|
|
||||||
// This file was generated by the swagger tool.
|
|
||||||
// Editing this file might prove futile when you re-run the swagger generate command
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/go-openapi/runtime"
|
|
||||||
|
|
||||||
"github.com/minio/console/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetClusterResourcesOKCode is the HTTP code returned for type GetClusterResourcesOK
|
|
||||||
const GetClusterResourcesOKCode int = 200
|
|
||||||
|
|
||||||
/*GetClusterResourcesOK A successful response.
|
|
||||||
|
|
||||||
swagger:response getClusterResourcesOK
|
|
||||||
*/
|
|
||||||
type GetClusterResourcesOK struct {
|
|
||||||
|
|
||||||
/*
|
|
||||||
In: Body
|
|
||||||
*/
|
|
||||||
Payload *models.ClusterResources `json:"body,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetClusterResourcesOK creates GetClusterResourcesOK with default headers values
|
|
||||||
func NewGetClusterResourcesOK() *GetClusterResourcesOK {
|
|
||||||
|
|
||||||
return &GetClusterResourcesOK{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPayload adds the payload to the get cluster resources o k response
|
|
||||||
func (o *GetClusterResourcesOK) WithPayload(payload *models.ClusterResources) *GetClusterResourcesOK {
|
|
||||||
o.Payload = payload
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPayload sets the payload to the get cluster resources o k response
|
|
||||||
func (o *GetClusterResourcesOK) SetPayload(payload *models.ClusterResources) {
|
|
||||||
o.Payload = payload
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteResponse to the client
|
|
||||||
func (o *GetClusterResourcesOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
|
||||||
|
|
||||||
rw.WriteHeader(200)
|
|
||||||
if o.Payload != nil {
|
|
||||||
payload := o.Payload
|
|
||||||
if err := producer.Produce(rw, payload); err != nil {
|
|
||||||
panic(err) // let the recovery middleware deal with this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*GetClusterResourcesDefault Generic error response.
|
|
||||||
|
|
||||||
swagger:response getClusterResourcesDefault
|
|
||||||
*/
|
|
||||||
type GetClusterResourcesDefault struct {
|
|
||||||
_statusCode int
|
|
||||||
|
|
||||||
/*
|
|
||||||
In: Body
|
|
||||||
*/
|
|
||||||
Payload *models.Error `json:"body,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGetClusterResourcesDefault creates GetClusterResourcesDefault with default headers values
|
|
||||||
func NewGetClusterResourcesDefault(code int) *GetClusterResourcesDefault {
|
|
||||||
if code <= 0 {
|
|
||||||
code = 500
|
|
||||||
}
|
|
||||||
|
|
||||||
return &GetClusterResourcesDefault{
|
|
||||||
_statusCode: code,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithStatusCode adds the status to the get cluster resources default response
|
|
||||||
func (o *GetClusterResourcesDefault) WithStatusCode(code int) *GetClusterResourcesDefault {
|
|
||||||
o._statusCode = code
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetStatusCode sets the status to the get cluster resources default response
|
|
||||||
func (o *GetClusterResourcesDefault) SetStatusCode(code int) {
|
|
||||||
o._statusCode = code
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPayload adds the payload to the get cluster resources default response
|
|
||||||
func (o *GetClusterResourcesDefault) WithPayload(payload *models.Error) *GetClusterResourcesDefault {
|
|
||||||
o.Payload = payload
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPayload sets the payload to the get cluster resources default response
|
|
||||||
func (o *GetClusterResourcesDefault) SetPayload(payload *models.Error) {
|
|
||||||
o.Payload = payload
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteResponse to the client
|
|
||||||
func (o *GetClusterResourcesDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
|
||||||
|
|
||||||
rw.WriteHeader(o._statusCode)
|
|
||||||
if o.Payload != nil {
|
|
||||||
payload := o.Payload
|
|
||||||
if err := producer.Produce(rw, payload); err != nil {
|
|
||||||
panic(err) // let the recovery middleware deal with this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,40 +30,40 @@ import (
|
|||||||
"github.com/minio/console/models"
|
"github.com/minio/console/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetClusterResourcesHandlerFunc turns a function with the right signature into a get cluster resources handler
|
// GetMaxAllocatableMemHandlerFunc turns a function with the right signature into a get max allocatable mem handler
|
||||||
type GetClusterResourcesHandlerFunc func(GetClusterResourcesParams, *models.Principal) middleware.Responder
|
type GetMaxAllocatableMemHandlerFunc func(GetMaxAllocatableMemParams, *models.Principal) middleware.Responder
|
||||||
|
|
||||||
// Handle executing the request and returning a response
|
// Handle executing the request and returning a response
|
||||||
func (fn GetClusterResourcesHandlerFunc) Handle(params GetClusterResourcesParams, principal *models.Principal) middleware.Responder {
|
func (fn GetMaxAllocatableMemHandlerFunc) Handle(params GetMaxAllocatableMemParams, principal *models.Principal) middleware.Responder {
|
||||||
return fn(params, principal)
|
return fn(params, principal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClusterResourcesHandler interface for that can handle valid get cluster resources params
|
// GetMaxAllocatableMemHandler interface for that can handle valid get max allocatable mem params
|
||||||
type GetClusterResourcesHandler interface {
|
type GetMaxAllocatableMemHandler interface {
|
||||||
Handle(GetClusterResourcesParams, *models.Principal) middleware.Responder
|
Handle(GetMaxAllocatableMemParams, *models.Principal) middleware.Responder
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGetClusterResources creates a new http.Handler for the get cluster resources operation
|
// NewGetMaxAllocatableMem creates a new http.Handler for the get max allocatable mem operation
|
||||||
func NewGetClusterResources(ctx *middleware.Context, handler GetClusterResourcesHandler) *GetClusterResources {
|
func NewGetMaxAllocatableMem(ctx *middleware.Context, handler GetMaxAllocatableMemHandler) *GetMaxAllocatableMem {
|
||||||
return &GetClusterResources{Context: ctx, Handler: handler}
|
return &GetMaxAllocatableMem{Context: ctx, Handler: handler}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*GetClusterResources swagger:route GET /cluster/resources AdminAPI getClusterResources
|
/*GetMaxAllocatableMem swagger:route GET /cluster/max-allocatable-memory AdminAPI getMaxAllocatableMem
|
||||||
|
|
||||||
Get Cluster Resources
|
Get maximum allocatable memory for given number of nodes
|
||||||
|
|
||||||
*/
|
*/
|
||||||
type GetClusterResources struct {
|
type GetMaxAllocatableMem struct {
|
||||||
Context *middleware.Context
|
Context *middleware.Context
|
||||||
Handler GetClusterResourcesHandler
|
Handler GetMaxAllocatableMemHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *GetClusterResources) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
func (o *GetMaxAllocatableMem) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||||
if rCtx != nil {
|
if rCtx != nil {
|
||||||
r = rCtx
|
r = rCtx
|
||||||
}
|
}
|
||||||
var Params = NewGetClusterResourcesParams()
|
var Params = NewGetMaxAllocatableMemParams()
|
||||||
|
|
||||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
"github.com/go-openapi/runtime/middleware"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
|
"github.com/go-openapi/validate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewGetMaxAllocatableMemParams creates a new GetMaxAllocatableMemParams object
|
||||||
|
// no default values defined in spec.
|
||||||
|
func NewGetMaxAllocatableMemParams() GetMaxAllocatableMemParams {
|
||||||
|
|
||||||
|
return GetMaxAllocatableMemParams{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMaxAllocatableMemParams contains all the bound params for the get max allocatable mem operation
|
||||||
|
// typically these are obtained from a http.Request
|
||||||
|
//
|
||||||
|
// swagger:parameters GetMaxAllocatableMem
|
||||||
|
type GetMaxAllocatableMemParams struct {
|
||||||
|
|
||||||
|
// HTTP Request Object
|
||||||
|
HTTPRequest *http.Request `json:"-"`
|
||||||
|
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
Minimum: 1
|
||||||
|
In: query
|
||||||
|
*/
|
||||||
|
NumNodes int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||||
|
// for simple values it will use straight method calls.
|
||||||
|
//
|
||||||
|
// To ensure default values, the struct must have been initialized with NewGetMaxAllocatableMemParams() beforehand.
|
||||||
|
func (o *GetMaxAllocatableMemParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
o.HTTPRequest = r
|
||||||
|
|
||||||
|
qs := runtime.Values(r.URL.Query())
|
||||||
|
|
||||||
|
qNumNodes, qhkNumNodes, _ := qs.GetOK("num_nodes")
|
||||||
|
if err := o.bindNumNodes(qNumNodes, qhkNumNodes, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindNumNodes binds and validates parameter NumNodes from query.
|
||||||
|
func (o *GetMaxAllocatableMemParams) bindNumNodes(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
if !hasKey {
|
||||||
|
return errors.Required("num_nodes", "query", rawData)
|
||||||
|
}
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
// AllowEmptyValue: false
|
||||||
|
if err := validate.RequiredString("num_nodes", "query", raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := swag.ConvertInt32(raw)
|
||||||
|
if err != nil {
|
||||||
|
return errors.InvalidType("num_nodes", "query", "int32", raw)
|
||||||
|
}
|
||||||
|
o.NumNodes = value
|
||||||
|
|
||||||
|
if err := o.validateNumNodes(formats); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateNumNodes carries on validations for parameter NumNodes
|
||||||
|
func (o *GetMaxAllocatableMemParams) validateNumNodes(formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if err := validate.MinimumInt("num_nodes", "query", int64(o.NumNodes), 1, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetMaxAllocatableMemOKCode is the HTTP code returned for type GetMaxAllocatableMemOK
|
||||||
|
const GetMaxAllocatableMemOKCode int = 200
|
||||||
|
|
||||||
|
/*GetMaxAllocatableMemOK A successful response.
|
||||||
|
|
||||||
|
swagger:response getMaxAllocatableMemOK
|
||||||
|
*/
|
||||||
|
type GetMaxAllocatableMemOK struct {
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: Body
|
||||||
|
*/
|
||||||
|
Payload *models.MaxAllocatableMemResponse `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetMaxAllocatableMemOK creates GetMaxAllocatableMemOK with default headers values
|
||||||
|
func NewGetMaxAllocatableMemOK() *GetMaxAllocatableMemOK {
|
||||||
|
|
||||||
|
return &GetMaxAllocatableMemOK{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPayload adds the payload to the get max allocatable mem o k response
|
||||||
|
func (o *GetMaxAllocatableMemOK) WithPayload(payload *models.MaxAllocatableMemResponse) *GetMaxAllocatableMemOK {
|
||||||
|
o.Payload = payload
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPayload sets the payload to the get max allocatable mem o k response
|
||||||
|
func (o *GetMaxAllocatableMemOK) SetPayload(payload *models.MaxAllocatableMemResponse) {
|
||||||
|
o.Payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *GetMaxAllocatableMemOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||||
|
|
||||||
|
rw.WriteHeader(200)
|
||||||
|
if o.Payload != nil {
|
||||||
|
payload := o.Payload
|
||||||
|
if err := producer.Produce(rw, payload); err != nil {
|
||||||
|
panic(err) // let the recovery middleware deal with this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*GetMaxAllocatableMemDefault Generic error response.
|
||||||
|
|
||||||
|
swagger:response getMaxAllocatableMemDefault
|
||||||
|
*/
|
||||||
|
type GetMaxAllocatableMemDefault struct {
|
||||||
|
_statusCode int
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: Body
|
||||||
|
*/
|
||||||
|
Payload *models.Error `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetMaxAllocatableMemDefault creates GetMaxAllocatableMemDefault with default headers values
|
||||||
|
func NewGetMaxAllocatableMemDefault(code int) *GetMaxAllocatableMemDefault {
|
||||||
|
if code <= 0 {
|
||||||
|
code = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
return &GetMaxAllocatableMemDefault{
|
||||||
|
_statusCode: code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStatusCode adds the status to the get max allocatable mem default response
|
||||||
|
func (o *GetMaxAllocatableMemDefault) WithStatusCode(code int) *GetMaxAllocatableMemDefault {
|
||||||
|
o._statusCode = code
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStatusCode sets the status to the get max allocatable mem default response
|
||||||
|
func (o *GetMaxAllocatableMemDefault) SetStatusCode(code int) {
|
||||||
|
o._statusCode = code
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPayload adds the payload to the get max allocatable mem default response
|
||||||
|
func (o *GetMaxAllocatableMemDefault) WithPayload(payload *models.Error) *GetMaxAllocatableMemDefault {
|
||||||
|
o.Payload = payload
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPayload sets the payload to the get max allocatable mem default response
|
||||||
|
func (o *GetMaxAllocatableMemDefault) SetPayload(payload *models.Error) {
|
||||||
|
o.Payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *GetMaxAllocatableMemDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||||
|
|
||||||
|
rw.WriteHeader(o._statusCode)
|
||||||
|
if o.Payload != nil {
|
||||||
|
payload := o.Payload
|
||||||
|
if err := producer.Produce(rw, payload); err != nil {
|
||||||
|
panic(err) // let the recovery middleware deal with this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,17 +26,23 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
golangswaggerpaths "path"
|
golangswaggerpaths "path"
|
||||||
|
|
||||||
|
"github.com/go-openapi/swag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetClusterResourcesURL generates an URL for the get cluster resources operation
|
// GetMaxAllocatableMemURL generates an URL for the get max allocatable mem operation
|
||||||
type GetClusterResourcesURL struct {
|
type GetMaxAllocatableMemURL struct {
|
||||||
|
NumNodes int32
|
||||||
|
|
||||||
_basePath string
|
_basePath string
|
||||||
|
// avoid unkeyed usage
|
||||||
|
_ struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||||
// base path specified in the swagger spec.
|
// base path specified in the swagger spec.
|
||||||
// When the value of the base path is an empty string
|
// When the value of the base path is an empty string
|
||||||
func (o *GetClusterResourcesURL) WithBasePath(bp string) *GetClusterResourcesURL {
|
func (o *GetMaxAllocatableMemURL) WithBasePath(bp string) *GetMaxAllocatableMemURL {
|
||||||
o.SetBasePath(bp)
|
o.SetBasePath(bp)
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
@@ -44,15 +50,15 @@ func (o *GetClusterResourcesURL) WithBasePath(bp string) *GetClusterResourcesURL
|
|||||||
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||||
// base path specified in the swagger spec.
|
// base path specified in the swagger spec.
|
||||||
// When the value of the base path is an empty string
|
// When the value of the base path is an empty string
|
||||||
func (o *GetClusterResourcesURL) SetBasePath(bp string) {
|
func (o *GetMaxAllocatableMemURL) SetBasePath(bp string) {
|
||||||
o._basePath = bp
|
o._basePath = bp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a url path and query string
|
// Build a url path and query string
|
||||||
func (o *GetClusterResourcesURL) Build() (*url.URL, error) {
|
func (o *GetMaxAllocatableMemURL) Build() (*url.URL, error) {
|
||||||
var _result url.URL
|
var _result url.URL
|
||||||
|
|
||||||
var _path = "/cluster/resources"
|
var _path = "/cluster/max-allocatable-memory"
|
||||||
|
|
||||||
_basePath := o._basePath
|
_basePath := o._basePath
|
||||||
if _basePath == "" {
|
if _basePath == "" {
|
||||||
@@ -60,11 +66,20 @@ func (o *GetClusterResourcesURL) Build() (*url.URL, error) {
|
|||||||
}
|
}
|
||||||
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
||||||
|
|
||||||
|
qs := make(url.Values)
|
||||||
|
|
||||||
|
numNodesQ := swag.FormatInt32(o.NumNodes)
|
||||||
|
if numNodesQ != "" {
|
||||||
|
qs.Set("num_nodes", numNodesQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
_result.RawQuery = qs.Encode()
|
||||||
|
|
||||||
return &_result, nil
|
return &_result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must is a helper function to panic when the url builder returns an error
|
// Must is a helper function to panic when the url builder returns an error
|
||||||
func (o *GetClusterResourcesURL) Must(u *url.URL, err error) *url.URL {
|
func (o *GetMaxAllocatableMemURL) Must(u *url.URL, err error) *url.URL {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -75,17 +90,17 @@ func (o *GetClusterResourcesURL) Must(u *url.URL, err error) *url.URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of the path with query string
|
// String returns the string representation of the path with query string
|
||||||
func (o *GetClusterResourcesURL) String() string {
|
func (o *GetMaxAllocatableMemURL) String() string {
|
||||||
return o.Must(o.Build()).String()
|
return o.Must(o.Build()).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildFull builds a full url with scheme, host, path and query string
|
// BuildFull builds a full url with scheme, host, path and query string
|
||||||
func (o *GetClusterResourcesURL) BuildFull(scheme, host string) (*url.URL, error) {
|
func (o *GetMaxAllocatableMemURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||||
if scheme == "" {
|
if scheme == "" {
|
||||||
return nil, errors.New("scheme is required for a full url on GetClusterResourcesURL")
|
return nil, errors.New("scheme is required for a full url on GetMaxAllocatableMemURL")
|
||||||
}
|
}
|
||||||
if host == "" {
|
if host == "" {
|
||||||
return nil, errors.New("host is required for a full url on GetClusterResourcesURL")
|
return nil, errors.New("host is required for a full url on GetMaxAllocatableMemURL")
|
||||||
}
|
}
|
||||||
|
|
||||||
base, err := o.Build()
|
base, err := o.Build()
|
||||||
@@ -99,6 +114,6 @@ func (o *GetClusterResourcesURL) BuildFull(scheme, host string) (*url.URL, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StringFull returns the string representation of a complete url
|
// StringFull returns the string representation of a complete url
|
||||||
func (o *GetClusterResourcesURL) StringFull(scheme, host string) string {
|
func (o *GetMaxAllocatableMemURL) StringFull(scheme, host string) string {
|
||||||
return o.Must(o.BuildFull(scheme, host)).String()
|
return o.Must(o.BuildFull(scheme, host)).String()
|
||||||
}
|
}
|
||||||
90
restapi/operations/admin_api/tenant_update_certificate.go
Normal file
90
restapi/operations/admin_api/tenant_update_certificate.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime/middleware"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TenantUpdateCertificateHandlerFunc turns a function with the right signature into a tenant update certificate handler
|
||||||
|
type TenantUpdateCertificateHandlerFunc func(TenantUpdateCertificateParams, *models.Principal) middleware.Responder
|
||||||
|
|
||||||
|
// Handle executing the request and returning a response
|
||||||
|
func (fn TenantUpdateCertificateHandlerFunc) Handle(params TenantUpdateCertificateParams, principal *models.Principal) middleware.Responder {
|
||||||
|
return fn(params, principal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TenantUpdateCertificateHandler interface for that can handle valid tenant update certificate params
|
||||||
|
type TenantUpdateCertificateHandler interface {
|
||||||
|
Handle(TenantUpdateCertificateParams, *models.Principal) middleware.Responder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTenantUpdateCertificate creates a new http.Handler for the tenant update certificate operation
|
||||||
|
func NewTenantUpdateCertificate(ctx *middleware.Context, handler TenantUpdateCertificateHandler) *TenantUpdateCertificate {
|
||||||
|
return &TenantUpdateCertificate{Context: ctx, Handler: handler}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TenantUpdateCertificate swagger:route PUT /namespaces/{namespace}/tenants/{tenant}/certificates AdminAPI tenantUpdateCertificate
|
||||||
|
|
||||||
|
Tenant Update Certificates
|
||||||
|
|
||||||
|
*/
|
||||||
|
type TenantUpdateCertificate struct {
|
||||||
|
Context *middleware.Context
|
||||||
|
Handler TenantUpdateCertificateHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *TenantUpdateCertificate) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||||
|
if rCtx != nil {
|
||||||
|
r = rCtx
|
||||||
|
}
|
||||||
|
var Params = NewTenantUpdateCertificateParams()
|
||||||
|
|
||||||
|
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||||
|
if err != nil {
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if aCtx != nil {
|
||||||
|
r = aCtx
|
||||||
|
}
|
||||||
|
var principal *models.Principal
|
||||||
|
if uprinc != nil {
|
||||||
|
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res := o.Handler.Handle(Params, principal) // actually handle the request
|
||||||
|
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
"github.com/go-openapi/runtime/middleware"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewTenantUpdateCertificateParams creates a new TenantUpdateCertificateParams object
|
||||||
|
// no default values defined in spec.
|
||||||
|
func NewTenantUpdateCertificateParams() TenantUpdateCertificateParams {
|
||||||
|
|
||||||
|
return TenantUpdateCertificateParams{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TenantUpdateCertificateParams contains all the bound params for the tenant update certificate operation
|
||||||
|
// typically these are obtained from a http.Request
|
||||||
|
//
|
||||||
|
// swagger:parameters TenantUpdateCertificate
|
||||||
|
type TenantUpdateCertificateParams struct {
|
||||||
|
|
||||||
|
// HTTP Request Object
|
||||||
|
HTTPRequest *http.Request `json:"-"`
|
||||||
|
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
In: body
|
||||||
|
*/
|
||||||
|
Body *models.TLSConfiguration
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
In: path
|
||||||
|
*/
|
||||||
|
Namespace string
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
In: path
|
||||||
|
*/
|
||||||
|
Tenant string
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||||
|
// for simple values it will use straight method calls.
|
||||||
|
//
|
||||||
|
// To ensure default values, the struct must have been initialized with NewTenantUpdateCertificateParams() beforehand.
|
||||||
|
func (o *TenantUpdateCertificateParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
o.HTTPRequest = r
|
||||||
|
|
||||||
|
if runtime.HasBody(r) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
var body models.TLSConfiguration
|
||||||
|
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
res = append(res, errors.Required("body", "body", ""))
|
||||||
|
} else {
|
||||||
|
res = append(res, errors.NewParseError("body", "body", "", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// validate body object
|
||||||
|
if err := body.Validate(route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) == 0 {
|
||||||
|
o.Body = &body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = append(res, errors.Required("body", "body", ""))
|
||||||
|
}
|
||||||
|
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
|
||||||
|
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
|
||||||
|
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindNamespace binds and validates parameter Namespace from path.
|
||||||
|
func (o *TenantUpdateCertificateParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
// Parameter is provided by construction from the route
|
||||||
|
|
||||||
|
o.Namespace = raw
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindTenant binds and validates parameter Tenant from path.
|
||||||
|
func (o *TenantUpdateCertificateParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
// Parameter is provided by construction from the route
|
||||||
|
|
||||||
|
o.Tenant = raw
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TenantUpdateCertificateCreatedCode is the HTTP code returned for type TenantUpdateCertificateCreated
|
||||||
|
const TenantUpdateCertificateCreatedCode int = 201
|
||||||
|
|
||||||
|
/*TenantUpdateCertificateCreated A successful response.
|
||||||
|
|
||||||
|
swagger:response tenantUpdateCertificateCreated
|
||||||
|
*/
|
||||||
|
type TenantUpdateCertificateCreated struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTenantUpdateCertificateCreated creates TenantUpdateCertificateCreated with default headers values
|
||||||
|
func NewTenantUpdateCertificateCreated() *TenantUpdateCertificateCreated {
|
||||||
|
|
||||||
|
return &TenantUpdateCertificateCreated{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *TenantUpdateCertificateCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||||
|
|
||||||
|
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
|
||||||
|
|
||||||
|
rw.WriteHeader(201)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TenantUpdateCertificateDefault Generic error response.
|
||||||
|
|
||||||
|
swagger:response tenantUpdateCertificateDefault
|
||||||
|
*/
|
||||||
|
type TenantUpdateCertificateDefault struct {
|
||||||
|
_statusCode int
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: Body
|
||||||
|
*/
|
||||||
|
Payload *models.Error `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTenantUpdateCertificateDefault creates TenantUpdateCertificateDefault with default headers values
|
||||||
|
func NewTenantUpdateCertificateDefault(code int) *TenantUpdateCertificateDefault {
|
||||||
|
if code <= 0 {
|
||||||
|
code = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TenantUpdateCertificateDefault{
|
||||||
|
_statusCode: code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStatusCode adds the status to the tenant update certificate default response
|
||||||
|
func (o *TenantUpdateCertificateDefault) WithStatusCode(code int) *TenantUpdateCertificateDefault {
|
||||||
|
o._statusCode = code
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStatusCode sets the status to the tenant update certificate default response
|
||||||
|
func (o *TenantUpdateCertificateDefault) SetStatusCode(code int) {
|
||||||
|
o._statusCode = code
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPayload adds the payload to the tenant update certificate default response
|
||||||
|
func (o *TenantUpdateCertificateDefault) WithPayload(payload *models.Error) *TenantUpdateCertificateDefault {
|
||||||
|
o.Payload = payload
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPayload sets the payload to the tenant update certificate default response
|
||||||
|
func (o *TenantUpdateCertificateDefault) SetPayload(payload *models.Error) {
|
||||||
|
o.Payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *TenantUpdateCertificateDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||||
|
|
||||||
|
rw.WriteHeader(o._statusCode)
|
||||||
|
if o.Payload != nil {
|
||||||
|
payload := o.Payload
|
||||||
|
if err := producer.Produce(rw, payload); err != nil {
|
||||||
|
panic(err) // let the recovery middleware deal with this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
golangswaggerpaths "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TenantUpdateCertificateURL generates an URL for the tenant update certificate operation
|
||||||
|
type TenantUpdateCertificateURL struct {
|
||||||
|
Namespace string
|
||||||
|
Tenant string
|
||||||
|
|
||||||
|
_basePath string
|
||||||
|
// avoid unkeyed usage
|
||||||
|
_ struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||||
|
// base path specified in the swagger spec.
|
||||||
|
// When the value of the base path is an empty string
|
||||||
|
func (o *TenantUpdateCertificateURL) WithBasePath(bp string) *TenantUpdateCertificateURL {
|
||||||
|
o.SetBasePath(bp)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||||
|
// base path specified in the swagger spec.
|
||||||
|
// When the value of the base path is an empty string
|
||||||
|
func (o *TenantUpdateCertificateURL) SetBasePath(bp string) {
|
||||||
|
o._basePath = bp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a url path and query string
|
||||||
|
func (o *TenantUpdateCertificateURL) Build() (*url.URL, error) {
|
||||||
|
var _result url.URL
|
||||||
|
|
||||||
|
var _path = "/namespaces/{namespace}/tenants/{tenant}/certificates"
|
||||||
|
|
||||||
|
namespace := o.Namespace
|
||||||
|
if namespace != "" {
|
||||||
|
_path = strings.Replace(_path, "{namespace}", namespace, -1)
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("namespace is required on TenantUpdateCertificateURL")
|
||||||
|
}
|
||||||
|
|
||||||
|
tenant := o.Tenant
|
||||||
|
if tenant != "" {
|
||||||
|
_path = strings.Replace(_path, "{tenant}", tenant, -1)
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("tenant is required on TenantUpdateCertificateURL")
|
||||||
|
}
|
||||||
|
|
||||||
|
_basePath := o._basePath
|
||||||
|
if _basePath == "" {
|
||||||
|
_basePath = "/api/v1"
|
||||||
|
}
|
||||||
|
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
||||||
|
|
||||||
|
return &_result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must is a helper function to panic when the url builder returns an error
|
||||||
|
func (o *TenantUpdateCertificateURL) Must(u *url.URL, err error) *url.URL {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if u == nil {
|
||||||
|
panic("url can't be nil")
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the path with query string
|
||||||
|
func (o *TenantUpdateCertificateURL) String() string {
|
||||||
|
return o.Must(o.Build()).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildFull builds a full url with scheme, host, path and query string
|
||||||
|
func (o *TenantUpdateCertificateURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||||
|
if scheme == "" {
|
||||||
|
return nil, errors.New("scheme is required for a full url on TenantUpdateCertificateURL")
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
return nil, errors.New("host is required for a full url on TenantUpdateCertificateURL")
|
||||||
|
}
|
||||||
|
|
||||||
|
base, err := o.Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Scheme = scheme
|
||||||
|
base.Host = host
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringFull returns the string representation of a complete url
|
||||||
|
func (o *TenantUpdateCertificateURL) StringFull(scheme, host string) string {
|
||||||
|
return o.Must(o.BuildFull(scheme, host)).String()
|
||||||
|
}
|
||||||
90
restapi/operations/admin_api/tenant_update_encryption.go
Normal file
90
restapi/operations/admin_api/tenant_update_encryption.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime/middleware"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TenantUpdateEncryptionHandlerFunc turns a function with the right signature into a tenant update encryption handler
|
||||||
|
type TenantUpdateEncryptionHandlerFunc func(TenantUpdateEncryptionParams, *models.Principal) middleware.Responder
|
||||||
|
|
||||||
|
// Handle executing the request and returning a response
|
||||||
|
func (fn TenantUpdateEncryptionHandlerFunc) Handle(params TenantUpdateEncryptionParams, principal *models.Principal) middleware.Responder {
|
||||||
|
return fn(params, principal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TenantUpdateEncryptionHandler interface for that can handle valid tenant update encryption params
|
||||||
|
type TenantUpdateEncryptionHandler interface {
|
||||||
|
Handle(TenantUpdateEncryptionParams, *models.Principal) middleware.Responder
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTenantUpdateEncryption creates a new http.Handler for the tenant update encryption operation
|
||||||
|
func NewTenantUpdateEncryption(ctx *middleware.Context, handler TenantUpdateEncryptionHandler) *TenantUpdateEncryption {
|
||||||
|
return &TenantUpdateEncryption{Context: ctx, Handler: handler}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TenantUpdateEncryption swagger:route PUT /namespaces/{namespace}/tenants/{tenant}/encryption AdminAPI tenantUpdateEncryption
|
||||||
|
|
||||||
|
Tenant Update Encryption
|
||||||
|
|
||||||
|
*/
|
||||||
|
type TenantUpdateEncryption struct {
|
||||||
|
Context *middleware.Context
|
||||||
|
Handler TenantUpdateEncryptionHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *TenantUpdateEncryption) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||||
|
if rCtx != nil {
|
||||||
|
r = rCtx
|
||||||
|
}
|
||||||
|
var Params = NewTenantUpdateEncryptionParams()
|
||||||
|
|
||||||
|
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||||
|
if err != nil {
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if aCtx != nil {
|
||||||
|
r = aCtx
|
||||||
|
}
|
||||||
|
var principal *models.Principal
|
||||||
|
if uprinc != nil {
|
||||||
|
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res := o.Handler.Handle(Params, principal) // actually handle the request
|
||||||
|
|
||||||
|
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/errors"
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
"github.com/go-openapi/runtime/middleware"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewTenantUpdateEncryptionParams creates a new TenantUpdateEncryptionParams object
|
||||||
|
// no default values defined in spec.
|
||||||
|
func NewTenantUpdateEncryptionParams() TenantUpdateEncryptionParams {
|
||||||
|
|
||||||
|
return TenantUpdateEncryptionParams{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TenantUpdateEncryptionParams contains all the bound params for the tenant update encryption operation
|
||||||
|
// typically these are obtained from a http.Request
|
||||||
|
//
|
||||||
|
// swagger:parameters TenantUpdateEncryption
|
||||||
|
type TenantUpdateEncryptionParams struct {
|
||||||
|
|
||||||
|
// HTTP Request Object
|
||||||
|
HTTPRequest *http.Request `json:"-"`
|
||||||
|
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
In: body
|
||||||
|
*/
|
||||||
|
Body *models.EncryptionConfiguration
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
In: path
|
||||||
|
*/
|
||||||
|
Namespace string
|
||||||
|
/*
|
||||||
|
Required: true
|
||||||
|
In: path
|
||||||
|
*/
|
||||||
|
Tenant string
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||||
|
// for simple values it will use straight method calls.
|
||||||
|
//
|
||||||
|
// To ensure default values, the struct must have been initialized with NewTenantUpdateEncryptionParams() beforehand.
|
||||||
|
func (o *TenantUpdateEncryptionParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||||
|
var res []error
|
||||||
|
|
||||||
|
o.HTTPRequest = r
|
||||||
|
|
||||||
|
if runtime.HasBody(r) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
var body models.EncryptionConfiguration
|
||||||
|
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
res = append(res, errors.Required("body", "body", ""))
|
||||||
|
} else {
|
||||||
|
res = append(res, errors.NewParseError("body", "body", "", err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// validate body object
|
||||||
|
if err := body.Validate(route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) == 0 {
|
||||||
|
o.Body = &body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = append(res, errors.Required("body", "body", ""))
|
||||||
|
}
|
||||||
|
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
|
||||||
|
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
|
||||||
|
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return errors.CompositeValidationError(res...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindNamespace binds and validates parameter Namespace from path.
|
||||||
|
func (o *TenantUpdateEncryptionParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
// Parameter is provided by construction from the route
|
||||||
|
|
||||||
|
o.Namespace = raw
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindTenant binds and validates parameter Tenant from path.
|
||||||
|
func (o *TenantUpdateEncryptionParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
|
var raw string
|
||||||
|
if len(rawData) > 0 {
|
||||||
|
raw = rawData[len(rawData)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: true
|
||||||
|
// Parameter is provided by construction from the route
|
||||||
|
|
||||||
|
o.Tenant = raw
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the swagger generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
|
||||||
|
"github.com/minio/console/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TenantUpdateEncryptionCreatedCode is the HTTP code returned for type TenantUpdateEncryptionCreated
|
||||||
|
const TenantUpdateEncryptionCreatedCode int = 201
|
||||||
|
|
||||||
|
/*TenantUpdateEncryptionCreated A successful response.
|
||||||
|
|
||||||
|
swagger:response tenantUpdateEncryptionCreated
|
||||||
|
*/
|
||||||
|
type TenantUpdateEncryptionCreated struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTenantUpdateEncryptionCreated creates TenantUpdateEncryptionCreated with default headers values
|
||||||
|
func NewTenantUpdateEncryptionCreated() *TenantUpdateEncryptionCreated {
|
||||||
|
|
||||||
|
return &TenantUpdateEncryptionCreated{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *TenantUpdateEncryptionCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||||
|
|
||||||
|
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
|
||||||
|
|
||||||
|
rw.WriteHeader(201)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TenantUpdateEncryptionDefault Generic error response.
|
||||||
|
|
||||||
|
swagger:response tenantUpdateEncryptionDefault
|
||||||
|
*/
|
||||||
|
type TenantUpdateEncryptionDefault struct {
|
||||||
|
_statusCode int
|
||||||
|
|
||||||
|
/*
|
||||||
|
In: Body
|
||||||
|
*/
|
||||||
|
Payload *models.Error `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTenantUpdateEncryptionDefault creates TenantUpdateEncryptionDefault with default headers values
|
||||||
|
func NewTenantUpdateEncryptionDefault(code int) *TenantUpdateEncryptionDefault {
|
||||||
|
if code <= 0 {
|
||||||
|
code = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TenantUpdateEncryptionDefault{
|
||||||
|
_statusCode: code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStatusCode adds the status to the tenant update encryption default response
|
||||||
|
func (o *TenantUpdateEncryptionDefault) WithStatusCode(code int) *TenantUpdateEncryptionDefault {
|
||||||
|
o._statusCode = code
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStatusCode sets the status to the tenant update encryption default response
|
||||||
|
func (o *TenantUpdateEncryptionDefault) SetStatusCode(code int) {
|
||||||
|
o._statusCode = code
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPayload adds the payload to the tenant update encryption default response
|
||||||
|
func (o *TenantUpdateEncryptionDefault) WithPayload(payload *models.Error) *TenantUpdateEncryptionDefault {
|
||||||
|
o.Payload = payload
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPayload sets the payload to the tenant update encryption default response
|
||||||
|
func (o *TenantUpdateEncryptionDefault) SetPayload(payload *models.Error) {
|
||||||
|
o.Payload = payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteResponse to the client
|
||||||
|
func (o *TenantUpdateEncryptionDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||||
|
|
||||||
|
rw.WriteHeader(o._statusCode)
|
||||||
|
if o.Payload != nil {
|
||||||
|
payload := o.Payload
|
||||||
|
if err := producer.Produce(rw, payload); err != nil {
|
||||||
|
panic(err) // let the recovery middleware deal with this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
// Code generated by go-swagger; DO NOT EDIT.
|
||||||
|
|
||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2020 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
package admin_api
|
||||||
|
|
||||||
|
// This file was generated by the swagger tool.
|
||||||
|
// Editing this file might prove futile when you re-run the generate command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
golangswaggerpaths "path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TenantUpdateEncryptionURL generates an URL for the tenant update encryption operation
|
||||||
|
type TenantUpdateEncryptionURL struct {
|
||||||
|
Namespace string
|
||||||
|
Tenant string
|
||||||
|
|
||||||
|
_basePath string
|
||||||
|
// avoid unkeyed usage
|
||||||
|
_ struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||||
|
// base path specified in the swagger spec.
|
||||||
|
// When the value of the base path is an empty string
|
||||||
|
func (o *TenantUpdateEncryptionURL) WithBasePath(bp string) *TenantUpdateEncryptionURL {
|
||||||
|
o.SetBasePath(bp)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||||
|
// base path specified in the swagger spec.
|
||||||
|
// When the value of the base path is an empty string
|
||||||
|
func (o *TenantUpdateEncryptionURL) SetBasePath(bp string) {
|
||||||
|
o._basePath = bp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a url path and query string
|
||||||
|
func (o *TenantUpdateEncryptionURL) Build() (*url.URL, error) {
|
||||||
|
var _result url.URL
|
||||||
|
|
||||||
|
var _path = "/namespaces/{namespace}/tenants/{tenant}/encryption"
|
||||||
|
|
||||||
|
namespace := o.Namespace
|
||||||
|
if namespace != "" {
|
||||||
|
_path = strings.Replace(_path, "{namespace}", namespace, -1)
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("namespace is required on TenantUpdateEncryptionURL")
|
||||||
|
}
|
||||||
|
|
||||||
|
tenant := o.Tenant
|
||||||
|
if tenant != "" {
|
||||||
|
_path = strings.Replace(_path, "{tenant}", tenant, -1)
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("tenant is required on TenantUpdateEncryptionURL")
|
||||||
|
}
|
||||||
|
|
||||||
|
_basePath := o._basePath
|
||||||
|
if _basePath == "" {
|
||||||
|
_basePath = "/api/v1"
|
||||||
|
}
|
||||||
|
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
||||||
|
|
||||||
|
return &_result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must is a helper function to panic when the url builder returns an error
|
||||||
|
func (o *TenantUpdateEncryptionURL) Must(u *url.URL, err error) *url.URL {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if u == nil {
|
||||||
|
panic("url can't be nil")
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the path with query string
|
||||||
|
func (o *TenantUpdateEncryptionURL) String() string {
|
||||||
|
return o.Must(o.Build()).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildFull builds a full url with scheme, host, path and query string
|
||||||
|
func (o *TenantUpdateEncryptionURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||||
|
if scheme == "" {
|
||||||
|
return nil, errors.New("scheme is required for a full url on TenantUpdateEncryptionURL")
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
return nil, errors.New("host is required for a full url on TenantUpdateEncryptionURL")
|
||||||
|
}
|
||||||
|
|
||||||
|
base, err := o.Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Scheme = scheme
|
||||||
|
base.Host = host
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringFull returns the string representation of a complete url
|
||||||
|
func (o *TenantUpdateEncryptionURL) StringFull(scheme, host string) string {
|
||||||
|
return o.Must(o.BuildFull(scheme, host)).String()
|
||||||
|
}
|
||||||
@@ -114,8 +114,8 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
|
|||||||
AdminAPIDeleteTenantHandler: admin_api.DeleteTenantHandlerFunc(func(params admin_api.DeleteTenantParams, principal *models.Principal) middleware.Responder {
|
AdminAPIDeleteTenantHandler: admin_api.DeleteTenantHandlerFunc(func(params admin_api.DeleteTenantParams, principal *models.Principal) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation admin_api.DeleteTenant has not yet been implemented")
|
return middleware.NotImplemented("operation admin_api.DeleteTenant has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
AdminAPIGetClusterResourcesHandler: admin_api.GetClusterResourcesHandlerFunc(func(params admin_api.GetClusterResourcesParams, principal *models.Principal) middleware.Responder {
|
AdminAPIGetMaxAllocatableMemHandler: admin_api.GetMaxAllocatableMemHandlerFunc(func(params admin_api.GetMaxAllocatableMemParams, principal *models.Principal) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation admin_api.GetClusterResources has not yet been implemented")
|
return middleware.NotImplemented("operation admin_api.GetMaxAllocatableMem has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
AdminAPIGetResourceQuotaHandler: admin_api.GetResourceQuotaHandlerFunc(func(params admin_api.GetResourceQuotaParams, principal *models.Principal) middleware.Responder {
|
AdminAPIGetResourceQuotaHandler: admin_api.GetResourceQuotaHandlerFunc(func(params admin_api.GetResourceQuotaParams, principal *models.Principal) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation admin_api.GetResourceQuota has not yet been implemented")
|
return middleware.NotImplemented("operation admin_api.GetResourceQuota has not yet been implemented")
|
||||||
@@ -213,6 +213,12 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
|
|||||||
AdminAPITenantInfoHandler: admin_api.TenantInfoHandlerFunc(func(params admin_api.TenantInfoParams, principal *models.Principal) middleware.Responder {
|
AdminAPITenantInfoHandler: admin_api.TenantInfoHandlerFunc(func(params admin_api.TenantInfoParams, principal *models.Principal) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation admin_api.TenantInfo has not yet been implemented")
|
return middleware.NotImplemented("operation admin_api.TenantInfo has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
|
AdminAPITenantUpdateCertificateHandler: admin_api.TenantUpdateCertificateHandlerFunc(func(params admin_api.TenantUpdateCertificateParams, principal *models.Principal) middleware.Responder {
|
||||||
|
return middleware.NotImplemented("operation admin_api.TenantUpdateCertificate has not yet been implemented")
|
||||||
|
}),
|
||||||
|
AdminAPITenantUpdateEncryptionHandler: admin_api.TenantUpdateEncryptionHandlerFunc(func(params admin_api.TenantUpdateEncryptionParams, principal *models.Principal) middleware.Responder {
|
||||||
|
return middleware.NotImplemented("operation admin_api.TenantUpdateEncryption has not yet been implemented")
|
||||||
|
}),
|
||||||
AdminAPITenantUpdateZonesHandler: admin_api.TenantUpdateZonesHandlerFunc(func(params admin_api.TenantUpdateZonesParams, principal *models.Principal) middleware.Responder {
|
AdminAPITenantUpdateZonesHandler: admin_api.TenantUpdateZonesHandlerFunc(func(params admin_api.TenantUpdateZonesParams, principal *models.Principal) middleware.Responder {
|
||||||
return middleware.NotImplemented("operation admin_api.TenantUpdateZones has not yet been implemented")
|
return middleware.NotImplemented("operation admin_api.TenantUpdateZones has not yet been implemented")
|
||||||
}),
|
}),
|
||||||
@@ -311,8 +317,8 @@ type ConsoleAPI struct {
|
|||||||
UserAPIDeleteServiceAccountHandler user_api.DeleteServiceAccountHandler
|
UserAPIDeleteServiceAccountHandler user_api.DeleteServiceAccountHandler
|
||||||
// AdminAPIDeleteTenantHandler sets the operation handler for the delete tenant operation
|
// AdminAPIDeleteTenantHandler sets the operation handler for the delete tenant operation
|
||||||
AdminAPIDeleteTenantHandler admin_api.DeleteTenantHandler
|
AdminAPIDeleteTenantHandler admin_api.DeleteTenantHandler
|
||||||
// AdminAPIGetClusterResourcesHandler sets the operation handler for the get cluster resources operation
|
// AdminAPIGetMaxAllocatableMemHandler sets the operation handler for the get max allocatable mem operation
|
||||||
AdminAPIGetClusterResourcesHandler admin_api.GetClusterResourcesHandler
|
AdminAPIGetMaxAllocatableMemHandler admin_api.GetMaxAllocatableMemHandler
|
||||||
// AdminAPIGetResourceQuotaHandler sets the operation handler for the get resource quota operation
|
// AdminAPIGetResourceQuotaHandler sets the operation handler for the get resource quota operation
|
||||||
AdminAPIGetResourceQuotaHandler admin_api.GetResourceQuotaHandler
|
AdminAPIGetResourceQuotaHandler admin_api.GetResourceQuotaHandler
|
||||||
// AdminAPIGetTenantUsageHandler sets the operation handler for the get tenant usage operation
|
// AdminAPIGetTenantUsageHandler sets the operation handler for the get tenant usage operation
|
||||||
@@ -377,6 +383,10 @@ type ConsoleAPI struct {
|
|||||||
AdminAPITenantAddZoneHandler admin_api.TenantAddZoneHandler
|
AdminAPITenantAddZoneHandler admin_api.TenantAddZoneHandler
|
||||||
// AdminAPITenantInfoHandler sets the operation handler for the tenant info operation
|
// AdminAPITenantInfoHandler sets the operation handler for the tenant info operation
|
||||||
AdminAPITenantInfoHandler admin_api.TenantInfoHandler
|
AdminAPITenantInfoHandler admin_api.TenantInfoHandler
|
||||||
|
// AdminAPITenantUpdateCertificateHandler sets the operation handler for the tenant update certificate operation
|
||||||
|
AdminAPITenantUpdateCertificateHandler admin_api.TenantUpdateCertificateHandler
|
||||||
|
// AdminAPITenantUpdateEncryptionHandler sets the operation handler for the tenant update encryption operation
|
||||||
|
AdminAPITenantUpdateEncryptionHandler admin_api.TenantUpdateEncryptionHandler
|
||||||
// AdminAPITenantUpdateZonesHandler sets the operation handler for the tenant update zones operation
|
// AdminAPITenantUpdateZonesHandler sets the operation handler for the tenant update zones operation
|
||||||
AdminAPITenantUpdateZonesHandler admin_api.TenantUpdateZonesHandler
|
AdminAPITenantUpdateZonesHandler admin_api.TenantUpdateZonesHandler
|
||||||
// AdminAPIUpdateGroupHandler sets the operation handler for the update group operation
|
// AdminAPIUpdateGroupHandler sets the operation handler for the update group operation
|
||||||
@@ -511,8 +521,8 @@ func (o *ConsoleAPI) Validate() error {
|
|||||||
if o.AdminAPIDeleteTenantHandler == nil {
|
if o.AdminAPIDeleteTenantHandler == nil {
|
||||||
unregistered = append(unregistered, "admin_api.DeleteTenantHandler")
|
unregistered = append(unregistered, "admin_api.DeleteTenantHandler")
|
||||||
}
|
}
|
||||||
if o.AdminAPIGetClusterResourcesHandler == nil {
|
if o.AdminAPIGetMaxAllocatableMemHandler == nil {
|
||||||
unregistered = append(unregistered, "admin_api.GetClusterResourcesHandler")
|
unregistered = append(unregistered, "admin_api.GetMaxAllocatableMemHandler")
|
||||||
}
|
}
|
||||||
if o.AdminAPIGetResourceQuotaHandler == nil {
|
if o.AdminAPIGetResourceQuotaHandler == nil {
|
||||||
unregistered = append(unregistered, "admin_api.GetResourceQuotaHandler")
|
unregistered = append(unregistered, "admin_api.GetResourceQuotaHandler")
|
||||||
@@ -610,6 +620,12 @@ func (o *ConsoleAPI) Validate() error {
|
|||||||
if o.AdminAPITenantInfoHandler == nil {
|
if o.AdminAPITenantInfoHandler == nil {
|
||||||
unregistered = append(unregistered, "admin_api.TenantInfoHandler")
|
unregistered = append(unregistered, "admin_api.TenantInfoHandler")
|
||||||
}
|
}
|
||||||
|
if o.AdminAPITenantUpdateCertificateHandler == nil {
|
||||||
|
unregistered = append(unregistered, "admin_api.TenantUpdateCertificateHandler")
|
||||||
|
}
|
||||||
|
if o.AdminAPITenantUpdateEncryptionHandler == nil {
|
||||||
|
unregistered = append(unregistered, "admin_api.TenantUpdateEncryptionHandler")
|
||||||
|
}
|
||||||
if o.AdminAPITenantUpdateZonesHandler == nil {
|
if o.AdminAPITenantUpdateZonesHandler == nil {
|
||||||
unregistered = append(unregistered, "admin_api.TenantUpdateZonesHandler")
|
unregistered = append(unregistered, "admin_api.TenantUpdateZonesHandler")
|
||||||
}
|
}
|
||||||
@@ -796,7 +812,7 @@ func (o *ConsoleAPI) initHandlerCache() {
|
|||||||
if o.handlers["GET"] == nil {
|
if o.handlers["GET"] == nil {
|
||||||
o.handlers["GET"] = make(map[string]http.Handler)
|
o.handlers["GET"] = make(map[string]http.Handler)
|
||||||
}
|
}
|
||||||
o.handlers["GET"]["/cluster/resources"] = admin_api.NewGetClusterResources(o.context, o.AdminAPIGetClusterResourcesHandler)
|
o.handlers["GET"]["/cluster/max-allocatable-memory"] = admin_api.NewGetMaxAllocatableMem(o.context, o.AdminAPIGetMaxAllocatableMemHandler)
|
||||||
if o.handlers["GET"] == nil {
|
if o.handlers["GET"] == nil {
|
||||||
o.handlers["GET"] = make(map[string]http.Handler)
|
o.handlers["GET"] = make(map[string]http.Handler)
|
||||||
}
|
}
|
||||||
@@ -928,6 +944,14 @@ func (o *ConsoleAPI) initHandlerCache() {
|
|||||||
if o.handlers["PUT"] == nil {
|
if o.handlers["PUT"] == nil {
|
||||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||||
}
|
}
|
||||||
|
o.handlers["PUT"]["/namespaces/{namespace}/tenants/{tenant}/certificates"] = admin_api.NewTenantUpdateCertificate(o.context, o.AdminAPITenantUpdateCertificateHandler)
|
||||||
|
if o.handlers["PUT"] == nil {
|
||||||
|
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||||
|
}
|
||||||
|
o.handlers["PUT"]["/namespaces/{namespace}/tenants/{tenant}/encryption"] = admin_api.NewTenantUpdateEncryption(o.context, o.AdminAPITenantUpdateEncryptionHandler)
|
||||||
|
if o.handlers["PUT"] == nil {
|
||||||
|
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||||
|
}
|
||||||
o.handlers["PUT"]["/namespaces/{namespace}/tenants/{tenant}/zones"] = admin_api.NewTenantUpdateZones(o.context, o.AdminAPITenantUpdateZonesHandler)
|
o.handlers["PUT"]["/namespaces/{namespace}/tenants/{tenant}/zones"] = admin_api.NewTenantUpdateZones(o.context, o.AdminAPITenantUpdateZonesHandler)
|
||||||
if o.handlers["PUT"] == nil {
|
if o.handlers["PUT"] == nil {
|
||||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ import (
|
|||||||
types "k8s.io/apimachinery/pkg/types"
|
types "k8s.io/apimachinery/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OperatorClient interface with all functions to be implemented
|
// OperatorClientI interface with all functions to be implemented
|
||||||
// by mock when testing, it should include all OperatorClient respective api calls
|
// by mock when testing, it should include all OperatorClientI respective api calls
|
||||||
// that are used within this project.
|
// that are used within this project.
|
||||||
type OperatorClient interface {
|
type OperatorClientI interface {
|
||||||
TenantDelete(ctx context.Context, namespace string, instanceName string, options metav1.DeleteOptions) error
|
TenantDelete(ctx context.Context, namespace string, instanceName string, options metav1.DeleteOptions) error
|
||||||
TenantGet(ctx context.Context, namespace string, instanceName string, options metav1.GetOptions) (*v1.Tenant, error)
|
TenantGet(ctx context.Context, namespace string, instanceName string, options metav1.GetOptions) (*v1.Tenant, error)
|
||||||
TenantPatch(ctx context.Context, namespace string, instanceName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error)
|
TenantPatch(ctx context.Context, namespace string, instanceName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func registerResourceQuotaHandlers(api *operations.ConsoleAPI) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getResourceQuota(ctx context.Context, client K8sClient, namespace, resourcequota string) (*models.ResourceQuota, error) {
|
func getResourceQuota(ctx context.Context, client K8sClientI, namespace, resourcequota string) (*models.ResourceQuota, error) {
|
||||||
resourceQuota, err := client.getResourceQuota(ctx, namespace, resourcequota, metav1.GetOptions{})
|
resourceQuota, err := client.getResourceQuota(ctx, namespace, resourcequota, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ func Test_ResourceQuota(t *testing.T) {
|
|||||||
kClient := k8sClientMock{}
|
kClient := k8sClientMock{}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
client K8sClient
|
client K8sClientI
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
119
swagger.yml
119
swagger.yml
@@ -1202,6 +1202,62 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- AdminAPI
|
- AdminAPI
|
||||||
|
|
||||||
|
/namespaces/{namespace}/tenants/{tenant}/certificates:
|
||||||
|
put:
|
||||||
|
summary: Tenant Update Certificates
|
||||||
|
operationId: TenantUpdateCertificate
|
||||||
|
parameters:
|
||||||
|
- name: namespace
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- name: tenant
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- name: body
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/tlsConfiguration"
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: A successful response.
|
||||||
|
default:
|
||||||
|
description: Generic error response.
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/error"
|
||||||
|
tags:
|
||||||
|
- AdminAPI
|
||||||
|
|
||||||
|
/namespaces/{namespace}/tenants/{tenant}/encryption:
|
||||||
|
put:
|
||||||
|
summary: Tenant Update Encryption
|
||||||
|
operationId: TenantUpdateEncryption
|
||||||
|
parameters:
|
||||||
|
- name: namespace
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- name: tenant
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- name: body
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/encryptionConfiguration"
|
||||||
|
responses:
|
||||||
|
201:
|
||||||
|
description: A successful response.
|
||||||
|
default:
|
||||||
|
description: Generic error response.
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/error"
|
||||||
|
tags:
|
||||||
|
- AdminAPI
|
||||||
|
|
||||||
/namespaces/{namespace}/resourcequotas/{resource-quota-name}:
|
/namespaces/{namespace}/resourcequotas/{resource-quota-name}:
|
||||||
get:
|
get:
|
||||||
summary: Get Resource Quota
|
summary: Get Resource Quota
|
||||||
@@ -1227,15 +1283,22 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- AdminAPI
|
- AdminAPI
|
||||||
|
|
||||||
/cluster/resources:
|
/cluster/max-allocatable-memory:
|
||||||
get:
|
get:
|
||||||
summary: Get Cluster Resources
|
summary: Get maximum allocatable memory for given number of nodes
|
||||||
operationId: GetClusterResources
|
operationId: GetMaxAllocatableMem
|
||||||
|
parameters:
|
||||||
|
- name: num_nodes
|
||||||
|
in: query
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
minimum: 1
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: A successful response.
|
description: A successful response.
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/clusterResources"
|
$ref: "#/definitions/maxAllocatableMemResponse"
|
||||||
default:
|
default:
|
||||||
description: Generic error response.
|
description: Generic error response.
|
||||||
schema:
|
schema:
|
||||||
@@ -2589,50 +2652,10 @@ definitions:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/zone"
|
$ref: "#/definitions/zone"
|
||||||
|
|
||||||
clusterResources:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
nodes:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/nodeInfo"
|
|
||||||
|
|
||||||
nodeInfo:
|
maxAllocatableMemResponse:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
name:
|
max_memory:
|
||||||
type: string
|
type: integer
|
||||||
taints:
|
format: int64
|
||||||
$ref: "#/definitions/nodeTaints"
|
|
||||||
allocatable_resources:
|
|
||||||
type: object
|
|
||||||
additionalProperties:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
description: Represents the resources of a node that are available for scheduling.
|
|
||||||
total_resources:
|
|
||||||
type: object
|
|
||||||
additionalProperties:
|
|
||||||
type: integer
|
|
||||||
format: int64
|
|
||||||
description: Represents the total resources of a node.
|
|
||||||
|
|
||||||
nodeTaints:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
no_schedule:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
no_execute:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
prefer_no_schedule:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user