Compare commits

...

10 Commits

Author SHA1 Message Date
Daniel Valdivia
410920823a Return Generated Console Credentials (#217)
Whe Console is configured, we auto generate credentials for Console and store them in a secret but we need to return them to the user so he knows what credentials he/she can use to log in to console.
2020-07-30 13:55:11 -07:00
Daniel Valdivia
3ffaeceaf4 Fix NPE on Resource Parsing (#216) 2020-07-29 12:11:48 -07:00
Cesar N
add9023b74 Add Attributes to models.Zone and add functions to parse (#215)
from/to operator.Zone to/from models.Zone

Tenant Add, GetTenantInfo and AddZone now can parse
operator.Zone extra attributes
2020-07-29 01:01:17 -07:00
Harshavardhana
af8eb9a147 fix: rename mcS3Client to mcClient (#214)
Co-authored-by: Minio Trusted <trusted@minio.io>
2020-07-28 13:11:03 -07:00
Daniel Valdivia
1201dcf546 List Tenant Total Size (#211) 2020-07-27 20:03:47 -05:00
Daniel Valdivia
7bf25c897c Update Dockerfile entrypoint (#210) 2020-07-27 17:18:46 -07:00
Daniel Valdivia
27a57b1e51 Add Tenant Usage API (#208) 2020-07-27 14:19:40 -07:00
Daniel Valdivia
c03642fdb1 Validate Add Zone Paramters (#207) 2020-07-27 14:06:12 -07:00
Cesar N
d5b689e254 Upgrade operator version to 3.0.2 (#209) 2020-07-27 13:33:54 -07:00
Minio Trusted
ac6e2f29e4 fix the repo name 2020-07-26 00:40:01 -07:00
32 changed files with 4074 additions and 216 deletions

View File

@@ -2,10 +2,17 @@
# Make sure to check the documentation at http://goreleaser.com
project_name: console
release:
name_template: "Version {{.Version}}"
github:
owner: minio
name: console
before:
hooks:
# you may remove this if you don't use vgo
- go mod tidy
builds:
-
goos:

View File

@@ -23,4 +23,4 @@ EXPOSE 9090
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=0 /go/src/github.com/minio/console/console .
CMD ["/console"]
ENTRYPOINT ["/console"]

2
go.mod
View File

@@ -20,7 +20,7 @@ require (
github.com/minio/mc v0.0.0-20200725183142-90d22b271f60
github.com/minio/minio v0.0.0-20200725154241-abbf6ce6ccf8
github.com/minio/minio-go/v7 v7.0.2-0.20200722162308-e0105ca08252
github.com/minio/operator v0.0.0-20200725185636-4a625e4fbb31
github.com/minio/operator v0.0.0-20200726122325-9efe901afebb
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/satori/go.uuid v1.2.0
github.com/stretchr/testify v1.6.1

6
go.sum
View File

@@ -463,10 +463,8 @@ github.com/minio/minio v0.0.0-20200725154241-abbf6ce6ccf8/go.mod h1:NBWtYp4t5pt3
github.com/minio/minio-go/v7 v7.0.1/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns=
github.com/minio/minio-go/v7 v7.0.2-0.20200722162308-e0105ca08252 h1:V2JkMDoSmEIhRcMJwX3qeJVOzy1B5bHpHbZaQu77vbs=
github.com/minio/minio-go/v7 v7.0.2-0.20200722162308-e0105ca08252/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns=
github.com/minio/operator v0.0.0-20200725185636-4a625e4fbb31 h1:FzB4mwu62LnVgOFhB7fLu15fAgIh6+1PHJoytkQPEsY=
github.com/minio/operator v0.0.0-20200725185636-4a625e4fbb31 h1:FzB4mwu62LnVgOFhB7fLu15fAgIh6+1PHJoytkQPEsY=
github.com/minio/operator v0.0.0-20200725185636-4a625e4fbb31/go.mod h1:G0pMmQFV5b5OrH7/OmVKtPoHzj3SmHNgqDlTew1NM/Y=
github.com/minio/operator v0.0.0-20200725185636-4a625e4fbb31/go.mod h1:G0pMmQFV5b5OrH7/OmVKtPoHzj3SmHNgqDlTew1NM/Y=
github.com/minio/operator v0.0.0-20200726122325-9efe901afebb h1:xAfr+GIP+4c6fU+Ad8oWHVWKtbQ60Su3dfEv3nPPyWM=
github.com/minio/operator v0.0.0-20200726122325-9efe901afebb/go.mod h1:G0pMmQFV5b5OrH7/OmVKtPoHzj3SmHNgqDlTew1NM/Y=
github.com/minio/selfupdate v0.3.0 h1:1qfaZscU3hWwX1cF5m5Dov8Z5aZNvPHk9LROzIkas1k=
github.com/minio/selfupdate v0.3.0/go.mod h1:b8ThJzzH7u2MkF6PcIra7KaXO9Khf6alWPvMSyTDCFM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=

View File

@@ -276,7 +276,7 @@ spec:
name: minio-operator
spec:
containers:
- image: minio/k8s-operator:v3.0.1
- image: minio/k8s-operator:v3.0.2
imagePullPolicy: IfNotPresent
name: minio-operator
serviceAccountName: minio-operator

View File

@@ -276,7 +276,7 @@ spec:
name: minio-operator
spec:
containers:
- image: minio/k8s-operator:v3.0.1
- image: minio/k8s-operator:v3.0.2
imagePullPolicy: IfNotPresent
name: minio-operator
serviceAccountName: minio-operator

View File

@@ -23,6 +23,7 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
@@ -35,12 +36,42 @@ type CreateTenantResponse struct {
// access key
AccessKey string `json:"access_key,omitempty"`
// console
Console *CreateTenantResponseConsole `json:"console,omitempty"`
// secret key
SecretKey string `json:"secret_key,omitempty"`
}
// Validate validates this create tenant response
func (m *CreateTenantResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateConsole(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *CreateTenantResponse) validateConsole(formats strfmt.Registry) error {
if swag.IsZero(m.Console) { // not required
return nil
}
if m.Console != nil {
if err := m.Console.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("console")
}
return err
}
}
return nil
}
@@ -61,3 +92,38 @@ func (m *CreateTenantResponse) UnmarshalBinary(b []byte) error {
*m = res
return nil
}
// CreateTenantResponseConsole create tenant response console
//
// swagger:model CreateTenantResponseConsole
type CreateTenantResponseConsole struct {
// access key
AccessKey string `json:"access_key,omitempty"`
// secret key
SecretKey string `json:"secret_key,omitempty"`
}
// Validate validates this create tenant response console
func (m *CreateTenantResponseConsole) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *CreateTenantResponseConsole) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *CreateTenantResponseConsole) UnmarshalBinary(b []byte) error {
var res CreateTenantResponseConsole
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,272 @@
// 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"
"github.com/go-openapi/validate"
)
// NodeSelectorTerm A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
//
// swagger:model nodeSelectorTerm
type NodeSelectorTerm struct {
// A list of node selector requirements by node's labels.
MatchExpressions []*NodeSelectorTermMatchExpressionsItems0 `json:"matchExpressions"`
// A list of node selector requirements by node's fields.
MatchFields []*NodeSelectorTermMatchFieldsItems0 `json:"matchFields"`
}
// Validate validates this node selector term
func (m *NodeSelectorTerm) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateMatchExpressions(formats); err != nil {
res = append(res, err)
}
if err := m.validateMatchFields(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *NodeSelectorTerm) validateMatchExpressions(formats strfmt.Registry) error {
if swag.IsZero(m.MatchExpressions) { // not required
return nil
}
for i := 0; i < len(m.MatchExpressions); i++ {
if swag.IsZero(m.MatchExpressions[i]) { // not required
continue
}
if m.MatchExpressions[i] != nil {
if err := m.MatchExpressions[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("matchExpressions" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *NodeSelectorTerm) validateMatchFields(formats strfmt.Registry) error {
if swag.IsZero(m.MatchFields) { // not required
return nil
}
for i := 0; i < len(m.MatchFields); i++ {
if swag.IsZero(m.MatchFields[i]) { // not required
continue
}
if m.MatchFields[i] != nil {
if err := m.MatchFields[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("matchFields" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *NodeSelectorTerm) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *NodeSelectorTerm) UnmarshalBinary(b []byte) error {
var res NodeSelectorTerm
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// NodeSelectorTermMatchExpressionsItems0 A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
//
// swagger:model NodeSelectorTermMatchExpressionsItems0
type NodeSelectorTermMatchExpressionsItems0 struct {
// The label key that the selector applies to.
// Required: true
Key *string `json:"key"`
// Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
// Required: true
Operator *string `json:"operator"`
// An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch.
Values []string `json:"values"`
}
// Validate validates this node selector term match expressions items0
func (m *NodeSelectorTermMatchExpressionsItems0) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateKey(formats); err != nil {
res = append(res, err)
}
if err := m.validateOperator(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *NodeSelectorTermMatchExpressionsItems0) validateKey(formats strfmt.Registry) error {
if err := validate.Required("key", "body", m.Key); err != nil {
return err
}
return nil
}
func (m *NodeSelectorTermMatchExpressionsItems0) validateOperator(formats strfmt.Registry) error {
if err := validate.Required("operator", "body", m.Operator); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *NodeSelectorTermMatchExpressionsItems0) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *NodeSelectorTermMatchExpressionsItems0) UnmarshalBinary(b []byte) error {
var res NodeSelectorTermMatchExpressionsItems0
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// NodeSelectorTermMatchFieldsItems0 A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
//
// swagger:model NodeSelectorTermMatchFieldsItems0
type NodeSelectorTermMatchFieldsItems0 struct {
// The label key that the selector applies to.
// Required: true
Key *string `json:"key"`
// Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
// Required: true
Operator *string `json:"operator"`
// An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch.
Values []string `json:"values"`
}
// Validate validates this node selector term match fields items0
func (m *NodeSelectorTermMatchFieldsItems0) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateKey(formats); err != nil {
res = append(res, err)
}
if err := m.validateOperator(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *NodeSelectorTermMatchFieldsItems0) validateKey(formats strfmt.Registry) error {
if err := validate.Required("key", "body", m.Key); err != nil {
return err
}
return nil
}
func (m *NodeSelectorTermMatchFieldsItems0) validateOperator(formats strfmt.Registry) error {
if err := validate.Required("operator", "body", m.Operator); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *NodeSelectorTermMatchFieldsItems0) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *NodeSelectorTermMatchFieldsItems0) UnmarshalBinary(b []byte) error {
var res NodeSelectorTermMatchFieldsItems0
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

251
models/pod_affinity_term.go Normal file
View File

@@ -0,0 +1,251 @@
// 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"
"github.com/go-openapi/validate"
)
// PodAffinityTerm Required. A pod affinity term, associated with the corresponding weight.
//
// swagger:model podAffinityTerm
type PodAffinityTerm struct {
// label selector
LabelSelector *PodAffinityTermLabelSelector `json:"labelSelector,omitempty"`
// namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means "this pod's namespace"
Namespaces []string `json:"namespaces"`
// This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed.
// Required: true
TopologyKey *string `json:"topologyKey"`
}
// Validate validates this pod affinity term
func (m *PodAffinityTerm) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateLabelSelector(formats); err != nil {
res = append(res, err)
}
if err := m.validateTopologyKey(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PodAffinityTerm) validateLabelSelector(formats strfmt.Registry) error {
if swag.IsZero(m.LabelSelector) { // not required
return nil
}
if m.LabelSelector != nil {
if err := m.LabelSelector.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("labelSelector")
}
return err
}
}
return nil
}
func (m *PodAffinityTerm) validateTopologyKey(formats strfmt.Registry) error {
if err := validate.Required("topologyKey", "body", m.TopologyKey); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *PodAffinityTerm) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PodAffinityTerm) UnmarshalBinary(b []byte) error {
var res PodAffinityTerm
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// PodAffinityTermLabelSelector A label query over a set of resources, in this case pods.
//
// swagger:model PodAffinityTermLabelSelector
type PodAffinityTermLabelSelector struct {
// matchExpressions is a list of label selector requirements. The requirements are ANDed.
MatchExpressions []*PodAffinityTermLabelSelectorMatchExpressionsItems0 `json:"matchExpressions"`
// matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
MatchLabels map[string]string `json:"matchLabels,omitempty"`
}
// Validate validates this pod affinity term label selector
func (m *PodAffinityTermLabelSelector) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateMatchExpressions(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PodAffinityTermLabelSelector) validateMatchExpressions(formats strfmt.Registry) error {
if swag.IsZero(m.MatchExpressions) { // not required
return nil
}
for i := 0; i < len(m.MatchExpressions); i++ {
if swag.IsZero(m.MatchExpressions[i]) { // not required
continue
}
if m.MatchExpressions[i] != nil {
if err := m.MatchExpressions[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("labelSelector" + "." + "matchExpressions" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *PodAffinityTermLabelSelector) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PodAffinityTermLabelSelector) UnmarshalBinary(b []byte) error {
var res PodAffinityTermLabelSelector
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// PodAffinityTermLabelSelectorMatchExpressionsItems0 A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
//
// swagger:model PodAffinityTermLabelSelectorMatchExpressionsItems0
type PodAffinityTermLabelSelectorMatchExpressionsItems0 struct {
// key is the label key that the selector applies to.
// Required: true
Key *string `json:"key"`
// operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.
// Required: true
Operator *string `json:"operator"`
// values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.
Values []string `json:"values"`
}
// Validate validates this pod affinity term label selector match expressions items0
func (m *PodAffinityTermLabelSelectorMatchExpressionsItems0) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateKey(formats); err != nil {
res = append(res, err)
}
if err := m.validateOperator(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PodAffinityTermLabelSelectorMatchExpressionsItems0) validateKey(formats strfmt.Registry) error {
if err := validate.Required("key", "body", m.Key); err != nil {
return err
}
return nil
}
func (m *PodAffinityTermLabelSelectorMatchExpressionsItems0) validateOperator(formats strfmt.Registry) error {
if err := validate.Required("operator", "body", m.Operator); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *PodAffinityTermLabelSelectorMatchExpressionsItems0) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *PodAffinityTermLabelSelectorMatchExpressionsItems0) UnmarshalBinary(b []byte) error {
var res PodAffinityTermLabelSelectorMatchExpressionsItems0
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -53,9 +53,6 @@ type Tenant struct {
// total size
TotalSize int64 `json:"total_size,omitempty"`
// used size
UsedSize int64 `json:"used_size,omitempty"`
// zones
Zones []*Zone `json:"zones"`
}

View File

@@ -47,12 +47,12 @@ type TenantList struct {
// namespace
Namespace string `json:"namespace,omitempty"`
// total size
TotalSize int64 `json:"total_size,omitempty"`
// volume count
VolumeCount int64 `json:"volume_count,omitempty"`
// volume size
VolumeSize int64 `json:"volume_size,omitempty"`
// zone count
ZoneCount int64 `json:"zone_count,omitempty"`
}

60
models/tenant_usage.go Normal file
View File

@@ -0,0 +1,60 @@
// 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 (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// TenantUsage tenant usage
//
// swagger:model tenantUsage
type TenantUsage struct {
// used size
UsedSize int64 `json:"used_size,omitempty"`
}
// Validate validates this tenant usage
func (m *TenantUsage) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *TenantUsage) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *TenantUsage) UnmarshalBinary(b []byte) error {
var res TenantUsage
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -34,13 +34,25 @@ import (
// swagger:model zone
type Zone struct {
// affinity
Affinity *ZoneAffinity `json:"affinity,omitempty"`
// name
Name string `json:"name,omitempty"`
// NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
NodeSelector map[string]string `json:"node_selector,omitempty"`
// resources
Resources *ZoneResources `json:"resources,omitempty"`
// servers
// Required: true
Servers *int64 `json:"servers"`
// tolerations
Tolerations ZoneTolerations `json:"tolerations,omitempty"`
// volume configuration
// Required: true
VolumeConfiguration *ZoneVolumeConfiguration `json:"volume_configuration"`
@@ -54,10 +66,22 @@ type Zone struct {
func (m *Zone) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAffinity(formats); err != nil {
res = append(res, err)
}
if err := m.validateResources(formats); err != nil {
res = append(res, err)
}
if err := m.validateServers(formats); err != nil {
res = append(res, err)
}
if err := m.validateTolerations(formats); err != nil {
res = append(res, err)
}
if err := m.validateVolumeConfiguration(formats); err != nil {
res = append(res, err)
}
@@ -72,6 +96,42 @@ func (m *Zone) Validate(formats strfmt.Registry) error {
return nil
}
func (m *Zone) validateAffinity(formats strfmt.Registry) error {
if swag.IsZero(m.Affinity) { // not required
return nil
}
if m.Affinity != nil {
if err := m.Affinity.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("affinity")
}
return err
}
}
return nil
}
func (m *Zone) validateResources(formats strfmt.Registry) error {
if swag.IsZero(m.Resources) { // not required
return nil
}
if m.Resources != nil {
if err := m.Resources.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("resources")
}
return err
}
}
return nil
}
func (m *Zone) validateServers(formats strfmt.Registry) error {
if err := validate.Required("servers", "body", m.Servers); err != nil {
@@ -81,6 +141,22 @@ func (m *Zone) validateServers(formats strfmt.Registry) error {
return nil
}
func (m *Zone) validateTolerations(formats strfmt.Registry) error {
if swag.IsZero(m.Tolerations) { // not required
return nil
}
if err := m.Tolerations.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("tolerations")
}
return err
}
return nil
}
func (m *Zone) validateVolumeConfiguration(formats strfmt.Registry) error {
if err := validate.Required("volume_configuration", "body", m.VolumeConfiguration); err != nil {

726
models/zone_affinity.go Normal file
View File

@@ -0,0 +1,726 @@
// 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"
"github.com/go-openapi/validate"
)
// ZoneAffinity If specified, affinity will define the pod's scheduling constraints
//
// swagger:model zoneAffinity
type ZoneAffinity struct {
// node affinity
NodeAffinity *ZoneAffinityNodeAffinity `json:"nodeAffinity,omitempty"`
// pod affinity
PodAffinity *ZoneAffinityPodAffinity `json:"podAffinity,omitempty"`
// pod anti affinity
PodAntiAffinity *ZoneAffinityPodAntiAffinity `json:"podAntiAffinity,omitempty"`
}
// Validate validates this zone affinity
func (m *ZoneAffinity) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateNodeAffinity(formats); err != nil {
res = append(res, err)
}
if err := m.validatePodAffinity(formats); err != nil {
res = append(res, err)
}
if err := m.validatePodAntiAffinity(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinity) validateNodeAffinity(formats strfmt.Registry) error {
if swag.IsZero(m.NodeAffinity) { // not required
return nil
}
if m.NodeAffinity != nil {
if err := m.NodeAffinity.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("nodeAffinity")
}
return err
}
}
return nil
}
func (m *ZoneAffinity) validatePodAffinity(formats strfmt.Registry) error {
if swag.IsZero(m.PodAffinity) { // not required
return nil
}
if m.PodAffinity != nil {
if err := m.PodAffinity.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAffinity")
}
return err
}
}
return nil
}
func (m *ZoneAffinity) validatePodAntiAffinity(formats strfmt.Registry) error {
if swag.IsZero(m.PodAntiAffinity) { // not required
return nil
}
if m.PodAntiAffinity != nil {
if err := m.PodAntiAffinity.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAntiAffinity")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinity) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinity) UnmarshalBinary(b []byte) error {
var res ZoneAffinity
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// ZoneAffinityNodeAffinity Describes node affinity scheduling rules for the pod.
//
// swagger:model ZoneAffinityNodeAffinity
type ZoneAffinityNodeAffinity struct {
// The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred.
PreferredDuringSchedulingIgnoredDuringExecution []*ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 `json:"preferredDuringSchedulingIgnoredDuringExecution"`
// required during scheduling ignored during execution
RequiredDuringSchedulingIgnoredDuringExecution *ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution `json:"requiredDuringSchedulingIgnoredDuringExecution,omitempty"`
}
// Validate validates this zone affinity node affinity
func (m *ZoneAffinityNodeAffinity) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePreferredDuringSchedulingIgnoredDuringExecution(formats); err != nil {
res = append(res, err)
}
if err := m.validateRequiredDuringSchedulingIgnoredDuringExecution(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinityNodeAffinity) validatePreferredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error {
if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution) { // not required
return nil
}
for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ {
if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required
continue
}
if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil {
if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("nodeAffinity" + "." + "preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *ZoneAffinityNodeAffinity) validateRequiredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error {
if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution) { // not required
return nil
}
if m.RequiredDuringSchedulingIgnoredDuringExecution != nil {
if err := m.RequiredDuringSchedulingIgnoredDuringExecution.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("nodeAffinity" + "." + "requiredDuringSchedulingIgnoredDuringExecution")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinityNodeAffinity) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinityNodeAffinity) UnmarshalBinary(b []byte) error {
var res ZoneAffinityNodeAffinity
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).
//
// swagger:model ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0
type ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 struct {
// A node selector term, associated with the corresponding weight.
// Required: true
Preference *NodeSelectorTerm `json:"preference"`
// Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100.
// Required: true
Weight *int32 `json:"weight"`
}
// Validate validates this zone affinity node affinity preferred during scheduling ignored during execution items0
func (m *ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePreference(formats); err != nil {
res = append(res, err)
}
if err := m.validateWeight(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) validatePreference(formats strfmt.Registry) error {
if err := validate.Required("preference", "body", m.Preference); err != nil {
return err
}
if m.Preference != nil {
if err := m.Preference.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("preference")
}
return err
}
}
return nil
}
func (m *ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) validateWeight(formats strfmt.Registry) error {
if err := validate.Required("weight", "body", m.Weight); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) UnmarshalBinary(b []byte) error {
var res ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node.
//
// swagger:model ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution
type ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution struct {
// Required. A list of node selector terms. The terms are ORed.
// Required: true
NodeSelectorTerms []*NodeSelectorTerm `json:"nodeSelectorTerms"`
}
// Validate validates this zone affinity node affinity required during scheduling ignored during execution
func (m *ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateNodeSelectorTerms(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution) validateNodeSelectorTerms(formats strfmt.Registry) error {
if err := validate.Required("nodeAffinity"+"."+"requiredDuringSchedulingIgnoredDuringExecution"+"."+"nodeSelectorTerms", "body", m.NodeSelectorTerms); err != nil {
return err
}
for i := 0; i < len(m.NodeSelectorTerms); i++ {
if swag.IsZero(m.NodeSelectorTerms[i]) { // not required
continue
}
if m.NodeSelectorTerms[i] != nil {
if err := m.NodeSelectorTerms[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("nodeAffinity" + "." + "requiredDuringSchedulingIgnoredDuringExecution" + "." + "nodeSelectorTerms" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution) UnmarshalBinary(b []byte) error {
var res ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// ZoneAffinityPodAffinity Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)).
//
// swagger:model ZoneAffinityPodAffinity
type ZoneAffinityPodAffinity struct {
// The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred.
PreferredDuringSchedulingIgnoredDuringExecution []*ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 `json:"preferredDuringSchedulingIgnoredDuringExecution"`
// If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied.
RequiredDuringSchedulingIgnoredDuringExecution []*PodAffinityTerm `json:"requiredDuringSchedulingIgnoredDuringExecution"`
}
// Validate validates this zone affinity pod affinity
func (m *ZoneAffinityPodAffinity) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePreferredDuringSchedulingIgnoredDuringExecution(formats); err != nil {
res = append(res, err)
}
if err := m.validateRequiredDuringSchedulingIgnoredDuringExecution(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinityPodAffinity) validatePreferredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error {
if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution) { // not required
return nil
}
for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ {
if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required
continue
}
if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil {
if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAffinity" + "." + "preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *ZoneAffinityPodAffinity) validateRequiredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error {
if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution) { // not required
return nil
}
for i := 0; i < len(m.RequiredDuringSchedulingIgnoredDuringExecution); i++ {
if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution[i]) { // not required
continue
}
if m.RequiredDuringSchedulingIgnoredDuringExecution[i] != nil {
if err := m.RequiredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAffinity" + "." + "requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinityPodAffinity) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinityPodAffinity) UnmarshalBinary(b []byte) error {
var res ZoneAffinityPodAffinity
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
//
// swagger:model ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0
type ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 struct {
// pod affinity term
// Required: true
PodAffinityTerm *PodAffinityTerm `json:"podAffinityTerm"`
// weight associated with matching the corresponding podAffinityTerm, in the range 1-100.
// Required: true
Weight *int32 `json:"weight"`
}
// Validate validates this zone affinity pod affinity preferred during scheduling ignored during execution items0
func (m *ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePodAffinityTerm(formats); err != nil {
res = append(res, err)
}
if err := m.validateWeight(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) validatePodAffinityTerm(formats strfmt.Registry) error {
if err := validate.Required("podAffinityTerm", "body", m.PodAffinityTerm); err != nil {
return err
}
if m.PodAffinityTerm != nil {
if err := m.PodAffinityTerm.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAffinityTerm")
}
return err
}
}
return nil
}
func (m *ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) validateWeight(formats strfmt.Registry) error {
if err := validate.Required("weight", "body", m.Weight); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) UnmarshalBinary(b []byte) error {
var res ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// ZoneAffinityPodAntiAffinity Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)).
//
// swagger:model ZoneAffinityPodAntiAffinity
type ZoneAffinityPodAntiAffinity struct {
// The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred.
PreferredDuringSchedulingIgnoredDuringExecution []*ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 `json:"preferredDuringSchedulingIgnoredDuringExecution"`
// If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied.
RequiredDuringSchedulingIgnoredDuringExecution []*PodAffinityTerm `json:"requiredDuringSchedulingIgnoredDuringExecution"`
}
// Validate validates this zone affinity pod anti affinity
func (m *ZoneAffinityPodAntiAffinity) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePreferredDuringSchedulingIgnoredDuringExecution(formats); err != nil {
res = append(res, err)
}
if err := m.validateRequiredDuringSchedulingIgnoredDuringExecution(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinityPodAntiAffinity) validatePreferredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error {
if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution) { // not required
return nil
}
for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ {
if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required
continue
}
if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil {
if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAntiAffinity" + "." + "preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *ZoneAffinityPodAntiAffinity) validateRequiredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error {
if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution) { // not required
return nil
}
for i := 0; i < len(m.RequiredDuringSchedulingIgnoredDuringExecution); i++ {
if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution[i]) { // not required
continue
}
if m.RequiredDuringSchedulingIgnoredDuringExecution[i] != nil {
if err := m.RequiredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAntiAffinity" + "." + "requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinityPodAntiAffinity) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinityPodAntiAffinity) UnmarshalBinary(b []byte) error {
var res ZoneAffinityPodAntiAffinity
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)
//
// swagger:model ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0
type ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0 struct {
// pod affinity term
// Required: true
PodAffinityTerm *PodAffinityTerm `json:"podAffinityTerm"`
// weight associated with matching the corresponding podAffinityTerm, in the range 1-100.
// Required: true
Weight *int32 `json:"weight"`
}
// Validate validates this zone affinity pod anti affinity preferred during scheduling ignored during execution items0
func (m *ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePodAffinityTerm(formats); err != nil {
res = append(res, err)
}
if err := m.validateWeight(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) validatePodAffinityTerm(formats strfmt.Registry) error {
if err := validate.Required("podAffinityTerm", "body", m.PodAffinityTerm); err != nil {
return err
}
if m.PodAffinityTerm != nil {
if err := m.PodAffinityTerm.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("podAffinityTerm")
}
return err
}
}
return nil
}
func (m *ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) validateWeight(formats strfmt.Registry) error {
if err := validate.Required("weight", "body", m.Weight); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0) UnmarshalBinary(b []byte) error {
var res ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

63
models/zone_resources.go Normal file
View File

@@ -0,0 +1,63 @@
// 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 (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ZoneResources If provided, use these requests and limit for cpu/memory resource allocation
//
// swagger:model zoneResources
type ZoneResources struct {
// Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
Limits map[string]int64 `json:"limits,omitempty"`
// Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
Requests map[string]int64 `json:"requests,omitempty"`
}
// Validate validates this zone resources
func (m *ZoneResources) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *ZoneResources) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneResources) UnmarshalBinary(b []byte) error {
var res ZoneResources
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

106
models/zone_tolerations.go Normal file
View File

@@ -0,0 +1,106 @@
// 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"
)
// ZoneTolerations Tolerations allows users to set entries like effect, key, operator, value.
//
// swagger:model zoneTolerations
type ZoneTolerations []*ZoneTolerationsItems0
// Validate validates this zone tolerations
func (m ZoneTolerations) Validate(formats strfmt.Registry) error {
var res []error
for i := 0; i < len(m); i++ {
if swag.IsZero(m[i]) { // not required
continue
}
if m[i] != nil {
if err := m[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(strconv.Itoa(i))
}
return err
}
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// ZoneTolerationsItems0 The pod this Toleration is attached to tolerates any taint that matches the triple <key,value,effect> using the matching operator <operator>.
//
// swagger:model ZoneTolerationsItems0
type ZoneTolerationsItems0 struct {
// Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
Effect string `json:"effect,omitempty"`
// Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.
Key string `json:"key,omitempty"`
// Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.
Operator string `json:"operator,omitempty"`
// TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system.
TolerationSeconds int64 `json:"tolerationSeconds,omitempty"`
// Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.
Value string `json:"value,omitempty"`
}
// Validate validates this zone tolerations items0
func (m *ZoneTolerationsItems0) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *ZoneTolerationsItems0) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ZoneTolerationsItems0) UnmarshalBinary(b []byte) error {
var res ZoneTolerationsItems0
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -314,7 +314,7 @@ func buildAssetManifestJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/asset-manifest.json", size: 1324, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/asset-manifest.json", size: 1324, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -454,7 +454,7 @@ func buildIndexHtml() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/index.html", size: 2653, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/index.html", size: 2653, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -634,7 +634,7 @@ func buildPrecacheManifest431582dfb340f36f9878214baec8dc4dJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/precache-manifest.431582dfb340f36f9878214baec8dc4d.js", size: 872, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/precache-manifest.431582dfb340f36f9878214baec8dc4d.js", size: 872, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -714,7 +714,7 @@ func buildServiceWorkerJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/service-worker.js", size: 1183, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/service-worker.js", size: 1183, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -734,7 +734,7 @@ func buildStaticCss2C54eff9aChunkCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/css/2.c54eff9a.chunk.css", size: 7679, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/css/2.c54eff9a.chunk.css", size: 7679, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -754,7 +754,7 @@ func buildStaticCss2C54eff9aChunkCssMap() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/css/2.c54eff9a.chunk.css.map", size: 14852, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/css/2.c54eff9a.chunk.css.map", size: 14852, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -774,7 +774,7 @@ func buildStaticCssMainDc35c5d0ChunkCss() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/css/main.dc35c5d0.chunk.css", size: 244, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/css/main.dc35c5d0.chunk.css", size: 244, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -794,7 +794,7 @@ func buildStaticCssMainDc35c5d0ChunkCssMap() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/css/main.dc35c5d0.chunk.css.map", size: 426, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/css/main.dc35c5d0.chunk.css.map", size: 426, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -814,7 +814,7 @@ func buildStaticJs256e77eefChunkJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/js/2.56e77eef.chunk.js", size: 1004066, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/js/2.56e77eef.chunk.js", size: 1004066, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -834,7 +834,7 @@ func buildStaticJs256e77eefChunkJsLicenseTxt() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/js/2.56e77eef.chunk.js.LICENSE.txt", size: 3031, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/js/2.56e77eef.chunk.js.LICENSE.txt", size: 3031, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -854,7 +854,7 @@ func buildStaticJs256e77eefChunkJsMap() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/js/2.56e77eef.chunk.js.map", size: 4194792, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/js/2.56e77eef.chunk.js.map", size: 4194792, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -874,7 +874,7 @@ func buildStaticJsMain8d549452ChunkJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/js/main.8d549452.chunk.js", size: 224981, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/js/main.8d549452.chunk.js", size: 224981, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -894,7 +894,7 @@ func buildStaticJsMain8d549452ChunkJsMap() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/js/main.8d549452.chunk.js.map", size: 768292, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/js/main.8d549452.chunk.js.map", size: 768292, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -914,7 +914,7 @@ func buildStaticJsRuntimeMainBa4e227dJs() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/js/runtime-main.ba4e227d.js", size: 1565, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/js/runtime-main.ba4e227d.js", size: 1565, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -934,7 +934,7 @@ func buildStaticJsRuntimeMainBa4e227dJsMap() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/js/runtime-main.ba4e227d.js.map", size: 8278, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/js/runtime-main.ba4e227d.js.map", size: 8278, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -954,7 +954,7 @@ func buildStaticMediaMinio_console_logo0851e1d0Svg() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "build/static/media/minio_console_logo.0851e1d0.svg", size: 2785, mode: os.FileMode(420), modTime: time.Unix(1595632751, 0)}
info := bindataFileInfo{name: "build/static/media/minio_console_logo.0851e1d0.svg", size: 2785, mode: os.FileMode(420), modTime: time.Unix(1595877009, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}

View File

@@ -19,6 +19,7 @@ package restapi
import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"net"
@@ -107,10 +108,19 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
err := getTenantAddZoneResponse(session, params)
if err != nil {
log.Println(err)
return admin_api.NewTenantAddZoneDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to update tenant")})
return admin_api.NewTenantAddZoneDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to add zone")})
}
return admin_api.NewTenantAddZoneCreated()
})
api.AdminAPIGetTenantUsageHandler = admin_api.GetTenantUsageHandlerFunc(func(params admin_api.GetTenantUsageParams, session *models.Principal) middleware.Responder {
payload, err := getTenantUsageResponse(session, params)
if err != nil {
log.Println(err)
return admin_api.NewGetTenantUsageDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to get tenant usage")})
}
return admin_api.NewGetTenantUsageOK().WithPayload(payload)
})
}
// deleteTenantAction performs the actions of deleting a tenant
@@ -177,7 +187,7 @@ func getTenant(ctx context.Context, operatorClient OperatorClient, namespace, te
return minInst, nil
}
func getTenantInfo(tenant *operator.Tenant, tenantInfo *usageInfo) *models.Tenant {
func getTenantInfo(tenant *operator.Tenant) *models.Tenant {
var instanceCount int64
var volumeCount int64
for _, zone := range tenant.Spec.Zones {
@@ -189,21 +199,7 @@ func getTenantInfo(tenant *operator.Tenant, tenantInfo *usageInfo) *models.Tenan
var totalSize int64
for _, z := range tenant.Spec.Zones {
zoneModel := &models.Zone{
Name: z.Name,
Servers: swag.Int64(int64(z.Servers)),
VolumesPerServer: &z.VolumesPerServer,
VolumeConfiguration: &models.ZoneVolumeConfiguration{},
}
if z.VolumeClaimTemplate != nil {
zoneModel.VolumeConfiguration.Size = swag.Int64(z.VolumeClaimTemplate.Spec.Resources.Requests.Storage().Value())
if z.VolumeClaimTemplate.Spec.StorageClassName != nil {
zoneModel.VolumeConfiguration.StorageClassName = *z.VolumeClaimTemplate.Spec.StorageClassName
}
}
zones = append(zones, zoneModel)
zones = append(zones, parseTenantZone(&z))
zoneSize := int64(z.Servers) * int64(z.VolumesPerServer) * z.VolumeClaimTemplate.Spec.Resources.Requests.Storage().Value()
totalSize = totalSize + zoneSize
}
@@ -216,7 +212,6 @@ func getTenantInfo(tenant *operator.Tenant, tenantInfo *usageInfo) *models.Tenan
Zones: zones,
Namespace: tenant.ObjectMeta.Namespace,
Image: tenant.Spec.Image,
UsedSize: tenantInfo.DisksUsage,
}
}
@@ -229,55 +224,18 @@ func getTenantInfoResponse(session *models.Principal, params admin_api.TenantInf
if err != nil {
return nil, err
}
clientset, err := cluster.K8sClient(session.SessionToken)
if err != nil {
log.Println("error getting k8sClient:", err)
return nil, err
}
opClient := &operatorClient{
client: opClientClientSet,
}
k8sClient := &k8sClient{
client: clientset,
}
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
if err != nil {
log.Println("error getting minioTenant:", err)
return nil, err
}
tenantScheme := getTenantScheme(minTenant)
svcName := minTenant.Spec.ServiceName
if svcName == "" {
svcName = minTenant.Name
// TODO:
// 1 get tenant services
// 2 filter out cluster ip svc
}
mAdmin, err := getTenantAdminClient(
ctx,
k8sClient,
params.Namespace,
params.Tenant,
svcName,
tenantScheme)
if err != nil {
log.Println("error getting tenant's admin client:", err)
return nil, err
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := adminClient{client: mAdmin}
// serialize output
adminInfo, err := getAdminInfo(ctx, adminClient)
if err != nil {
log.Println("error getting admin info:", err)
return nil, err
}
info := getTenantInfo(minTenant, adminInfo)
info := getTenantInfo(minTenant)
return info, nil
}
@@ -297,29 +255,34 @@ func listTenants(ctx context.Context, operatorClient OperatorClient, namespace s
var tenants []*models.TenantList
for _, minInst := range minTenants.Items {
for _, tenant := range minTenants.Items {
var totalSize int64
var instanceCount int64
var volumeCount int64
for _, zone := range minInst.Spec.Zones {
for _, zone := range tenant.Spec.Zones {
instanceCount = instanceCount + int64(zone.Servers)
volumeCount = volumeCount + int64(zone.Servers*zone.VolumesPerServer)
if zone.VolumeClaimTemplate != nil {
zoneSize := int64(zone.VolumesPerServer) * int64(zone.Servers) * zone.VolumeClaimTemplate.Spec.Resources.Requests.Storage().Value()
totalSize = totalSize + zoneSize
}
}
tenants = append(tenants, &models.TenantList{
CreationDate: minInst.ObjectMeta.CreationTimestamp.String(),
Name: minInst.ObjectMeta.Name,
ZoneCount: int64(len(minInst.Spec.Zones)),
CreationDate: tenant.ObjectMeta.CreationTimestamp.String(),
Name: tenant.ObjectMeta.Name,
ZoneCount: int64(len(tenant.Spec.Zones)),
InstanceCount: instanceCount,
VolumeCount: volumeCount,
CurrentState: minInst.Status.CurrentState,
Namespace: minInst.ObjectMeta.Namespace,
CurrentState: tenant.Status.CurrentState,
Namespace: tenant.ObjectMeta.Namespace,
TotalSize: totalSize,
})
}
return &models.ListTenantsResponse{
Tenants: tenants,
Total: 0,
Total: int64(len(tenants)),
}, nil
}
@@ -369,6 +332,13 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
}
minioImage = *minImg
}
// get Kubernetes Client
clientset, err := cluster.K8sClient(session.SessionToken)
if err != nil {
return nil, err
}
ns := *params.Body.Namespace
// if access/secret are provided, use them, else create a random pair
accessKey := RandomCharString(16)
@@ -392,11 +362,6 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
},
}
clientset, err := cluster.K8sClient(session.SessionToken)
if err != nil {
return nil, err
}
ns := *params.Body.Namespace
_, err = clientset.CoreV1().Secrets(ns).Create(context.Background(), &instanceSecret, metav1.CreateOptions{})
if err != nil {
return nil, err
@@ -411,12 +376,6 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
enableConsole = *params.Body.EnableConsole
}
// TODO: Calculate this ourselves?
memorySize, err := resource.ParseQuantity(getTenantMemorySize())
if err != nil {
return nil, err
}
//Construct a MinIO Instance with everything we are getting from parameters
minInst := operator.Tenant{
ObjectMeta: metav1.ObjectMeta{
@@ -432,11 +391,13 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
},
}
// optionals are set below
var consoleAccess string
var consoleSecret string
if enableConsole {
consoleSelector := fmt.Sprintf("%s-console", *params.Body.Name)
consoleSecretName := fmt.Sprintf("%s-secret", consoleSelector)
consoleAccess = RandomCharString(16)
consoleSecret = RandomCharString(32)
imm := true
instanceSecret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
@@ -447,8 +408,8 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
"CONSOLE_HMAC_JWT_SECRET": []byte(RandomCharString(16)),
"CONSOLE_PBKDF_PASSPHRASE": []byte(RandomCharString(16)),
"CONSOLE_PBKDF_SALT": []byte(RandomCharString(8)),
"CONSOLE_ACCESS_KEY": []byte(RandomCharString(16)),
"CONSOLE_SECRET_KEY": []byte(RandomCharString(32)),
"CONSOLE_ACCESS_KEY": []byte(consoleAccess),
"CONSOLE_SECRET_KEY": []byte(consoleSecret),
},
}
_, err = clientset.CoreV1().Secrets(ns).Create(context.Background(), &instanceSecret, metav1.CreateOptions{})
@@ -469,39 +430,12 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
minInst.Spec.ServiceName = params.Body.ServiceName
}
// set the zones if they are provided
if len(params.Body.Zones) > 0 {
for _, zone := range params.Body.Zones {
volumeSize := resource.NewQuantity(*zone.VolumeConfiguration.Size, resource.DecimalExponent)
volTemp := corev1.PersistentVolumeClaimSpec{
AccessModes: []corev1.PersistentVolumeAccessMode{
corev1.ReadWriteOnce,
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: *volumeSize,
},
},
}
if zone.VolumeConfiguration.StorageClassName != "" {
volTemp.StorageClassName = &zone.VolumeConfiguration.StorageClassName
}
minInst.Spec.Zones = append(minInst.Spec.Zones, operator.Zone{
Name: zone.Name,
Servers: int32(*zone.Servers),
VolumesPerServer: *zone.VolumesPerServer,
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "data",
},
Spec: volTemp,
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: memorySize,
},
},
})
for _, zone := range params.Body.Zones {
zone, err := parseTenantZoneRequest(zone)
if err != nil {
return nil, err
}
minInst.Spec.Zones = append(minInst.Spec.Zones, *zone)
}
// Set Mount Path if provided
@@ -533,11 +467,16 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
return nil, err
}
}
return &models.CreateTenantResponse{
response := &models.CreateTenantResponse{
AccessKey: accessKey,
SecretKey: secretKey,
}, nil
}
// Attach Console Credentials
if enableConsole {
response.Console.AccessKey = consoleAccess
response.Console.SecretKey = consoleSecret
}
return response, nil
}
// updateTenantAction does an update on the minioTenant by patching the desired changes
@@ -595,22 +534,23 @@ func getUpdateTenantResponse(session *models.Principal, params admin_api.UpdateT
// addTenantZone creates a zone to a defined tenant
func addTenantZone(ctx context.Context, operatorClient OperatorClient, params admin_api.TenantAddZoneParams) error {
minInst, err := operatorClient.TenantGet(ctx, params.Namespace, params.Tenant, metav1.GetOptions{})
tenant, err := operatorClient.TenantGet(ctx, params.Namespace, params.Tenant, metav1.GetOptions{})
if err != nil {
return err
}
minInst.Spec.Zones = append(minInst.Spec.Zones, operator.Zone{
Name: params.Body.Name,
Servers: int32(*params.Body.Servers),
})
payloadBytes, err := json.Marshal(minInst)
zoneParams := params.Body
zone, err := parseTenantZoneRequest(zoneParams)
if err != nil {
return err
}
tenant.Spec.Zones = append(tenant.Spec.Zones, *zone)
payloadBytes, err := json.Marshal(tenant)
if err != nil {
return err
}
_, err = operatorClient.TenantPatch(ctx, params.Namespace, minInst.Name, types.MergePatchType, payloadBytes, metav1.PatchOptions{})
_, err = operatorClient.TenantPatch(ctx, params.Namespace, tenant.Name, types.MergePatchType, payloadBytes, metav1.PatchOptions{})
if err != nil {
return err
}
@@ -633,3 +573,461 @@ func getTenantAddZoneResponse(session *models.Principal, params admin_api.Tenant
}
return nil
}
// getTenantUsageResponse returns the usage of a tenant
func getTenantUsageResponse(session *models.Principal, params admin_api.GetTenantUsageParams) (*models.TenantUsage, error) {
// 5 seconds timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
if err != nil {
return nil, err
}
clientset, err := cluster.K8sClient(session.SessionToken)
if err != nil {
log.Println("error getting k8sClient:", err)
return nil, err
}
opClient := &operatorClient{
client: opClientClientSet,
}
k8sClient := &k8sClient{
client: clientset,
}
minTenant, err := getTenant(ctx, opClient, params.Namespace, params.Tenant)
if err != nil {
log.Println("error getting minioTenant:", err)
return nil, err
}
tenantScheme := getTenantScheme(minTenant)
svcName := minTenant.Spec.ServiceName
if svcName == "" {
svcName = minTenant.Name
// TODO:
// 1 get tenant services
// 2 filter out cluster ip svc
}
mAdmin, err := getTenantAdminClient(
ctx,
k8sClient,
params.Namespace,
params.Tenant,
svcName,
tenantScheme)
if err != nil {
log.Println("error getting tenant's admin client:", err)
return nil, err
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := adminClient{client: mAdmin}
// serialize output
adminInfo, err := getAdminInfo(ctx, adminClient)
if err != nil {
log.Println("error getting admin info:", err)
return nil, err
}
info := &models.TenantUsage{UsedSize: adminInfo.Usage}
return info, nil
}
// parseTenantZoneRequest parse zone request and returns the equivalent
// operator.Zone object
func parseTenantZoneRequest(zoneParams *models.Zone) (*operator.Zone, error) {
if zoneParams.VolumeConfiguration == nil {
return nil, errors.New("a volume configuration must be specified")
}
if zoneParams.VolumeConfiguration.Size == nil || *zoneParams.VolumeConfiguration.Size <= int64(0) {
return nil, errors.New("volume size must be greater than 0")
}
if zoneParams.Servers == nil || *zoneParams.Servers <= 0 {
return nil, errors.New("number of servers must be greater than 0")
}
if zoneParams.VolumesPerServer == nil || *zoneParams.VolumesPerServer <= 0 {
return nil, errors.New("number of volumes per server must be greater than 0")
}
volumeSize := resource.NewQuantity(*zoneParams.VolumeConfiguration.Size, resource.DecimalExponent)
volTemp := corev1.PersistentVolumeClaimSpec{
AccessModes: []corev1.PersistentVolumeAccessMode{
corev1.ReadWriteOnce,
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: *volumeSize,
},
},
}
if zoneParams.VolumeConfiguration.StorageClassName != "" {
volTemp.StorageClassName = &zoneParams.VolumeConfiguration.StorageClassName
}
// parse resources' requests
var resourcesRequests corev1.ResourceList
var resourcesLimits corev1.ResourceList
if zoneParams.Resources != nil {
for key, val := range zoneParams.Resources.Requests {
resourcesRequests[corev1.ResourceName(key)] = *resource.NewQuantity(val, resource.BinarySI)
}
for key, val := range zoneParams.Resources.Limits {
resourcesLimits[corev1.ResourceName(key)] = *resource.NewQuantity(val, resource.BinarySI)
}
}
// parse Node Affinity
nodeSelectorTerms := []corev1.NodeSelectorTerm{}
preferredSchedulingTerm := []corev1.PreferredSchedulingTerm{}
if zoneParams.Affinity != nil && zoneParams.Affinity.NodeAffinity != nil {
if zoneParams.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
for _, elem := range zoneParams.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms {
term := parseModelsNodeSelectorTerm(elem)
nodeSelectorTerms = append(nodeSelectorTerms, term)
}
}
for _, elem := range zoneParams.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
pst := corev1.PreferredSchedulingTerm{
Weight: *elem.Weight,
Preference: parseModelsNodeSelectorTerm(elem.Preference),
}
preferredSchedulingTerm = append(preferredSchedulingTerm, pst)
}
}
var nodeAffinity *corev1.NodeAffinity
if len(nodeSelectorTerms) > 0 || len(preferredSchedulingTerm) > 0 {
nodeAffinity = &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: nodeSelectorTerms,
},
PreferredDuringSchedulingIgnoredDuringExecution: preferredSchedulingTerm,
}
}
// parse Pod Affinity
podAffinityTerms := []corev1.PodAffinityTerm{}
weightedPodAffinityTerms := []corev1.WeightedPodAffinityTerm{}
if zoneParams.Affinity != nil && zoneParams.Affinity.PodAffinity != nil {
for _, elem := range zoneParams.Affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution {
podAffinityTerms = append(podAffinityTerms, parseModelPodAffinityTerm(elem))
}
for _, elem := range zoneParams.Affinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
wAffinityTerm := corev1.WeightedPodAffinityTerm{
Weight: *elem.Weight,
PodAffinityTerm: parseModelPodAffinityTerm(elem.PodAffinityTerm),
}
weightedPodAffinityTerms = append(weightedPodAffinityTerms, wAffinityTerm)
}
}
var podAffinity *corev1.PodAffinity
if len(podAffinityTerms) > 0 || len(weightedPodAffinityTerms) > 0 {
podAffinity = &corev1.PodAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: podAffinityTerms,
PreferredDuringSchedulingIgnoredDuringExecution: weightedPodAffinityTerms,
}
}
// parse Pod Anti Affinity
podAntiAffinityTerms := []corev1.PodAffinityTerm{}
weightedPodAntiAffinityTerms := []corev1.WeightedPodAffinityTerm{}
if zoneParams.Affinity != nil && zoneParams.Affinity.PodAntiAffinity != nil {
for _, elem := range zoneParams.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution {
podAntiAffinityTerms = append(podAntiAffinityTerms, parseModelPodAffinityTerm(elem))
}
for _, elem := range zoneParams.Affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
wAffinityTerm := corev1.WeightedPodAffinityTerm{
Weight: *elem.Weight,
PodAffinityTerm: parseModelPodAffinityTerm(elem.PodAffinityTerm),
}
weightedPodAntiAffinityTerms = append(weightedPodAntiAffinityTerms, wAffinityTerm)
}
}
var podAntiAffinity *corev1.PodAntiAffinity
if len(podAntiAffinityTerms) > 0 || len(weightedPodAntiAffinityTerms) > 0 {
podAntiAffinity = &corev1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: podAntiAffinityTerms,
PreferredDuringSchedulingIgnoredDuringExecution: weightedPodAntiAffinityTerms,
}
}
var affinity *corev1.Affinity
if nodeAffinity != nil || podAffinity != nil || podAntiAffinity != nil {
affinity = &corev1.Affinity{
NodeAffinity: nodeAffinity,
PodAffinity: podAffinity,
PodAntiAffinity: podAntiAffinity,
}
}
// parse tolerations
tolerations := []corev1.Toleration{}
for _, elem := range zoneParams.Tolerations {
toleration := corev1.Toleration{
Key: elem.Key,
Operator: corev1.TolerationOperator(elem.Operator),
Value: elem.Value,
Effect: corev1.TaintEffect(elem.Effect),
TolerationSeconds: &elem.TolerationSeconds,
}
tolerations = append(tolerations, toleration)
}
zone := &operator.Zone{
Name: zoneParams.Name,
Servers: int32(*zoneParams.Servers),
VolumesPerServer: *zoneParams.VolumesPerServer,
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "data",
},
Spec: volTemp,
},
Resources: corev1.ResourceRequirements{
Requests: resourcesRequests,
Limits: resourcesLimits,
},
NodeSelector: zoneParams.NodeSelector,
Affinity: affinity,
Tolerations: tolerations,
}
return zone, nil
}
func parseModelPodAffinityTerm(term *models.PodAffinityTerm) corev1.PodAffinityTerm {
labelMatchExpressions := []metav1.LabelSelectorRequirement{}
for _, exp := range term.LabelSelector.MatchExpressions {
labelSelectorReq := metav1.LabelSelectorRequirement{
Key: *exp.Key,
Operator: metav1.LabelSelectorOperator(*exp.Operator),
Values: exp.Values,
}
labelMatchExpressions = append(labelMatchExpressions, labelSelectorReq)
}
podAffinityTerm := corev1.PodAffinityTerm{
LabelSelector: &metav1.LabelSelector{
MatchExpressions: labelMatchExpressions,
MatchLabels: term.LabelSelector.MatchLabels,
},
Namespaces: term.Namespaces,
TopologyKey: *term.TopologyKey,
}
return podAffinityTerm
}
func parseModelsNodeSelectorTerm(elem *models.NodeSelectorTerm) corev1.NodeSelectorTerm {
var term corev1.NodeSelectorTerm
for _, matchExpression := range elem.MatchExpressions {
matchExp := corev1.NodeSelectorRequirement{
Key: *matchExpression.Key,
Operator: corev1.NodeSelectorOperator(*matchExpression.Operator),
Values: matchExpression.Values,
}
term.MatchExpressions = append(term.MatchExpressions, matchExp)
}
for _, matchField := range elem.MatchFields {
matchF := corev1.NodeSelectorRequirement{
Key: *matchField.Key,
Operator: corev1.NodeSelectorOperator(*matchField.Operator),
Values: matchField.Values,
}
term.MatchFields = append(term.MatchFields, matchF)
}
return term
}
// parseTenantZone operator Zone object and returns the equivalent
// models.Zone object
func parseTenantZone(zone *operator.Zone) *models.Zone {
var size *int64
var storageClassName string
if zone.VolumeClaimTemplate != nil {
size = swag.Int64(zone.VolumeClaimTemplate.Spec.Resources.Requests.Storage().Value())
if zone.VolumeClaimTemplate.Spec.StorageClassName != nil {
storageClassName = *zone.VolumeClaimTemplate.Spec.StorageClassName
}
}
// parse resources' requests
var resources *models.ZoneResources
resourcesRequests := make(map[string]int64)
resourcesLimits := make(map[string]int64)
for key, val := range zone.Resources.Requests {
resourcesRequests[key.String()] = val.Value()
}
for key, val := range zone.Resources.Limits {
resourcesLimits[key.String()] = val.Value()
}
if len(resourcesRequests) > 0 || len(resourcesLimits) > 0 {
resources = &models.ZoneResources{
Limits: resourcesLimits,
Requests: resourcesRequests,
}
}
// parse Node Affinity
nodeSelectorTerms := []*models.NodeSelectorTerm{}
preferredSchedulingTerm := []*models.ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{}
if zone.Affinity != nil && zone.Affinity.NodeAffinity != nil {
if zone.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil {
for _, elem := range zone.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms {
term := parseNodeSelectorTerm(&elem)
nodeSelectorTerms = append(nodeSelectorTerms, term)
}
}
for _, elem := range zone.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
pst := &models.ZoneAffinityNodeAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{
Weight: swag.Int32(elem.Weight),
Preference: parseNodeSelectorTerm(&elem.Preference),
}
preferredSchedulingTerm = append(preferredSchedulingTerm, pst)
}
}
var nodeAffinity *models.ZoneAffinityNodeAffinity
if len(nodeSelectorTerms) > 0 || len(preferredSchedulingTerm) > 0 {
nodeAffinity = &models.ZoneAffinityNodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &models.ZoneAffinityNodeAffinityRequiredDuringSchedulingIgnoredDuringExecution{
NodeSelectorTerms: nodeSelectorTerms,
},
PreferredDuringSchedulingIgnoredDuringExecution: preferredSchedulingTerm,
}
}
// parse Pod Affinity
podAffinityTerms := []*models.PodAffinityTerm{}
weightedPodAffinityTerms := []*models.ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{}
if zone.Affinity != nil && zone.Affinity.PodAffinity != nil {
for _, elem := range zone.Affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution {
podAffinityTerms = append(podAffinityTerms, parsePodAffinityTerm(&elem))
}
for _, elem := range zone.Affinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
wAffinityTerm := &models.ZoneAffinityPodAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{
Weight: swag.Int32(elem.Weight),
PodAffinityTerm: parsePodAffinityTerm(&elem.PodAffinityTerm),
}
weightedPodAffinityTerms = append(weightedPodAffinityTerms, wAffinityTerm)
}
}
var podAffinity *models.ZoneAffinityPodAffinity
if len(podAffinityTerms) > 0 || len(weightedPodAffinityTerms) > 0 {
podAffinity = &models.ZoneAffinityPodAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: podAffinityTerms,
PreferredDuringSchedulingIgnoredDuringExecution: weightedPodAffinityTerms,
}
}
// parse Pod Anti Affinity
podAntiAffinityTerms := []*models.PodAffinityTerm{}
weightedPodAntiAffinityTerms := []*models.ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{}
if zone.Affinity != nil && zone.Affinity.PodAntiAffinity != nil {
for _, elem := range zone.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution {
podAntiAffinityTerms = append(podAntiAffinityTerms, parsePodAffinityTerm(&elem))
}
for _, elem := range zone.Affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution {
wAffinityTerm := &models.ZoneAffinityPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecutionItems0{
Weight: swag.Int32(elem.Weight),
PodAffinityTerm: parsePodAffinityTerm(&elem.PodAffinityTerm),
}
weightedPodAntiAffinityTerms = append(weightedPodAntiAffinityTerms, wAffinityTerm)
}
}
var podAntiAffinity *models.ZoneAffinityPodAntiAffinity
if len(podAntiAffinityTerms) > 0 || len(weightedPodAntiAffinityTerms) > 0 {
podAntiAffinity = &models.ZoneAffinityPodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: podAntiAffinityTerms,
PreferredDuringSchedulingIgnoredDuringExecution: weightedPodAntiAffinityTerms,
}
}
// build affinity object
var affinity *models.ZoneAffinity
if nodeAffinity != nil || podAffinity != nil || podAntiAffinity != nil {
affinity = &models.ZoneAffinity{
NodeAffinity: nodeAffinity,
PodAffinity: podAffinity,
PodAntiAffinity: podAntiAffinity,
}
}
// parse tolerations
var tolerations models.ZoneTolerations
for _, elem := range zone.Tolerations {
toleration := &models.ZoneTolerationsItems0{
Key: elem.Key,
Operator: string(elem.Operator),
Value: elem.Value,
Effect: string(elem.Effect),
TolerationSeconds: *elem.TolerationSeconds,
}
tolerations = append(tolerations, toleration)
}
zoneModel := &models.Zone{
Name: zone.Name,
Servers: swag.Int64(int64(zone.Servers)),
VolumesPerServer: swag.Int32(zone.VolumesPerServer),
VolumeConfiguration: &models.ZoneVolumeConfiguration{
Size: size,
StorageClassName: storageClassName,
},
NodeSelector: zone.NodeSelector,
Resources: resources,
Affinity: affinity,
Tolerations: tolerations,
}
return zoneModel
}
func parsePodAffinityTerm(term *corev1.PodAffinityTerm) *models.PodAffinityTerm {
labelMatchExpressions := []*models.PodAffinityTermLabelSelectorMatchExpressionsItems0{}
for _, exp := range term.LabelSelector.MatchExpressions {
labelSelectorReq := &models.PodAffinityTermLabelSelectorMatchExpressionsItems0{
Key: swag.String(exp.Key),
Operator: swag.String(string(exp.Operator)),
Values: exp.Values,
}
labelMatchExpressions = append(labelMatchExpressions, labelSelectorReq)
}
podAffinityTerm := &models.PodAffinityTerm{
LabelSelector: &models.PodAffinityTermLabelSelector{
MatchExpressions: labelMatchExpressions,
MatchLabels: term.LabelSelector.MatchLabels,
},
Namespaces: term.Namespaces,
TopologyKey: swag.String(term.TopologyKey),
}
return podAffinityTerm
}
func parseNodeSelectorTerm(term *corev1.NodeSelectorTerm) *models.NodeSelectorTerm {
var t models.NodeSelectorTerm
for _, matchExpression := range term.MatchExpressions {
matchExp := &models.NodeSelectorTermMatchExpressionsItems0{
Key: swag.String(matchExpression.Key),
Operator: swag.String(string(matchExpression.Operator)),
Values: matchExpression.Values,
}
t.MatchExpressions = append(t.MatchExpressions, matchExp)
}
for _, matchField := range term.MatchFields {
matchF := &models.NodeSelectorTermMatchFieldsItems0{
Key: swag.String(matchField.Key),
Operator: swag.String(string(matchField.Operator)),
Values: matchField.Values,
}
t.MatchFields = append(t.MatchFields, matchF)
}
return &t
}

