diff --git a/lib/bare_metal.go b/lib/bare_metal.go new file mode 100644 index 0000000..92710ad --- /dev/null +++ b/lib/bare_metal.go @@ -0,0 +1,398 @@ +package lib + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "net/url" + "sort" + "strconv" + "strings" +) + +// BareMetalServer represents a bare metal server on Vultr. +type BareMetalServer struct { + ID string `json:"SUBID"` + Name string `json:"label"` + OS string `json:"os"` + RAM string `json:"ram"` + Disk string `json:"disk"` + MainIP string `json:"main_ip"` + CPUs int `json:"cpu_count"` + Location string `json:"location"` + RegionID int `json:"DCID,string"` + DefaultPassword string `json:"default_password"` + Created string `json:"date_created"` + Status string `json:"status"` + NetmaskV4 string `json:"netmask_v4"` + GatewayV4 string `json:"gateway_v4"` + PlanID int `json:"METALPLANID"` + V6Networks []V6Network `json:"v6_networks"` + Tag string `json:"tag"` + OSID string `json:"OSID"` + AppID string `json:"APPID"` +} + +// BareMetalServerOptions are optional parameters to be used during bare metal server creation. +type BareMetalServerOptions struct { + Script int + UserData string + Snapshot string + SSHKey string + ReservedIP string + IPV6 bool + DontNotifyOnActivate bool + Hostname string + Tag string + AppID string +} + +type bareMetalServers []BareMetalServer + +func (b bareMetalServers) Len() int { return len(b) } +func (b bareMetalServers) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b bareMetalServers) Less(i, j int) bool { + // sort order: name, ip + if strings.ToLower(b[i].Name) < strings.ToLower(b[j].Name) { + return true + } else if strings.ToLower(b[i].Name) > strings.ToLower(b[j].Name) { + return false + } + return b[i].MainIP < b[j].MainIP +} + +// UnmarshalJSON implements json.Unmarshaller on BareMetal. +// This is needed because the Vultr API is inconsistent in it's JSON responses for bare metal servers. +// Some fields can change type, from JSON number to JSON string and vice-versa. +func (b *BareMetalServer) UnmarshalJSON(data []byte) error { + if b == nil { + *b = BareMetalServer{} + } + + var fields map[string]interface{} + if err := json.Unmarshal(data, &fields); err != nil { + return err + } + + value := fmt.Sprintf("%v", fields["cpu_count"]) + if len(value) == 0 || value == "" { + value = "0" + } + cpu, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + b.CPUs = int(cpu) + + 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 + } + b.RegionID = int(region) + + value = fmt.Sprintf("%v", fields["METALPLANID"]) + if len(value) == 0 || value == "" { + value = "0" + } + plan, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + b.PlanID = int(plan) + + value = fmt.Sprintf("%v", fields["OSID"]) + if value == "" { + value = "" + } + b.OSID = value + + value = fmt.Sprintf("%v", fields["APPID"]) + if value == "" || value == "0" { + value = "" + } + b.AppID = value + + b.ID = fmt.Sprintf("%v", fields["SUBID"]) + b.Name = fmt.Sprintf("%v", fields["label"]) + b.OS = fmt.Sprintf("%v", fields["os"]) + b.RAM = fmt.Sprintf("%v", fields["ram"]) + b.Disk = fmt.Sprintf("%v", fields["disk"]) + b.MainIP = fmt.Sprintf("%v", fields["main_ip"]) + b.Location = fmt.Sprintf("%v", fields["location"]) + b.DefaultPassword = fmt.Sprintf("%v", fields["default_password"]) + b.Created = fmt.Sprintf("%v", fields["date_created"]) + b.Status = fmt.Sprintf("%v", fields["status"]) + b.NetmaskV4 = fmt.Sprintf("%v", fields["netmask_v4"]) + b.GatewayV4 = fmt.Sprintf("%v", fields["gateway_v4"]) + + v6networks := make([]V6Network, 0) + if networks, ok := fields["v6_networks"].([]interface{}); ok { + for _, network := range networks { + if network, ok := network.(map[string]interface{}); ok { + v6network := V6Network{ + Network: fmt.Sprintf("%v", network["v6_network"]), + MainIP: fmt.Sprintf("%v", network["v6_main_ip"]), + NetworkSize: fmt.Sprintf("%v", network["v6_network_size"]), + } + v6networks = append(v6networks, v6network) + } + } + b.V6Networks = v6networks + } + + b.Tag = fmt.Sprintf("%v", fields["tag"]) + + return nil +} + +// GetBareMetalServers returns a list of current bare metal servers on the Vultr account. +func (c *Client) GetBareMetalServers() ([]BareMetalServer, error) { + var bareMetalServerMap map[string]BareMetalServer + if err := c.get(`baremetal/list`, &bareMetalServerMap); err != nil { + return nil, err + } + + var bareMetalServerList []BareMetalServer + for _, bareMetalServer := range bareMetalServerMap { + bareMetalServerList = append(bareMetalServerList, bareMetalServer) + } + sort.Sort(bareMetalServers(bareMetalServerList)) + return bareMetalServerList, nil +} + +// GetBareMetalServersByTag returns a list of all bare metal servers matching by tag. +func (c *Client) GetBareMetalServersByTag(tag string) ([]BareMetalServer, error) { + var bareMetalServerMap map[string]BareMetalServer + if err := c.get(`baremetal/list?tag=`+tag, &bareMetalServerMap); err != nil { + return nil, err + } + + var bareMetalServerList []BareMetalServer + for _, bareMetalServer := range bareMetalServerMap { + bareMetalServerList = append(bareMetalServerList, bareMetalServer) + } + sort.Sort(bareMetalServers(bareMetalServerList)) + return bareMetalServerList, nil +} + +// GetBareMetalServer returns the bare metal server with the given ID. +func (c *Client) GetBareMetalServer(id string) (BareMetalServer, error) { + var b BareMetalServer + if err := c.get(`baremetal/list?SUBID=`+id, &b); err != nil { + return BareMetalServer{}, err + } + return b, nil +} + +// CreateBareMetalServer creates a new bare metal server on Vultr. BareMetalServerOptions are optional settings. +func (c *Client) CreateBareMetalServer(name string, regionID, planID, osID int, options *BareMetalServerOptions) (BareMetalServer, error) { + values := url.Values{ + "label": {name}, + "DCID": {fmt.Sprintf("%v", regionID)}, + "METALPLANID": {fmt.Sprintf("%v", planID)}, + "OSID": {fmt.Sprintf("%v", osID)}, + } + + if options != nil { + if options.Script != 0 { + values.Add("SCRIPTID", fmt.Sprintf("%v", options.Script)) + } + + if options.UserData != "" { + values.Add("userdata", base64.StdEncoding.EncodeToString([]byte(options.UserData))) + } + + if options.Snapshot != "" { + values.Add("SNAPSHOTID", options.Snapshot) + } + + if options.SSHKey != "" { + values.Add("SSHKEYID", options.SSHKey) + } + + values.Add("enable_ipv6", "no") + if options.IPV6 { + values.Set("enable_ipv6", "yes") + } + + values.Add("notify_activate", "yes") + if options.DontNotifyOnActivate { + values.Set("notify_activate", "no") + } + + if options.Hostname != "" { + values.Add("hostname", options.Hostname) + } + + if options.Tag != "" { + values.Add("tag", options.Tag) + } + + if options.AppID != "" { + values.Add("APPID", options.AppID) + } + } + + var b BareMetalServer + if err := c.post(`baremetal/create`, values, &b); err != nil { + return BareMetalServer{}, err + } + b.Name = name + b.RegionID = regionID + b.PlanID = planID + + return b, nil +} + +// RenameBareMetalServer renames an existing bare metal server. +func (c *Client) RenameBareMetalServer(id, name string) error { + values := url.Values{ + "SUBID": {id}, + "label": {name}, + } + + return c.post(`baremetal/label_set`, values, nil) +} + +// TagBareMetalServer replaces the tag on an existing bare metal server. +func (c *Client) TagBareMetalServer(id, tag string) error { + values := url.Values{ + "SUBID": {id}, + "tag": {tag}, + } + + return c.post(`baremetal/tag_set`, values, nil) +} + +// HaltBareMetalServer stops an existing bare metal server. +func (c *Client) HaltBareMetalServer(id string) error { + values := url.Values{ + "SUBID": {id}, + } + + return c.post(`baremetal/halt`, values, nil) +} + +// RebootBareMetalServer reboots an existing bare metal server. +func (c *Client) RebootBareMetalServer(id string) error { + values := url.Values{ + "SUBID": {id}, + } + + return c.post(`baremetal/reboot`, values, nil) +} + +// ReinstallBareMetalServer reinstalls the operating system on an existing bare metal server. +func (c *Client) ReinstallBareMetalServer(id string) error { + values := url.Values{ + "SUBID": {id}, + } + + return c.post(`baremetal/reinstall`, values, nil) +} + +// ChangeOSofBareMetalServer changes the bare metal server to a different operating system. +func (c *Client) ChangeOSofBareMetalServer(id string, osID int) error { + values := url.Values{ + "SUBID": {id}, + "OSID": {fmt.Sprintf("%v", osID)}, + } + + return c.post(`baremetal/os_change`, values, nil) +} + +// ListOSforBareMetalServer lists all available operating systems to which an existing bare metal server can be changed. +func (c *Client) ListOSforBareMetalServer(id string) ([]OS, error) { + var osMap map[string]OS + if err := c.get(`baremetal/os_change_list?SUBID=`+id, &osMap); err != nil { + return nil, err + } + + var os []OS + for _, o := range osMap { + os = append(os, o) + } + sort.Sort(oses(os)) + return os, nil +} + +// DeleteBareMetalServer deletes an existing bare metal server. +func (c *Client) DeleteBareMetalServer(id string) error { + values := url.Values{ + "SUBID": {id}, + } + + return c.post(`baremetal/destroy`, values, nil) +} + +// BandwidthOfBareMetalServer retrieves the bandwidth used by a bare metal server. +func (c *Client) BandwidthOfBareMetalServer(id string) ([]map[string]string, error) { + var bandwidthMap map[string][][]interface{} + if err := c.get(`server/bandwidth?SUBID=`+id, &bandwidthMap); err != nil { + return nil, err + } + + var bandwidth []map[string]string + // parse incoming bytes + for _, b := range bandwidthMap["incoming_bytes"] { + bMap := make(map[string]string) + bMap["date"] = fmt.Sprintf("%v", b[0]) + var bytes int64 + switch b[1].(type) { + case float64: + bytes = int64(b[1].(float64)) + case int64: + bytes = b[1].(int64) + } + bMap["incoming"] = fmt.Sprintf("%v", bytes) + bandwidth = append(bandwidth, bMap) + } + + // parse outgoing bytes (we'll assume that incoming and outgoing dates are always a match) + for _, b := range bandwidthMap["outgoing_bytes"] { + for i := range bandwidth { + if bandwidth[i]["date"] == fmt.Sprintf("%v", b[0]) { + var bytes int64 + switch b[1].(type) { + case float64: + bytes = int64(b[1].(float64)) + case int64: + bytes = b[1].(int64) + } + bandwidth[i]["outgoing"] = fmt.Sprintf("%v", bytes) + break + } + } + } + + return bandwidth, nil +} + +// ChangeApplicationofBareMetalServer changes the bare metal server to a different application. +func (c *Client) ChangeApplicationofBareMetalServer(id string, appID string) error { + values := url.Values{ + "SUBID": {id}, + "APPID": {appID}, + } + + return c.post(`baremetal/app_change`, values, nil) +} + +// ListApplicationsforBareMetalServer lists all available operating systems to which an existing bare metal server can be changed. +func (c *Client) ListApplicationsforBareMetalServer(id string) ([]Application, error) { + var appMap map[string]Application + if err := c.get(`baremetal/app_change_list?SUBID=`+id, &appMap); err != nil { + return nil, err + } + + var apps []Application + for _, app := range appMap { + apps = append(apps, app) + } + sort.Sort(applications(apps)) + return apps, nil +} diff --git a/lib/bare_metal_plans.go b/lib/bare_metal_plans.go new file mode 100644 index 0000000..5854264 --- /dev/null +++ b/lib/bare_metal_plans.go @@ -0,0 +1,79 @@ +package lib + +import ( + "fmt" + "sort" +) + +// BareMetalPlan is a bare metal-compatible plan on Vultr. +type BareMetalPlan struct { + Deprecated bool `json:"deprecated"` + ID int `json:"METALPLANID,string"` + Name string `json:"name"` + CPUs int `json:"cpu_count"` + RAM int `json:"ram"` + Disk string `json:"disk"` + Bandwidth int `json:"bandwidth_tb"` + Price int `json:"price_per_month"` + Regions []int `json:"available_locations"` + Type string `json:"type"` +} + +type bareMetalPlans []BareMetalPlan + +func (b bareMetalPlans) Len() int { return len(b) } +func (b bareMetalPlans) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b bareMetalPlans) Less(i, j int) bool { + ba := b[i].Price + bb := b[j].Price + ra := b[i].RAM + rb := b[j].RAM + da := b[i].Disk + db := b[j].Disk + + // sort order: price, vcpu, ram, disk + if ba < bb { + return true + } else if ba > bb { + return false + } + + if b[i].CPUs < b[j].CPUs { + return true + } else if b[i].CPUs > b[j].CPUs { + return false + } + + if ra < rb { + return true + } else if ra > rb { + return false + } + + return da < db +} + +// GetBareMetalPlans returns a list of all available bare metal plans on Vultr account. +func (c *Client) GetBareMetalPlans() ([]BareMetalPlan, error) { + var bareMetalPlanMap map[string]BareMetalPlan + if err := c.get(`plans/list_baremetal`, &bareMetalPlanMap); err != nil { + return nil, err + } + + var b bareMetalPlans + for _, bareMetalPlan := range bareMetalPlanMap { + b = append(b, bareMetalPlan) + } + + sort.Sort(bareMetalPlans(b)) + return b, nil +} + +// GetAvailableBareMetalPlansForRegion returns available bare metal plans for specified region. +func (c *Client) GetAvailableBareMetalPlansForRegion(id int) ([]int, error) { + var bareMetalPlanIDs []int + if err := c.get(fmt.Sprintf(`regions/availability?DCID=%v`, id), &bareMetalPlanIDs); err != nil { + return nil, err + } + return bareMetalPlanIDs, nil +} diff --git a/lib/bare_metal_plans_test.go b/lib/bare_metal_plans_test.go new file mode 100644 index 0000000..0dede91 --- /dev/null +++ b/lib/bare_metal_plans_test.go @@ -0,0 +1,95 @@ +package lib + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_BareMetalPlans_GetBareMetalPlans_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + bareMetalPlans, err := client.GetBareMetalPlans() + assert.Nil(t, bareMetalPlans) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalPlans_GetBareMetalPlans_NoBareMetalPlans(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + bareMetalPlans, err := client.GetBareMetalPlans() + if err != nil { + t.Error(err) + } + assert.Nil(t, bareMetalPlans) +} + +func Test_BareMetalPlans_GetBareMetalPlans_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{ +"30":{"METALPLANID":"30","name":"1024 MB RAM,20 GB SSD,2.00 TB BW","cpu_count":2,"ram":1024,"disk":"20","bandwidth_tb":2,"price_per_month":7}, +"29":{"METALPLANID":"29","name":"768 MB RAM,15 GB SSD,1.00 TB BW","cpu_count":1,"ram":768,"disk":"15","bandwidth_tb":1,"price_per_month":5,"available_locations":[1,2,3]}}`) + defer server.Close() + + bareMetalPlans, err := client.GetBareMetalPlans() + if err != nil { + t.Error(err) + } + if assert.NotNil(t, bareMetalPlans) { + assert.Equal(t, 2, len(bareMetalPlans)) + + assert.Equal(t, 29, bareMetalPlans[0].ID) + assert.Equal(t, "768 MB RAM,15 GB SSD,1.00 TB BW", bareMetalPlans[0].Name) + assert.Equal(t, 1, bareMetalPlans[0].CPUs) + assert.Equal(t, 768, bareMetalPlans[0].RAM) + assert.Equal(t, 5, bareMetalPlans[0].Price) + assert.Equal(t, 1, bareMetalPlans[0].Regions[0]) + assert.Equal(t, 3, bareMetalPlans[0].Regions[2]) + + assert.Equal(t, 30, bareMetalPlans[1].ID) + assert.Equal(t, "1024 MB RAM,20 GB SSD,2.00 TB BW", bareMetalPlans[1].Name) + assert.Equal(t, 2, bareMetalPlans[1].CPUs) + assert.Equal(t, "20", bareMetalPlans[1].Disk) + assert.Equal(t, 2, bareMetalPlans[1].Bandwidth) + assert.Equal(t, 0, len(bareMetalPlans[1].Regions)) + } +} + +func Test_BareMetalPlans_GetAvailableBareMetalPlansForRegion_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + bareMetalPlans, err := client.GetAvailableBareMetalPlansForRegion(1) + assert.Nil(t, bareMetalPlans) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalPlans_GetAvailableBareMetalPlansForRegion_NoBareMetalPlans(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + bareMetalPlans, err := client.GetAvailableBareMetalPlansForRegion(2) + if err != nil { + t.Error(err) + } + assert.Nil(t, bareMetalPlans) +} + +func Test_BareMetalPlans_GetAvailableBareMetalPlansForRegion_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[29,30,3,27,28,11,13,81]`) + defer server.Close() + + bareMetalPlans, err := client.GetAvailableBareMetalPlansForRegion(3) + if err != nil { + t.Error(err) + } + if assert.NotNil(t, bareMetalPlans) { + assert.Equal(t, 8, len(bareMetalPlans)) + } +} diff --git a/lib/bare_metal_test.go b/lib/bare_metal_test.go new file mode 100644 index 0000000..5a4eb5c --- /dev/null +++ b/lib/bare_metal_test.go @@ -0,0 +1,565 @@ +package lib + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_BareMetalServers_GetBareMetalServers_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + bareMetalServers, err := client.GetBareMetalServers() + assert.Nil(t, bareMetalServers) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_GetBareMetalServers_NoBareMetalServers(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + bareMetalServers, err := client.GetBareMetalServers() + if err != nil { + t.Error(err) + } + assert.Nil(t, bareMetalServers) +} + +func Test_BareMetalServers_GetBareMetalServers_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{ +"789032":{"SUBID":"789032","os":"CentOs 6.5 i368","ram":"1024 MB","disk":"Virtual 20 GB","main_ip":"192.168.1.2", + "cpu_count":1,"location":"Amsterdam","DCID":"21","default_password":"more oops!","date_created":"2011-01-01 01:01:01", + "status":"stopped","netmask_v4":"255.255.254.0","gateway_v4":"192.168.1.1","METALPLANID":31, + "v6_networks": [{"v6_network": "2002:DB9:1000::", "v6_main_ip": "2000:DB8:1000::0000", "v6_network_size": 32 }], + "label":"test beta","OSID": "127","APPID": "2"}, +"9753721":{"SUBID":"9753721","os":"Ubuntu 14.04 x64","ram":"768 MB","disk":"Virtual 15 GB","main_ip":"123.456.789.0", + "cpu_count":2,"location":"Frankfurt","DCID":"9","default_password":"oops!","date_created":"2017-07-07 07:07:07", + "status":"active","netmask_v4":"255.255.255.0","gateway_v4":"123.456.789.1","METALPLANID":29, + "label":"test alpha","APPID": "0"}}`) + defer server.Close() + + bareMetalServers, err := client.GetBareMetalServers() + if err != nil { + t.Error(err) + } + if assert.NotNil(t, bareMetalServers) { + assert.Equal(t, 2, len(bareMetalServers)) + + assert.Equal(t, "9753721", bareMetalServers[0].ID) + assert.Equal(t, "test alpha", bareMetalServers[0].Name) + assert.Equal(t, "Ubuntu 14.04 x64", bareMetalServers[0].OS) + assert.Equal(t, "768 MB", bareMetalServers[0].RAM) + assert.Equal(t, "Virtual 15 GB", bareMetalServers[0].Disk) + assert.Equal(t, "123.456.789.0", bareMetalServers[0].MainIP) + assert.Equal(t, 2, bareMetalServers[0].CPUs) + assert.Equal(t, "Frankfurt", bareMetalServers[0].Location) + assert.Equal(t, 9, bareMetalServers[0].RegionID) + assert.Equal(t, "oops!", bareMetalServers[0].DefaultPassword) + assert.Equal(t, "2017-07-07 07:07:07", bareMetalServers[0].Created) + assert.Equal(t, "255.255.255.0", bareMetalServers[0].NetmaskV4) + assert.Equal(t, "123.456.789.1", bareMetalServers[0].GatewayV4) + assert.Equal(t, 0, len(bareMetalServers[0].V6Networks)) + assert.Equal(t, "", bareMetalServers[0].OSID) + assert.Equal(t, "", bareMetalServers[0].AppID) + + assert.Equal(t, "789032", bareMetalServers[1].ID) + assert.Equal(t, "test beta", bareMetalServers[1].Name) + assert.Equal(t, "stopped", bareMetalServers[1].Status) + assert.Equal(t, 31, bareMetalServers[1].PlanID) + assert.Equal(t, 1, len(bareMetalServers[1].V6Networks)) + assert.Equal(t, "2002:DB9:1000::", bareMetalServers[1].V6Networks[0].Network) + assert.Equal(t, "2000:DB8:1000::0000", bareMetalServers[1].V6Networks[0].MainIP) + assert.Equal(t, "32", bareMetalServers[1].V6Networks[0].NetworkSize) + assert.Equal(t, "127", bareMetalServers[1].OSID) + assert.Equal(t, "2", bareMetalServers[1].AppID) + } +} + +func Test_BareMetalServers_GetBareMetalServersByTag_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + bareMetalServers, err := client.GetBareMetalServersByTag("Unknown") + assert.Nil(t, bareMetalServers) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_GetBareMetalServersByTag_NoBareMetalServers(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + bareMetalServers, err := client.GetBareMetalServersByTag("Nothing") + if err != nil { + t.Error(err) + } + assert.Nil(t, bareMetalServers) +} + +func Test_BareMetalServers_GetBareMetalServersByTag_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{ +"789032":{"SUBID":"789032","os":"CentOs 6.5 i368","ram":"1024 MB","disk":"Virtual 20 GB","main_ip":"192.168.1.2", + "cpu_count":"1","location":"Amsterdam","DCID":"21","default_password":"more oops!","date_created":"2011-01-01 01:01:01", + "status":"stopped","netmask_v4":"255.255.254.0","gateway_v4":"192.168.1.1","METALPLANID":"31", + "v6_networks": [{"v6_network": "2001:DB8:1000::", "v6_main_ip": "2001:DB8:1000::100", "v6_network_size": "64" }], + "label":"test 002","tag":"Database"}}`) + defer server.Close() + + bareMetalServers, err := client.GetBareMetalServersByTag("Database") + if err != nil { + t.Error(err) + } + if assert.NotNil(t, bareMetalServers) { + assert.Equal(t, 1, len(bareMetalServers)) + assert.Equal(t, "test 002", bareMetalServers[0].Name) + assert.Equal(t, "stopped", bareMetalServers[0].Status) + assert.Equal(t, 31, bareMetalServers[0].PlanID) + assert.Equal(t, 1, len(bareMetalServers[0].V6Networks)) + assert.Equal(t, "2001:DB8:1000::", bareMetalServers[0].V6Networks[0].Network) + assert.Equal(t, "2001:DB8:1000::100", bareMetalServers[0].V6Networks[0].MainIP) + assert.Equal(t, "64", bareMetalServers[0].V6Networks[0].NetworkSize) + } +} + +func Test_BareMetalServers_GetBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + _, err := client.GetBareMetalServer("789032") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_GetBareMetalServer_NoBareMetalServer(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + s, err := client.GetBareMetalServer("789032") + if err != nil { + t.Error(err) + } + assert.Equal(t, BareMetalServer{}, s) +} + +func Test_BareMetalServers_GetBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, ` +{"SUBID":"9753721","os":"Ubuntu 14.04 x64","ram":"768 MB","disk":"Virtual 15 GB","main_ip":"123.456.789.0", + "cpu_count":"2","location":"Frankfurt","DCID":"9","default_password":"oops!","date_created":"2017-07-07 07:07:07", + "status":"active","netmask_v4":"255.255.255.0","gateway_v4":"123.456.789.1","METALPLANID":"29","label":"test alpha", + "v6_networks": [{"v6_network": "::", "v6_main_ip": "", "v6_network_size": "0" }]}`) + defer server.Close() + + s, err := client.GetBareMetalServer("789032") + if err != nil { + t.Error(err) + } + if assert.NotNil(t, s) { + assert.Equal(t, "test alpha", s.Name) + assert.Equal(t, "Ubuntu 14.04 x64", s.OS) + assert.Equal(t, "768 MB", s.RAM) + assert.Equal(t, "Virtual 15 GB", s.Disk) + assert.Equal(t, "123.456.789.0", s.MainIP) + assert.Equal(t, 2, s.CPUs) + assert.Equal(t, "Frankfurt", s.Location) + assert.Equal(t, 9, s.RegionID) + assert.Equal(t, "oops!", s.DefaultPassword) + assert.Equal(t, "2017-07-07 07:07:07", s.Created) + assert.Equal(t, "255.255.255.0", s.NetmaskV4) + assert.Equal(t, "123.456.789.1", s.GatewayV4) + assert.Equal(t, "active", s.Status) + assert.Equal(t, 29, s.PlanID) + assert.Equal(t, 1, len(s.V6Networks)) + assert.Equal(t, "::", s.V6Networks[0].Network) + assert.Equal(t, "", s.V6Networks[0].MainIP) + assert.Equal(t, "0", s.V6Networks[0].NetworkSize) + } +} + +func Test_BareMetalServers_CreateBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + s, err := client.CreateBareMetalServer("test", 1, 2, 3, nil) + assert.Equal(t, BareMetalServer{}, s) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_CreateBareMetalServer_NoBareMetalServer(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + s, err := client.CreateBareMetalServer("test", 1, 2, 3, nil) + if err != nil { + t.Error(err) + } + assert.Equal(t, "", s.ID) +} + +func Test_BareMetalServers_CreateBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{"SUBID":"123456789", + "cpu_count":"1", + "DCID":17, + "VPSPLANID":"29"}`) + defer server.Close() + + s, err := client.CreateBareMetalServer("test", 1, 2, 3, nil) + if err != nil { + t.Error(err) + } + if assert.NotNil(t, s) { + assert.Equal(t, "123456789", s.ID) + assert.Equal(t, "test", s.Name) + assert.Equal(t, 1, s.RegionID) + assert.Equal(t, 2, s.PlanID) + } + + options := &BareMetalServerOptions{ + Script: 2, + Snapshot: "alpha", + SSHKey: "key123", + IPV6: true, + } + s2, err := client.CreateBareMetalServer("test2", 4, 5, 6, options) + if err != nil { + t.Error(err) + } + if assert.NotNil(t, s2) { + assert.Equal(t, "123456789", s2.ID) + assert.Equal(t, "test2", s2.Name) + assert.Equal(t, 4, s2.RegionID) + assert.Equal(t, 5, s2.PlanID) + } + +} + +func Test_BareMetalServers_RenameBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.RenameBareMetalServer("123456789", "new-name") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_RenameBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.RenameBareMetalServer("123456789", "new-name")) +} + +func Test_BareMetalServers_TagBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.TagBareMetalServer("123456789", "new-tag") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_TagBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.TagBareMetalServer("123456789", "new-tag")) +} + +func Test_BareMetalServers_HaltBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.HaltBareMetalServer("123456789") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_HaltBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.HaltBareMetalServer("123456789")) +} + +func Test_BareMetalServers_RebootBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.RebootBareMetalServer("123456789") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_RebootBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.RebootBareMetalServer("123456789")) +} + +func Test_BareMetalServers_ReinstallBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.ReinstallBareMetalServer("123456789") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_ReinstallBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.ReinstallBareMetalServer("123456789")) +} + +func Test_BareMetalServers_DeleteBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.DeleteBareMetalServer("123456789") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_DeleteBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.DeleteBareMetalServer("123456789")) +} + +func Test_BareMetalServers_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_BareMetalServers_SetFirewallGroup_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.SetFirewallGroup("123456789", "123456789")) +} + +func Test_BareMetalServers_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_BareMetalServers_UnsetFirewallGroup_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.UnsetFirewallGroup("123456789")) +} + +func Test_BareMetalServers_ChangeOSofBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.ChangeOSofBareMetalServer("123456789", 160) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_ChangeOSofBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.ChangeOSofBareMetalServer("123456789", 160)) +} + +func Test_BareMetalServers_ListOSforBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + os, err := client.ListOSforBareMetalServer("123456789") + assert.Nil(t, os) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_ListOSforBareMetalServer_NoOS(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + os, err := client.ListOSforBareMetalServer("123456789") + if err != nil { + t.Error(err) + } + assert.Nil(t, os) +} + +func Test_BareMetalServers_ListOSforBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{ +"179":{"OSID":179,"name":"CoreOS Stable","arch":"x64","family":"coreos","windows":false,"surcharge":"1.25"}, +"127":{"OSID":127,"name":"CentOS 6 x64","arch":"x64","family":"centos","windows":false,"surcharge":"0.00"}, +"124":{"OSID":124,"name":"Windows 2012 R2 x64","arch":"x64","family":"windows","windows":true,"surcharge":"5.99"}}`) + defer server.Close() + + os, err := client.ListOSforBareMetalServer("123456789") + if err != nil { + t.Error(err) + } + if assert.NotNil(t, os) { + assert.Equal(t, 3, len(os)) + + assert.Equal(t, 127, os[0].ID) + assert.Equal(t, "CentOS 6 x64", os[0].Name) + assert.Equal(t, "x64", os[0].Arch) + assert.Equal(t, "centos", os[0].Family) + assert.Equal(t, "0.00", os[0].Surcharge) + + assert.Equal(t, 179, os[1].ID) + assert.Equal(t, "coreos", os[1].Family) + assert.Equal(t, "CoreOS Stable", os[1].Name) + assert.Equal(t, false, os[1].Windows) + assert.Equal(t, "1.25", os[1].Surcharge) + + assert.Equal(t, 124, os[2].ID) + assert.Equal(t, "windows", os[2].Family) + assert.Equal(t, "Windows 2012 R2 x64", os[2].Name) + assert.Equal(t, true, os[2].Windows) + assert.Equal(t, "5.99", os[2].Surcharge) + } +} + +func Test_BareMetalServers_BandwidthOfBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + bandwidth, err := client.BandwidthOfBareMetalServer("123456789") + assert.Nil(t, bandwidth) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_BandwidthOfBareMetalServer_NoOS(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + bandwidth, err := client.BandwidthOfBareMetalServer("123456789") + if err != nil { + t.Error(err) + } + assert.Nil(t, bandwidth) +} + +func Test_BareMetalServers_BandwidthOfBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{ + "incoming_bytes": [ + ["2014-06-10",81072581],["2014-06-11",222387466], + ["2014-06-12",216885232],["2014-06-13",117262318] + ], + "outgoing_bytes": [ + ["2014-06-10",4059610],["2014-06-11",13432380], + ["2014-06-12",2455005],["2014-06-13",1106963] + ]}`) + defer server.Close() + + bandwidth, err := client.BandwidthOfBareMetalServer("123456789") + if err != nil { + t.Error(err) + } + if assert.NotNil(t, bandwidth) { + assert.Equal(t, 4, len(bandwidth)) + assert.Equal(t, "2014-06-10", bandwidth[0]["date"]) + assert.Equal(t, "81072581", bandwidth[0]["incoming"]) + assert.Equal(t, "4059610", bandwidth[0]["outgoing"]) + assert.Equal(t, "2014-06-12", bandwidth[2]["date"]) + assert.Equal(t, "216885232", bandwidth[2]["incoming"]) + assert.Equal(t, "2455005", bandwidth[2]["outgoing"]) + } +} + +func Test_BareMetalServers_ChangeApplicationofBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + err := client.ChangeApplicationofBareMetalServer("123456789", "3") + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_ChangeApplicationofBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{no-response?!}`) + defer server.Close() + + assert.Nil(t, client.ChangeApplicationofBareMetalServer("123456789", "3")) +} + +func Test_BareMetalServers_ListApplicationsforBareMetalServer_Error(t *testing.T) { + server, client := getTestServerAndClient(http.StatusNotAcceptable, `{error}`) + defer server.Close() + + apps, err := client.ListApplicationsforBareMetalServer("123456789") + assert.Nil(t, apps) + if assert.NotNil(t, err) { + assert.Equal(t, `{error}`, err.Error()) + } +} + +func Test_BareMetalServers_ListApplicationsforBareMetalServer_NoOS(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `[]`) + defer server.Close() + + apps, err := client.ListApplicationsforBareMetalServer("123456789") + if err != nil { + t.Error(err) + } + assert.Nil(t, apps) +} + +func Test_BareMetalServers_ListApplicationsforBareMetalServer_OK(t *testing.T) { + server, client := getTestServerAndClient(http.StatusOK, `{ +"2": {"APPID": "2","name": "WordPress","short_name": "wordpress","deploy_name": "WordPress on CentOS 6 x64","surcharge": 0}, +"1": {"APPID": "1","name": "LEMP","short_name": "lemp","deploy_name": "LEMP on CentOS 6 x64","surcharge": 5} +}`) + defer server.Close() + + apps, err := client.ListApplicationsforBareMetalServer("123456789") + if err != nil { + t.Error(err) + } + if assert.NotNil(t, apps) { + assert.Equal(t, 2, len(apps)) + + assert.Equal(t, "1", apps[0].ID) + assert.Equal(t, "LEMP", apps[0].Name) + assert.Equal(t, "lemp", apps[0].ShortName) + assert.Equal(t, "LEMP on CentOS 6 x64", apps[0].DeployName) + assert.Equal(t, float64(5), apps[0].Surcharge) + + assert.Equal(t, "2", apps[1].ID) + assert.Equal(t, "WordPress", apps[1].Name) + assert.Equal(t, "wordpress", apps[1].ShortName) + assert.Equal(t, "WordPress on CentOS 6 x64", apps[1].DeployName) + } +}