Skip to content

Commit

Permalink
Kfcluster resource (#144)
Browse files Browse the repository at this point in the history
* Update json flag for lb

Signed-off-by: Haardik Dharma <haardik@civo.com>

* Fix formatting

Signed-off-by: Haardik Dharma <haardik@civo.com>

* Add KfCluster Resource

---------

Signed-off-by: Haardik Dharma <haardik@civo.com>
Co-authored-by: Haardik Dharma <haardik@civo.com>
  • Loading branch information
haardikdharma10 and haardikdharma10 authored Apr 13, 2023
1 parent a293823 commit e6c1296
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 0 deletions.
146 changes: 146 additions & 0 deletions kfcluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package civogo

import (
"bytes"
"encoding/json"
"fmt"
"strings"
)

// KfCluster represents a cluster with Kubeflow installed.
type KfCluster struct {
ID string `json:"id"`
Name string `json:"name,validate:required"`
NetworkID string `json:"network_id,validate:required"`
FirewallName string `json:"firewall_name"`
Size string `json:"size"`
KubeflowInstalled string `json:"kubeflow_installed"`
DashboardURL string `json:"dashboard_url"`
Namespace string `json:"-"`
}

// CreateKfClusterReq is the request for creating a KfCluster.
type CreateKfClusterReq struct {
Name string `json:"name" validate:"required"`
NetworkID string `json:"network_id" validate:"required"`
FirewallID string `json:"firewall_id"`
Size string `json:"size"` //what sizes?
}

// UpdateKfClusterReq is the request for updating a KfCluster.
type UpdateKfClusterReq struct {
Name string `json:"name"`
// Size string `json:"size"`
}

// PaginatedKfClusters returns a paginated list of KfCluster object
type PaginatedKfClusters struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Pages int `json:"pages"`
Items []KfCluster `json:"items"`
}

// ListKfClusters returns all applications in that specific region
func (c *Client) ListKfClusters() (*PaginatedKfClusters, error) {
resp, err := c.SendGetRequest("/v2/kfclusters")
if err != nil {
return nil, decodeError(err)
}

kfc := &PaginatedKfClusters{}
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&kfc); err != nil {
return nil, decodeError(err)
}

return kfc, nil
}

// GetKfCluster returns a kubeflow cluster by ID
func (c *Client) GetKfCluster(id string) (*KfCluster, error) {
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/kfclusters/%s", id))
if err != nil {
return nil, decodeError(err)
}

kfc := &KfCluster{}
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&kfc); err != nil {
return nil, decodeError(err)
}

return kfc, nil
}

// FindKfCluster finds a kubeflow cluster by either part of the ID or part of the name
func (c *Client) FindKfCluster(search string) (*KfCluster, error) {
kfClusters, err := c.ListKfClusters()
if err != nil {
return nil, decodeError(err)
}

exactMatch := false
partialMatchesCount := 0
result := KfCluster{}

for _, value := range kfClusters.Items {
if value.Name == search || value.ID == search {
exactMatch = true
result = value
} else if strings.Contains(value.Name, search) || strings.Contains(value.ID, search) {
if !exactMatch {
result = value
partialMatchesCount++
}
}
}

if exactMatch || partialMatchesCount == 1 {
return &result, nil
} else if partialMatchesCount > 1 {
err := fmt.Errorf("unable to find %s because there were multiple matches", search)
return nil, MultipleMatchesError.wrap(err)
} else {
err := fmt.Errorf("unable to find %s, zero matches", search)
return nil, ZeroMatchesError.wrap(err)
}
}

// CreateKfCluster creates a new kubeflow cluster
func (c *Client) CreateKfCluster(req CreateKfClusterReq) (*KfCluster, error) {
body, err := c.SendPostRequest("/v2/kfclusters", req)
if err != nil {
return nil, decodeError(err)
}

var kfc KfCluster
if err := json.NewDecoder(bytes.NewReader(body)).Decode(&kfc); err != nil {
return nil, err
}

return &kfc, nil
}

// UpdateKfCluster updates a kubeflow cluster
func (c *Client) UpdateKfCluster(id string, kfc *UpdateKfClusterReq) (*KfCluster, error) {
body, err := c.SendPutRequest(fmt.Sprintf("/v2/kfclusters/%s", id), kfc)
if err != nil {
return nil, decodeError(err)
}

updatedKfCluster := &KfCluster{}
if err := json.NewDecoder(bytes.NewReader(body)).Decode(updatedKfCluster); err != nil {
return nil, err
}

return updatedKfCluster, nil
}

// DeleteKfCluster deletes an application
func (c *Client) DeleteKfCluster(id string) (*SimpleResponse, error) {
resp, err := c.SendDeleteRequest(fmt.Sprintf("/v2/kfclusters/%s", id))
if err != nil {
return nil, decodeError(err)
}

return c.DecodeSimpleResponse(resp)
}
108 changes: 108 additions & 0 deletions kfcluster_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package civogo

import (
"reflect"
"testing"
)

func TestListKfClusters(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/kfclusters": `{"page": 1, "per_page": 20, "pages": 2, "items":[{"id": "12345", "name": "test-kfcluster"}]}`,
})
defer server.Close()

got, err := client.ListKfClusters()
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := &PaginatedKfClusters{
Page: 1,
PerPage: 20,
Pages: 2,
Items: []KfCluster{
{
ID: "12345",
Name: "test-kfcluster",
},
},
}
if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestFindKfCluster(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/kfclusters": `{
"page": 1,
"per_page": 20,
"pages": 1,
"items": [
{
"id": "12345",
"name": "test-kfcluster"
}
]
}`,
})
defer server.Close()

got, _ := client.FindKfCluster("test-kfcluster")
if got.ID != "12345" {
t.Errorf("Expected %s, got %s", "12345", got.ID)
}
}

func TestCreateKfCluster(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/kfclusters": `{
"id": "12345",
"name": "test-kfcluster",
"size": "g3.kf.small",
"network_id": "09090"
}`,
})
defer server.Close()

cfg := CreateKfClusterReq{
Name: "test-kfcluster",
Size: "g3.kf.small",
NetworkID: "09090",
}
got, err := client.CreateKfCluster(cfg)
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := &KfCluster{
ID: "12345",
Name: "test-kfcluster",
Size: "g3.kf.small",
NetworkID: "09090",
}

if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

func TestDeleteKfCluster(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/kfclusters/12345": `{"result": "success"}`,
})
defer server.Close()

got, err := client.DeleteKfCluster("12345")
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

expected := &SimpleResponse{Result: "success"}
if !reflect.DeepEqual(got, expected) {
t.Errorf("Expected %+v, got %+v", expected, got)
}
}

0 comments on commit e6c1296

Please sign in to comment.