View File

@@ -315,13 +315,12 @@ func Test_TenantInfo(t *testing.T) {
},
Namespace: "minio-ns",
Image: "minio/minio:RELEASE.2020-06-14T18-32-17Z",
UsedSize: int64(1024),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getTenantInfo(tt.args.minioTenant, tt.args.tenantInfo)
got := getTenantInfo(tt.args.minioTenant)
if !reflect.DeepEqual(got, tt.want) {
ji, _ := json.Marshal(got)
vi, _ := json.Marshal(tt.want)
@@ -415,10 +414,92 @@ func Test_TenantAddZone(t *testing.T) {
Body: &models.Zone{
Name: "zone-1",
Servers: swag.Int64(int64(4)),
VolumeConfiguration: &models.ZoneVolumeConfiguration{
Size: swag.Int64(2147483648),
StorageClassName: "standard",
},
VolumesPerServer: swag.Int32(4),
},
},
},
wantErr: false,
}, {
name: "Add zone, error size",
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "default",
mockTenantPatch: func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error) {
return &v1.Tenant{}, nil
},
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error) {
return &v1.Tenant{}, nil
},
params: admin_api.TenantAddZoneParams{
Body: &models.Zone{
Name: "zone-1",
Servers: swag.Int64(int64(4)),
VolumeConfiguration: &models.ZoneVolumeConfiguration{
Size: swag.Int64(0),
StorageClassName: "standard",
},
VolumesPerServer: swag.Int32(4),
},
},
},
wantErr: true,
},
{
name: "Add zone, error servers negative",
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "default",
mockTenantPatch: func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error) {
return &v1.Tenant{}, nil
},
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error) {
return &v1.Tenant{}, nil
},
params: admin_api.TenantAddZoneParams{
Body: &models.Zone{
Name: "zone-1",
Servers: swag.Int64(int64(-1)),
VolumeConfiguration: &models.ZoneVolumeConfiguration{
Size: swag.Int64(2147483648),
StorageClassName: "standard",
},
VolumesPerServer: swag.Int32(4),
},
},
},
wantErr: true,
},
{
name: "Add zone, error volumes per server negative",
args: args{
ctx: context.Background(),
operatorClient: opClient,
nameSpace: "default",
mockTenantPatch: func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error) {
return &v1.Tenant{}, nil
},
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error) {
return &v1.Tenant{}, nil
},
params: admin_api.TenantAddZoneParams{
Body: &models.Zone{
Name: "zone-1",
Servers: swag.Int64(int64(4)),
VolumeConfiguration: &models.ZoneVolumeConfiguration{
Size: swag.Int64(2147483648),
StorageClassName: "standard",
},
VolumesPerServer: swag.Int32(-1),
},
},
},
wantErr: true,
},
{
name: "Error on patch, handle error",

View File

@@ -93,10 +93,10 @@ func (c minioClient) getBucketPolicy(ctx context.Context, bucketName string) (st
return c.client.GetBucketPolicy(ctx, bucketName)
}
// MCS3Client interface with all functions to be implemented
// MCClient interface with all functions to be implemented
// by mock when testing, it should include all mc/S3Client respective api calls
// that are used within this project.
type MCS3Client interface {
type MCClient interface {
addNotificationConfig(ctx context.Context, arn string, events []string, prefix, suffix string, ignoreExisting bool) *probe.Error
removeNotificationConfig(ctx context.Context, arn string, event string, prefix string, suffix string) *probe.Error
watch(ctx context.Context, options mc.WatchOptions) (*mc.WatchObject, *probe.Error)
@@ -106,21 +106,21 @@ type MCS3Client interface {
//
// Define the structure of a mc S3Client and define the functions that are actually used
// from mcS3client api.
type mcS3Client struct {
type mcClient struct {
client *mc.S3Client
}
// implements S3Client.AddNotificationConfig()
func (c mcS3Client) addNotificationConfig(ctx context.Context, arn string, events []string, prefix, suffix string, ignoreExisting bool) *probe.Error {
func (c mcClient) addNotificationConfig(ctx context.Context, arn string, events []string, prefix, suffix string, ignoreExisting bool) *probe.Error {
return c.client.AddNotificationConfig(ctx, arn, events, prefix, suffix, ignoreExisting)
}
// implements S3Client.RemoveNotificationConfig()
func (c mcS3Client) removeNotificationConfig(ctx context.Context, arn string, event string, prefix string, suffix string) *probe.Error {
func (c mcClient) removeNotificationConfig(ctx context.Context, arn string, event string, prefix string, suffix string) *probe.Error {
return c.client.RemoveNotificationConfig(ctx, arn, event, prefix, suffix)
}
func (c mcS3Client) watch(ctx context.Context, options mc.WatchOptions) (*mc.WatchObject, *probe.Error) {
func (c mcClient) watch(ctx context.Context, options mc.WatchOptions) (*mc.WatchObject, *probe.Error) {
return c.client.Watch(ctx, options)
}

View File

@@ -39,10 +39,6 @@ var TLSPort = "9443"
// TLSRedirect console tls redirect rule
var TLSRedirect = "off"
// defaultTenantMemorySize default value used
// when generating minioTenant request
var defaultTenantMemorySize = "16Gi"
func getAccessKey() string {
return env.Get(ConsoleAccessKey, "minioadmin")
}
@@ -232,9 +228,3 @@ func getSecureFeaturePolicy() string {
func getSecureExpectCTHeader() string {
return env.Get(ConsoleSecureExpectCTHeader, "")
}
// getTenantMemorySize Memory size value to be used when generating the
// Tenant request
func getTenantMemorySize() string {
return env.Get(ConsoleTenantMemorySize, defaultTenantMemorySize)
}

View File

@@ -1,22 +0,0 @@
// 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
const (
// ConsoleTenantMemorySize Memory size to be used when creating Tenant request
ConsoleTenantMemorySize = "CONSOLE_TENANT_MEMORY_SIZE"
)

File diff suppressed because it is too large Load Diff

View 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"
)
// GetTenantUsageHandlerFunc turns a function with the right signature into a get tenant usage handler
type GetTenantUsageHandlerFunc func(GetTenantUsageParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn GetTenantUsageHandlerFunc) Handle(params GetTenantUsageParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// GetTenantUsageHandler interface for that can handle valid get tenant usage params
type GetTenantUsageHandler interface {
Handle(GetTenantUsageParams, *models.Principal) middleware.Responder
}
// NewGetTenantUsage creates a new http.Handler for the get tenant usage operation
func NewGetTenantUsage(ctx *middleware.Context, handler GetTenantUsageHandler) *GetTenantUsage {
return &GetTenantUsage{Context: ctx, Handler: handler}
}
/*GetTenantUsage swagger:route GET /namespaces/{namespace}/tenants/{tenant}/usage AdminAPI getTenantUsage
Get Usage For The Tenant
*/
type GetTenantUsage struct {
Context *middleware.Context
Handler GetTenantUsageHandler
}
func (o *GetTenantUsage) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
}
var Params = NewGetTenantUsageParams()
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)
}

View File

@@ -0,0 +1,114 @@
// 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"
"github.com/go-openapi/strfmt"
)
// NewGetTenantUsageParams creates a new GetTenantUsageParams object
// no default values defined in spec.
func NewGetTenantUsageParams() GetTenantUsageParams {
return GetTenantUsageParams{}
}
// GetTenantUsageParams contains all the bound params for the get tenant usage operation
// typically these are obtained from a http.Request
//
// swagger:parameters GetTenantUsage
type GetTenantUsageParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
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 NewGetTenantUsageParams() beforehand.
func (o *GetTenantUsageParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
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 *GetTenantUsageParams) 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 *GetTenantUsageParams) 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
}

View File

@@ -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"
)
// GetTenantUsageOKCode is the HTTP code returned for type GetTenantUsageOK
const GetTenantUsageOKCode int = 200
/*GetTenantUsageOK A successful response.
swagger:response getTenantUsageOK
*/
type GetTenantUsageOK struct {
/*
In: Body
*/
Payload *models.TenantUsage `json:"body,omitempty"`
}
// NewGetTenantUsageOK creates GetTenantUsageOK with default headers values
func NewGetTenantUsageOK() *GetTenantUsageOK {
return &GetTenantUsageOK{}
}
// WithPayload adds the payload to the get tenant usage o k response
func (o *GetTenantUsageOK) WithPayload(payload *models.TenantUsage) *GetTenantUsageOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get tenant usage o k response
func (o *GetTenantUsageOK) SetPayload(payload *models.TenantUsage) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetTenantUsageOK) 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
}
}
}
/*GetTenantUsageDefault Generic error response.
swagger:response getTenantUsageDefault
*/
type GetTenantUsageDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewGetTenantUsageDefault creates GetTenantUsageDefault with default headers values
func NewGetTenantUsageDefault(code int) *GetTenantUsageDefault {
if code <= 0 {
code = 500
}
return &GetTenantUsageDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the get tenant usage default response
func (o *GetTenantUsageDefault) WithStatusCode(code int) *GetTenantUsageDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the get tenant usage default response
func (o *GetTenantUsageDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the get tenant usage default response
func (o *GetTenantUsageDefault) WithPayload(payload *models.Error) *GetTenantUsageDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get tenant usage default response
func (o *GetTenantUsageDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetTenantUsageDefault) 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
}
}
}

