diff --git a/models/cluster_resources.go b/models/cluster_resources.go
deleted file mode 100644
index 0e27986bf..000000000
--- a/models/cluster_resources.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Code generated by go-swagger; DO NOT EDIT.
-
-// This file is part of MinIO Console Server
-// Copyright (c) 2020 MinIO, Inc.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-//
-
-package models
-
-// This file was generated by the swagger tool.
-// Editing this file might prove futile when you re-run the swagger generate command
-
-import (
- "strconv"
-
- "github.com/go-openapi/errors"
- "github.com/go-openapi/strfmt"
- "github.com/go-openapi/swag"
-)
-
-// ClusterResources cluster resources
-//
-// swagger:model clusterResources
-type ClusterResources struct {
-
- // nodes
- Nodes []*NodeInfo `json:"nodes"`
-}
-
-// Validate validates this cluster resources
-func (m *ClusterResources) Validate(formats strfmt.Registry) error {
- var res []error
-
- if err := m.validateNodes(formats); err != nil {
- res = append(res, err)
- }
-
- if len(res) > 0 {
- return errors.CompositeValidationError(res...)
- }
- return nil
-}
-
-func (m *ClusterResources) validateNodes(formats strfmt.Registry) error {
-
- if swag.IsZero(m.Nodes) { // not required
- return nil
- }
-
- for i := 0; i < len(m.Nodes); i++ {
- if swag.IsZero(m.Nodes[i]) { // not required
- continue
- }
-
- if m.Nodes[i] != nil {
- if err := m.Nodes[i].Validate(formats); err != nil {
- if ve, ok := err.(*errors.Validation); ok {
- return ve.ValidateName("nodes" + "." + strconv.Itoa(i))
- }
- return err
- }
- }
-
- }
-
- return nil
-}
-
-// MarshalBinary interface implementation
-func (m *ClusterResources) MarshalBinary() ([]byte, error) {
- if m == nil {
- return nil, nil
- }
- return swag.WriteJSON(m)
-}
-
-// UnmarshalBinary interface implementation
-func (m *ClusterResources) UnmarshalBinary(b []byte) error {
- var res ClusterResources
- if err := swag.ReadJSON(b, &res); err != nil {
- return err
- }
- *m = res
- return nil
-}
diff --git a/models/node_taints.go b/models/max_allocatable_mem_response.go
similarity index 71%
rename from models/node_taints.go
rename to models/max_allocatable_mem_response.go
index fe635e4aa..6ecb60687 100644
--- a/models/node_taints.go
+++ b/models/max_allocatable_mem_response.go
@@ -27,28 +27,22 @@ import (
"github.com/go-openapi/swag"
)
-// NodeTaints node taints
+// MaxAllocatableMemResponse max allocatable mem response
//
-// swagger:model nodeTaints
-type NodeTaints struct {
+// swagger:model maxAllocatableMemResponse
+type MaxAllocatableMemResponse struct {
- // no execute
- NoExecute []string `json:"no_execute"`
-
- // no schedule
- NoSchedule []string `json:"no_schedule"`
-
- // prefer no schedule
- PreferNoSchedule []string `json:"prefer_no_schedule"`
+ // max memory
+ MaxMemory int64 `json:"max_memory,omitempty"`
}
-// Validate validates this node taints
-func (m *NodeTaints) Validate(formats strfmt.Registry) error {
+// Validate validates this max allocatable mem response
+func (m *MaxAllocatableMemResponse) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
-func (m *NodeTaints) MarshalBinary() ([]byte, error) {
+func (m *MaxAllocatableMemResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
@@ -56,8 +50,8 @@ func (m *NodeTaints) MarshalBinary() ([]byte, error) {
}
// UnmarshalBinary interface implementation
-func (m *NodeTaints) UnmarshalBinary(b []byte) error {
- var res NodeTaints
+func (m *MaxAllocatableMemResponse) UnmarshalBinary(b []byte) error {
+ var res MaxAllocatableMemResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
diff --git a/models/node_info.go b/models/node_info.go
deleted file mode 100644
index 7880eb28f..000000000
--- a/models/node_info.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Code generated by go-swagger; DO NOT EDIT.
-
-// This file is part of MinIO Console Server
-// Copyright (c) 2020 MinIO, Inc.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-//
-
-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/errors"
- "github.com/go-openapi/strfmt"
- "github.com/go-openapi/swag"
-)
-
-// NodeInfo node info
-//
-// swagger:model nodeInfo
-type NodeInfo struct {
-
- // Represents the resources of a node that are available for scheduling.
- AllocatableResources map[string]int64 `json:"allocatable_resources,omitempty"`
-
- // name
- Name string `json:"name,omitempty"`
-
- // taints
- Taints *NodeTaints `json:"taints,omitempty"`
-
- // Represents the total resources of a node.
- TotalResources map[string]int64 `json:"total_resources,omitempty"`
-}
-
-// Validate validates this node info
-func (m *NodeInfo) Validate(formats strfmt.Registry) error {
- var res []error
-
- if err := m.validateTaints(formats); err != nil {
- res = append(res, err)
- }
-
- if len(res) > 0 {
- return errors.CompositeValidationError(res...)
- }
- return nil
-}
-
-func (m *NodeInfo) validateTaints(formats strfmt.Registry) error {
-
- if swag.IsZero(m.Taints) { // not required
- return nil
- }
-
- if m.Taints != nil {
- if err := m.Taints.Validate(formats); err != nil {
- if ve, ok := err.(*errors.Validation); ok {
- return ve.ValidateName("taints")
- }
- return err
- }
- }
-
- return nil
-}
-
-// MarshalBinary interface implementation
-func (m *NodeInfo) MarshalBinary() ([]byte, error) {
- if m == nil {
- return nil, nil
- }
- return swag.WriteJSON(m)
-}
-
-// UnmarshalBinary interface implementation
-func (m *NodeInfo) UnmarshalBinary(b []byte) error {
- var res NodeInfo
- if err := swag.ReadJSON(b, &res); err != nil {
- return err
- }
- *m = res
- return nil
-}
diff --git a/restapi/admin_nodes.go b/restapi/admin_nodes.go
index 3397b6fa0..18e8268ef 100644
--- a/restapi/admin_nodes.go
+++ b/restapi/admin_nodes.go
@@ -18,12 +18,13 @@ package restapi
import (
"context"
- "fmt"
"log"
- "strings"
+ "sort"
"github.com/minio/console/cluster"
+ "errors"
+
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
"github.com/minio/console/models"
@@ -35,73 +36,94 @@ import (
)
func registerNodesHandlers(api *operations.ConsoleAPI) {
- api.AdminAPIGetClusterResourcesHandler = admin_api.GetClusterResourcesHandlerFunc(func(params admin_api.GetClusterResourcesParams, session *models.Principal) middleware.Responder {
- resp, err := getClusterResourcesResponse(session)
+ api.AdminAPIGetMaxAllocatableMemHandler = admin_api.GetMaxAllocatableMemHandlerFunc(func(params admin_api.GetMaxAllocatableMemParams, principal *models.Principal) middleware.Responder {
+ resp, err := getMaxAllocatableMemoryResponse(principal, params.NumNodes)
if err != nil {
- return admin_api.NewGetClusterResourcesDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
+ return admin_api.NewGetMaxAllocatableMemDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
}
- return admin_api.NewGetClusterResourcesOK().WithPayload(resp)
+ return admin_api.NewGetMaxAllocatableMemOK().WithPayload(resp)
})
}
-// getClusterResources get cluster nodes and collects taints, available and allocatable resources of the node
-func getClusterResources(ctx context.Context, clientset v1.CoreV1Interface) (*models.ClusterResources, error) {
+// getMaxAllocatableMemory get max allocatable memory given a desired number of nodes
+func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface, numNodes int32) (*models.MaxAllocatableMemResponse, error) {
+ if numNodes == 0 {
+ return nil, errors.New("error NumNodes must be greated than 0")
+ }
+
// get all nodes from cluster
nodes, err := clientset.Nodes().List(ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}
- // construct ClusterResources response
- res := &models.ClusterResources{}
+ availableMemSizes := []int64{}
+OUTER:
for _, n := range nodes.Items {
- // Get Total Resources
- totalResources := make(map[string]int64)
- for resource, quantity := range n.Status.Capacity {
- totalResources[string(resource)] = quantity.Value()
- }
-
- // Get Allocatable Resources
- allocatableResources := make(map[string]int64)
- for resource, quantity := range n.Status.Allocatable {
- allocatableResources[string(resource)] = quantity.Value()
- }
-
- // Get Node taints and split them by effect
- taints := &models.NodeTaints{}
+ // Don't consider node if it has a NoSchedule or NoExecute Taint
for _, t := range n.Spec.Taints {
- var taint string
- // when value is not defined the taint string is created without `=`
- if strings.TrimSpace(t.Value) != "" {
- taint = fmt.Sprintf("%s=%s:%s", t.Key, t.Value, t.Effect)
- } else {
- taint = fmt.Sprintf("%s:%s", t.Key, t.Effect)
- }
switch t.Effect {
case corev1.TaintEffectNoSchedule:
- taints.NoSchedule = append(taints.NoSchedule, taint)
+ continue OUTER
case corev1.TaintEffectNoExecute:
- taints.NoExecute = append(taints.NoExecute, taint)
- case corev1.TaintEffectPreferNoSchedule:
- taints.PreferNoSchedule = append(taints.PreferNoSchedule, taint)
+ continue OUTER
default:
continue
}
}
-
- // create node object an add it to the nodes list
- nodeInfo := &models.NodeInfo{
- Name: n.Name,
- Taints: taints,
- AllocatableResources: allocatableResources,
- TotalResources: totalResources,
+ if quantity, ok := n.Status.Allocatable[corev1.ResourceMemory]; ok {
+ availableMemSizes = append(availableMemSizes, quantity.Value())
}
- res.Nodes = append(res.Nodes, nodeInfo)
}
+
+ maxAllocatableMemory := getMaxClusterMemory(numNodes, availableMemSizes)
+
+ res := &models.MaxAllocatableMemResponse{
+ MaxMemory: maxAllocatableMemory,
+ }
+
return res, nil
}
-func getClusterResourcesResponse(session *models.Principal) (*models.ClusterResources, error) {
+// getMaxClusterMemory returns the maximum memory size that can be used
+// across numNodes (number of nodes)
+func getMaxClusterMemory(numNodes int32, nodesMemorySizes []int64) int64 {
+ if int32(len(nodesMemorySizes)) < numNodes || numNodes == 0 {
+ return 0
+ }
+
+ // sort nodesMemorySizes int64 array
+ sort.Slice(nodesMemorySizes, func(i, j int) bool { return nodesMemorySizes[i] < nodesMemorySizes[j] })
+ maxIndex := 0
+ maxAllocatableMemory := nodesMemorySizes[maxIndex]
+
+ for i, size := range nodesMemorySizes {
+ // maxAllocatableMemory is the minimum value of nodesMemorySizes array
+ // only within the size of numNodes, if more nodes are available
+ // then the maxAllocatableMemory is equal to the next minimum value
+ // on the sorted nodesMemorySizes array.
+ // e.g. with numNodes = 4;
+ // maxAllocatableMemory of [2,4,8,8] => 2
+ // maxAllocatableMemory of [2,4,8,8,16] => 4
+ if int32(i) < numNodes {
+ maxAllocatableMemory = min(maxAllocatableMemory, size)
+ } else {
+ maxIndex++
+ maxAllocatableMemory = nodesMemorySizes[maxIndex]
+ }
+ }
+ return maxAllocatableMemory
+}
+
+// min returns the smaller of x or y.
+func min(x, y int64) int64 {
+ if x > y {
+ return y
+ }
+ return x
+}
+
+func getMaxAllocatableMemoryResponse(session *models.Principal, numNodes int32) (*models.MaxAllocatableMemResponse, error) {
ctx := context.Background()
client, err := cluster.K8sClient(session.SessionToken)
if err != nil {
@@ -109,7 +131,7 @@ func getClusterResourcesResponse(session *models.Principal) (*models.ClusterReso
return nil, err
}
- clusterResources, err := getClusterResources(ctx, client.CoreV1())
+ clusterResources, err := getMaxAllocatableMemory(ctx, client.CoreV1(), numNodes)
if err != nil {
log.Println("error getting cluster's resources:", err)
return nil, err
diff --git a/restapi/admin_nodes_test.go b/restapi/admin_nodes_test.go
index 513546064..bed3d0bf8 100644
--- a/restapi/admin_nodes_test.go
+++ b/restapi/admin_nodes_test.go
@@ -18,7 +18,6 @@ package restapi
import (
"context"
- "encoding/json"
"reflect"
"testing"
@@ -31,45 +30,68 @@ import (
"k8s.io/client-go/kubernetes/fake"
)
-func Test_GetClusterResources(t *testing.T) {
+func Test_MaxAllocatableMemory(t *testing.T) {
type args struct {
- ctx context.Context
- objs []runtime.Object
+ ctx context.Context
+ numNodes int32
+ objs []runtime.Object
}
tests := []struct {
name string
args args
- expected *models.ClusterResources
+ expected *models.MaxAllocatableMemResponse
wantErr bool
}{
{
- name: "Get Nodes Taints and Resources",
+ name: "Get Max Ram No Taints",
args: args{
- ctx: context.Background(),
+ ctx: context.Background(),
+ numNodes: 2,
objs: []runtime.Object{
&corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node1",
},
- Spec: corev1.NodeSpec{
- Taints: []corev1.Taint{
- corev1.Taint{
- Key: "node.kubernetes.io/unreachable",
- Effect: corev1.TaintEffectNoSchedule,
- },
- corev1.Taint{
- Key: "own.minio.io/taint",
- Effect: corev1.TaintEffectNoExecute,
- Value: "val",
- },
- corev1.Taint{
- Key: "node.kubernetes.io/unschedulable",
- Effect: corev1.TaintEffectPreferNoSchedule,
- },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("2Ki"),
+ corev1.ResourceCPU: resource.MustParse("4Ki"),
},
},
+ },
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node2",
+ },
Status: corev1.NodeStatus{
- Capacity: corev1.ResourceList{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("512"),
+ corev1.ResourceCPU: resource.MustParse("1Ki"),
+ },
+ },
+ },
+ },
+ },
+ expected: &models.MaxAllocatableMemResponse{
+ MaxMemory: int64(512),
+ },
+ wantErr: false,
+ },
+ {
+ // Description: if there are more nodes than the amount
+ // of nodes we want to use, but one has taints of NoSchedule
+ // node should not be considered for max memory
+ name: "Get Max Ram on nodes with NoSchedule",
+ args: args{
+ ctx: context.Background(),
+ numNodes: 2,
+ objs: []runtime.Object{
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node1",
+ },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
corev1.ResourceMemory: resource.MustParse("2Ki"),
corev1.ResourceCPU: resource.MustParse("4Ki"),
},
@@ -88,71 +110,256 @@ func Test_GetClusterResources(t *testing.T) {
},
},
Status: corev1.NodeStatus{
- Capacity: corev1.ResourceList{
- corev1.ResourceMemory: resource.MustParse("1Ki"),
- corev1.ResourceCPU: resource.MustParse("2Ki"),
- },
Allocatable: corev1.ResourceList{
- corev1.ResourceMemory: resource.MustParse("512"),
+ corev1.ResourceMemory: resource.MustParse("6Ki"),
+ corev1.ResourceCPU: resource.MustParse("1Ki"),
+ },
+ },
+ },
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node3",
+ },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("4Ki"),
corev1.ResourceCPU: resource.MustParse("1Ki"),
},
},
},
},
},
- expected: &models.ClusterResources{
- Nodes: []*models.NodeInfo{
- &models.NodeInfo{
- Name: "node1",
- Taints: &models.NodeTaints{
- NoExecute: []string{
- "own.minio.io/taint=val:NoExecute",
- },
- NoSchedule: []string{
- "node.kubernetes.io/unreachable:NoSchedule",
- },
- PreferNoSchedule: []string{
- "node.kubernetes.io/unschedulable:PreferNoSchedule",
+ expected: &models.MaxAllocatableMemResponse{
+ MaxMemory: int64(2048),
+ },
+ wantErr: false,
+ },
+ {
+ // Description: if there are more nodes than the amount
+ // of nodes we want to use, but one has taints of NoExecute
+ // node should not be considered for max memory
+ // if one node has PreferNoSchedule that should be considered.
+ name: "Get Max Ram on nodes with NoExecute",
+ args: args{
+ ctx: context.Background(),
+ numNodes: 2,
+ objs: []runtime.Object{
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node1",
+ },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("2Ki"),
+ corev1.ResourceCPU: resource.MustParse("4Ki"),
},
},
- TotalResources: map[string]int64{
- "memory": int64(2048),
- "cpu": int64(4096),
- },
- AllocatableResources: map[string]int64{},
},
- &models.NodeInfo{
- Name: "node2",
- Taints: &models.NodeTaints{
- NoSchedule: []string{
- "node.kubernetes.io/unreachable:NoSchedule",
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node2",
+ },
+ Spec: corev1.NodeSpec{
+ Taints: []corev1.Taint{
+ corev1.Taint{
+ Key: "node.kubernetes.io/unreachable",
+ Effect: corev1.TaintEffectNoExecute,
+ },
},
},
- TotalResources: map[string]int64{
- "memory": int64(1024),
- "cpu": int64(2048),
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("6Ki"),
+ corev1.ResourceCPU: resource.MustParse("1Ki"),
+ },
},
- AllocatableResources: map[string]int64{
- "memory": int64(512),
- "cpu": int64(1024),
+ },
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node3",
+ },
+ Spec: corev1.NodeSpec{
+ Taints: []corev1.Taint{
+ corev1.Taint{
+ Key: "node.kubernetes.io/unreachable",
+ Effect: corev1.TaintEffectPreferNoSchedule,
+ },
+ },
+ },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("4Ki"),
+ corev1.ResourceCPU: resource.MustParse("1Ki"),
+ },
},
},
},
},
+ expected: &models.MaxAllocatableMemResponse{
+ MaxMemory: int64(2048),
+ },
wantErr: false,
},
+ {
+ // Description: if there are more nodes than the amount
+ // of nodes we want to use, max allocatable memory should
+ // be the minimum ram on the n nodes requested
+ name: "Get Max Ram, several nodes available",
+ args: args{
+ ctx: context.Background(),
+ numNodes: 2,
+ objs: []runtime.Object{
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node1",
+ },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("2Ki"),
+ corev1.ResourceCPU: resource.MustParse("4Ki"),
+ },
+ },
+ },
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node2",
+ },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("6Ki"),
+ corev1.ResourceCPU: resource.MustParse("1Ki"),
+ },
+ },
+ },
+ &corev1.Node{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "node3",
+ },
+ Status: corev1.NodeStatus{
+ Allocatable: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("4Ki"),
+ corev1.ResourceCPU: resource.MustParse("1Ki"),
+ },
+ },
+ },
+ },
+ },
+ expected: &models.MaxAllocatableMemResponse{
+ MaxMemory: int64(4096),
+ },
+ wantErr: false,
+ },
+ {
+ // Description: if request has nil as request, expect error
+ name: "Nil nodes should be greater than 0",
+ args: args{
+ ctx: context.Background(),
+ numNodes: 0,
+ },
+ wantErr: true,
+ },
}
for _, tt := range tests {
kubeClient := fake.NewSimpleClientset(tt.args.objs...)
t.Run(tt.name, func(t *testing.T) {
- got, err := getClusterResources(tt.args.ctx, kubeClient.CoreV1())
+ got, err := getMaxAllocatableMemory(tt.args.ctx, kubeClient.CoreV1(), tt.args.numNodes)
if (err != nil) != tt.wantErr {
- t.Errorf("deleteTenantAction() error = %v, wantErr %v", err, tt.wantErr)
+ t.Errorf("getMaxAllocatableMemory() error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(got, tt.expected) {
- ji, _ := json.Marshal(got)
- vi, _ := json.Marshal(tt.expected)
- t.Errorf("\ngot: %s \nwant: %s", ji, vi)
+ t.Errorf("\ngot: %d \nwant: %d", got, tt.expected)
+ }
+ })
+ }
+}
+
+func Test_MaxMemoryFunc(t *testing.T) {
+ type args struct {
+ numNodes int32
+ nodesMemorySizes []int64
+ }
+ tests := []struct {
+ name string
+ args args
+ expected int64
+ wantErr bool
+ }{
+ {
+ name: "Get Max memory",
+ args: args{
+ numNodes: int32(4),
+ nodesMemorySizes: []int64{4294967296, 8589934592, 8589934592, 17179869184, 17179869184, 17179869184, 25769803776, 25769803776, 68719476736},
+ },
+ expected: int64(17179869184),
+ wantErr: false,
+ },
+ {
+ // Description, if not enough nodes return 0
+ name: "Get Max memory Not enough nodes",
+ args: args{
+ numNodes: int32(4),
+ nodesMemorySizes: []int64{4294967296, 8589934592, 68719476736},
+ },
+ expected: int64(0),
+ wantErr: false,
+ },
+ {
+ // Description, if not enough nodes return 0
+ name: "Get Max memory no nodes",
+ args: args{
+ numNodes: int32(4),
+ nodesMemorySizes: []int64{},
+ },
+ expected: int64(0),
+ wantErr: false,
+ },
+ {
+ // Description, if not enough nodes return 0
+ name: "Get Max memory no nodes, no request",
+ args: args{
+ numNodes: int32(0),
+ nodesMemorySizes: []int64{},
+ },
+ expected: int64(0),
+ wantErr: false,
+ },
+ {
+ // Description, if there are multiple nodes
+ // and required nodes is only 1, max should be equal to max memory
+ name: "Get Max memory one node",
+ args: args{
+ numNodes: int32(1),
+ nodesMemorySizes: []int64{4294967296, 8589934592, 68719476736},
+ },
+ expected: int64(68719476736),
+ wantErr: false,
+ },
+ {
+ // Description: if more nodes max memory should be the minimum
+ // value across pairs of numNodes
+ name: "Get Max memory two nodes",
+ args: args{
+ numNodes: int32(2),
+ nodesMemorySizes: []int64{8589934592, 68719476736, 4294967296},
+ },
+ expected: int64(8589934592),
+ wantErr: false,
+ },
+ {
+ name: "Get Max Multiple Memory Sizes",
+ args: args{
+ numNodes: int32(4),
+ nodesMemorySizes: []int64{0, 0, 0, 0, 4294967296, 8589934592, 8589934592, 17179869184, 17179869184, 17179869184, 25769803776, 25769803776, 68719476736, 34359738368, 34359738368, 34359738368, 34359738368},
+ },
+ expected: int64(34359738368),
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := getMaxClusterMemory(tt.args.numNodes, tt.args.nodesMemorySizes)
+ if !reflect.DeepEqual(got, tt.expected) {
+ t.Errorf("\ngot: %d \nwant: %d", got, tt.expected)
}
})
}
diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go
index b696bd95f..3c3e3623b 100644
--- a/restapi/embedded_spec.go
+++ b/restapi/embedded_spec.go
@@ -437,18 +437,28 @@ func init() {
}
}
},
- "/cluster/resources": {
+ "/cluster/max-allocatable-memory": {
"get": {
"tags": [
"AdminAPI"
],
- "summary": "Get Cluster Resources",
- "operationId": "GetClusterResources",
+ "summary": "Get maximum allocatable memory for given number of nodes",
+ "operationId": "GetMaxAllocatableMem",
+ "parameters": [
+ {
+ "minimum": 1,
+ "type": "integer",
+ "format": "int32",
+ "name": "num_nodes",
+ "in": "query",
+ "required": true
+ }
+ ],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
- "$ref": "#/definitions/clusterResources"
+ "$ref": "#/definitions/maxAllocatableMemResponse"
}
},
"default": {
@@ -2044,17 +2054,6 @@ func init() {
}
}
},
- "clusterResources": {
- "type": "object",
- "properties": {
- "nodes": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/nodeInfo"
- }
- }
- }
- },
"configDescription": {
"type": "object",
"properties": {
@@ -2594,30 +2593,12 @@ func init() {
}
}
},
- "nodeInfo": {
+ "maxAllocatableMemResponse": {
"type": "object",
"properties": {
- "allocatable_resources": {
- "description": "Represents the resources of a node that are available for scheduling.",
- "type": "object",
- "additionalProperties": {
- "type": "integer",
- "format": "int64"
- }
- },
- "name": {
- "type": "string"
- },
- "taints": {
- "$ref": "#/definitions/nodeTaints"
- },
- "total_resources": {
- "description": "Represents the total resources of a node.",
- "type": "object",
- "additionalProperties": {
- "type": "integer",
- "format": "int64"
- }
+ "max_memory": {
+ "type": "integer",
+ "format": "int64"
}
}
},
@@ -2685,29 +2666,6 @@ func init() {
}
}
},
- "nodeTaints": {
- "type": "object",
- "properties": {
- "no_execute": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "no_schedule": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "prefer_no_schedule": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
"nofiticationService": {
"type": "string",
"enum": [
@@ -4019,18 +3977,28 @@ func init() {
}
}
},
- "/cluster/resources": {
+ "/cluster/max-allocatable-memory": {
"get": {
"tags": [
"AdminAPI"
],
- "summary": "Get Cluster Resources",
- "operationId": "GetClusterResources",
+ "summary": "Get maximum allocatable memory for given number of nodes",
+ "operationId": "GetMaxAllocatableMem",
+ "parameters": [
+ {
+ "minimum": 1,
+ "type": "integer",
+ "format": "int32",
+ "name": "num_nodes",
+ "in": "query",
+ "required": true
+ }
+ ],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
- "$ref": "#/definitions/clusterResources"
+ "$ref": "#/definitions/maxAllocatableMemResponse"
}
},
"default": {
@@ -6143,17 +6111,6 @@ func init() {
}
}
},
- "clusterResources": {
- "type": "object",
- "properties": {
- "nodes": {
- "type": "array",
- "items": {
- "$ref": "#/definitions/nodeInfo"
- }
- }
- }
- },
"configDescription": {
"type": "object",
"properties": {
@@ -6693,30 +6650,12 @@ func init() {
}
}
},
- "nodeInfo": {
+ "maxAllocatableMemResponse": {
"type": "object",
"properties": {
- "allocatable_resources": {
- "description": "Represents the resources of a node that are available for scheduling.",
- "type": "object",
- "additionalProperties": {
- "type": "integer",
- "format": "int64"
- }
- },
- "name": {
- "type": "string"
- },
- "taints": {
- "$ref": "#/definitions/nodeTaints"
- },
- "total_resources": {
- "description": "Represents the total resources of a node.",
- "type": "object",
- "additionalProperties": {
- "type": "integer",
- "format": "int64"
- }
+ "max_memory": {
+ "type": "integer",
+ "format": "int64"
}
}
},
@@ -6740,29 +6679,6 @@ func init() {
}
}
},
- "nodeTaints": {
- "type": "object",
- "properties": {
- "no_execute": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "no_schedule": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "prefer_no_schedule": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
"nofiticationService": {
"type": "string",
"enum": [
diff --git a/restapi/operations/admin_api/get_cluster_resources_parameters.go b/restapi/operations/admin_api/get_cluster_resources_parameters.go
deleted file mode 100644
index 0d05da75a..000000000
--- a/restapi/operations/admin_api/get_cluster_resources_parameters.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// Code generated by go-swagger; DO NOT EDIT.
-
-// This file is part of MinIO Console Server
-// Copyright (c) 2020 MinIO, Inc.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-//
-
-package admin_api
-
-// This file was generated by the swagger tool.
-// Editing this file might prove futile when you re-run the swagger generate command
-
-import (
- "net/http"
-
- "github.com/go-openapi/errors"
- "github.com/go-openapi/runtime/middleware"
-)
-
-// NewGetClusterResourcesParams creates a new GetClusterResourcesParams object
-// no default values defined in spec.
-func NewGetClusterResourcesParams() GetClusterResourcesParams {
-
- return GetClusterResourcesParams{}
-}
-
-// GetClusterResourcesParams contains all the bound params for the get cluster resources operation
-// typically these are obtained from a http.Request
-//
-// swagger:parameters GetClusterResources
-type GetClusterResourcesParams struct {
-
- // HTTP Request Object
- HTTPRequest *http.Request `json:"-"`
-}
-
-// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
-// for simple values it will use straight method calls.
-//
-// To ensure default values, the struct must have been initialized with NewGetClusterResourcesParams() beforehand.
-func (o *GetClusterResourcesParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
- var res []error
-
- o.HTTPRequest = r
-
- if len(res) > 0 {
- return errors.CompositeValidationError(res...)
- }
- return nil
-}
diff --git a/restapi/operations/admin_api/get_cluster_resources_responses.go b/restapi/operations/admin_api/get_cluster_resources_responses.go
deleted file mode 100644
index f798a99b0..000000000
--- a/restapi/operations/admin_api/get_cluster_resources_responses.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Code generated by go-swagger; DO NOT EDIT.
-
-// This file is part of MinIO Console Server
-// Copyright (c) 2020 MinIO, Inc.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-//
-
-package admin_api
-
-// This file was generated by the swagger tool.
-// Editing this file might prove futile when you re-run the swagger generate command
-
-import (
- "net/http"
-
- "github.com/go-openapi/runtime"
-
- "github.com/minio/console/models"
-)
-
-// GetClusterResourcesOKCode is the HTTP code returned for type GetClusterResourcesOK
-const GetClusterResourcesOKCode int = 200
-
-/*GetClusterResourcesOK A successful response.
-
-swagger:response getClusterResourcesOK
-*/
-type GetClusterResourcesOK struct {
-
- /*
- In: Body
- */
- Payload *models.ClusterResources `json:"body,omitempty"`
-}
-
-// NewGetClusterResourcesOK creates GetClusterResourcesOK with default headers values
-func NewGetClusterResourcesOK() *GetClusterResourcesOK {
-
- return &GetClusterResourcesOK{}
-}
-
-// WithPayload adds the payload to the get cluster resources o k response
-func (o *GetClusterResourcesOK) WithPayload(payload *models.ClusterResources) *GetClusterResourcesOK {
- o.Payload = payload
- return o
-}
-
-// SetPayload sets the payload to the get cluster resources o k response
-func (o *GetClusterResourcesOK) SetPayload(payload *models.ClusterResources) {
- o.Payload = payload
-}
-
-// WriteResponse to the client
-func (o *GetClusterResourcesOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
-
- rw.WriteHeader(200)
- if o.Payload != nil {
- payload := o.Payload
- if err := producer.Produce(rw, payload); err != nil {
- panic(err) // let the recovery middleware deal with this
- }
- }
-}
-
-/*GetClusterResourcesDefault Generic error response.
-
-swagger:response getClusterResourcesDefault
-*/
-type GetClusterResourcesDefault struct {
- _statusCode int
-
- /*
- In: Body
- */
- Payload *models.Error `json:"body,omitempty"`
-}
-
-// NewGetClusterResourcesDefault creates GetClusterResourcesDefault with default headers values
-func NewGetClusterResourcesDefault(code int) *GetClusterResourcesDefault {
- if code <= 0 {
- code = 500
- }
-
- return &GetClusterResourcesDefault{
- _statusCode: code,
- }
-}
-
-// WithStatusCode adds the status to the get cluster resources default response
-func (o *GetClusterResourcesDefault) WithStatusCode(code int) *GetClusterResourcesDefault {
- o._statusCode = code
- return o
-}
-
-// SetStatusCode sets the status to the get cluster resources default response
-func (o *GetClusterResourcesDefault) SetStatusCode(code int) {
- o._statusCode = code
-}
-
-// WithPayload adds the payload to the get cluster resources default response
-func (o *GetClusterResourcesDefault) WithPayload(payload *models.Error) *GetClusterResourcesDefault {
- o.Payload = payload
- return o
-}
-
-// SetPayload sets the payload to the get cluster resources default response
-func (o *GetClusterResourcesDefault) SetPayload(payload *models.Error) {
- o.Payload = payload
-}
-
-// WriteResponse to the client
-func (o *GetClusterResourcesDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
-
- rw.WriteHeader(o._statusCode)
- if o.Payload != nil {
- payload := o.Payload
- if err := producer.Produce(rw, payload); err != nil {
- panic(err) // let the recovery middleware deal with this
- }
- }
-}
diff --git a/restapi/operations/admin_api/get_cluster_resources.go b/restapi/operations/admin_api/get_max_allocatable_mem.go
similarity index 60%
rename from restapi/operations/admin_api/get_cluster_resources.go
rename to restapi/operations/admin_api/get_max_allocatable_mem.go
index 37b9647b5..6e9c4e8ee 100644
--- a/restapi/operations/admin_api/get_cluster_resources.go
+++ b/restapi/operations/admin_api/get_max_allocatable_mem.go
@@ -30,40 +30,40 @@ import (
"github.com/minio/console/models"
)
-// GetClusterResourcesHandlerFunc turns a function with the right signature into a get cluster resources handler
-type GetClusterResourcesHandlerFunc func(GetClusterResourcesParams, *models.Principal) middleware.Responder
+// GetMaxAllocatableMemHandlerFunc turns a function with the right signature into a get max allocatable mem handler
+type GetMaxAllocatableMemHandlerFunc func(GetMaxAllocatableMemParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
-func (fn GetClusterResourcesHandlerFunc) Handle(params GetClusterResourcesParams, principal *models.Principal) middleware.Responder {
+func (fn GetMaxAllocatableMemHandlerFunc) Handle(params GetMaxAllocatableMemParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
-// GetClusterResourcesHandler interface for that can handle valid get cluster resources params
-type GetClusterResourcesHandler interface {
- Handle(GetClusterResourcesParams, *models.Principal) middleware.Responder
+// GetMaxAllocatableMemHandler interface for that can handle valid get max allocatable mem params
+type GetMaxAllocatableMemHandler interface {
+ Handle(GetMaxAllocatableMemParams, *models.Principal) middleware.Responder
}
-// NewGetClusterResources creates a new http.Handler for the get cluster resources operation
-func NewGetClusterResources(ctx *middleware.Context, handler GetClusterResourcesHandler) *GetClusterResources {
- return &GetClusterResources{Context: ctx, Handler: handler}
+// NewGetMaxAllocatableMem creates a new http.Handler for the get max allocatable mem operation
+func NewGetMaxAllocatableMem(ctx *middleware.Context, handler GetMaxAllocatableMemHandler) *GetMaxAllocatableMem {
+ return &GetMaxAllocatableMem{Context: ctx, Handler: handler}
}
-/*GetClusterResources swagger:route GET /cluster/resources AdminAPI getClusterResources
+/*GetMaxAllocatableMem swagger:route GET /cluster/max-allocatable-memory AdminAPI getMaxAllocatableMem
-Get Cluster Resources
+Get maximum allocatable memory for given number of nodes
*/
-type GetClusterResources struct {
+type GetMaxAllocatableMem struct {
Context *middleware.Context
- Handler GetClusterResourcesHandler
+ Handler GetMaxAllocatableMemHandler
}
-func (o *GetClusterResources) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+func (o *GetMaxAllocatableMem) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
}
- var Params = NewGetClusterResourcesParams()
+ var Params = NewGetMaxAllocatableMemParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
diff --git a/restapi/operations/admin_api/get_max_allocatable_mem_parameters.go b/restapi/operations/admin_api/get_max_allocatable_mem_parameters.go
new file mode 100644
index 000000000..3e3f8c6d3
--- /dev/null
+++ b/restapi/operations/admin_api/get_max_allocatable_mem_parameters.go
@@ -0,0 +1,119 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/runtime/middleware"
+ "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag"
+ "github.com/go-openapi/validate"
+)
+
+// NewGetMaxAllocatableMemParams creates a new GetMaxAllocatableMemParams object
+// no default values defined in spec.
+func NewGetMaxAllocatableMemParams() GetMaxAllocatableMemParams {
+
+ return GetMaxAllocatableMemParams{}
+}
+
+// GetMaxAllocatableMemParams contains all the bound params for the get max allocatable mem operation
+// typically these are obtained from a http.Request
+//
+// swagger:parameters GetMaxAllocatableMem
+type GetMaxAllocatableMemParams struct {
+
+ // HTTP Request Object
+ HTTPRequest *http.Request `json:"-"`
+
+ /*
+ Required: true
+ Minimum: 1
+ In: query
+ */
+ NumNodes int32
+}
+
+// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
+// for simple values it will use straight method calls.
+//
+// To ensure default values, the struct must have been initialized with NewGetMaxAllocatableMemParams() beforehand.
+func (o *GetMaxAllocatableMemParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
+ var res []error
+
+ o.HTTPRequest = r
+
+ qs := runtime.Values(r.URL.Query())
+
+ qNumNodes, qhkNumNodes, _ := qs.GetOK("num_nodes")
+ if err := o.bindNumNodes(qNumNodes, qhkNumNodes, route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
+
+// bindNumNodes binds and validates parameter NumNodes from query.
+func (o *GetMaxAllocatableMemParams) bindNumNodes(rawData []string, hasKey bool, formats strfmt.Registry) error {
+ if !hasKey {
+ return errors.Required("num_nodes", "query", rawData)
+ }
+ var raw string
+ if len(rawData) > 0 {
+ raw = rawData[len(rawData)-1]
+ }
+
+ // Required: true
+ // AllowEmptyValue: false
+ if err := validate.RequiredString("num_nodes", "query", raw); err != nil {
+ return err
+ }
+
+ value, err := swag.ConvertInt32(raw)
+ if err != nil {
+ return errors.InvalidType("num_nodes", "query", "int32", raw)
+ }
+ o.NumNodes = value
+
+ if err := o.validateNumNodes(formats); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// validateNumNodes carries on validations for parameter NumNodes
+func (o *GetMaxAllocatableMemParams) validateNumNodes(formats strfmt.Registry) error {
+
+ if err := validate.MinimumInt("num_nodes", "query", int64(o.NumNodes), 1, false); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/restapi/operations/admin_api/get_max_allocatable_mem_responses.go b/restapi/operations/admin_api/get_max_allocatable_mem_responses.go
new file mode 100644
index 000000000..3a9f3af03
--- /dev/null
+++ b/restapi/operations/admin_api/get_max_allocatable_mem_responses.go
@@ -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 .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime"
+
+ "github.com/minio/console/models"
+)
+
+// GetMaxAllocatableMemOKCode is the HTTP code returned for type GetMaxAllocatableMemOK
+const GetMaxAllocatableMemOKCode int = 200
+
+/*GetMaxAllocatableMemOK A successful response.
+
+swagger:response getMaxAllocatableMemOK
+*/
+type GetMaxAllocatableMemOK struct {
+
+ /*
+ In: Body
+ */
+ Payload *models.MaxAllocatableMemResponse `json:"body,omitempty"`
+}
+
+// NewGetMaxAllocatableMemOK creates GetMaxAllocatableMemOK with default headers values
+func NewGetMaxAllocatableMemOK() *GetMaxAllocatableMemOK {
+
+ return &GetMaxAllocatableMemOK{}
+}
+
+// WithPayload adds the payload to the get max allocatable mem o k response
+func (o *GetMaxAllocatableMemOK) WithPayload(payload *models.MaxAllocatableMemResponse) *GetMaxAllocatableMemOK {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the get max allocatable mem o k response
+func (o *GetMaxAllocatableMemOK) SetPayload(payload *models.MaxAllocatableMemResponse) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *GetMaxAllocatableMemOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(200)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
+
+/*GetMaxAllocatableMemDefault Generic error response.
+
+swagger:response getMaxAllocatableMemDefault
+*/
+type GetMaxAllocatableMemDefault struct {
+ _statusCode int
+
+ /*
+ In: Body
+ */
+ Payload *models.Error `json:"body,omitempty"`
+}
+
+// NewGetMaxAllocatableMemDefault creates GetMaxAllocatableMemDefault with default headers values
+func NewGetMaxAllocatableMemDefault(code int) *GetMaxAllocatableMemDefault {
+ if code <= 0 {
+ code = 500
+ }
+
+ return &GetMaxAllocatableMemDefault{
+ _statusCode: code,
+ }
+}
+
+// WithStatusCode adds the status to the get max allocatable mem default response
+func (o *GetMaxAllocatableMemDefault) WithStatusCode(code int) *GetMaxAllocatableMemDefault {
+ o._statusCode = code
+ return o
+}
+
+// SetStatusCode sets the status to the get max allocatable mem default response
+func (o *GetMaxAllocatableMemDefault) SetStatusCode(code int) {
+ o._statusCode = code
+}
+
+// WithPayload adds the payload to the get max allocatable mem default response
+func (o *GetMaxAllocatableMemDefault) WithPayload(payload *models.Error) *GetMaxAllocatableMemDefault {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the get max allocatable mem default response
+func (o *GetMaxAllocatableMemDefault) SetPayload(payload *models.Error) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *GetMaxAllocatableMemDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(o._statusCode)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
diff --git a/restapi/operations/admin_api/get_cluster_resources_urlbuilder.go b/restapi/operations/admin_api/get_max_allocatable_mem_urlbuilder.go
similarity index 72%
rename from restapi/operations/admin_api/get_cluster_resources_urlbuilder.go
rename to restapi/operations/admin_api/get_max_allocatable_mem_urlbuilder.go
index c09ee7c35..2b36513d3 100644
--- a/restapi/operations/admin_api/get_cluster_resources_urlbuilder.go
+++ b/restapi/operations/admin_api/get_max_allocatable_mem_urlbuilder.go
@@ -26,17 +26,23 @@ import (
"errors"
"net/url"
golangswaggerpaths "path"
+
+ "github.com/go-openapi/swag"
)
-// GetClusterResourcesURL generates an URL for the get cluster resources operation
-type GetClusterResourcesURL struct {
+// GetMaxAllocatableMemURL generates an URL for the get max allocatable mem operation
+type GetMaxAllocatableMemURL struct {
+ NumNodes int32
+
_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 *GetClusterResourcesURL) WithBasePath(bp string) *GetClusterResourcesURL {
+func (o *GetMaxAllocatableMemURL) WithBasePath(bp string) *GetMaxAllocatableMemURL {
o.SetBasePath(bp)
return o
}
@@ -44,15 +50,15 @@ func (o *GetClusterResourcesURL) WithBasePath(bp string) *GetClusterResourcesURL
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
-func (o *GetClusterResourcesURL) SetBasePath(bp string) {
+func (o *GetMaxAllocatableMemURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
-func (o *GetClusterResourcesURL) Build() (*url.URL, error) {
+func (o *GetMaxAllocatableMemURL) Build() (*url.URL, error) {
var _result url.URL
- var _path = "/cluster/resources"
+ var _path = "/cluster/max-allocatable-memory"
_basePath := o._basePath
if _basePath == "" {
@@ -60,11 +66,20 @@ func (o *GetClusterResourcesURL) Build() (*url.URL, error) {
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
+ qs := make(url.Values)
+
+ numNodesQ := swag.FormatInt32(o.NumNodes)
+ if numNodesQ != "" {
+ qs.Set("num_nodes", numNodesQ)
+ }
+
+ _result.RawQuery = qs.Encode()
+
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
-func (o *GetClusterResourcesURL) Must(u *url.URL, err error) *url.URL {
+func (o *GetMaxAllocatableMemURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
@@ -75,17 +90,17 @@ func (o *GetClusterResourcesURL) Must(u *url.URL, err error) *url.URL {
}
// String returns the string representation of the path with query string
-func (o *GetClusterResourcesURL) String() string {
+func (o *GetMaxAllocatableMemURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
-func (o *GetClusterResourcesURL) BuildFull(scheme, host string) (*url.URL, error) {
+func (o *GetMaxAllocatableMemURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
- return nil, errors.New("scheme is required for a full url on GetClusterResourcesURL")
+ return nil, errors.New("scheme is required for a full url on GetMaxAllocatableMemURL")
}
if host == "" {
- return nil, errors.New("host is required for a full url on GetClusterResourcesURL")
+ return nil, errors.New("host is required for a full url on GetMaxAllocatableMemURL")
}
base, err := o.Build()
@@ -99,6 +114,6 @@ func (o *GetClusterResourcesURL) BuildFull(scheme, host string) (*url.URL, error
}
// StringFull returns the string representation of a complete url
-func (o *GetClusterResourcesURL) StringFull(scheme, host string) string {
+func (o *GetMaxAllocatableMemURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}
diff --git a/restapi/operations/console_api.go b/restapi/operations/console_api.go
index c21ad2257..d015da226 100644
--- a/restapi/operations/console_api.go
+++ b/restapi/operations/console_api.go
@@ -114,8 +114,8 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
AdminAPIDeleteTenantHandler: admin_api.DeleteTenantHandlerFunc(func(params admin_api.DeleteTenantParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation admin_api.DeleteTenant has not yet been implemented")
}),
- AdminAPIGetClusterResourcesHandler: admin_api.GetClusterResourcesHandlerFunc(func(params admin_api.GetClusterResourcesParams, principal *models.Principal) middleware.Responder {
- return middleware.NotImplemented("operation admin_api.GetClusterResources has not yet been implemented")
+ AdminAPIGetMaxAllocatableMemHandler: admin_api.GetMaxAllocatableMemHandlerFunc(func(params admin_api.GetMaxAllocatableMemParams, principal *models.Principal) middleware.Responder {
+ return middleware.NotImplemented("operation admin_api.GetMaxAllocatableMem has not yet been implemented")
}),
AdminAPIGetResourceQuotaHandler: admin_api.GetResourceQuotaHandlerFunc(func(params admin_api.GetResourceQuotaParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation admin_api.GetResourceQuota has not yet been implemented")
@@ -311,8 +311,8 @@ type ConsoleAPI struct {
UserAPIDeleteServiceAccountHandler user_api.DeleteServiceAccountHandler
// AdminAPIDeleteTenantHandler sets the operation handler for the delete tenant operation
AdminAPIDeleteTenantHandler admin_api.DeleteTenantHandler
- // AdminAPIGetClusterResourcesHandler sets the operation handler for the get cluster resources operation
- AdminAPIGetClusterResourcesHandler admin_api.GetClusterResourcesHandler
+ // AdminAPIGetMaxAllocatableMemHandler sets the operation handler for the get max allocatable mem operation
+ AdminAPIGetMaxAllocatableMemHandler admin_api.GetMaxAllocatableMemHandler
// 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
@@ -511,8 +511,8 @@ func (o *ConsoleAPI) Validate() error {
if o.AdminAPIDeleteTenantHandler == nil {
unregistered = append(unregistered, "admin_api.DeleteTenantHandler")
}
- if o.AdminAPIGetClusterResourcesHandler == nil {
- unregistered = append(unregistered, "admin_api.GetClusterResourcesHandler")
+ if o.AdminAPIGetMaxAllocatableMemHandler == nil {
+ unregistered = append(unregistered, "admin_api.GetMaxAllocatableMemHandler")
}
if o.AdminAPIGetResourceQuotaHandler == nil {
unregistered = append(unregistered, "admin_api.GetResourceQuotaHandler")
@@ -796,7 +796,7 @@ func (o *ConsoleAPI) initHandlerCache() {
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
- o.handlers["GET"]["/cluster/resources"] = admin_api.NewGetClusterResources(o.context, o.AdminAPIGetClusterResourcesHandler)
+ o.handlers["GET"]["/cluster/max-allocatable-memory"] = admin_api.NewGetMaxAllocatableMem(o.context, o.AdminAPIGetMaxAllocatableMemHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
diff --git a/swagger.yml b/swagger.yml
index 6b37c442c..24d017668 100644
--- a/swagger.yml
+++ b/swagger.yml
@@ -1227,15 +1227,22 @@ paths:
tags:
- AdminAPI
- /cluster/resources:
+ /cluster/max-allocatable-memory:
get:
- summary: Get Cluster Resources
- operationId: GetClusterResources
+ summary: Get maximum allocatable memory for given number of nodes
+ operationId: GetMaxAllocatableMem
+ parameters:
+ - name: num_nodes
+ in: query
+ required: true
+ type: integer
+ format: int32
+ minimum: 1
responses:
200:
description: A successful response.
schema:
- $ref: "#/definitions/clusterResources"
+ $ref: "#/definitions/maxAllocatableMemResponse"
default:
description: Generic error response.
schema:
@@ -2589,50 +2596,10 @@ definitions:
type: array
items:
$ref: "#/definitions/zone"
-
- clusterResources:
- type: object
- properties:
- nodes:
- type: array
- items:
- $ref: "#/definitions/nodeInfo"
- nodeInfo:
+ maxAllocatableMemResponse:
type: object
properties:
- name:
- type: string
- taints:
- $ref: "#/definitions/nodeTaints"
- allocatable_resources:
- type: object
- additionalProperties:
- type: integer
- format: int64
- description: Represents the resources of a node that are available for scheduling.
- total_resources:
- type: object
- additionalProperties:
- type: integer
- format: int64
- description: Represents the total resources of a node.
-
- nodeTaints:
- type: object
- properties:
- no_schedule:
- type: array
- items:
- type: string
- no_execute:
- type: array
- items:
- type: string
- prefer_no_schedule:
- type: array
- items:
- type: string
-
-
-
+ max_memory:
+ type: integer
+ format: int64