From 624891ae1fb8099d21b22c9e51a64b920b5d0458 Mon Sep 17 00:00:00 2001 From: Cesar N Date: Wed, 2 Sep 2020 17:06:02 -0700 Subject: [PATCH] Replace resources api to return the max allocatable memory (#264) --- models/cluster_resources.go | 97 ----- ...nts.go => max_allocatable_mem_response.go} | 26 +- models/node_info.go | 97 ----- restapi/admin_nodes.go | 112 +++--- restapi/admin_nodes_test.go | 331 ++++++++++++++---- restapi/embedded_spec.go | 156 ++------- .../get_cluster_resources_parameters.go | 62 ---- .../get_cluster_resources_responses.go | 133 ------- ...esources.go => get_max_allocatable_mem.go} | 30 +- .../get_max_allocatable_mem_parameters.go | 119 +++++++ .../get_max_allocatable_mem_responses.go | 133 +++++++ ... => get_max_allocatable_mem_urlbuilder.go} | 39 ++- restapi/operations/console_api.go | 14 +- swagger.yml | 63 +--- 14 files changed, 698 insertions(+), 714 deletions(-) delete mode 100644 models/cluster_resources.go rename models/{node_taints.go => max_allocatable_mem_response.go} (71%) delete mode 100644 models/node_info.go delete mode 100644 restapi/operations/admin_api/get_cluster_resources_parameters.go delete mode 100644 restapi/operations/admin_api/get_cluster_resources_responses.go rename restapi/operations/admin_api/{get_cluster_resources.go => get_max_allocatable_mem.go} (60%) create mode 100644 restapi/operations/admin_api/get_max_allocatable_mem_parameters.go create mode 100644 restapi/operations/admin_api/get_max_allocatable_mem_responses.go rename restapi/operations/admin_api/{get_cluster_resources_urlbuilder.go => get_max_allocatable_mem_urlbuilder.go} (72%) 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