From f28dc156b83a7b9069ca4bd6ff7738c50c8a9ad6 Mon Sep 17 00:00:00 2001 From: JamesClonk Date: Sun, 18 Dec 2016 12:14:24 +0100 Subject: [PATCH] cleanup, prepare v1.12.0 --- README.md | 4 +- cmd/commands.go | 23 +++--- cmd/commands_reservedip.go | 99 ++++++++++++----------- lib/block_storage.go | 2 +- lib/client.go | 2 +- lib/reservedip.go | 156 +++++++++++++++++++++++++------------ lib/reservedip_test.go | 51 ++++++------ 7 files changed, 204 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index 4184fd4..f53c7d8 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ $ export VULTR_API_KEY=87dFbC91rJjkL/18zJEQxS * Run it ```sh $ vultr version -Client version: v1.11 +Client version: 1.12.0 Vultr API endpoint: https://api.vultr.com/ Vultr API version: v1 OS/Arch (client): linux/amd64 @@ -46,7 +46,7 @@ $ export VULTR_API_KEY=89dFbb91rGjkL/12zJEQxS * Run it ```sh $ vultr version -Client version: v1.11 +Client version: 1.12.0 Vultr API endpoint: https://api.vultr.com/ Vultr API version: v1 OS/Arch (client): linux/amd64 diff --git a/cmd/commands.go b/cmd/commands.go index 6f54692..e0e0fa9 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -116,19 +116,16 @@ func (c *CLI) RegisterCommands() { }) c.Command("scripts", "list all startup scripts on current account", scriptsList) - c.Command("reservedip", "modify reserved ip's", func(cmd *cli.Cmd) { - cmd.Command("attach", "attach a reserved IP to an existing subscription", reservedIpAttach) - cmd.Command("convert", "convert an existing IP on a subscription to a reserved IP", reservedIpConvert) - cmd.Command("create", "create a new reserved IP", func(cmd *cli.Cmd) { - cmd.Command("v4", "create ipv4", func(cmd *cli.Cmd) { reservedIpCreate(cmd, "v4") }) - cmd.Command("v6", "create ipv6", func(cmd *cli.Cmd) { reservedIpCreate(cmd, "v6") }) - }) - cmd.Command("destroy", "remove a reserved IP from your account", reservedIpDestroy) - cmd.Command("detach", "detach a reserved IP from an existing subscription", reservedIpDetach) - cmd.Command("list", "list all the active reserved IPs on this account", reservedIpList) - }) - c.Command("reservedips", "list all the active reserved IPs on this account", reservedIpList) - + // reserved ips + c.Command("reservedip", "modify reserved IPs", func(cmd *cli.Cmd) { + cmd.Command("attach", "attach reserved IP to an existing virtual machine", reservedIpAttach) + cmd.Command("convert", "convert existing IP on a virtual machine to a reserved IP", reservedIpConvert) + cmd.Command("create", "create new reserved IP", reservedIpCreate) + cmd.Command("delete", "delete reserved IP from your account", reservedIpDestroy) + cmd.Command("detach", "detach reserved IP from an existing virtual machine", reservedIpDetach) + cmd.Command("list", "list all active reserved IPs on current account", reservedIpList) + }) + c.Command("reservedips", "list all active reserved IPs on current account", reservedIpList) // version c.Command("version", "vultr CLI version", func(cmd *cli.Cmd) { diff --git a/cmd/commands_reservedip.go b/cmd/commands_reservedip.go index d4f0408..8f90d04 100644 --- a/cmd/commands_reservedip.go +++ b/cmd/commands_reservedip.go @@ -8,83 +8,83 @@ import ( ) func reservedIpAttach(cmd *cli.Cmd) { - ip_address := cmd.StringArg("ip_address", "", "ip_address to attach") - attach_subid := cmd.StringArg("attach_SUBID", "", "subid to attach ip") + cmd.Spec = "SUBID IP_ADDRESS" + + serverId := cmd.StringArg("SUBID", "", "SUBID of virtual machine to attach to (see )") + ip := cmd.StringArg("IP_ADDRESS", "", "IP address to attach (see )") + cmd.Action = func() { - err := GetClient().AttachReservedIp(*ip_address, *attach_subid) - if err != nil { + if err := GetClient().AttachReservedIp(*ip, *serverId); err != nil { log.Fatal(err) } - fmt.Printf("Attach IP to SUBID\n\n") - lengths := []int{40, 10} - tabsPrint(Columns{"ip_address", "attached_SUBID"}, lengths) - tabsPrint(Columns{*ip_address, *attach_subid}, lengths) - tabsFlush() + fmt.Println("Reserved IP attached") } } func reservedIpConvert(cmd *cli.Cmd) { - cmd.Spec = "SUBID IPADDRESS" - subid := cmd.StringArg("SUBID", "", "subid convert to reverse") - ip_address := cmd.StringArg("IPADDRESS", "", "ipaddress to convert") + cmd.Spec = "SUBID IP_ADDRESS" + + serverId := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") + ip := cmd.StringArg("IP_ADDRESS", "", "IP address to convert to reserved IP") + cmd.Action = func() { - // fmt.Println("meno-0") - // fmt.Printf("meno-3 %v %v\n", *subid, *ip_address) - osubid, err := GetClient().ConvertReservedIp(*subid, *ip_address) + id, err := GetClient().ConvertReservedIp(*serverId, *ip) if err != nil { log.Fatal(err) } - fmt.Printf("SUBIID to Attach IP\n\n") - lengths := []int{10, 40, 10} - tabsPrint(Columns{"SUBID", "ip_address", "attach_subid"}, lengths) - tabsPrint(Columns{*subid, *ip_address, osubid.SUBID}, lengths) + + fmt.Printf("Reserved IP converted\n\n") + lengths := []int{12, 48, 12} + tabsPrint(Columns{"ID", "IP_ADDRESS", "ATTACHED_TO"}, lengths) + tabsPrint(Columns{id, *ip, *serverId}, lengths) tabsFlush() } } -func reservedIpCreate(cmd *cli.Cmd, ip_type string) { - dcid := cmd.StringArg("DCID", "", "DCID Datacenter id") +func reservedIpCreate(cmd *cli.Cmd) { + cmd.Spec = "[-r -t]" + + regionID := cmd.IntOpt("r region", 1, "Region (DCID)") + ipType := cmd.StringOpt("t type", "v4", "Type of new reserved IP (v4 or v6)") + cmd.Action = func() { - subid, err := GetClient().CreateReservedIp(*dcid, ip_type) + id, err := GetClient().CreateReservedIp(*regionID, *ipType) if err != nil { log.Fatal(err) } + fmt.Printf("Reserved IP created\n\n") - lengths := []int{10, 4} - tabsPrint(Columns{"SUBID", "TYPE"}, lengths) - tabsPrint(Columns{subid, ip_type}, lengths) + lengths := []int{12, 6, 10} + tabsPrint(Columns{"ID", "TYPE", "DCID"}, lengths) + tabsPrint(Columns{id, *ipType, *regionID}, lengths) tabsFlush() } } func reservedIpDestroy(cmd *cli.Cmd) { - subid := cmd.StringArg("SUBID", "", "SUBID of the ip") + cmd.Spec = "SUBID" + + id := cmd.StringArg("SUBID", "", "SUBID of reserved IP (see )") + cmd.Action = func() { - err := GetClient().DestroyReservedIp(*subid) - if err != nil { + if err := GetClient().DestroyReservedIp(*id); err != nil { log.Fatal(err) } - fmt.Printf("Destroyed IP\n\n") - lengths := []int{10} - tabsPrint(Columns{"SUBID"}, lengths) - tabsPrint(Columns{*subid}, lengths) - tabsFlush() + fmt.Println("Reserved IP deleted") } } func reservedIpDetach(cmd *cli.Cmd) { - ip_address := cmd.StringArg("ip_address", "", "ip_address to attach") - detach_subid := cmd.StringArg("detach_SUBID", "", "subid to detach ip") + cmd.Spec = "SUBID IP_ADDRESS" + + serverId := cmd.StringArg("SUBID", "", "SUBID of virtual machine to detach from (see )") + ip := cmd.StringArg("IP_ADDRESS", "", "IP address to detach (see )") + cmd.Action = func() { - err := GetClient().DetachReservedIp(*ip_address, *detach_subid) - if err != nil { + if err := GetClient().DetachReservedIp(*ip, *serverId); err != nil { log.Fatal(err) } - fmt.Printf("Detach IP to SUBID\n\n") - lengths := []int{40, 10} - tabsPrint(Columns{"ip_address", "detached_SUBID"}, lengths) - tabsPrint(Columns{*ip_address, *detach_subid}, lengths) - tabsFlush() + fmt.Println("Reserved IP detached") } } @@ -99,10 +99,19 @@ func reservedIpList(cmd *cli.Cmd) { fmt.Println() return } - lengths := []int{10, 4, 4, 32, 4, 10, 10} - tabsPrint(Columns{"SUBID", "DCID", "ip_type", "subnet", "prefix", "label", "attached"}, lengths) + + lengths := []int{12, 8, 8, 48, 6, 32, 12} + tabsPrint(Columns{"SUBID", "DCID", "IP_TYPE", "SUBNET", "SIZE", "LABEL", "ATTACHED_TO"}, lengths) for _, ip := range ips { - tabsPrint(Columns{ip.SUBID, ip.DCID, ip.Ip_type, ip.Subnet, ip.Subnet_size, ip.Label, ip.Attached_SUBID}, lengths) + tabsPrint(Columns{ + ip.ID, + ip.RegionID, + ip.IPType, + ip.Subnet, + ip.SubnetSize, + ip.Label, + ip.AttachedTo, + }, lengths) } tabsFlush() } diff --git a/lib/block_storage.go b/lib/block_storage.go index b3c382d..6149ffe 100644 --- a/lib/block_storage.go +++ b/lib/block_storage.go @@ -20,7 +20,7 @@ type BlockStorage struct { } // Implements json.Unmarshaller on BlockStorage. -// This is needed because the Vultr API is inconsistent in it's JSON responses for account info. +// This is needed because the Vultr API is inconsistent in it's JSON responses. // Some fields can change type, from JSON number to JSON string and vice-versa. func (b *BlockStorage) UnmarshalJSON(data []byte) (err error) { if b == nil { diff --git a/lib/client.go b/lib/client.go index 374c9ac..74470fb 100644 --- a/lib/client.go +++ b/lib/client.go @@ -18,7 +18,7 @@ import ( const ( // Version of this libary - Version = "v1.11-mabels" + Version = "1.12.0" // APIVersion of Vultr APIVersion = "v1" diff --git a/lib/reservedip.go b/lib/reservedip.go index 93c561a..20e680c 100644 --- a/lib/reservedip.go +++ b/lib/reservedip.go @@ -1,87 +1,147 @@ package lib -import "net/url" -// import "fmt" - -// Ips on Vultr account - -// "1313044": { -// "SUBID": 1313044, -// "DCID": 1, -// "ip_type": "v4", -// "subnet": "10.234.22.53", -// "subnet_size": 32, -// "label": "my first reserved ip", -// "attached_SUBID": 123456 -// }, - -type SubId struct { - SUBID int `json:"SUBID"` +import ( + "encoding/json" + "fmt" + "net/url" + "strconv" +) + +// IP on Vultr +type IP struct { + ID string `json:"SUBID,string"` + RegionID int `json:"DCID,string"` + IPType string `json:"ip_type"` + Subnet string `json:"subnet"` + SubnetSize int `json:"subnet_size"` + Label string `json:"label"` + AttachedTo string `json:"attached_SUBID,string"` } -type Ip struct { - SUBID int `json:"SUBID"` - DCID int `json:"DCID"` - Ip_type string `json:"ip_type"` - Subnet string `json:"subnet"` - Subnet_size int `json:"subnet_size"` - Label string `json:"label"` - Attached_SUBID bool `json:"attached_SUBID"` +// Implements json.Unmarshaller on IP. +// This is needed because the Vultr API is inconsistent in it's JSON responses. +// Some fields can change type, from JSON number to JSON string and vice-versa. +func (i *IP) UnmarshalJSON(data []byte) (err error) { + if i == nil { + *i = IP{} + } + + var fields map[string]interface{} + if err := json.Unmarshal(data, &fields); err != nil { + return err + } + + value := fmt.Sprintf("%v", fields["SUBID"]) + if len(value) == 0 || value == "" || value == "0" { + i.ID = "" + } else { + id, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + i.ID = strconv.FormatFloat(id, 'f', -1, 64) + } + + value = fmt.Sprintf("%v", fields["DCID"]) + if len(value) == 0 || value == "" { + value = "0" + } + region, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + i.RegionID = int(region) + + value = fmt.Sprintf("%v", fields["attached_SUBID"]) + if len(value) == 0 || value == "" || value == "0" || value == "false" { + i.AttachedTo = "" + } else { + attached, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + i.AttachedTo = strconv.FormatFloat(attached, 'f', -1, 64) + } + + value = fmt.Sprintf("%v", fields["subnet_size"]) + if len(value) == 0 || value == "" { + value = "0" + } + size, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + i.SubnetSize = int(size) + + i.IPType = fmt.Sprintf("%v", fields["ip_type"]) + i.Subnet = fmt.Sprintf("%v", fields["subnet"]) + i.Label = fmt.Sprintf("%v", fields["label"]) + + return } -func (c *Client) ListReservedIp() (ips []Ip, err error) { - var ipMap map[string]Ip - err = c.get(`reservedip/list`, &ipMap) +func (c *Client) ListReservedIp() ([]IP, error) { + var ipMap map[string]IP + + err := c.get(`reservedip/list`, &ipMap) if err != nil { return nil, err } + + ips := make([]IP, 0) for _, ip := range ipMap { ips = append(ips, ip) } return ips, nil } -func (c *Client) CreateReservedIp(dcid string, ip_type string) (subid SubId, err error) { +func (c *Client) CreateReservedIp(regionID int, ipType string) (string, error) { values := url.Values{ - "DCID": {dcid}, - "ip_type": {ip_type}, + "DCID": {fmt.Sprintf("%v", regionID)}, + "ip_type": {ipType}, } - err = c.post(`reservedip/create`, values, &subid) + + result := IP{} + err := c.post(`reservedip/create`, values, &result) if err != nil { - return subid, err + return "", err } - return subid, nil + return result.ID, nil } -func (c *Client) DestroyReservedIp(subid string) (err error) { +func (c *Client) DestroyReservedIp(id string) error { values := url.Values{ - "SUBID": {subid}, + "SUBID": {id}, } return c.post(`reservedip/destroy`, values, nil) } -func (c *Client) AttachReservedIp(ip_address string, attach_subid string) (err error) { +func (c *Client) AttachReservedIp(ip string, serverId string) error { values := url.Values{ - "ip_address": {ip_address}, - "attach_SUBID": {attach_subid}, + "ip_address": {ip}, + "attach_SUBID": {serverId}, } return c.post(`reservedip/attach`, values, nil) } -func (c *Client) ConvertReservedIp(subid string, ip_address string) (subId SubId, err error) { +func (c *Client) ConvertReservedIp(serverId string, ip string) (string, error) { values := url.Values{ - "SUBID": {subid}, - "ip_address": {ip_address}, + "SUBID": {serverId}, + "ip_address": {ip}, + } + + result := IP{} + err := c.post(`reservedip/convert`, values, &result) + if err != nil { + return "", err } - // fmt.Printf("%s:%s\n", subid, ip_address) - err = c.post(`reservedip/convert`, values, &subId) - return subId, err + return result.ID, err } -func (c *Client) DetachReservedIp(detach_subid string, ip_address string) (err error) { +func (c *Client) DetachReservedIp(serverId string, ip string) error { values := url.Values{ - "ip_address": {ip_address}, - "detach_SUBID": {detach_subid}, + "ip_address": {ip}, + "detach_SUBID": {serverId}, } return c.post(`reservedip/detach`, values, nil) } diff --git a/lib/reservedip_test.go b/lib/reservedip_test.go index bbddb4b..25a3ab6 100644 --- a/lib/reservedip_test.go +++ b/lib/reservedip_test.go @@ -20,6 +20,7 @@ func Test_Plans_ListReservedIp_Fail(t *testing.T) { func Test_Plans_ListReservedIp_Ok_Empty(t *testing.T) { server, client := getTestServerAndClient(http.StatusNotAcceptable, `{}`) defer server.Close() + list, err := client.ListReservedIp() if err == nil { t.Error(err) @@ -30,40 +31,40 @@ func Test_Plans_ListReservedIp_Ok_Empty(t *testing.T) { func Test_Plans_ListReservedIp_Ok(t *testing.T) { server, client := getTestServerAndClient(http.StatusOK, `{ - "4":{"SUBID":4,"DCID":5,"ip_type":"v7","subnet":"subnet", + "4":{"SUBID":4,"DCID":5,"ip_type":"v4","subnet":"subnet1", "subnet_size":8,"label":"label","attached_SUBID":false}, - "9":{"SUBID":9,"DCID":5,"ip_type":"v7","subnet":"subnet", - "subnet_size":8,"label":"label","attached_SUBID":true} + "9":{"SUBID":9,"DCID":5,"ip_type":"v6","subnet":"subnet2", + "subnet_size":16,"label":"label","attached_SUBID":123} }`) defer server.Close() + list, err := client.ListReservedIp() if err != nil { t.Error(err) } - assert.Equal(t, list[0].SUBID, 4) - assert.Equal(t, list[0].DCID, 5) - assert.Equal(t, list[0].Ip_type, "v7") - assert.Equal(t, list[0].Subnet, "subnet") - assert.Equal(t, list[0].Subnet_size, 8) + assert.Equal(t, list[0].ID, "4") + assert.Equal(t, list[0].RegionID, 5) + assert.Equal(t, list[0].IPType, "v4") + assert.Equal(t, list[0].Subnet, "subnet1") + assert.Equal(t, list[0].SubnetSize, 8) assert.Equal(t, list[0].Label, "label") - assert.Equal(t, list[0].Attached_SUBID, false) - - assert.Equal(t, list[1].SUBID, 9) - assert.Equal(t, list[1].DCID, 5) - assert.Equal(t, list[1].Ip_type, "v7") - assert.Equal(t, list[1].Subnet, "subnet") - assert.Equal(t, list[1].Subnet_size, 8) - assert.Equal(t, list[1].Label, "label") - assert.Equal(t, list[1].Attached_SUBID, true) - + assert.Equal(t, list[0].AttachedTo, "") + + assert.Equal(t, list[1].ID, "9") + assert.Equal(t, list[1].RegionID, 5) + assert.Equal(t, list[1].IPType, "v6") + assert.Equal(t, list[1].Subnet, "subnet2") + assert.Equal(t, list[1].SubnetSize, 16) + assert.Equal(t, list[1].Label, "label") + assert.Equal(t, list[1].AttachedTo, "123") } func Test_Plans_CreateReservedIp_Fail(t *testing.T) { server, client := getTestServerAndClient(http.StatusNotAcceptable, ``) defer server.Close() - _, err := client.CreateReservedIp("dcid", "ip") + _, err := client.CreateReservedIp(1, "ip") if err == nil { t.Error(err) } @@ -72,11 +73,12 @@ func Test_Plans_CreateReservedIp_Fail(t *testing.T) { func Test_Plans_CreateReservedIp_OK(t *testing.T) { server, client := getTestServerAndClient(http.StatusOK, `{"SUBID":4711}`) defer server.Close() - subid, err := client.CreateReservedIp("dcid", "ip") + + id, err := client.CreateReservedIp(1, "ip") if err != nil { t.Error(err) } - assert.Equal(t, subid.SUBID, 4711) + assert.Equal(t, id, "4711") } func Test_Plans_DestroyReservedIp_Fail(t *testing.T) { @@ -92,6 +94,7 @@ func Test_Plans_DestroyReservedIp_Fail(t *testing.T) { func Test_Plans_DestroyReservedIp_OK(t *testing.T) { server, client := getTestServerAndClient(http.StatusOK, ``) defer server.Close() + err := client.DestroyReservedIp("subid") if err != nil { t.Error(err) @@ -111,6 +114,7 @@ func Test_Plans_AttachReservedIp_Fail(t *testing.T) { func Test_Plans_AttachReservedIp_OK(t *testing.T) { server, client := getTestServerAndClient(http.StatusOK, ``) defer server.Close() + err := client.AttachReservedIp("subid", "ip") if err != nil { t.Error(err) @@ -130,11 +134,12 @@ func Test_Plans_ConvertReservedIp_Fail(t *testing.T) { func Test_Plans_ConvertReservedIp_OK(t *testing.T) { server, client := getTestServerAndClient(http.StatusOK, `{"SUBID":4711}`) defer server.Close() - subid, err := client.ConvertReservedIp("subid", "ip") + + id, err := client.ConvertReservedIp("subid", "ip") if err != nil { t.Error(err) } - assert.Equal(t, subid.SUBID, 4711) + assert.Equal(t, id, "4711") } func Test_Plans_DetachReservedIp_Fail(t *testing.T) {