Skip to content

Commit

Permalink
Add AsRequest method on LoadBalancer
Browse files Browse the repository at this point in the history
Updating a LoadBalancer requires a LoadBalancerRequest, which is not
easily creatable from a LoadBalancer.

Serializing the LoadBalancer to JSON and then deserializing it to a
LoadBalancerRequest mostly works, except that Region is a string on
the Request but not on the LB (since the LB returns the entire
Region object), so json.Unmarshal returns an error.

An explicit AsRequest method makes it easier for consumers of the API
to modify existing LoadBalancer objects, and is designed to avoid
modifying attributes on the original LoadBalancer when the
LoadBalancerRequest is modified.
  • Loading branch information
lukegb committed Jul 22, 2017
1 parent 3484038 commit 6dfa314
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 10 deletions.
26 changes: 26 additions & 0 deletions load_balancers.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ func (l LoadBalancer) String() string {
return Stringify(l)
}

// AsRequest creates a LoadBalancerRequest that can be submitted to Update with the current values of the LoadBalancer.
// Modifying the returned LoadBalancerRequest will not modify the original LoadBalancer.
func (l LoadBalancer) AsRequest() *LoadBalancerRequest {
r := LoadBalancerRequest{
Name: l.Name,
Algorithm: l.Algorithm,
ForwardingRules: append([]ForwardingRule(nil), l.ForwardingRules...),
DropletIDs: append([]int(nil), l.DropletIDs...),
Tag: l.Tag,
RedirectHttpToHttps: l.RedirectHttpToHttps,
HealthCheck: l.HealthCheck,
}
if l.HealthCheck != nil {
r.HealthCheck = &HealthCheck{}
*r.HealthCheck = *l.HealthCheck
}
if l.StickySessions != nil {
r.StickySessions = &StickySessions{}
*r.StickySessions = *l.StickySessions
}
if l.Region != nil {
r.Region = l.Region.Slug
}
return &r
}

