diff --git a/glide.lock b/glide.lock index 5d31248..66a783c 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 46040e93c697f75645748e2dd93530e6edbacfc84be790c52918265a05bbb664 -updated: 2017-06-18T23:18:53.717448962+02:00 +hash: cd5ba72ca00f13f7ed17b9b5f6b90e448363ab4ce10e0a65459d462d0ba8569f +updated: 2017-08-11T00:59:48.098189132+02:00 imports: - name: github.com/docker/docker version: a8a31eff10544860d2188dddabdee4d727545796 @@ -20,7 +20,7 @@ imports: - libmachine/version - version - name: github.com/JamesClonk/vultr - version: 253a3520b6e35123fe5879eb057b1599426b6a2a + version: 2fd0705ce648e602e6c9c57329a174270a4f6688 subpackages: - lib - name: github.com/juju/ratelimit diff --git a/glide.yaml b/glide.yaml index a73fc5e..a198b74 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,7 +1,7 @@ package: github.com/janeczku/docker-machine-vultr import: - package: github.com/JamesClonk/vultr - version: 253a352 + version: 2fd0705 subpackages: - lib - package: github.com/docker/machine diff --git a/vendor/github.com/JamesClonk/vultr/cmd/commands.go b/vendor/github.com/JamesClonk/vultr/cmd/commands.go index d67ecfc..8f35be6 100644 --- a/vendor/github.com/JamesClonk/vultr/cmd/commands.go +++ b/vendor/github.com/JamesClonk/vultr/cmd/commands.go @@ -30,6 +30,7 @@ func (c *CLI) RegisterCommands() { cmd.Command("group", "show and change firewall groups", func(cmd *cli.Cmd) { cmd.Command("create", "create a firewall group", firewallGroupCreate) cmd.Command("delete", "delete a firewall group", firewallGroupDelete) + cmd.Command("set-description", "set firewall group description", firewallGroupSetDescription) cmd.Command("list", "list all firewall groups", firewallGroupList) }) cmd.Command("rule", "show and change firewall rules", func(cmd *cli.Cmd) { @@ -73,6 +74,7 @@ func (c *CLI) RegisterCommands() { c.Command("server", "modify virtual machines", func(cmd *cli.Cmd) { cmd.Command("create", "create a new virtual machine", serversCreate) cmd.Command("rename", "rename a virtual machine", serversRename) + cmd.Command("tag", "tag a virtual machine", serversTag) cmd.Command("start", "start a virtual machine (restart if already running)", serversStart) cmd.Command("halt", "halt a virtual machine (hard power off)", serversHalt) cmd.Command("reboot", "reboot a virtual machine (hard reboot)", serversReboot) @@ -96,6 +98,8 @@ func (c *CLI) RegisterCommands() { cmd.Command("show", "show detailed information of a virtual machine", serversShow) // ip information cmd.Command("list-ipv4", "list IPv4 information of a virtual machine", ipv4List) + cmd.Command("create-ipv4", "add a new IPv4 address to a virtual machine", ipv4Create) + cmd.Command("delete-ipv4", "remove IPv4 address from a virtual machine", ipv4Delete) cmd.Command("list-ipv6", "list IPv6 information of a virtual machine", ipv6List) // reverse dns cmd.Command("reverse-dns", "modify reverse DNS entries", func(cmd *cli.Cmd) { @@ -105,6 +109,9 @@ func (c *CLI) RegisterCommands() { cmd.Command("delete-ipv6", "delete IPv6 reverse DNS entry", reverseIpv6Delete) cmd.Command("list-ipv6", "list IPv6 reverse DNS entries of a virtual machine", reverseIpv6List) }) + // firewall groups + cmd.Command("set-firewall-group", "set firewall group of a virtual machine", serversSetFirewallGroup) + cmd.Command("unset-firewall-group", "remove virtual machine from firewall group", serversUnsetFirewallGroup) }) c.Command("servers", "list all active or pending virtual machines on current account", serversList) diff --git a/vendor/github.com/JamesClonk/vultr/cmd/commands_firewall.go b/vendor/github.com/JamesClonk/vultr/cmd/commands_firewall.go index a6aa511..bfbf6cf 100644 --- a/vendor/github.com/JamesClonk/vultr/cmd/commands_firewall.go +++ b/vendor/github.com/JamesClonk/vultr/cmd/commands_firewall.go @@ -41,6 +41,21 @@ func firewallGroupDelete(cmd *cli.Cmd) { } } +func firewallGroupSetDescription(cmd *cli.Cmd) { + cmd.Spec = "GROUP_ID DESCRIPTION" + + gid := cmd.StringArg("GROUP_ID", "", "Firewall group ID") + desc := cmd.StringArg("DESCRIPTION", "", "New description for the firewall group") + + cmd.Action = func() { + if err := GetClient().SetFirewallGroupDescription(*gid, *desc); err != nil { + log.Fatal(err) + } + + fmt.Printf("Set description for firewall group %s: %s\n", *gid, *desc) + } +} + func firewallGroupList(cmd *cli.Cmd) { cmd.Action = func() { groups, err := GetClient().GetFirewallGroups() diff --git a/vendor/github.com/JamesClonk/vultr/cmd/commands_servers.go b/vendor/github.com/JamesClonk/vultr/cmd/commands_servers.go index 2e8fdf9..f800330 100644 --- a/vendor/github.com/JamesClonk/vultr/cmd/commands_servers.go +++ b/vendor/github.com/JamesClonk/vultr/cmd/commands_servers.go @@ -29,6 +29,7 @@ func serversCreate(cmd *cli.Cmd) { hostname := cmd.StringOpt("hostname", "", "Hostname to assign to this server") tag := cmd.StringOpt("tag", "", "Tag to assign to this server") appID := cmd.StringOpt("a app", "", "If launching an application (OSID 186), this is the APPID to launch") + reservedIP := cmd.StringOpt("ip", "", "IP address of the floating IP to use as the main IP of this server") ipv6 := cmd.BoolOpt("ipv6", false, "Assign an IPv6 subnet to this virtual machine (where available)") privateNetworking := cmd.BoolOpt("private-networking", false, "Add private networking support for this virtual machine") autoBackups := cmd.BoolOpt("autobackups", false, "Enable automatic backups for this virtual machine") @@ -41,6 +42,7 @@ func serversCreate(cmd *cli.Cmd) { Script: *script, Snapshot: *snapshot, SSHKey: *sshkey, + ReservedIP: *reservedIP, IPV6: *ipv6, PrivateNetworking: *privateNetworking, AutoBackups: *autoBackups, @@ -83,6 +85,44 @@ func serversRename(cmd *cli.Cmd) { } } +func serversTag(cmd *cli.Cmd) { + cmd.Spec = "SUBID -t" + id := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") + tag := cmd.StringOpt("t tag", "", "new tag for virtual machine") + + cmd.Action = func() { + if err := GetClient().TagServer(*id, *tag); err != nil { + log.Fatal(err) + } + fmt.Printf("Virtual machine tagged with: %v\n", *tag) + } +} + +func serversSetFirewallGroup(cmd *cli.Cmd) { + cmd.Spec = "SUBID GROUP_ID" + id := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") + gid := cmd.StringArg("GROUP_ID", "", "Firewall group ID (see )") + + cmd.Action = func() { + if err := GetClient().SetFirewallGroup(*id, *gid); err != nil { + log.Fatal(err) + } + fmt.Printf("Virtual machine added to firewall group: %v\n", *gid) + } +} + +func serversUnsetFirewallGroup(cmd *cli.Cmd) { + cmd.Spec = "SUBID" + id := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") + + cmd.Action = func() { + if err := GetClient().UnsetFirewallGroup(*id); err != nil { + log.Fatal(err) + } + fmt.Println("Virtual machine removed from firewall group") + } +} + func serversStart(cmd *cli.Cmd) { id := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") cmd.Action = func() { @@ -380,6 +420,32 @@ func ipv4List(cmd *cli.Cmd) { } } +func ipv4Create(cmd *cli.Cmd) { + cmd.Spec = "SUBID" + id := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") + reboot := cmd.BoolOpt("r reboot", false, "reboot virtual machine after attaching IPv4 address") + + cmd.Action = func() { + if err := GetClient().CreateIPv4(*id, *reboot); err != nil { + log.Fatal(err) + } + fmt.Println("IPv4 address attached to virtual machine") + } +} + +func ipv4Delete(cmd *cli.Cmd) { + cmd.Spec = "SUBID IP" + id := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") + ip := cmd.StringArg("IP", "", "IPv4 of virtual machine (see )") + + cmd.Action = func() { + if err := GetClient().DeleteIPv4(*id, *ip); err != nil { + log.Fatal(err) + } + fmt.Println("IPv4 address deleted") + } +} + func ipv6List(cmd *cli.Cmd) { id := cmd.StringArg("SUBID", "", "SUBID of virtual machine (see )") cmd.Action = func() { diff --git a/vendor/github.com/JamesClonk/vultr/lib/client.go b/vendor/github.com/JamesClonk/vultr/lib/client.go index 61df58e..0f805a1 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/client.go +++ b/vendor/github.com/JamesClonk/vultr/lib/client.go @@ -1,6 +1,7 @@ package lib import ( + "bytes" "crypto/tls" "encoding/json" "errors" @@ -168,8 +169,25 @@ func (c *Client) do(req *http.Request, data interface{}) error { // Throttle http requests to avoid hitting Vultr's API rate-limit c.bucket.Wait(1) + // Request body gets drained on each read so we + // need to save it's content for retrying requests + var err error + var requestBody []byte + if req.Body != nil { + requestBody, err = ioutil.ReadAll(req.Body) + if err != nil { + return fmt.Errorf("Error reading request body: %v", err) + } + req.Body.Close() + } + var apiError error for tryCount := 1; tryCount <= c.MaxAttempts; tryCount++ { + // Restore request body to the original state + if requestBody != nil { + req.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody)) + } + resp, err := c.client.Do(req) if err != nil { return err diff --git a/vendor/github.com/JamesClonk/vultr/lib/client_test.go b/vendor/github.com/JamesClonk/vultr/lib/client_test.go index 6af852a..ba5cfd2 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/client_test.go +++ b/vendor/github.com/JamesClonk/vultr/lib/client_test.go @@ -132,3 +132,27 @@ func Test_Client_Retry(t *testing.T) { wg.Wait() } + +// Test that body state is preserved when retrying POST requests +func Test_Client_Retry_Post(t *testing.T) { + server := getTestServerThrottled(`{"SUBID":"5671234"}`) + defer server.Close() + + options := Options{ + Endpoint: server.URL, + MaxRetries: 5, + } + client := NewClient("test-key", &options) + + var wg sync.WaitGroup + wg.Add(10) + for i := 0; i < 10; i++ { + go func() { + defer wg.Done() + _, err := client.CreateBlockStorage("delta", 33, 150) + assert.NoError(t, err) + }() + } + + wg.Wait() +} diff --git a/vendor/github.com/JamesClonk/vultr/lib/dns.go b/vendor/github.com/JamesClonk/vultr/lib/dns.go index 77a8616..e66275b 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/dns.go +++ b/vendor/github.com/JamesClonk/vultr/lib/dns.go @@ -72,7 +72,7 @@ func (c *Client) GetDNSRecords(domain string) (records []DNSRecord, err error) { func (c *Client) CreateDNSDomain(domain, serverIP string) error { values := url.Values{ "domain": {domain}, - "serverIP": {serverIP}, + "serverip": {serverIP}, } if err := c.post(`dns/create_domain`, values, nil); err != nil { diff --git a/vendor/github.com/JamesClonk/vultr/lib/firewall.go b/vendor/github.com/JamesClonk/vultr/lib/firewall.go index c902ca1..c9c54e9 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/firewall.go +++ b/vendor/github.com/JamesClonk/vultr/lib/firewall.go @@ -156,6 +156,19 @@ func (c *Client) DeleteFirewallGroup(groupID string) error { return nil } +// SetFirewallGroupDescription sets the description of an existing firewall group +func (c *Client) SetFirewallGroupDescription(groupID, description string) error { + values := url.Values{ + "FIREWALLGROUPID": {groupID}, + "description": {description}, + } + + if err := c.post(`firewall/group_set_description`, values, nil); err != nil { + return err + } + return nil +} + // GetFirewallRules returns a list of rules for the given firewall group func (c *Client) GetFirewallRules(groupID string) ([]FirewallRule, error) { var ruleMap map[string]FirewallRule diff --git a/vendor/github.com/JamesClonk/vultr/lib/firewall_test.go b/vendor/github.com/JamesClonk/vultr/lib/firewall_test.go index 70b830b..4b72c32 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/firewall_test.go +++ b/vendor/github.com/JamesClonk/vultr/lib/firewall_test.go @@ -89,6 +89,23 @@ func Test_Firewall_DeleteGroup_Ok(t *testing.T) { } } +func Test_Firewall_SetGroupDescription_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.SetFirewallGroupDescription("123456789", "new description") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_Firewall_SetGroupDescription_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.SetFirewallGroupDescription("123456789", "new description")) +} + func Test_Firewall_GetRules_Fail(t *testing.T) { server, client := getTestServerAndClient(http.StatusNotAcceptable, ``) defer server.Close() diff --git a/vendor/github.com/JamesClonk/vultr/lib/ip.go b/vendor/github.com/JamesClonk/vultr/lib/ip.go index de21b1f..4d169cb 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/ip.go +++ b/vendor/github.com/JamesClonk/vultr/lib/ip.go @@ -1,6 +1,7 @@ package lib import ( + "fmt" "net/url" "sort" ) @@ -78,6 +79,32 @@ func (c *Client) ListIPv4(id string) (list []IPv4, err error) { return list, nil } +// CreateIPv4 creates an IPv4 address and attaches it to a virtual machine +func (c *Client) CreateIPv4(id string, reboot bool) error { + values := url.Values{ + "SUBID": {id}, + "reboot": {fmt.Sprintf("%t", reboot)}, + } + + if err := c.post(`server/create_ipv4`, values, nil); err != nil { + return err + } + return nil +} + +// DeleteIPv4 deletes an IPv4 address and detaches it from a virtual machine +func (c *Client) DeleteIPv4(id, ip string) error { + values := url.Values{ + "SUBID": {id}, + "ip": {ip}, + } + + if err := c.post(`server/destroy_ipv4`, values, nil); err != nil { + return err + } + return nil +} + // ListIPv6 lists the IPv4 information of a virtual machine func (c *Client) ListIPv6(id string) (list []IPv6, err error) { var ipMap map[string][]IPv6 diff --git a/vendor/github.com/JamesClonk/vultr/lib/ip_test.go b/vendor/github.com/JamesClonk/vultr/lib/ip_test.go index cd3a344..0116457 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/ip_test.go +++ b/vendor/github.com/JamesClonk/vultr/lib/ip_test.go @@ -61,6 +61,40 @@ func Test_IP_ListIPv4_OK(t *testing.T) { } } +func Test_IP_CreateIPv4_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.CreateIPv4("123456789", true) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_IP_CreateIPv4_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.CreateIPv4("123456789", true)) +} + +func Test_IP_DeleteIPv4_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.DeleteIPv4("123456789", "123.123.123.123") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_IP_DeleteIPv4_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.DeleteIPv4("123456789", "123.123.123.123")) +} + func Test_IP_ListIPv6_Error(t *testing.T) { server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) defer server.Close() diff --git a/vendor/github.com/JamesClonk/vultr/lib/servers.go b/vendor/github.com/JamesClonk/vultr/lib/servers.go index 280082d..418198a 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/servers.go +++ b/vendor/github.com/JamesClonk/vultr/lib/servers.go @@ -51,6 +51,7 @@ type ServerOptions struct { UserData string Snapshot string SSHKey string + ReservedIP string IPV6 bool PrivateNetworking bool AutoBackups bool @@ -288,6 +289,10 @@ func (c *Client) CreateServer(name string, regionID, planID, osID int, options * values.Add("SSHKEYID", options.SSHKey) } + if options.ReservedIP != "" { + values.Add("reserved_ip_v4", options.ReservedIP) + } + values.Add("enable_ipv6", "no") if options.IPV6 { values.Set("enable_ipv6", "yes") @@ -349,6 +354,19 @@ func (c *Client) RenameServer(id, name string) error { return nil } +// TagServer replaces the tag on an existing virtual machine +func (c *Client) TagServer(id, tag string) error { + values := url.Values{ + "SUBID": {id}, + "tag": {tag}, + } + + if err := c.post(`server/tag_set`, values, nil); err != nil { + return err + } + return nil +} + // StartServer starts an existing virtual machine func (c *Client) StartServer(id string) error { values := url.Values{ @@ -469,6 +487,24 @@ func (c *Client) DeleteServer(id string) error { return nil } +// SetFirewallGroup adds a virtual machine to a firewall group +func (c *Client) SetFirewallGroup(id, firewallgroup string) error { + values := url.Values{ + "SUBID": {id}, + "FIREWALLGROUPID": {firewallgroup}, + } + + if err := c.post(`server/firewall_group_set`, values, nil); err != nil { + return err + } + return nil +} + +// UnsetFirewallGroup removes a virtual machine from a firewall group +func (c *Client) UnsetFirewallGroup(id string) error { + return c.SetFirewallGroup(id, "0") +} + // BandwidthOfServer retrieves the bandwidth used by a virtual machine func (c *Client) BandwidthOfServer(id string) (bandwidth []map[string]string, err error) { var bandwidthMap map[string][][]string diff --git a/vendor/github.com/JamesClonk/vultr/lib/servers_test.go b/vendor/github.com/JamesClonk/vultr/lib/servers_test.go index 88048da..6ff0d82 100644 --- a/vendor/github.com/JamesClonk/vultr/lib/servers_test.go +++ b/vendor/github.com/JamesClonk/vultr/lib/servers_test.go @@ -296,6 +296,23 @@ func Test_Servers_RenameServer_OK(t *testing.T) { assert.Nil(t, client.RenameServer("123456789", "new-name")) } +func Test_Servers_TagServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.TagServer("123456789", "new-tag") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_Servers_TagServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.TagServer("123456789", "new-tag")) +} + func Test_Servers_StartServer_Error(t *testing.T) { server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) defer server.Close() @@ -381,6 +398,40 @@ func Test_Servers_DeleteServer_OK(t *testing.T) { assert.Nil(t, client.DeleteServer("123456789")) } +func Test_Servers_SetFirewallGroup_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.SetFirewallGroup("123456789", "123456789") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_Servers_SetFirewallGroup_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.SetFirewallGroup("123456789", "123456789")) +} + +func Test_Servers_UnsetFirewallGroup_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.UnsetFirewallGroup("123456789") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_Servers_UnsetFirewallGroup_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.UnsetFirewallGroup("123456789")) +} + func Test_Servers_ChangeOSofServer_Error(t *testing.T) { server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) defer server.Close()