From b17da22c11a5c4c3e001ca554aa94f5ef72c02a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Thu, 10 Nov 2022 11:21:28 +0100 Subject: [PATCH] fix: error when updating IPv6 Primary IP (#215) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The API returns a CIDR range in the `ip` field for ipv6 primary IPs. This caused the `PrimaryIPClient.Update` call to fail, because the response was parsed as a `net.IP`, but should have been parsed using `net.ParseNetwork`. The required logic was already implemented in the `PrimaryIPFromSchema` function, but not used for the update call. With this commit, the struct `hcloud.PrimaryIPUpdateResult` is removed, because using it to parse the response causes the error and it was never returned from any of our methods, so consumers should not be using it. This error was originally found in hcloud-cli, and caused following error message: ➜ ~ hcloud primary-ip update --auto-delete=false test-ip hcloud: updating Primary IP test-ip failed: invalid IP address: 2001:db8::/64 --- hcloud/primary_ip.go | 10 ++-------- hcloud/primary_ip_test.go | 12 ++++++++---- hcloud/schema/primary_ip.go | 6 ++++++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/hcloud/primary_ip.go b/hcloud/primary_ip.go index eccd407b..66cc4148 100644 --- a/hcloud/primary_ip.go +++ b/hcloud/primary_ip.go @@ -90,12 +90,6 @@ type PrimaryIPUpdateOpts struct { Name string `json:"name,omitempty"` } -// PrimaryIPUpdateResult defines the response -// when updating a Primary IP. -type PrimaryIPUpdateResult struct { - PrimaryIP PrimaryIP `json:"primary_ip"` -} - // PrimaryIPAssignOpts defines the request to // assign a Primary IP to an assignee (usually a server). type PrimaryIPAssignOpts struct { @@ -313,12 +307,12 @@ func (c *PrimaryIPClient) Update(ctx context.Context, primaryIP *PrimaryIP, reqB return nil, nil, err } - respBody := PrimaryIPUpdateResult{} + var respBody schema.PrimaryIPUpdateResult resp, err := c.client.Do(req, &respBody) if err != nil { return nil, resp, err } - return &respBody.PrimaryIP, resp, nil + return PrimaryIPFromSchema(respBody.PrimaryIP), resp, nil } // Assign a Primary IP to a resource diff --git a/hcloud/primary_ip_test.go b/hcloud/primary_ip_test.go index 6c517eeb..43e46991 100644 --- a/hcloud/primary_ip_test.go +++ b/hcloud/primary_ip_test.go @@ -3,6 +3,7 @@ package hcloud import ( "context" "encoding/json" + "net" "net/http" "testing" @@ -333,8 +334,8 @@ func TestPrimaryIPClient(t *testing.T) { t.Log(cmp.Diff(expectedReqBody, reqBody)) t.Error("unexpected request body") } - json.NewEncoder(w).Encode(PrimaryIPUpdateResult{ - PrimaryIP: PrimaryIP{ID: 1}, + json.NewEncoder(w).Encode(schema.PrimaryIPUpdateResult{ + PrimaryIP: schema.PrimaryIP{ID: 1, IP: "2001:db8::/64"}, }) }) @@ -347,11 +348,14 @@ func TestPrimaryIPClient(t *testing.T) { Labels: &labels, } - primaryIP := PrimaryIP{ID: 1} + primaryIP := PrimaryIP{ID: 1, IP: net.ParseIP("2001:db8::")} result, resp, err := env.Client.PrimaryIP.Update(ctx, &primaryIP, opts) assert.NoError(t, err) assert.NotNil(t, resp, "no response returned") - assert.Equal(t, *result, primaryIP, "no primary IP returned") + if result.ID != 1 { + t.Errorf("unexpected Primary IP ID: %v", result.ID) + } + assert.Equal(t, primaryIP.IP, result.IP, "parsed the wrong IP") }) t.Run("Assign", func(t *testing.T) { env := newTestEnv() diff --git a/hcloud/schema/primary_ip.go b/hcloud/schema/primary_ip.go index b21e28b4..1cfb0847 100644 --- a/hcloud/schema/primary_ip.go +++ b/hcloud/schema/primary_ip.go @@ -47,3 +47,9 @@ type PrimaryIPGetResult struct { type PrimaryIPListResult struct { PrimaryIPs []PrimaryIP `json:"primary_ips"` } + +// PrimaryIPUpdateResult defines the response +// when updating a Primary IP. +type PrimaryIPUpdateResult struct { + PrimaryIP PrimaryIP `json:"primary_ip"` +}