Skip to content

Commit e173142

Browse files
authored
feat(kubernetes) node group node details (#244)
Provide information about node group nodes and add experimental resource to remove specific node from node group.
1 parent 98fa059 commit e173142

7 files changed

Lines changed: 165 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ See updating [Changelog example here](https://keepachangelog.com/en/1.0.0/)
77

88
### Added
99
- client functions `NewDefaultHTTPClient` and `NewDefaultHTTPTransport` to provide HTTP client default properties
10+
- kubernetes: experimental support for deleting nodes from node groups
11+
12+
### Changed
13+
- `service.GetKubernetesNodeGroup` method to return `upcloud.KubernetesNodeGroupDetails` type which is extended version of the previous `upcloud.KubernetesNodeGroup`
1014

1115
## [6.3.2]
1216

upcloud/kubernetes.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,20 @@ const (
1717
KubernetesClusterTaintEffectNoExecute KubernetesClusterTaintEffect = "NoExecute"
1818
KubernetesClusterTaintEffectNoSchedule KubernetesClusterTaintEffect = "NoSchedule"
1919
KubernetesClusterTaintEffectPreferNoSchedule KubernetesClusterTaintEffect = "PreferNoSchedule"
20+
21+
KubernetesNodeStateFailed KubernetesNodeState = "failed"
22+
KubernetesNodeStatePending KubernetesNodeState = "pending"
23+
KubernetesNodeStateRunning KubernetesNodeState = "running"
24+
KubernetesNodeStateTerminating KubernetesNodeState = "terminating"
25+
KubernetesNodeStateUnknown KubernetesNodeState = "unknown"
2026
)
2127

2228
type (
2329
KubernetesClusterState string
2430
KubernetesNodeGroupState string
2531
KubernetesClusterType string
2632
KubernetesClusterTaintEffect string
33+
KubernetesNodeState string
2734
)
2835

2936
type KubernetesCluster struct {
@@ -51,6 +58,18 @@ type KubernetesNodeGroup struct {
5158
Taints []KubernetesTaint `json:"taints,omitempty"`
5259
}
5360

61+
type KubernetesNodeGroupDetails struct {
62+
KubernetesNodeGroup
63+
64+
Nodes []KubernetesNode `json:"nodes,omitempty"`
65+
}
66+
67+
type KubernetesNode struct {
68+
UUID string `json:"uuid,omitempty"`
69+
Name string `json:"name,omitempty"`
70+
State KubernetesNodeState `json:"state,omitempty"`
71+
}
72+
5473
type KubernetesKubeletArg struct {
5574
Key string `json:"key"`
5675
Value string `json:"value"`

upcloud/kubernetes_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"testing"
66

77
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
89
)
910

1011
const exampleKubernetesClusterJSON string = `{
@@ -93,6 +94,59 @@ func TestKubernetes(t *testing.T) {
9394
})
9495
}
9596

97+
func TestKubernetesNodeGroupDetails(t *testing.T) {
98+
t.Parallel()
99+
100+
const nodeGroupDetailsJSON = `
101+
{
102+
"anti_affinity": true,
103+
"count": 2,
104+
"name": "grp-1",
105+
"plan": "1xCPU-1GB",
106+
"state": "running",
107+
"nodes": [
108+
{
109+
"name": "grp-1-7l7zj",
110+
"state": "running",
111+
"uuid": "00a02bfa-f565-40c9-b088-f2c7b8a75f97"
112+
},
113+
{
114+
"name": "grp-1-glkwv",
115+
"state": "terminating",
116+
"uuid": "00b56302-e211-40d9-83fa-177f0171e75a"
117+
}
118+
]
119+
}
120+
`
121+
got := KubernetesNodeGroupDetails{}
122+
err := json.Unmarshal([]byte(nodeGroupDetailsJSON), &got)
123+
want := KubernetesNodeGroupDetails{
124+
KubernetesNodeGroup: KubernetesNodeGroup{
125+
AntiAffinity: true,
126+
Count: 2,
127+
Name: "grp-1",
128+
Plan: "1xCPU-1GB",
129+
State: KubernetesNodeGroupStateRunning,
130+
},
131+
Nodes: []KubernetesNode{
132+
{
133+
UUID: "00a02bfa-f565-40c9-b088-f2c7b8a75f97",
134+
Name: "grp-1-7l7zj",
135+
State: KubernetesNodeStateRunning,
136+
},
137+
{
138+
UUID: "00b56302-e211-40d9-83fa-177f0171e75a",
139+
Name: "grp-1-glkwv",
140+
State: KubernetesNodeStateTerminating,
141+
},
142+
},
143+
}
144+
require.NoError(t, err)
145+
require.Equal(t, want, got)
146+
// just to check that embedded KubernetesNodeGroup fields are directly available
147+
require.Equal(t, KubernetesNodeGroupStateRunning, got.State)
148+
}
149+
96150
func exampleKubernetesCluster() KubernetesCluster {
97151
return KubernetesCluster{
98152
Name: "upcloud-go-sdk-unit-test",

upcloud/request/kubernetes.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,13 @@ type GetKubernetesPlansRequest struct{}
172172
func (r *GetKubernetesPlansRequest) RequestURL() string {
173173
return fmt.Sprintf("%s/plans", kubernetesClusterBasePath)
174174
}
175+
176+
type DeleteKubernetesNodeGroupNodeRequest struct {
177+
ClusterUUID string
178+
Name string
179+
NodeName string
180+
}
181+
182+
func (r *DeleteKubernetesNodeGroupNodeRequest) RequestURL() string {
183+
return fmt.Sprintf("%s/%s/node-groups/%s/%s", kubernetesClusterBasePath, r.ClusterUUID, r.Name, r.NodeName)
184+
}

upcloud/request/kubernetes_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ func TestModifyKubernetesNodeGroupRequest(t *testing.T) {
330330
assert.JSONEq(t, expectedJSON, string(gotJS))
331331
}
332332

333+
func TestDeleteKubernetesNodeGroupNodeRequest(t *testing.T) {
334+
r := DeleteKubernetesNodeGroupNodeRequest{
335+
ClusterUUID: "id",
336+
Name: "nid",
337+
NodeName: "name",
338+
}
339+
assert.Equal(t, fmt.Sprintf("%s/id/node-groups/nid/name", kubernetesClusterBasePath), r.RequestURL())
340+
}
341+
333342
func TestDeleteKubernetesNodeGroupRequest(t *testing.T) {
334343
t.Parallel()
335344
r := DeleteKubernetesNodeGroupRequest{ClusterUUID: "id", Name: "nid"}

upcloud/service/kubernetes.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ type Kubernetes interface {
1818
GetKubernetesVersions(ctx context.Context, r *request.GetKubernetesVersionsRequest) ([]string, error)
1919
WaitForKubernetesClusterState(ctx context.Context, r *request.WaitForKubernetesClusterStateRequest) (*upcloud.KubernetesCluster, error)
2020
GetKubernetesNodeGroups(ctx context.Context, r *request.GetKubernetesNodeGroupsRequest) ([]upcloud.KubernetesNodeGroup, error)
21-
GetKubernetesNodeGroup(ctx context.Context, r *request.GetKubernetesNodeGroupRequest) (*upcloud.KubernetesNodeGroup, error)
21+
GetKubernetesNodeGroup(ctx context.Context, r *request.GetKubernetesNodeGroupRequest) (*upcloud.KubernetesNodeGroupDetails, error)
2222
CreateKubernetesNodeGroup(ctx context.Context, r *request.CreateKubernetesNodeGroupRequest) (*upcloud.KubernetesNodeGroup, error)
2323
ModifyKubernetesNodeGroup(ctx context.Context, r *request.ModifyKubernetesNodeGroupRequest) (*upcloud.KubernetesNodeGroup, error)
2424
DeleteKubernetesNodeGroup(ctx context.Context, r *request.DeleteKubernetesNodeGroupRequest) error
25+
DeleteKubernetesNodeGroupNode(ctx context.Context, r *request.DeleteKubernetesNodeGroupNodeRequest) error
2526
GetKubernetesPlans(ctx context.Context, r *request.GetKubernetesPlansRequest) ([]upcloud.KubernetesPlan, error)
2627
}
2728

@@ -124,8 +125,8 @@ func (s *Service) GetKubernetesNodeGroups(ctx context.Context, r *request.GetKub
124125
}
125126

126127
// GetKubernetesNodeGroup retrieves details of a node group (EXPERIMENTAL).
127-
func (s *Service) GetKubernetesNodeGroup(ctx context.Context, r *request.GetKubernetesNodeGroupRequest) (*upcloud.KubernetesNodeGroup, error) {
128-
ng := upcloud.KubernetesNodeGroup{}
128+
func (s *Service) GetKubernetesNodeGroup(ctx context.Context, r *request.GetKubernetesNodeGroupRequest) (*upcloud.KubernetesNodeGroupDetails, error) {
129+
ng := upcloud.KubernetesNodeGroupDetails{}
129130
return &ng, s.get(ctx, r.RequestURL(), &ng)
130131
}
131132

@@ -146,6 +147,11 @@ func (s *Service) DeleteKubernetesNodeGroup(ctx context.Context, r *request.Dele
146147
return s.delete(ctx, r)
147148
}
148149

150+
// DeleteKubernetesNodeGroupNode deletes an existing node from the node group (EXPERIMENTAL).
151+
func (s *Service) DeleteKubernetesNodeGroupNode(ctx context.Context, r *request.DeleteKubernetesNodeGroupNodeRequest) error {
152+
return s.delete(ctx, r)
153+
}
154+
149155
// GetKubernetesPlans retrieves a list of Kubernetes plans (EXPERIMENTAL).
150156
func (s *Service) GetKubernetesPlans(ctx context.Context, r *request.GetKubernetesPlansRequest) ([]upcloud.KubernetesPlan, error) {
151157
plans := make([]upcloud.KubernetesPlan, 0)

upcloud/service/kubernetes_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/UpCloudLtd/upcloud-go-api/v6/upcloud/client"
1313
"github.com/UpCloudLtd/upcloud-go-api/v6/upcloud/request"
1414
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
1516
)
1617

1718
const exampleClusterResponse = `
@@ -98,6 +99,27 @@ const exampleNodeGroupResponse = `
9899
}
99100
`
100101

102+
const exampleNodeGroupDetailsResponse = `
103+
{
104+
"anti_affinity": true,
105+
"count": 2,
106+
"name": "grp-1",
107+
"plan": "1xCPU-1GB",
108+
"state": "running",
109+
"nodes": [
110+
{
111+
"name": "grp-1-7l7zj",
112+
"state": "running",
113+
"uuid": "00a02bfa-f565-40c9-b088-f2c7b8a75f97"
114+
},
115+
{
116+
"name": "grp-1-glkwv",
117+
"state": "terminating",
118+
"uuid": "00b56302-e211-40d9-83fa-177f0171e75a"
119+
}
120+
]
121+
}`
122+
101123
const exampleNetworkResponse = `
102124
{
103125
"network": {
@@ -305,6 +327,27 @@ func TestGetKubernetesNodeGroup(t *testing.T) {
305327
assert.Equal(t, "my-test-group", res.Name)
306328
}
307329

330+
func TestGetKubernetesNodeGroupDetails(t *testing.T) {
331+
t.Parallel()
332+
333+
srv, svc := setupTestServerAndService(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
334+
assert.Equal(t, http.MethodGet, r.Method)
335+
assert.Equal(t, fmt.Sprintf("/%s/kubernetes/_UUID_/node-groups/_NAME_", client.APIVersion), r.URL.Path)
336+
fmt.Fprint(w, exampleNodeGroupDetailsResponse)
337+
}))
338+
defer srv.Close()
339+
340+
res, err := svc.GetKubernetesNodeGroup(context.Background(), &request.GetKubernetesNodeGroupRequest{
341+
ClusterUUID: "_UUID_",
342+
Name: "_NAME_",
343+
})
344+
require.NoError(t, err)
345+
require.Equal(t, "grp-1", res.Name)
346+
require.Len(t, res.Nodes, 2)
347+
require.Equal(t, upcloud.KubernetesNodeStateRunning, res.Nodes[0].State)
348+
require.Equal(t, upcloud.KubernetesNodeStateTerminating, res.Nodes[1].State)
349+
}
350+
308351
func TestCreateKubernetesNodeGroup(t *testing.T) {
309352
t.Parallel()
310353

@@ -397,6 +440,23 @@ func TestDeleteKubernetesNodeGroup(t *testing.T) {
397440
assert.NoError(t, err)
398441
}
399442

443+
func TestDeleteKubernetesNodeGroupNode(t *testing.T) {
444+
t.Parallel()
445+
446+
srv, svc := setupTestServerAndService(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
447+
assert.Equal(t, http.MethodDelete, r.Method)
448+
assert.Equal(t, fmt.Sprintf("/%s/kubernetes/_UUID_/node-groups/_NAME_/_NODE_", client.APIVersion), r.URL.Path)
449+
}))
450+
defer srv.Close()
451+
452+
err := svc.DeleteKubernetesNodeGroupNode(context.Background(), &request.DeleteKubernetesNodeGroupNodeRequest{
453+
ClusterUUID: "_UUID_",
454+
Name: "_NAME_",
455+
NodeName: "_NODE_",
456+
})
457+
assert.NoError(t, err)
458+
}
459+
400460
func TestWaitForKubernetesClusterState(t *testing.T) {
401461
t.Parallel()
402462

0 commit comments

Comments
 (0)