// ForwardingRule represents load balancer forwarding rules.
type ForwardingRule struct {
EntryProtocol string `json:"entry_protocol,omitempty"`
Expand Down
125 changes: 115 additions & 10 deletions load_balancers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ var lbUpdateJSONResponse = `
}
`

func TestLoadBlanacers_Get(t *testing.T) {
func TestLoadBalancers_Get(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -333,7 +333,7 @@ func TestLoadBlanacers_Get(t *testing.T) {
assert.Equal(t, expected, loadBalancer)
}

func TestLoadBlanacers_Create(t *testing.T) {
func TestLoadBalancers_Create(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -440,7 +440,7 @@ func TestLoadBlanacers_Create(t *testing.T) {
assert.Equal(t, expected, loadBalancer)
}

func TestLoadBlanacers_Update(t *testing.T) {
func TestLoadBalancers_Update(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -547,7 +547,7 @@ func TestLoadBlanacers_Update(t *testing.T) {
assert.Equal(t, expected, loadBalancer)
}

func TestLoadBlanacers_List(t *testing.T) {
func TestLoadBalancers_List(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -608,7 +608,7 @@ func TestLoadBlanacers_List(t *testing.T) {
assert.Equal(t, expected, loadBalancers)
}

func TestLoadBlanacers_List_Pagination(t *testing.T) {
func TestLoadBalancers_List_Pagination(t *testing.T) {
setup()
defer teardown()

Expand All @@ -630,7 +630,7 @@ func TestLoadBlanacers_List_Pagination(t *testing.T) {
assert.Equal(t, "http://localhost:3001/v2/load_balancers?page=3&per_page=1", resp.Links.Pages.Last)
}

func TestLoadBlanacers_Delete(t *testing.T) {
func TestLoadBalancers_Delete(t *testing.T) {
setup()
defer teardown()

Expand All @@ -648,7 +648,7 @@ func TestLoadBlanacers_Delete(t *testing.T) {
}
}

func TestLoadBlanacers_AddDroplets(t *testing.T) {
func TestLoadBalancers_AddDroplets(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -678,7 +678,7 @@ func TestLoadBlanacers_AddDroplets(t *testing.T) {
}
}

func TestLoadBlanacers_RemoveDroplets(t *testing.T) {
func TestLoadBalancers_RemoveDroplets(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -708,7 +708,7 @@ func TestLoadBlanacers_RemoveDroplets(t *testing.T) {
}
}

func TestLoadBlanacers_AddForwardingRules(t *testing.T) {
func TestLoadBalancers_AddForwardingRules(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -752,7 +752,7 @@ func TestLoadBlanacers_AddForwardingRules(t *testing.T) {
}
}

func TestLoadBlanacers_RemoveForwardingRules(t *testing.T) {
func TestLoadBalancers_RemoveForwardingRules(t *testing.T) {
setup()
defer teardown()

Expand Down Expand Up @@ -794,3 +794,108 @@ func TestLoadBlanacers_RemoveForwardingRules(t *testing.T) {
t.Errorf("LoadBalancers.RemoveForwardingRules returned error: %v", err)
}
}

func TestLoadBalancers_AsRequest(t *testing.T) {
lb := &LoadBalancer{
ID: "37e6be88-01ec-4ec7-9bc6-a514d4719057",
Name: "test-loadbalancer",
IP: "10.0.0.1",
Algorithm: "least_connections",
Status: "active",
Created: "2011-06-24T12:00:00Z",
HealthCheck: &HealthCheck{
Protocol: "http",
Port: 80,
Path: "/ping",
CheckIntervalSeconds: 30,
ResponseTimeoutSeconds: 10,
HealthyThreshold: 3,
UnhealthyThreshold: 3,
},
StickySessions: &StickySessions{
Type: "cookies",
CookieName: "nomnom",
CookieTtlSeconds: 32,
},
Region: &Region{
Slug: "lon1",
},
RedirectHttpToHttps: true,
}
lb.DropletIDs = make([]int, 1, 2)
lb.DropletIDs[0] = 12345
lb.ForwardingRules = make([]ForwardingRule, 1, 2)
lb.ForwardingRules[0] = ForwardingRule{
EntryProtocol: "http",
EntryPort: 80,
TargetProtocol: "http",
TargetPort: 80,
}

want := &LoadBalancerRequest{
Name: "test-loadbalancer",
Algorithm: "least_connections",
Region: "lon1",
ForwardingRules: []ForwardingRule{ForwardingRule{
EntryProtocol: "http",
EntryPort: 80,
TargetProtocol: "http",
TargetPort: 80,
}},
HealthCheck: &HealthCheck{
Protocol: "http",
Port: 80,
Path: "/ping",
CheckIntervalSeconds: 30,
ResponseTimeoutSeconds: 10,
HealthyThreshold: 3,
UnhealthyThreshold: 3,
},
StickySessions: &StickySessions{
Type: "cookies",
CookieName: "nomnom",
CookieTtlSeconds: 32,
},
DropletIDs: []int{12345},
RedirectHttpToHttps: true,
}

r := lb.AsRequest()
assert.Equal(t, want, r)
assert.False(t, r.HealthCheck == lb.HealthCheck, "HealthCheck points to same struct")
assert.False(t, r.StickySessions == lb.StickySessions, "StickySessions points to same struct")

r.DropletIDs = append(r.DropletIDs, 54321)
r.ForwardingRules = append(r.ForwardingRules, ForwardingRule{
EntryProtocol: "https",
EntryPort: 443,
TargetProtocol: "https",
TargetPort: 443,
TlsPassthrough: true,
})

// Check that original LoadBalancer hasn't changed
lb.DropletIDs = append(lb.DropletIDs, 13579)
lb.ForwardingRules = append(lb.ForwardingRules, ForwardingRule{
EntryProtocol: "tcp",
EntryPort: 587,
TargetProtocol: "tcp",
TargetPort: 587,
})
assert.Equal(t, []int{12345, 54321}, r.DropletIDs)
assert.Equal(t, []ForwardingRule{
ForwardingRule{
EntryProtocol: "http",
EntryPort: 80,
TargetProtocol: "http",
TargetPort: 80,
},
ForwardingRule{
EntryProtocol: "https",
EntryPort: 443,
TargetProtocol: "https",
TargetPort: 443,
TlsPassthrough: true,
},
}, r.ForwardingRules)
}

0 comments on commit 6dfa314

Please sign in to comment.