From 53fb5257a6d83b72a432f9d9ebdcde7668801b3d Mon Sep 17 00:00:00 2001 From: Oleg Isakov Date: Fri, 21 Aug 2026 12:36:08 +0300 Subject: [PATCH] add k8s autoscale methods --- .../autoscale_node_group_response.json | 21 ++ ...utoscale_node_group_template_response.json | 5 + pkg/kubernetes_clusters.go | 215 ++++++++++++++- pkg/kubernetes_clusters_test.go | 253 +++++++++++++++++- pkg/types.go | 60 +++++ 5 files changed, 546 insertions(+), 8 deletions(-) create mode 100644 pkg/fixtures/kubernetes_clusters/autoscale_node_group_response.json create mode 100644 pkg/fixtures/kubernetes_clusters/autoscale_node_group_template_response.json diff --git a/pkg/fixtures/kubernetes_clusters/autoscale_node_group_response.json b/pkg/fixtures/kubernetes_clusters/autoscale_node_group_response.json new file mode 100644 index 0000000..30a5cc7 --- /dev/null +++ b/pkg/fixtures/kubernetes_clusters/autoscale_node_group_response.json @@ -0,0 +1,21 @@ +{ + "id": "autoscale-node-group-id", + "name": "autoscale-workers", + "description": "autoscale worker node group", + "type": "autoscale", + "node_type": "sbm", + "min_nodes": 1, + "max_nodes": 5, + "target_nodes": 2, + "current_nodes": 2, + "node_spec": { + "flavor_id": "flavor-id" + }, + "node_template": { + "labels": { + "env": "test" + } + }, + "created_at": "2024-11-11T09:57:56Z", + "updated_at": "2024-11-11T09:57:56Z" +} diff --git a/pkg/fixtures/kubernetes_clusters/autoscale_node_group_template_response.json b/pkg/fixtures/kubernetes_clusters/autoscale_node_group_template_response.json new file mode 100644 index 0000000..0b34a55 --- /dev/null +++ b/pkg/fixtures/kubernetes_clusters/autoscale_node_group_template_response.json @@ -0,0 +1,5 @@ +{ + "flavor_name": "SBM-Autoscale-Flavor", + "logical_cpu_count": 32, + "ram_size": 128 +} diff --git a/pkg/kubernetes_clusters.go b/pkg/kubernetes_clusters.go index 830a10b..32036ad 100644 --- a/pkg/kubernetes_clusters.go +++ b/pkg/kubernetes_clusters.go @@ -15,11 +15,13 @@ const ( kubernetesClusterNodeGroupPath = kubernetesClusterPathWithID + "/node_groups" kubernetesClusterNodeGroupPathWithID = kubernetesClusterNodeGroupPath + "/%s" - // /v1/kubernetes_clusters/{kubernetes_cluster_id}/nodes - // /v1/kubernetes_clusters/{kubernetes_cluster_id}/nodes/{node_id} - // /v1/kubernetes_clusters/{kubernetes_cluster_id}/nodes/move - // /v1/kubernetes_clusters/{kubernetes_cluster_id}/node_groups - // /v1/kubernetes_clusters/{kubernetes_cluster_id}/node_groups/{node_group_id} + kubernetesClusterAutoscaleNodeGroupPath = kubernetesClusterPathWithID + "/autoscale_node_groups" + kubernetesClusterAutoscaleNodeGroupPathWithID = kubernetesClusterAutoscaleNodeGroupPath + "/%s" + kubernetesClusterAutoscaleNodeGroupTemplatePath = kubernetesClusterAutoscaleNodeGroupPathWithID + "/autoscale_template" + kubernetesClusterAutoscaleNodeGroupDecreaseSizePath = kubernetesClusterAutoscaleNodeGroupPathWithID + "/decrease_target_size" + kubernetesClusterAutoscaleNodeGroupDeleteNodesPath = kubernetesClusterAutoscaleNodeGroupPathWithID + "/delete_nodes" + kubernetesClusterAutoscaleNodeGroupIncreaseSizePath = kubernetesClusterAutoscaleNodeGroupPathWithID + "/increase_size" + kubernetesClusterAutoscaleNodeGroupNodesPath = kubernetesClusterAutoscaleNodeGroupPathWithID + "/nodes" ) // KubernetesClustersService is an interface for interfacing with Kubernetes Cluster endpoints @@ -42,9 +44,21 @@ type KubernetesClustersService interface { UpdateNodeGroup(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterNodeGroupUpdateInput) (*KubernetesClusterNodeGroup, error) DeleteNodeGroup(ctx context.Context, clusterID string, nodeGroupID string) error + // autoscale node group operations + GetAutoscaleNodeGroup(ctx context.Context, clusterID string, nodeGroupID string) (*KubernetesClusterAutoscaleNodeGroup, error) + CreateAutoscaleNodeGroup(ctx context.Context, clusterID string, input KubernetesClusterAutoscaleNodeGroupCreateInput) (*KubernetesClusterAutoscaleNodeGroup, error) + UpdateAutoscaleNodeGroup(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupUpdateInput) (*KubernetesClusterAutoscaleNodeGroup, error) + DeleteAutoscaleNodeGroup(ctx context.Context, clusterID string, nodeGroupID string) error + GetAutoscaleNodeGroupTemplate(ctx context.Context, clusterID string, nodeGroupID string) (*KubernetesClusterAutoscaleNodeGroupTemplate, error) + DecreaseAutoscaleNodeGroupTargetSize(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupDecreaseTargetSizeInput) (*KubernetesClusterAutoscaleNodeGroup, error) + IncreaseAutoscaleNodeGroupSize(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupIncreaseSizeInput) (*KubernetesClusterAutoscaleNodeGroup, error) + DeleteAutoscaleNodeGroupNodes(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupDeleteNodesInput) (*KubernetesClusterAutoscaleNodeGroup, error) + // Additional collections Nodes(id string) Collection[KubernetesClusterNode] NodeGroups(id string) Collection[KubernetesClusterNodeGroup] + AutoscaleNodeGroups(clusterID string) Collection[KubernetesClusterAutoscaleNodeGroup] + AutoscaleNodeGroupNodes(clusterID string, nodeGroupID string) Collection[KubernetesClusterNode] } // KubernetesClustersHandler handles operations around kubernetes clusters @@ -74,6 +88,22 @@ func (h *KubernetesClustersHandler) NodeGroups(id string) Collection[KubernetesC return NewCollection[KubernetesClusterNodeGroup](h.client, path) } +// AutoscaleNodeGroups builds a new Collection[KubernetesClusterAutoscaleNodeGroup] interface +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/KubernetesClusterAutoscaleNodeGroups +func (h *KubernetesClustersHandler) AutoscaleNodeGroups(clusterID string) Collection[KubernetesClusterAutoscaleNodeGroup] { + path := h.client.buildPath(kubernetesClusterAutoscaleNodeGroupPath, []interface{}{clusterID}...) + + return NewCollection[KubernetesClusterAutoscaleNodeGroup](h.client, path) +} + +// AutoscaleNodeGroupNodes builds a new Collection[KubernetesClusterNode] interface +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/ListTheNodesOfAnAutoscaleNodeGroup +func (h *KubernetesClustersHandler) AutoscaleNodeGroupNodes(clusterID string, nodeGroupID string) Collection[KubernetesClusterNode] { + path := h.client.buildPath(kubernetesClusterAutoscaleNodeGroupNodesPath, []interface{}{clusterID, nodeGroupID}...) + + return NewCollection[KubernetesClusterNode](h.client, path) +} + // Get a Kubernetes cluster // Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/GetAKubernetesCluster func (h *KubernetesClustersHandler) Get(ctx context.Context, id string) (*KubernetesCluster, error) { @@ -237,6 +267,8 @@ func (h *KubernetesClustersHandler) UpdateNodeGroup(ctx context.Context, cluster return &nodeGroup, nil } +// DeleteNodeGroup deletes a node group for a Kubernetes cluster +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/DeleteANodeGroupForAKubernetesCluster // DeleteNodeGroup deletes a node group for a Kubernetes cluster // Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/DeleteANodeGroupForAKubernetesCluster func (h *KubernetesClustersHandler) DeleteNodeGroup(ctx context.Context, clusterID string, nodeGroupID string) error { @@ -246,3 +278,176 @@ func (h *KubernetesClustersHandler) DeleteNodeGroup(ctx context.Context, cluster return err } + +// GetAutoscaleNodeGroup gets an autoscale node group for a Kubernetes cluster +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/ShowAnAutoscaleNodeGroup +func (h *KubernetesClustersHandler) GetAutoscaleNodeGroup(ctx context.Context, clusterID string, nodeGroupID string) (*KubernetesClusterAutoscaleNodeGroup, error) { + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupPathWithID, []interface{}{clusterID, nodeGroupID}...) + + body, err := h.client.buildAndExecRequest(ctx, "GET", url, nil) + + if err != nil { + return nil, err + } + + var nodeGroup KubernetesClusterAutoscaleNodeGroup + if err := json.Unmarshal(body, &nodeGroup); err != nil { + return nil, err + } + + return &nodeGroup, nil +} + +// CreateAutoscaleNodeGroup creates an autoscale node group for a Kubernetes cluster +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/CreateANewAutoscaleNodeGroup +func (h *KubernetesClustersHandler) CreateAutoscaleNodeGroup(ctx context.Context, clusterID string, input KubernetesClusterAutoscaleNodeGroupCreateInput) (*KubernetesClusterAutoscaleNodeGroup, error) { + payload, err := json.Marshal(input) + + if err != nil { + return nil, err + } + + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupPath, []interface{}{clusterID}...) + + body, err := h.client.buildAndExecRequest(ctx, "POST", url, payload) + + if err != nil { + return nil, err + } + + var nodeGroup KubernetesClusterAutoscaleNodeGroup + if err := json.Unmarshal(body, &nodeGroup); err != nil { + return nil, err + } + + return &nodeGroup, nil +} + +// UpdateAutoscaleNodeGroup updates an autoscale node group for a Kubernetes cluster +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/UpdateAnAutoscaleNodeGroup +func (h *KubernetesClustersHandler) UpdateAutoscaleNodeGroup(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupUpdateInput) (*KubernetesClusterAutoscaleNodeGroup, error) { + payload, err := json.Marshal(input) + + if err != nil { + return nil, err + } + + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupPathWithID, []interface{}{clusterID, nodeGroupID}...) + + body, err := h.client.buildAndExecRequest(ctx, "PUT", url, payload) + + if err != nil { + return nil, err + } + + var nodeGroup KubernetesClusterAutoscaleNodeGroup + if err := json.Unmarshal(body, &nodeGroup); err != nil { + return nil, err + } + + return &nodeGroup, nil +} + +// DeleteAutoscaleNodeGroup deletes an autoscale node group for a Kubernetes cluster +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/DeleteAnAutoscaleNodeGroup +func (h *KubernetesClustersHandler) DeleteAutoscaleNodeGroup(ctx context.Context, clusterID string, nodeGroupID string) error { + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupPathWithID, []interface{}{clusterID, nodeGroupID}...) + + _, err := h.client.buildAndExecRequest(ctx, "DELETE", url, nil) + + return err +} + +// GetAutoscaleNodeGroupTemplate shows what a node of an autoscale node group looks like +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/ShowWhatANodeOfTheGroupLooksLike +func (h *KubernetesClustersHandler) GetAutoscaleNodeGroupTemplate(ctx context.Context, clusterID string, nodeGroupID string) (*KubernetesClusterAutoscaleNodeGroupTemplate, error) { + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupTemplatePath, []interface{}{clusterID, nodeGroupID}...) + + body, err := h.client.buildAndExecRequest(ctx, "GET", url, nil) + + if err != nil { + return nil, err + } + + var template KubernetesClusterAutoscaleNodeGroupTemplate + if err := json.Unmarshal(body, &template); err != nil { + return nil, err + } + + return &template, nil +} + +// DecreaseAutoscaleNodeGroupTargetSize lowers the target size of an autoscale node group without touching its nodes +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/LowerTheTargetSizeOfTheGroupWithoutTouchingItsNodes +func (h *KubernetesClustersHandler) DecreaseAutoscaleNodeGroupTargetSize(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupDecreaseTargetSizeInput) (*KubernetesClusterAutoscaleNodeGroup, error) { + payload, err := json.Marshal(input) + + if err != nil { + return nil, err + } + + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupDecreaseSizePath, []interface{}{clusterID, nodeGroupID}...) + + body, err := h.client.buildAndExecRequest(ctx, "POST", url, payload) + + if err != nil { + return nil, err + } + + var nodeGroup KubernetesClusterAutoscaleNodeGroup + if err := json.Unmarshal(body, &nodeGroup); err != nil { + return nil, err + } + + return &nodeGroup, nil +} + +// IncreaseAutoscaleNodeGroupSize raises the target size of an autoscale node group and orders the nodes +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/RaiseTheTargetSizeOfTheGroupAndOrderTheNodes +func (h *KubernetesClustersHandler) IncreaseAutoscaleNodeGroupSize(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupIncreaseSizeInput) (*KubernetesClusterAutoscaleNodeGroup, error) { + payload, err := json.Marshal(input) + + if err != nil { + return nil, err + } + + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupIncreaseSizePath, []interface{}{clusterID, nodeGroupID}...) + + body, err := h.client.buildAndExecRequest(ctx, "POST", url, payload) + + if err != nil { + return nil, err + } + + var nodeGroup KubernetesClusterAutoscaleNodeGroup + if err := json.Unmarshal(body, &nodeGroup); err != nil { + return nil, err + } + + return &nodeGroup, nil +} + +// DeleteAutoscaleNodeGroupNodes releases nodes of an autoscale node group and lowers the target size to match +// Endpoint: https://developers.servers.com/api-documentation/v1/#tag/Kubernetes-Cluster/operation/ReleaseNodesOfTheGroupAndLowerTheTargetSizeToMatch +func (h *KubernetesClustersHandler) DeleteAutoscaleNodeGroupNodes(ctx context.Context, clusterID string, nodeGroupID string, input KubernetesClusterAutoscaleNodeGroupDeleteNodesInput) (*KubernetesClusterAutoscaleNodeGroup, error) { + payload, err := json.Marshal(input) + + if err != nil { + return nil, err + } + + url := h.client.buildURL(kubernetesClusterAutoscaleNodeGroupDeleteNodesPath, []interface{}{clusterID, nodeGroupID}...) + + body, err := h.client.buildAndExecRequest(ctx, "POST", url, payload) + + if err != nil { + return nil, err + } + + var nodeGroup KubernetesClusterAutoscaleNodeGroup + if err := json.Unmarshal(body, &nodeGroup); err != nil { + return nil, err + } + + return &nodeGroup, nil +} diff --git a/pkg/kubernetes_clusters_test.go b/pkg/kubernetes_clusters_test.go index 0be95c4..62e2fee 100644 --- a/pkg/kubernetes_clusters_test.go +++ b/pkg/kubernetes_clusters_test.go @@ -8,9 +8,10 @@ import ( ) const ( - clusterID = "YQdJqobO" - nodeID = "MYer06bO" - nodeGroupID = "node-group-id" + clusterID = "YQdJqobO" + nodeID = "MYer06bO" + nodeGroupID = "node-group-id" + autoscaleNodeGroupID = "autoscale-node-group-id" ) func TestKubernetesClusterCollection(t *testing.T) { @@ -312,3 +313,249 @@ func TestKubernetesClusterUpdateNode(t *testing.T) { g.Expect(node.NodeGroup.Name).To(Equal("workers")) g.Expect(node.NodeGroup.Type).To(Equal("static")) } + +func TestKubernetesClusterAutoscaleNodeGroupsCollection(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups"). + WithRequestMethod("GET"). + WithResponseBodyStubInline(`[]`). + WithResponseCode(200). + Build() + + defer ts.Close() + + collection := client.KubernetesClusters.AutoscaleNodeGroups(clusterID) + + ctx := context.TODO() + + list, err := collection.List(ctx) + + g.Expect(err).To(BeNil()) + g.Expect(list).To(BeEmpty()) + g.Expect(collection.HasNextPage()).To(Equal(false)) + g.Expect(collection.HasPreviousPage()).To(Equal(false)) + g.Expect(collection.HasFirstPage()).To(Equal(false)) + g.Expect(collection.HasLastPage()).To(Equal(false)) +} + +func TestKubernetesClusterCreateAutoscaleNodeGroup(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups"). + WithRequestMethod("POST"). + WithResponseBodyStubFile("fixtures/kubernetes_clusters/autoscale_node_group_response.json"). + WithResponseCode(201). + Build() + + defer ts.Close() + + ctx := context.TODO() + + nodeGroup, err := client.KubernetesClusters.CreateAutoscaleNodeGroup(ctx, clusterID, KubernetesClusterAutoscaleNodeGroupCreateInput{ + Name: "autoscale-workers", + NodeType: "sbm", + MinNodes: 1, + MaxNodes: 5, + NodeSpec: map[string]any{"flavor_id": "flavor-id"}, + }) + + g.Expect(err).To(BeNil()) + g.Expect(nodeGroup).ToNot(BeNil()) + g.Expect(nodeGroup.ID).To(Equal(autoscaleNodeGroupID)) + g.Expect(nodeGroup.Name).To(Equal("autoscale-workers")) + g.Expect(*nodeGroup.Description).To(Equal("autoscale worker node group")) + g.Expect(nodeGroup.Type).To(Equal("autoscale")) + g.Expect(nodeGroup.NodeType).To(Equal("sbm")) + g.Expect(nodeGroup.MinNodes).To(Equal(int64(1))) + g.Expect(nodeGroup.MaxNodes).To(Equal(int64(5))) + g.Expect(nodeGroup.TargetNodes).To(Equal(int64(2))) + g.Expect(nodeGroup.CurrentNodes).To(Equal(int64(2))) + g.Expect(nodeGroup.Created.String()).To(Equal("2024-11-11 09:57:56 +0000 UTC")) + g.Expect(nodeGroup.Updated.String()).To(Equal("2024-11-11 09:57:56 +0000 UTC")) +} + +func TestKubernetesClusterGetAutoscaleNodeGroup(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID). + WithRequestMethod("GET"). + WithResponseBodyStubFile("fixtures/kubernetes_clusters/autoscale_node_group_response.json"). + WithResponseCode(200). + Build() + + defer ts.Close() + + ctx := context.TODO() + + nodeGroup, err := client.KubernetesClusters.GetAutoscaleNodeGroup(ctx, clusterID, autoscaleNodeGroupID) + + g.Expect(err).To(BeNil()) + g.Expect(nodeGroup).ToNot(BeNil()) + g.Expect(nodeGroup.ID).To(Equal(autoscaleNodeGroupID)) + g.Expect(nodeGroup.Name).To(Equal("autoscale-workers")) +} + +func TestKubernetesClusterUpdateAutoscaleNodeGroup(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID). + WithRequestMethod("PUT"). + WithResponseBodyStubFile("fixtures/kubernetes_clusters/autoscale_node_group_response.json"). + WithResponseCode(202). + Build() + + defer ts.Close() + + ctx := context.TODO() + + nodeGroup, err := client.KubernetesClusters.UpdateAutoscaleNodeGroup(ctx, clusterID, autoscaleNodeGroupID, KubernetesClusterAutoscaleNodeGroupUpdateInput{ + Name: "autoscale-workers", + MaxNodes: 5, + }) + + g.Expect(err).To(BeNil()) + g.Expect(nodeGroup).ToNot(BeNil()) + g.Expect(nodeGroup.ID).To(Equal(autoscaleNodeGroupID)) + g.Expect(nodeGroup.Name).To(Equal("autoscale-workers")) +} + +func TestKubernetesClusterDeleteAutoscaleNodeGroup(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID). + WithRequestMethod("DELETE"). + WithResponseCode(204). + Build() + + defer ts.Close() + + ctx := context.TODO() + + err := client.KubernetesClusters.DeleteAutoscaleNodeGroup(ctx, clusterID, autoscaleNodeGroupID) + + g.Expect(err).To(BeNil()) +} + +func TestKubernetesClusterGetAutoscaleNodeGroupTemplate(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID + "/autoscale_template"). + WithRequestMethod("GET"). + WithResponseBodyStubFile("fixtures/kubernetes_clusters/autoscale_node_group_template_response.json"). + WithResponseCode(200). + Build() + + defer ts.Close() + + ctx := context.TODO() + + template, err := client.KubernetesClusters.GetAutoscaleNodeGroupTemplate(ctx, clusterID, autoscaleNodeGroupID) + + g.Expect(err).To(BeNil()) + g.Expect(template).ToNot(BeNil()) + g.Expect(template.FlavorName).To(Equal("SBM-Autoscale-Flavor")) + g.Expect(*template.LogicalCPUCount).To(Equal(int64(32))) + g.Expect(*template.RAMSize).To(Equal(int64(128))) +} + +func TestKubernetesClusterDecreaseAutoscaleNodeGroupTargetSize(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID + "/decrease_target_size"). + WithRequestMethod("POST"). + WithResponseBodyStubFile("fixtures/kubernetes_clusters/autoscale_node_group_response.json"). + WithResponseCode(200). + Build() + + defer ts.Close() + + ctx := context.TODO() + + nodeGroup, err := client.KubernetesClusters.DecreaseAutoscaleNodeGroupTargetSize(ctx, clusterID, autoscaleNodeGroupID, KubernetesClusterAutoscaleNodeGroupDecreaseTargetSizeInput{ + Delta: 1, + }) + + g.Expect(err).To(BeNil()) + g.Expect(nodeGroup).ToNot(BeNil()) + g.Expect(nodeGroup.ID).To(Equal(autoscaleNodeGroupID)) +} + +func TestKubernetesClusterIncreaseAutoscaleNodeGroupSize(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID + "/increase_size"). + WithRequestMethod("POST"). + WithResponseBodyStubFile("fixtures/kubernetes_clusters/autoscale_node_group_response.json"). + WithResponseCode(200). + Build() + + defer ts.Close() + + ctx := context.TODO() + + nodeGroup, err := client.KubernetesClusters.IncreaseAutoscaleNodeGroupSize(ctx, clusterID, autoscaleNodeGroupID, KubernetesClusterAutoscaleNodeGroupIncreaseSizeInput{ + Delta: 1, + }) + + g.Expect(err).To(BeNil()) + g.Expect(nodeGroup).ToNot(BeNil()) + g.Expect(nodeGroup.ID).To(Equal(autoscaleNodeGroupID)) +} + +func TestKubernetesClusterDeleteAutoscaleNodeGroupNodes(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID + "/delete_nodes"). + WithRequestMethod("POST"). + WithResponseBodyStubFile("fixtures/kubernetes_clusters/autoscale_node_group_response.json"). + WithResponseCode(200). + Build() + + defer ts.Close() + + ctx := context.TODO() + + nodeGroup, err := client.KubernetesClusters.DeleteAutoscaleNodeGroupNodes(ctx, clusterID, autoscaleNodeGroupID, KubernetesClusterAutoscaleNodeGroupDeleteNodesInput{ + NodeIDs: []string{nodeID}, + }) + + g.Expect(err).To(BeNil()) + g.Expect(nodeGroup).ToNot(BeNil()) + g.Expect(nodeGroup.ID).To(Equal(autoscaleNodeGroupID)) +} + +func TestKubernetesClusterAutoscaleNodeGroupNodesCollection(t *testing.T) { + g := NewGomegaWithT(t) + + ts, client := newFakeServer(). + WithRequestPath("/kubernetes_clusters/" + clusterID + "/autoscale_node_groups/" + autoscaleNodeGroupID + "/nodes"). + WithRequestMethod("GET"). + WithResponseBodyStubInline(`[]`). + WithResponseCode(200). + Build() + + defer ts.Close() + + collection := client.KubernetesClusters.AutoscaleNodeGroupNodes(clusterID, autoscaleNodeGroupID) + + ctx := context.TODO() + + list, err := collection.List(ctx) + + g.Expect(err).To(BeNil()) + g.Expect(list).To(BeEmpty()) + g.Expect(collection.HasNextPage()).To(Equal(false)) + g.Expect(collection.HasPreviousPage()).To(Equal(false)) + g.Expect(collection.HasFirstPage()).To(Equal(false)) + g.Expect(collection.HasLastPage()).To(Equal(false)) +} diff --git a/pkg/types.go b/pkg/types.go index ea28e67..519abdd 100644 --- a/pkg/types.go +++ b/pkg/types.go @@ -1261,6 +1261,7 @@ type KubernetesClusterNodeGroup struct { ID string `json:"id"` Name string `json:"name"` Description *string `json:"description"` + Type string `json:"type"` NodeCount int64 `json:"node_count"` Created time.Time `json:"created_at"` Updated time.Time `json:"updated_at"` @@ -1304,6 +1305,65 @@ type KubernetesClusterNodeUpdateInput struct { NodeGroupID string `json:"node_group_id"` } +// KubernetesClusterAutoscaleNodeGroup represents a Kubernetes cluster autoscale node group +type KubernetesClusterAutoscaleNodeGroup struct { + ID string `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + Type string `json:"type"` + NodeType string `json:"node_type"` + MinNodes int64 `json:"min_nodes"` + MaxNodes int64 `json:"max_nodes"` + TargetNodes int64 `json:"target_nodes"` + CurrentNodes int64 `json:"current_nodes"` + NodeSpec map[string]any `json:"node_spec"` + NodeTemplate map[string]any `json:"node_template"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` +} + +// KubernetesClusterAutoscaleNodeGroupTemplate represents what a node of an autoscale node group looks like +type KubernetesClusterAutoscaleNodeGroupTemplate struct { + FlavorName string `json:"flavor_name"` + LogicalCPUCount *int64 `json:"logical_cpu_count"` + RAMSize *int64 `json:"ram_size"` +} + +// KubernetesClusterAutoscaleNodeGroupCreateInput represents input for creating an autoscale node group +type KubernetesClusterAutoscaleNodeGroupCreateInput struct { + Name string `json:"name"` + Description string `json:"description,omitempty"` + NodeType string `json:"node_type"` + MinNodes int64 `json:"min_nodes"` + MaxNodes int64 `json:"max_nodes"` + NodeSpec map[string]any `json:"node_spec"` + NodeTemplate map[string]any `json:"node_template,omitempty"` +} + +// KubernetesClusterAutoscaleNodeGroupUpdateInput represents input for updating an autoscale node group +type KubernetesClusterAutoscaleNodeGroupUpdateInput struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + MinNodes int64 `json:"min_nodes,omitempty"` + MaxNodes int64 `json:"max_nodes,omitempty"` + NodeTemplate map[string]string `json:"node_template,omitempty"` +} + +// KubernetesClusterAutoscaleNodeGroupDecreaseTargetSizeInput represents input for lowering the target size of an autoscale node group +type KubernetesClusterAutoscaleNodeGroupDecreaseTargetSizeInput struct { + Delta int64 `json:"delta"` +} + +// KubernetesClusterAutoscaleNodeGroupIncreaseSizeInput represents input for raising the target size of an autoscale node group +type KubernetesClusterAutoscaleNodeGroupIncreaseSizeInput struct { + Delta int64 `json:"delta"` +} + +// KubernetesClusterAutoscaleNodeGroupDeleteNodesInput represents input for releasing nodes of an autoscale node group +type KubernetesClusterAutoscaleNodeGroupDeleteNodesInput struct { + NodeIDs []string `json:"node_ids"` +} + // InvoiceList represents invoices list type InvoiceList struct { ID string `json:"id"`