Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

godo/kubernetes: add maintenance policy support #224

Merged
merged 3 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 95 additions & 2 deletions kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding"
"encoding/json"
"fmt"
"net/http"
"strings"
Expand Down Expand Up @@ -53,12 +54,15 @@ type KubernetesClusterCreateRequest struct {
VPCUUID string `json:"vpc_uuid,omitempty"`

NodePools []*KubernetesNodePoolCreateRequest `json:"node_pools,omitempty"`

MaintenancePolicy *KubernetesMaintenancePolicy `json:"maintenance_policy"`
}

// KubernetesClusterUpdateRequest represents a request to update a Kubernetes cluster.
type KubernetesClusterUpdateRequest struct {
Name string `json:"name,omitempty"`
Tags []string `json:"tags,omitempty"`
Name string `json:"name,omitempty"`
Tags []string `json:"tags,omitempty"`
MaintenancePolicy *KubernetesMaintenancePolicy `json:"maintenance_policy"`
}

// KubernetesNodePoolCreateRequest represents a request to create a node pool for a
Expand Down Expand Up @@ -99,11 +103,100 @@ type KubernetesCluster struct {

NodePools []*KubernetesNodePool `json:"node_pools,omitempty"`

MaintenancePolicy *KubernetesMaintenancePolicy `json:"maintenance_policy,omitempty"`

Status *KubernetesClusterStatus `json:"status,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}

// KubernetesMaintenancePolicy is a configuration to set the maintenance window
// of a cluster
type KubernetesMaintenancePolicy struct {
StartTime string `json:"start_time"`
Duration string `json:"duration"`
Day KubernetesMaintenancePolicyDay `json:"day"`
}

// KubernetesMaintenancePolicyDay represents the possible days of a maintenance
// window
type KubernetesMaintenancePolicyDay int

const (
KubernetesMaintenanceDayAny KubernetesMaintenancePolicyDay = iota
KubernetesMaintenanceDayMonday
KubernetesMaintenanceDayTuesday
KubernetesMaintenanceDayWednesday
KubernetesMaintenanceDayThursday
KubernetesMaintenanceDayFriday
KubernetesMaintenanceDaySaturday
KubernetesMaintenanceDaySunday
)

var (
days = [...]string{
"any",
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday",
}

toDay = map[string]KubernetesMaintenancePolicyDay{
"any": KubernetesMaintenanceDayAny,
"monday": KubernetesMaintenanceDayMonday,
"tuesday": KubernetesMaintenanceDayTuesday,
"wednesday": KubernetesMaintenanceDayWednesday,
"thursday": KubernetesMaintenanceDayThursday,
"friday": KubernetesMaintenanceDayFriday,
"saturday": KubernetesMaintenanceDaySaturday,
"sunday": KubernetesMaintenanceDaySunday,
}
)

// KubernetesMaintenanceToDay returns the appropriate KubernetesMaintenancePolicyDay for the given string.
func KubernetesMaintenanceToDay(day string) (KubernetesMaintenancePolicyDay, error) {
d, ok := toDay[day]
if !ok {
return 0, fmt.Errorf("unknown day: %q", day)
}

return d, nil
}

func (k KubernetesMaintenancePolicyDay) String() string {
if KubernetesMaintenanceDayAny <= k && k <= KubernetesMaintenanceDaySunday {
return days[k]
}
return fmt.Sprintf("%d !Weekday", k)

}

func (k *KubernetesMaintenancePolicyDay) UnmarshalJSON(data []byte) error {
var val string
if err := json.Unmarshal(data, &val); err != nil {
return err
}

parsed, err := KubernetesMaintenanceToDay(val)
if err != nil {
return err
}
*k = parsed
return nil
}

func (k KubernetesMaintenancePolicyDay) MarshalJSON() ([]byte, error) {
if KubernetesMaintenanceDayAny <= k && k <= KubernetesMaintenanceDaySunday {
return json.Marshal(days[k])
}

return nil, fmt.Errorf("invalid day: %d", k)
}

// Possible states for a cluster.
const (
KubernetesClusterStatusProvisioning = KubernetesClusterStatusState("provisioning")
Expand Down
97 changes: 93 additions & 4 deletions kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ func TestKubernetesClusters_Get(t *testing.T) {
},
},
},
MaintenancePolicy: &KubernetesMaintenancePolicy{
StartTime: "00:00",
Day: KubernetesMaintenanceDayMonday,
},
CreatedAt: time.Date(2018, 6, 15, 7, 10, 23, 0, time.UTC),
UpdatedAt: time.Date(2018, 6, 15, 7, 11, 26, 0, time.UTC),
}
Expand Down Expand Up @@ -294,6 +298,10 @@ func TestKubernetesClusters_Get(t *testing.T) {
]
}
],
"maintenance_policy": {
"start_time": "00:00",
"day": "monday"
},
"created_at": "2018-06-15T07:10:23Z",
"updated_at": "2018-06-15T07:11:26Z"
}
Expand Down Expand Up @@ -348,6 +356,10 @@ func TestKubernetesClusters_Create(t *testing.T) {
Tags: []string{"tag-1"},
},
},
MaintenancePolicy: &KubernetesMaintenancePolicy{
StartTime: "00:00",
Day: KubernetesMaintenanceDayMonday,
},
}
createRequest := &KubernetesClusterCreateRequest{
Name: want.Name,
Expand All @@ -363,6 +375,7 @@ func TestKubernetesClusters_Create(t *testing.T) {
Tags: want.NodePools[0].Tags,
},
},
MaintenancePolicy: want.MaintenancePolicy,
}

jBlob := `
Expand All @@ -389,7 +402,11 @@ func TestKubernetesClusters_Create(t *testing.T) {
"tag-1"
]
}
]
],
"maintenance_policy": {
"start_time": "00:00",
"day": "monday"
}
}
}`

Expand Down Expand Up @@ -434,10 +451,15 @@ func TestKubernetesClusters_Update(t *testing.T) {
Tags: []string{"tag-1"},
},
},
MaintenancePolicy: &KubernetesMaintenancePolicy{
StartTime: "00:00",
Day: KubernetesMaintenanceDayMonday,
},
}
updateRequest := &KubernetesClusterUpdateRequest{
Name: want.Name,
Tags: want.Tags,
Name: want.Name,
Tags: want.Tags,
MaintenancePolicy: want.MaintenancePolicy,
}

jBlob := `
Expand All @@ -464,7 +486,11 @@ func TestKubernetesClusters_Update(t *testing.T) {
"tag-1"
]
}
]
],
"maintenance_policy": {
"start_time": "00:00",
"day": "monday"
}
}
}`

Expand Down Expand Up @@ -798,3 +824,66 @@ func TestKubernetesVersions_List(t *testing.T) {
require.NoError(t, err)
require.Equal(t, want, got)
}

var maintenancePolicyDayTests = []struct {
name string
json string
day KubernetesMaintenancePolicyDay
valid bool
}{
{
name: "sunday",
day: KubernetesMaintenanceDaySunday,
json: `"sunday"`,
valid: true,
},

{
name: "any",
day: KubernetesMaintenanceDayAny,
json: `"any"`,
valid: true,
},

{
name: "invalid",
day: 100, // invalid input
json: `"invalid weekday (100)"`,
valid: false,
},
}

func TestWeekday_UnmarshalJSON(t *testing.T) {
for _, ts := range maintenancePolicyDayTests {
t.Run(ts.name, func(t *testing.T) {
var got KubernetesMaintenancePolicyDay
err := json.Unmarshal([]byte(ts.json), &got)
valid := err == nil
if valid != ts.valid {
t.Errorf("valid unmarshal case\n\tgot: %+v\n\twant : %+v", valid, ts.valid)
}

if valid && got != ts.day {
t.Errorf("\ninput: %s\ngot : %+v\nwant : %+v\n",
ts.day, got, ts.day)
}
})
}
}

func TestWeekday_MarshalJSON(t *testing.T) {
for _, ts := range maintenancePolicyDayTests {
t.Run(ts.name, func(t *testing.T) {
out, err := json.Marshal(ts.day)
valid := err == nil
if valid != ts.valid {
t.Errorf("valid marshal case\n\tgot: %+v\n\twant : %+v", valid, ts.valid)
}

if valid && ts.json != string(out) {
t.Errorf("\ninput: %s\ngot : %+v\nwant : %+v\n",
ts.day, string(out), ts.json)
}
})
}
}