View File

@@ -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"
)
// GetTenantUsageURL generates an URL for the get tenant usage operation
type GetTenantUsageURL 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 *GetTenantUsageURL) WithBasePath(bp string) *GetTenantUsageURL {
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 *GetTenantUsageURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *GetTenantUsageURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/namespaces/{namespace}/tenants/{tenant}/usage"
namespace := o.Namespace
if namespace != "" {
_path = strings.Replace(_path, "{namespace}", namespace, -1)
} else {
return nil, errors.New("namespace is required on GetTenantUsageURL")
}
tenant := o.Tenant
if tenant != "" {
_path = strings.Replace(_path, "{tenant}", tenant, -1)
} else {
return nil, errors.New("tenant is required on GetTenantUsageURL")
}
_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 *GetTenantUsageURL) 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 *GetTenantUsageURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *GetTenantUsageURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on GetTenantUsageURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on GetTenantUsageURL")
}
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 *GetTenantUsageURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -117,6 +117,9 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
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")
}),
AdminAPIGetTenantUsageHandler: admin_api.GetTenantUsageHandlerFunc(func(params admin_api.GetTenantUsageParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation admin_api.GetTenantUsage has not yet been implemented")
}),
AdminAPIGetUserInfoHandler: admin_api.GetUserInfoHandlerFunc(func(params admin_api.GetUserInfoParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation admin_api.GetUserInfo has not yet been implemented")
}),
@@ -304,6 +307,8 @@ type ConsoleAPI struct {
AdminAPIDeleteTenantHandler admin_api.DeleteTenantHandler
// AdminAPIGetResourceQuotaHandler sets the operation handler for the get resource quota operation
AdminAPIGetResourceQuotaHandler admin_api.GetResourceQuotaHandler
// AdminAPIGetTenantUsageHandler sets the operation handler for the get tenant usage operation
AdminAPIGetTenantUsageHandler admin_api.GetTenantUsageHandler
// AdminAPIGetUserInfoHandler sets the operation handler for the get user info operation
AdminAPIGetUserInfoHandler admin_api.GetUserInfoHandler
// AdminAPIGroupInfoHandler sets the operation handler for the group info operation
@@ -499,6 +504,9 @@ func (o *ConsoleAPI) Validate() error {
if o.AdminAPIGetResourceQuotaHandler == nil {
unregistered = append(unregistered, "admin_api.GetResourceQuotaHandler")
}
if o.AdminAPIGetTenantUsageHandler == nil {
unregistered = append(unregistered, "admin_api.GetTenantUsageHandler")
}
if o.AdminAPIGetUserInfoHandler == nil {
unregistered = append(unregistered, "admin_api.GetUserInfoHandler")
}
@@ -776,6 +784,10 @@ func (o *ConsoleAPI) initHandlerCache() {
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/namespaces/{namespace}/tenants/{tenant}/usage"] = admin_api.NewGetTenantUsage(o.context, o.AdminAPIGetTenantUsageHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/users/{name}"] = admin_api.NewGetUserInfo(o.context, o.AdminAPIGetUserInfoHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)

View File

@@ -153,7 +153,7 @@ func getListBucketEventsResponse(session *models.Principal, params user_api.List
// If notificationEvents is empty, by default will set [get, put, delete], else the provided
// ones will be set.
// this function follows same behavior as minio/mc for adding a bucket event
func createBucketEvent(ctx context.Context, client MCS3Client, arn string, notificationEvents []models.NotificationEventType, prefix, suffix string, ignoreExisting bool) error {
func createBucketEvent(ctx context.Context, client MCClient, arn string, notificationEvents []models.NotificationEventType, prefix, suffix string, ignoreExisting bool) error {
var events []string
if len(notificationEvents) == 0 {
// default event values are [get, put, delete]
@@ -187,8 +187,8 @@ func getCreateBucketEventsResponse(session *models.Principal, bucketName string,
}
// create a mc S3Client interface implementation
// defining the client to be used
mcS3Client := mcS3Client{client: s3Client}
err = createBucketEvent(ctx, mcS3Client, *eventReq.Configuration.Arn, eventReq.Configuration.Events, eventReq.Configuration.Prefix, eventReq.Configuration.Suffix, eventReq.IgnoreExisting)
mcClient := mcClient{client: s3Client}
err = createBucketEvent(ctx, mcClient, *eventReq.Configuration.Arn, eventReq.Configuration.Events, eventReq.Configuration.Prefix, eventReq.Configuration.Suffix, eventReq.IgnoreExisting)
if err != nil {
log.Println("error creating bucket event:", err)
return err
@@ -197,7 +197,7 @@ func getCreateBucketEventsResponse(session *models.Principal, bucketName string,
}
// deleteBucketEventNotification calls S3Client.RemoveNotificationConfig to remove a bucket event notification
func deleteBucketEventNotification(ctx context.Context, client MCS3Client, arn string, events []models.NotificationEventType, prefix, suffix *string) error {
func deleteBucketEventNotification(ctx context.Context, client MCClient, arn string, events []models.NotificationEventType, prefix, suffix *string) error {
eventSingleString := joinNotificationEvents(events)
perr := client.removeNotificationConfig(ctx, arn, eventSingleString, *prefix, *suffix)
if perr != nil {
@@ -224,8 +224,8 @@ func getDeleteBucketEventsResponse(session *models.Principal, bucketName string,
}
// create a mc S3Client interface implementation
// defining the client to be used
mcS3Client := mcS3Client{client: s3Client}
err = deleteBucketEventNotification(ctx, mcS3Client, arn, events, prefix, suffix)
mcClient := mcClient{client: s3Client}
err = deleteBucketEventNotification(ctx, mcClient, arn, events, prefix, suffix)
if err != nil {
log.Println("error deleting bucket event:", err)
return err

View File

@@ -34,7 +34,7 @@ type watchOptions struct {
mc.WatchOptions
}
func startWatch(ctx context.Context, conn WSConn, wsc MCS3Client, options watchOptions) error {
func startWatch(ctx context.Context, conn WSConn, wsc MCClient, options watchOptions) error {
wo, pErr := wsc.watch(ctx, options.WatchOptions)
if pErr != nil {
fmt.Println("error initializing watch:", pErr.Cause)

View File

@@ -61,8 +61,8 @@ type ConsoleWebsocket interface {
type wsS3Client struct {
// websocket connection.
conn wsConn
// mcS3Client
client MCS3Client
// mcClient
client MCClient
}
// WSConn interface with all functions to be implemented
@@ -197,7 +197,7 @@ func newWebSocketS3Client(conn *websocket.Conn, claims *models.Principal, bucket
wsConnection := wsConn{conn: conn}
// create a s3Client interface implementation
// defining the client to be used
mcS3C := mcS3Client{client: s3Client}
mcS3C := mcClient{client: s3Client}
// create websocket client and handle request
wsS3Client := &wsS3Client{conn: wsConnection, client: mcS3C}
return wsS3Client, nil

View File

@@ -1144,6 +1144,31 @@ paths:
tags:
- AdminAPI
/namespaces/{namespace}/tenants/{tenant}/usage:
get:
summary: Get Usage For The Tenant
operationId: GetTenantUsage
parameters:
- name: namespace
in: path
required: true
type: string
- name: tenant
in: path
required: true
type: string
responses:
200:
description: A successful response.
schema:
$ref: "#/definitions/tenantUsage"
default:
description: Generic error response.
schema:
$ref: "#/definitions/error"
tags:
- AdminAPI
/namespaces/{namespace}/resourcequotas/{resource-quota-name}:
get:
summary: Get Resource Quota
@@ -1704,6 +1729,10 @@ definitions:
total_size:
type: integer
format: int64
tenantUsage:
type: object
properties:
used_size:
type: integer
format: int64
@@ -1717,7 +1746,7 @@ definitions:
type: integer
instance_count:
type: integer
volume_size:
total_size:
type: integer
volume_count:
type: integer
@@ -1788,6 +1817,13 @@ definitions:
type: string
secret_key:
type: string
console:
type: object
properties:
access_key:
type: string
secret_key:
type: string
zone:
type: object
required:
@@ -1811,6 +1847,409 @@ definitions:
type: integer
storage_class_name:
type: string
resources:
$ref: "#/definitions/zoneResources"
node_selector:
type: object
additionalProperties:
type: string
description: "NodeSelector is a selector which must be true for
the pod to fit on a node. Selector which must match a node's
labels for the pod to be scheduled on that node. More info:
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/"
affinity:
$ref: "#/definitions/zoneAffinity"
tolerations:
$ref: "#/definitions/zoneTolerations"
zoneTolerations:
description: Tolerations allows users to set entries like effect,
key, operator, value.
items:
description: The pod this Toleration is attached to tolerates
any taint that matches the triple <key,value,effect> using
the matching operator <operator>.
properties:
effect:
description: Effect indicates the taint effect to match.
Empty means match all taint effects. When specified, allowed
values are NoSchedule, PreferNoSchedule and NoExecute.
type: string
key:
description: Key is the taint key that the toleration applies
to. Empty means match all taint keys. If the key is empty,
operator must be Exists; this combination means to match
all values and all keys.
type: string
operator:
description: Operator represents a key's relationship to
the value. Valid operators are Exists and Equal. Defaults
to Equal. Exists is equivalent to wildcard for value,
so that a pod can tolerate all taints of a particular
category.
type: string
tolerationSeconds:
description: TolerationSeconds represents the period of
time the toleration (which must be of effect NoExecute,
otherwise this field is ignored) tolerates the taint.
By default, it is not set, which means tolerate the taint
forever (do not evict). Zero and negative values will
be treated as 0 (evict immediately) by the system.
format: int64
type: integer
value:
description: Value is the taint value the toleration matches
to. If the operator is Exists, the value should be empty,
otherwise just a regular string.
type: string
type: object
type: array
zoneResources:
description: If provided, use these requests and limit for cpu/memory
resource allocation
properties:
limits:
additionalProperties:
type: integer
format: int64
description: "Limits describes the maximum amount of compute
resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"
type: object
requests:
additionalProperties:
additionalProperties:
type: integer
format: int64
description: "Requests describes the minimum amount of compute
resources required. If Requests is omitted for a container,
it defaults to Limits if that is explicitly specified, otherwise
to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"
type: object
type: object
zoneAffinity:
description: If specified, affinity will define the pod's scheduling
constraints
properties:
nodeAffinity:
description: Describes node affinity scheduling rules for
the pod.
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: The scheduler will prefer to schedule pods
to nodes that satisfy the affinity expressions specified
by this field, but it may choose a node that violates
one or more of the expressions. The node that is most
preferred is the one with the greatest sum of weights,
i.e. for each node that meets all of the scheduling
requirements (resource request, requiredDuringScheduling
affinity expressions, etc.), compute a sum by iterating
through the elements of this field and adding "weight"
to the sum if the node matches the corresponding matchExpressions;
the node(s) with the highest sum are the most preferred.
items:
description: An empty preferred scheduling term matches
all objects with implicit weight 0 (i.e. it's a no-op).
A null preferred scheduling term matches no objects
(i.e. is also a no-op).
properties:
preference:
description: A node selector term, associated with
the corresponding weight.
$ref: "#/definitions/nodeSelectorTerm"
type: object
weight:
description: Weight associated with matching the
corresponding nodeSelectorTerm, in the range 1-100.
format: int32
type: integer
required:
- preference
- weight
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
description: If the affinity requirements specified by
this field are not met at scheduling time, the pod will
not be scheduled onto the node. If the affinity requirements
specified by this field cease to be met at some point
during pod execution (e.g. due to an update), the system
may or may not try to eventually evict the pod from
its node.
properties:
nodeSelectorTerms:
description: Required. A list of node selector terms.
The terms are ORed.
items:
$ref: "#/definitions/nodeSelectorTerm"
type: array
required:
- nodeSelectorTerms
type: object
type: object
podAffinity:
description: Describes pod affinity scheduling rules (e.g.
co-locate this pod in the same node, zone, etc. as some
other pod(s)).
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: The scheduler will prefer to schedule pods
to nodes that satisfy the affinity expressions specified
by this field, but it may choose a node that violates
one or more of the expressions. The node that is most
preferred is the one with the greatest sum of weights,
i.e. for each node that meets all of the scheduling
requirements (resource request, requiredDuringScheduling
affinity expressions, etc.), compute a sum by iterating
through the elements of this field and adding "weight"
to the sum if the node has pods which matches the corresponding
podAffinityTerm; the node(s) with the highest sum are
the most preferred.
items:
description:
The weights of all of the matched WeightedPodAffinityTerm
fields are added per-node to find the most preferred
node(s)
properties:
podAffinityTerm:
$ref: "#/definitions/podAffinityTerm"
weight:
description: weight associated with matching the
corresponding podAffinityTerm, in the range 1-100.
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
description: If the affinity requirements specified by
this field are not met at scheduling time, the pod will
not be scheduled onto the node. If the affinity requirements
specified by this field cease to be met at some point
during pod execution (e.g. due to a pod label update),
the system may or may not try to eventually evict the
pod from its node. When there are multiple elements,
the lists of nodes corresponding to each podAffinityTerm
are intersected, i.e. all terms must be satisfied.
items:
$ref: "#/definitions/podAffinityTerm"
type: array
type: object
podAntiAffinity:
description: Describes pod anti-affinity scheduling rules
(e.g. avoid putting this pod in the same node, zone, etc.
as some other pod(s)).
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: The scheduler will prefer to schedule pods
to nodes that satisfy the anti-affinity expressions
specified by this field, but it may choose a node that
violates one or more of the expressions. The node that
is most preferred is the one with the greatest sum of
weights, i.e. for each node that meets all of the scheduling
requirements (resource request, requiredDuringScheduling
anti-affinity expressions, etc.), compute a sum by iterating
through the elements of this field and adding "weight"
to the sum if the node has pods which matches the corresponding
podAffinityTerm; the node(s) with the highest sum are
the most preferred.
items:
description:
The weights of all of the matched WeightedPodAffinityTerm
fields are added per-node to find the most preferred
node(s)
properties:
podAffinityTerm:
$ref: "#/definitions/podAffinityTerm"
weight:
description: weight associated with matching the
corresponding podAffinityTerm, in the range 1-100.
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
requiredDuringSchedulingIgnoredDuringExecution:
description: If the anti-affinity requirements specified
by this field are not met at scheduling time, the pod
will not be scheduled onto the node. If the anti-affinity
requirements specified by this field cease to be met
at some point during pod execution (e.g. due to a pod
label update), the system may or may not try to eventually
evict the pod from its node. When there are multiple
elements, the lists of nodes corresponding to each podAffinityTerm
are intersected, i.e. all terms must be satisfied.
items:
$ref: "#/definitions/podAffinityTerm"
type: array
type: object
type: object
nodeSelectorTerm:
type: object
description: A null or empty node selector term
matches no objects. The requirements of them are
ANDed. The TopologySelectorTerm type implements
a subset of the NodeSelectorTerm.
properties:
matchExpressions:
description: A list of node selector requirements
by node's labels.
items:
description: A node selector requirement is
a selector that contains values, a key,
and an operator that relates the key and
values.
properties:
key:
description: The label key that the selector
applies to.
type: string
operator:
description: Represents a key's relationship
to a set of values. Valid operators
are In, NotIn, Exists, DoesNotExist.
Gt, and Lt.
type: string
values:
description: An array of string values.
If the operator is In or NotIn, the
values array must be non-empty. If the
operator is Exists or DoesNotExist,
the values array must be empty. If the
operator is Gt or Lt, the values array
must have a single element, which will
be interpreted as an integer. This array
is replaced during a strategic merge
patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchFields:
description: A list of node selector requirements
by node's fields.
items:
description: A node selector requirement is
a selector that contains values, a key,
and an operator that relates the key and
values.
properties:
key:
description: The label key that the selector
applies to.
type: string
operator:
description: Represents a key's relationship
to a set of values. Valid operators
are In, NotIn, Exists, DoesNotExist.
Gt, and Lt.
type: string
values:
description: An array of string values.
If the operator is In or NotIn, the
values array must be non-empty. If the
operator is Exists or DoesNotExist,
the values array must be empty. If the
operator is Gt or Lt, the values array
must have a single element, which will
be interpreted as an integer. This array
is replaced during a strategic merge
patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
podAffinityTerm:
description: Required. A pod affinity term, associated
with the corresponding weight.
properties:
labelSelector:
description: A label query over a set of resources,
in this case pods.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The requirements
are ANDed.
items:
description: A label selector requirement
is a selector that contains values,
a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label key
that the selector applies to.
type: string
operator:
description: operator represents a
key's relationship to a set of values.
Valid operators are In, NotIn, Exists
and DoesNotExist.
type: string
values:
description: values is an array of
string values. If the operator is
In or NotIn, the values array must
be non-empty. If the operator is
Exists or DoesNotExist, the values
array must be empty. This array
is replaced during a strategic merge
patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator
is "In", and the values array contains
only "value". The requirements are ANDed.
type: object
type: object
namespaces:
description: namespaces specifies which namespaces
the labelSelector applies to (matches against);
null or empty list means "this pod's namespace"
items:
type: string
type: array
topologyKey:
description: This pod should be co-located (affinity)
or not co-located (anti-affinity) with the
pods matching the labelSelector in the specified
namespaces, where co-located is defined as
running on a node whose value of the label
with key topologyKey matches that of any node
on which any of the selected pods is running.
Empty topologyKey is not allowed.
type: string
required:
- topologyKey
type: object
resourceQuota:
type: object