diff --git a/common.go b/common.go index 8dd5ab6c..0f4eb6af 100644 --- a/common.go +++ b/common.go @@ -18,3 +18,10 @@ type idNameRoot struct { Count int IDNames []IDName `json:"results"` } + +type SortOrder string + +const ( + SortOrderDesc SortOrder = "desc" + SortOrderAsc SortOrder = "asc" +) diff --git a/mkaas.go b/mkaas.go index 16de4828..7006fda2 100644 --- a/mkaas.go +++ b/mkaas.go @@ -15,6 +15,7 @@ const ( type MKaaSService interface { MKaaSClusters MKaaSPools + MKaaSNodes } type MKaaSClusters interface { @@ -26,6 +27,32 @@ type MKaaSClusters interface { ClusterDelete(context.Context, int) (*TaskResponse, *Response, error) } +type NodeState string + +const ( + NodeStatePending NodeState = "PENDING" + NodeStateCreating NodeState = "CREATING" + NodeStateReady NodeState = "READY" + NodeStateFailed NodeState = "FAILED" + NodeStateScheduledDelete NodeState = "SCHEDULED_TO_DELETE" + NodeStateDeleting NodeState = "DELETING" + NodeStateDeleted NodeState = "DELETED" +) + +type NodeSortKey string + +const ( + NodeSortKeyID NodeSortKey = "id" + NodeSortKeyName NodeSortKey = "name" + NodeSortKeyCreatedAt NodeSortKey = "created_at" + NodeSortKeySequenceNumber NodeSortKey = "sequence_number" +) + +type MKaaSNodes interface { + NodesList(ctx context.Context, clusterID, poolID int, opts *MKaaSNodeListOptions) ([]MKaaSNode, *Response, error) + NodeDelete(ctx context.Context, clusterID, poolID, nodeID int) (*TaskResponse, *Response, error) +} + type MKaaSPools interface { PoolCreate(ctx context.Context, clusterID int, reqBody MKaaSPoolCreateRequest) (*TaskResponse, *Response, error) PoolsList(ctx context.Context, clusterID int, opts *MKaaSPoolListOptions) ([]MKaaSPool, *Response, error) @@ -56,6 +83,31 @@ type MKaaSPoolsRoot struct { Pools []MKaaSPool `json:"results"` } +type MKaaSNodesList struct { + Nodes []MKaaSNode `json:"nodes"` + Total int `json:"total"` + Limit int `json:"limit"` + Offset int `json:"offset"` +} + +type MKaaSNode struct { + ID int `json:"id"` + Name string `json:"name"` + PoolID int `json:"pool_id"` + State NodeState `json:"state"` + Status string `json:"status"` + IPAddress string `json:"ip_address"` + CreatedAt string `json:"created_at"` +} + +type MKaaSNodeListOptions struct { + State NodeState `url:"state,omitempty"` + Limit int `url:"limit,omitempty"` + Offset int `url:"offset,omitempty"` + SortBy NodeSortKey `url:"sort_by,omitempty"` + SortOrder SortOrder `url:"sort_order,omitempty"` +} + type MKaaSClusterListOptions struct { Name string `url:"name,omitempty"` Status string `url:"status,omitempty"` @@ -514,3 +566,68 @@ func (m *MKaaSServiceOp) PoolUpdateLabels( return tasks, resp, err } + +func (m *MKaaSServiceOp) NodesList( + ctx context.Context, clusterID, poolID int, opts *MKaaSNodeListOptions, +) ([]MKaaSNode, *Response, error) { + if resp, err := m.client.Validate(); err != nil { + return nil, resp, err + } + + path := fmt.Sprintf( + "%s/%d/pools/%d/nodes", + m.client.addProjectRegionPath(MKaaSClustersBasePathV2), + clusterID, + poolID, + ) + path, err := addOptions(path, opts) + if err != nil { + return nil, nil, err + } + + req, err := m.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(MKaaSNodesList) + resp, err := m.client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + if root.Nodes == nil { + return []MKaaSNode{}, resp, nil + } + + return root.Nodes, resp, nil +} + +func (m *MKaaSServiceOp) NodeDelete( + ctx context.Context, clusterID, poolID, nodeID int, +) (*TaskResponse, *Response, error) { + if resp, err := m.client.Validate(); err != nil { + return nil, resp, err + } + + path := fmt.Sprintf( + "%s/%d/pools/%d/nodes/%d", + m.client.addProjectRegionPath(MKaaSClustersBasePathV2), + clusterID, + poolID, + nodeID, + ) + + req, err := m.client.NewRequest(ctx, http.MethodDelete, path, nil) + if err != nil { + return nil, nil, err + } + + tasks := new(TaskResponse) + resp, err := m.client.Do(ctx, req, tasks) + if err != nil { + return nil, resp, err + } + + return tasks, resp, err +} diff --git a/mkaas_test.go b/mkaas_test.go index f2b7adc8..2487c4af 100644 --- a/mkaas_test.go +++ b/mkaas_test.go @@ -20,6 +20,7 @@ const ( mkaasKeypairName = "keypair" mkaasFlavor = "g1-standard-2-4" mkaasVersion = "v1.31.0" + mkaasTestPoolID = 1099 ) func TestMKaaSServiceOp_ClusterCreate(t *testing.T) { @@ -461,3 +462,84 @@ func TestMKaaSServiceOp_PoolUpdateLabels(t *testing.T) { require.Equal(t, resp.StatusCode, 200) require.Equal(t, respActual, expectedResp) } + +func TestMKaaSServiceOp_NodesList(t *testing.T) { + setup() + defer teardown() + + expectedResp := []MKaaSNode{{ID: testResourceIntID, Name: "test-node", PoolID: mkaasTestPoolID, State: NodeStateReady}} + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), + strconv.Itoa(testResourceIntID), "pools", strconv.Itoa(mkaasTestPoolID), "nodes") + + mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + resp, err := json.Marshal(expectedResp) + if err != nil { + t.Errorf("failed to marshal response: %v", err) + } + _, _ = fmt.Fprintf(w, `{"nodes":%s}`, string(resp)) + }) + + respActual, resp, err := client.MkaaS.NodesList(ctx, testResourceIntID, mkaasTestPoolID, nil) + require.NoError(t, err) + require.Equal(t, resp.StatusCode, 200) + require.Equal(t, respActual, expectedResp) +} + +func TestMKaaSServiceOp_NodeDelete(t *testing.T) { + setup() + defer teardown() + + const testNodeID = testResourceIntID + 1 + + expectedResp := &TaskResponse{Tasks: []string{taskID}} + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), + strconv.Itoa(testResourceIntID), "pools", strconv.Itoa(mkaasTestPoolID), "nodes", strconv.Itoa(testNodeID)) + + mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodDelete) + resp, err := json.Marshal(expectedResp) + if err != nil { + t.Errorf("failed to marshal response: %v", err) + } + _, _ = fmt.Fprint(w, string(resp)) + }) + + respActual, resp, err := client.MkaaS.NodeDelete(ctx, testResourceIntID, mkaasTestPoolID, testNodeID) + require.NoError(t, err) + require.Equal(t, resp.StatusCode, 200) + require.Equal(t, respActual, expectedResp) +} + +func TestMKaaSServiceOp_NodesList_WithOptions(t *testing.T) { + setup() + defer teardown() + + expectedResp := []MKaaSNode{{ID: testResourceIntID, Name: "test-node", PoolID: mkaasTestPoolID, State: NodeStateReady}} + URL := path.Join(MKaaSClustersBasePathV2, strconv.Itoa(projectID), strconv.Itoa(regionID), + strconv.Itoa(testResourceIntID), "pools", strconv.Itoa(mkaasTestPoolID), "nodes") + + mux.HandleFunc(URL, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + assert.Equal(t, r.URL.Query().Get("state"), string(NodeStateReady)) + assert.Equal(t, r.URL.Query().Get("limit"), "10") + assert.Equal(t, r.URL.Query().Get("sort_by"), string(NodeSortKeyName)) + assert.Equal(t, r.URL.Query().Get("sort_order"), string(SortOrderAsc)) + resp, err := json.Marshal(expectedResp) + if err != nil { + t.Errorf("failed to marshal response: %v", err) + } + _, _ = fmt.Fprintf(w, `{"nodes":%s}`, string(resp)) + }) + + opts := &MKaaSNodeListOptions{ + State: NodeStateReady, + Limit: 10, + SortBy: NodeSortKeyName, + SortOrder: SortOrderAsc, + } + respActual, resp, err := client.MkaaS.NodesList(ctx, testResourceIntID, mkaasTestPoolID, opts) + require.NoError(t, err) + require.Equal(t, resp.StatusCode, 200) + require.Equal(t, respActual, expectedResp) +}