From 58881732b3c0933d98db393d2edb829abb0b5e0c Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Thu, 22 Oct 2020 22:19:59 -0400 Subject: [PATCH] packngo v0.5.0 By updating to packngo v0.5.0, the provider will make use of the new api.equinix.com/metal/v1 URLs (rather than api.packet.net). The network type detection should be improved, as a result, the network type conversion should be improved. Devices listing can now use the `search` parameter, which should improve the performance of hostname lookups in the `packet_device` data source. Signed-off-by: Marques Johansson --- CHANGELOG.md | 4 +- go.mod | 2 +- go.sum | 6 +- packet/datasource_packet_device.go | 9 +- packet/helpers_device.go | 5 +- packet/resource_packet_device.go | 5 +- packet/resource_packet_device_network_type.go | 6 +- vendor/github.com/packethost/packngo/Makefile | 2 +- .../github.com/packethost/packngo/OWNERS.md | 4 +- .../github.com/packethost/packngo/devices.go | 86 ++++++-- .../github.com/packethost/packngo/packngo.go | 65 ++++-- vendor/github.com/packethost/packngo/ports.go | 195 +++++++++--------- vendor/modules.txt | 2 +- 13 files changed, 236 insertions(+), 155 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb960c39..154fd68a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ ## 3.1.0 (Unreleased) BREAKING CHANGES: -- packngo updated to v0.4.1, changing the API endpoint from api.packet.net to api.equinix.com/metal/v1 +- packngo updated to v0.4.1+, changing the API endpoint from api.packet.net to api.equinix.com/metal/v1 FEATURES: - [#249](https://github.com/packethost/terraform-provider-packet/pull/249) New datasource `packet_project_ssh_key` IMPROVEMENTS: +- `packet_device` datasource should query by hostname much faster +- `packet_device_network_type` conversions should be more reliable - Test sweeper added for SSH keys - Acceptance testing moved to Github Actions - Improved logging when resources are not found and removed from state diff --git a/go.mod b/go.mod index 5f42a025..e1026440 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.6.6 github.com/hashicorp/terraform-plugin-sdk v1.0.0 github.com/mattn/go-colorable v0.1.1 // indirect - github.com/packethost/packngo v0.4.1 + github.com/packethost/packngo v0.5.0 github.com/vmihailenco/msgpack v4.0.1+incompatible // indirect golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect gopkg.in/yaml.v2 v2.2.8 // indirect diff --git a/go.sum b/go.sum index b7a4edf4..800081b3 100644 --- a/go.sum +++ b/go.sum @@ -161,10 +161,8 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/packethost/packngo v0.3.0 h1:mE5UHyhr5sKN1Qa0GtExRG9ECUX/muazI0f53gSrt5E= -github.com/packethost/packngo v0.3.0/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= -github.com/packethost/packngo v0.4.1 h1:HWeO3y3xvGIhdaW15VLz7uswKE27YRvXtONDjcMqvqk= -github.com/packethost/packngo v0.4.1/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= +github.com/packethost/packngo v0.5.0 h1:WGpfeRMstPqgyXGUXl6b9xFsbUudXU3p0+JlYri290U= +github.com/packethost/packngo v0.5.0/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/packet/datasource_packet_device.go b/packet/datasource_packet_device.go index b86c4e68..a8e5ad2a 100644 --- a/packet/datasource_packet_device.go +++ b/packet/datasource_packet_device.go @@ -188,7 +188,7 @@ func dataSourcePacketDeviceRead(d *schema.ResourceData, meta interface{}) error hostname := hostnameRaw.(string) projectId := projectIdRaw.(string) - ds, _, err := client.Devices.List(projectId, nil) + ds, _, err := client.Devices.List(projectId, &packngo.ListOptions{Search: hostname}) if err != nil { return err } @@ -225,7 +225,7 @@ func dataSourcePacketDeviceRead(d *schema.ResourceData, meta interface{}) error storageString, err := structure.NormalizeJsonString(string(rawStorageBytes)) if err != nil { - return fmt.Errorf("[ERR] Errori normalizing storage JSON string for device (%s): %s", d.Id(), err) + return fmt.Errorf("[ERR] Error normalizing storage JSON string for device (%s): %s", d.Id(), err) } d.Set("storage", storageString) } @@ -233,10 +233,7 @@ func dataSourcePacketDeviceRead(d *schema.ResourceData, meta interface{}) error if len(device.HardwareReservation.Href) > 0 { d.Set("hardware_reservation_id", path.Base(device.HardwareReservation.Href)) } - networkType, err := device.GetNetworkType() - if err != nil { - return err - } + networkType := device.GetNetworkType() d.Set("network_type", networkType) diff --git a/packet/helpers_device.go b/packet/helpers_device.go index 64deee23..917b9b55 100644 --- a/packet/helpers_device.go +++ b/packet/helpers_device.go @@ -173,10 +173,7 @@ func waitForDeviceAttribute(d *schema.ResourceData, targets []string, pending [] if err == nil { retAttrVal := device.State if attribute == "network_type" { - networkType, nterr := device.GetNetworkType() - if nterr != nil { - return "error", "error", nterr - } + networkType := device.GetNetworkType() retAttrVal = networkType } return retAttrVal, retAttrVal, nil diff --git a/packet/resource_packet_device.go b/packet/resource_packet_device.go index f0529161..b681cd97 100644 --- a/packet/resource_packet_device.go +++ b/packet/resource_packet_device.go @@ -465,10 +465,7 @@ func resourcePacketDeviceRead(d *schema.ResourceData, meta interface{}) error { if len(device.HardwareReservation.Href) > 0 { d.Set("hardware_reservation_id", path.Base(device.HardwareReservation.Href)) } - networkType, err := device.GetNetworkType() - if err != nil { - return err - } + networkType := device.GetNetworkType() d.Set("network_type", networkType) wfrd := "wait_for_reservation_deprovision" diff --git a/packet/resource_packet_device_network_type.go b/packet/resource_packet_device_network_type.go index 157bff49..4c855da3 100644 --- a/packet/resource_packet_device_network_type.go +++ b/packet/resource_packet_device_network_type.go @@ -43,10 +43,8 @@ func getDevIDandNetworkType(d *schema.ResourceData, c *packngo.Client) (string, if err != nil { return "", "", err } - devType, err := dev.GetNetworkType() - if err != nil { - return "", "", err - } + devType := dev.GetNetworkType() + return dev.ID, devType, nil } diff --git a/vendor/github.com/packethost/packngo/Makefile b/vendor/github.com/packethost/packngo/Makefile index 99f7a8ab..57d98505 100644 --- a/vendor/github.com/packethost/packngo/Makefile +++ b/vendor/github.com/packethost/packngo/Makefile @@ -18,7 +18,7 @@ build: golangci-lint: ifeq (, $(shell which golangci-lint)) - $(GO) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.24.0 + $(GO) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.27.0 endif golint: diff --git a/vendor/github.com/packethost/packngo/OWNERS.md b/vendor/github.com/packethost/packngo/OWNERS.md index b8f43e0a..8b002e98 100644 --- a/vendor/github.com/packethost/packngo/OWNERS.md +++ b/vendor/github.com/packethost/packngo/OWNERS.md @@ -1,7 +1,7 @@ # Owners This project is governed by [Equinix Metal] and benefits from a community of users that -collaborate and contribute to its use in Go powered projects, such as th [Equinix Metal +collaborate and contribute to its use in Go powered projects, such as the [Equinix Metal Terraform provider], [Docker machine driver], Kubernetes drivers for [CSI] and [CCM], the [Equinix Metal CLI], and others. @@ -23,4 +23,4 @@ Maintainers of this repository are defined within the [CODEOWNERS] file. [SUPPORT.md]: SUPPORT.md [packethost/standards glossary]: https://github.com/packethost/standards/blob/master/glossary.md#ownersmd -[CODEOWNERS]: CODEOWNERS \ No newline at end of file +[CODEOWNERS]: CODEOWNERS diff --git a/vendor/github.com/packethost/packngo/devices.go b/vendor/github.com/packethost/packngo/devices.go index dde3955e..c45595e7 100644 --- a/vendor/github.com/packethost/packngo/devices.go +++ b/vendor/github.com/packethost/packngo/devices.go @@ -6,6 +6,13 @@ import ( const deviceBasePath = "/devices" +const ( + NetworkTypeHybrid = "hybrid" + NetworkTypeL2Bonded = "layer2-bonded" + NetworkTypeL2Individual = "layer2-individual" + NetworkTypeL3 = "layer3" +) + // DeviceService interface defines available device methods type DeviceService interface { List(ProjectID string, listOpt *ListOptions) ([]Device, *Response, error) @@ -146,29 +153,61 @@ func (d *Device) GetPortByName(name string) (*Port, error) { return nil, fmt.Errorf("Port %s not found in device %s", name, d.ID) } -func (d *Device) GetNetworkType() (string, error) { - numOfBonds := d.NumOfBonds() - if (numOfBonds < 1) || (numOfBonds > 2) { - return "", fmt.Errorf("Wrong number of Bond ports") +type ports map[string]*Port + +func (ports ports) allBonded() bool { + if ports == nil { + return false } - bond0, err := d.GetPortByName("bond0") - if err != nil { - return "", err + + if len(ports) == 0 { + return false } - if numOfBonds == 2 { - bond1, err := d.GetPortByName("bond1") - if err != nil { - return "", err + + for _, p := range ports { + if (p == nil) || (!p.Data.Bonded) { + return false } - if bond0.NetworkType == bond1.NetworkType { - return bond0.NetworkType, nil + } + return true +} + +func (d *Device) HasManagementIPs() bool { + for _, ip := range d.Network { + if ip.Management { + return true } - if (bond0.NetworkType == "layer3") && (bond1.NetworkType == "layer2-individual") { - return "hybrid", nil + } + return false +} + +// GetNetworkType returns a composite network type identification for a device +// based on the plan, network_type, and IP management state of the device. +// GetNetworkType provides the same composite state rendered in the Packet +// Portal for a given device. +func (d *Device) GetNetworkType() string { + if d.Plan != nil { + if d.Plan.Slug == "baremetal_0" || d.Plan.Slug == "baremetal_1" { + return NetworkTypeL3 + } + if d.Plan.Slug == "baremetal_1e" { + return NetworkTypeHybrid } - return "", fmt.Errorf("Strange 2-bond ports conf - bond0: %s, bond1: %s", bond0.NetworkType, bond1.NetworkType) } - return bond0.NetworkType, nil + + bonds := ports(d.GetBondPorts()) + phys := ports(d.GetPhysicalPorts()) + + if bonds.allBonded() { + if phys.allBonded() { + if !d.HasManagementIPs() { + return NetworkTypeL2Bonded + } + return NetworkTypeL3 + } + return NetworkTypeHybrid + } + return NetworkTypeL2Individual } type IPAddressCreateRequest struct { @@ -283,8 +322,17 @@ type DeviceServiceOp struct { } // List returns devices on a project +// +// Regarding ListOptions.Search: The API documentation does not provide guidance +// on the fields that will be searched using this parameter, so this behavior is +// undefined and prone to change. +// +// As of 2020-10-20, ListOptions.Search will look for matches in the following +// Device properties: Hostname, Description, Tags, ID, ShortID, Network.Address, +// Plan.Name, Plan.Slug, Facility.Code, Facility.Name, OS.Name, OS.Slug, +// HardwareReservation.ID, HardwareReservation.ShortID func (s *DeviceServiceOp) List(projectID string, listOpt *ListOptions) (devices []Device, resp *Response, err error) { - listOpt = makeSureListOptionsInclude(listOpt, "facility") + listOpt = listOpt.Including("facility") params := urlQuery(listOpt) path := fmt.Sprintf("%s/%s%s?%s", projectBasePath, projectID, deviceBasePath, params) @@ -312,7 +360,7 @@ func (s *DeviceServiceOp) List(projectID string, listOpt *ListOptions) (devices // Get returns a device by id func (s *DeviceServiceOp) Get(deviceID string, getOpt *GetOptions) (*Device, *Response, error) { - getOpt = makeSureGetOptionsInclude(getOpt, "facility") + getOpt = getOpt.Including("facility") params := urlQuery(getOpt) path := fmt.Sprintf("%s/%s?%s", deviceBasePath, deviceID, params) diff --git a/vendor/github.com/packethost/packngo/packngo.go b/vendor/github.com/packethost/packngo/packngo.go index 3bb29933..9d5e3441 100644 --- a/vendor/github.com/packethost/packngo/packngo.go +++ b/vendor/github.com/packethost/packngo/packngo.go @@ -23,7 +23,7 @@ import ( const ( authTokenEnvVar = "PACKET_AUTH_TOKEN" - libraryVersion = "0.4.1" + libraryVersion = "0.5.0" baseURL = "https://api.equinix.com/metal/v1/" userAgent = "packngo/" + libraryVersion mediaType = "application/json" @@ -87,6 +87,14 @@ type ListOptions struct { // PerPage is the number of results to return per page for paginated result // sets, PerPage int `url:"per_page,omitempty"` + + // Search is a special API query parameter that, for resources that support + // it, will filter results to those with any one of various fields matching + // the supplied keyword. For example, a resource may have a defined search + // behavior matches either a name or a fingerprint field, while another + // resource may match entirely different fields. Search is currently + // implemented for SSHKeys and uses an exact match. + Search string `url:"search,omitempty"` } // GetOptions returns GetOptions from ListOptions (and is nil-receiver safe) @@ -100,7 +108,8 @@ func (l *ListOptions) GetOptions() *GetOptions { } // SearchOptions are options common to API GET requests that include a -// multi-field search filter. +// multi-field search filter. SearchOptions are used in List functions that are +// known to support `search` but do not offer pagination. type SearchOptions struct { // avoid embedding GetOptions (for similar behavior to ListOptions) @@ -135,24 +144,52 @@ type OptionsGetter interface { GetOptions() *GetOptions } -func makeSureGetOptionsInclude(g *GetOptions, s string) *GetOptions { +// Including ensures that the variadic refs are included in a copy of the +// options, resulting in expansion of the the referred sub-resources. Unknown +// values within refs will be silently ignore by the API. +func (g *GetOptions) Including(refs ...string) *GetOptions { if g == nil { - return &GetOptions{Includes: []string{s}} + return &GetOptions{Includes: refs} } - if !contains(g.Includes, s) { - g.Includes = append(g.Includes, s) + out := *g + for _, v := range refs { + if !contains(out.Includes, v) { + out.Includes = append(out.Includes, v) + } } - return g + return &out } -func makeSureListOptionsInclude(l *ListOptions, s string) *ListOptions { +// Including ensures that the variadic refs are included in a copy of the +// options, resulting in expansion of the the referred sub-resources. Unknown +// values within refs will be silently ignore by the API. +func (l *ListOptions) Including(refs ...string) *ListOptions { if l == nil { - return &ListOptions{Includes: []string{s}} + return &ListOptions{Includes: refs} } - if !contains(l.Includes, s) { - l.Includes = append(l.Includes, s) + out := *l + for _, v := range refs { + if !contains(out.Includes, v) { + out.Includes = append(out.Includes, v) + } } - return l + return &out +} + +// Including ensures that the variadic refs are included in a copy of the +// options, resulting in expansion of the the referred sub-resources. Unknown +// values within refs will be silently ignore by the API. +func (s *SearchOptions) Including(refs ...string) *SearchOptions { + if s == nil { + return &SearchOptions{Includes: refs} + } + out := *s + for _, v := range refs { + if !contains(out.Includes, v) { + out.Includes = append(out.Includes, v) + } + } + return &out } type paramsReady interface { @@ -202,6 +239,10 @@ func (l *ListOptions) Params() url.Values { params.Set("per_page", fmt.Sprintf("%d", l.PerPage)) } + if l.Search != "" { + params.Set("search", l.Search) + } + return params } diff --git a/vendor/github.com/packethost/packngo/ports.go b/vendor/github.com/packethost/packngo/ports.go index 63074af8..6e7133f1 100644 --- a/vendor/github.com/packethost/packngo/ports.go +++ b/vendor/github.com/packethost/packngo/ports.go @@ -1,8 +1,10 @@ package packngo import ( + "context" "fmt" "strings" + "time" ) const portBasePath = "/ports" @@ -20,8 +22,9 @@ type DevicePortService interface { PortToLayerTwo(string, string) (*Port, *Response, error) PortToLayerThree(string, string) (*Port, *Response, error) GetPortByName(string, string) (*Port, error) - Convert1BondDevice(*Device, string) error - Convert2BondDevice(*Device, string) error + GetOddEthPorts(*Device) (map[string]*Port, error) + GetAllEthPorts(*Device) (map[string]*Port, error) + ConvertDevice(*Device, string) error } type PortData struct { @@ -161,7 +164,7 @@ func (i *DevicePortServiceOp) PortToLayerThree(deviceID, portName string) (*Port if err != nil { return nil, nil, err } - if p.NetworkType == "layer3" { + if (p.NetworkType == NetworkTypeL3) || (p.NetworkType == NetworkTypeHybrid) { return p, nil, nil } path := fmt.Sprintf("%s/%s/convert/layer-3", portBasePath, p.ID) @@ -188,65 +191,115 @@ func (i *DevicePortServiceOp) DeviceNetworkType(deviceID string) (string, error) if err != nil { return "", err } - return d.GetNetworkType() + return d.GetNetworkType(), nil } -func (i *DevicePortServiceOp) Convert2BondDevice(d *Device, targetType string) error { +func (i *DevicePortServiceOp) GetAllEthPorts(d *Device) (map[string]*Port, error) { + d, _, err := i.client.Devices.Get(d.ID, nil) + if err != nil { + return nil, err + } + return d.GetPhysicalPorts(), nil +} + +func (i *DevicePortServiceOp) GetOddEthPorts(d *Device) (map[string]*Port, error) { + d, _, err := i.client.Devices.Get(d.ID, nil) + if err != nil { + return nil, err + } + ret := map[string]*Port{} + eth1, err := d.GetPortByName("eth1") + if err != nil { + return nil, err + } + ret["eth1"] = eth1 + + eth3, err := d.GetPortByName("eth3") + if err != nil { + return ret, nil + } + ret["eth3"] = eth3 + return ret, nil + +} + +func (i *DevicePortServiceOp) ConvertDevice(d *Device, targetType string) error { bondPorts := d.GetBondPorts() - ethPorts := d.GetPhysicalPorts() - if targetType == "layer3" { - for _, p := range ethPorts { + if targetType == NetworkTypeL3 { + // TODO: remove vlans from all the ports + for _, p := range bondPorts { _, _, err := i.client.DevicePorts.Bond(p, false) if err != nil { return err } } - for _, p := range bondPorts { - _, _, err := i.client.DevicePorts.PortToLayerThree(d.ID, p.Name) + _, _, err := i.client.DevicePorts.PortToLayerThree(d.ID, "bond0") + if err != nil { + return err + } + allEthPorts, err := i.client.DevicePorts.GetAllEthPorts(d) + if err != nil { + return err + } + for _, p := range allEthPorts { + _, _, err := i.client.DevicePorts.Bond(p, false) if err != nil { return err } } } - if targetType == "hybrid" { - for _, p := range d.GetPortsInBond("bond1") { - _, _, err := i.client.DevicePorts.Disbond(p, false) + if targetType == NetworkTypeHybrid { + for _, p := range bondPorts { + _, _, err := i.client.DevicePorts.Bond(p, false) if err != nil { return err } } + _, _, err := i.client.DevicePorts.PortToLayerThree(d.ID, "bond0") if err != nil { return err } - _, _, err = i.client.DevicePorts.PortToLayerTwo(d.ID, "bond1") + + // ports need to be refreshed before bonding/disbonding + oddEthPorts, err := i.client.DevicePorts.GetOddEthPorts(d) if err != nil { return err } - } - if targetType == "layer2-individual" { - for _, p := range bondPorts { - _, _, err := i.client.DevicePorts.PortToLayerTwo(d.ID, p.Name) + + for _, p := range oddEthPorts { + _, _, err := i.client.DevicePorts.Disbond(p, false) if err != nil { return err } } - for _, p := range ethPorts { - _, _, err := i.client.DevicePorts.Disbond(p, false) + } + if targetType == NetworkTypeL2Individual { + _, _, err := i.client.DevicePorts.PortToLayerTwo(d.ID, "bond0") + if err != nil { + return err + } + for _, p := range bondPorts { + _, _, err = i.client.DevicePorts.Disbond(p, true) if err != nil { return err } } } - if targetType == "layer2-bonded" { + if targetType == NetworkTypeL2Bonded { + for _, p := range bondPorts { _, _, err := i.client.DevicePorts.PortToLayerTwo(d.ID, p.Name) if err != nil { return err } } - for _, p := range ethPorts { + allEthPorts, err := i.client.DevicePorts.GetAllEthPorts(d) + if err != nil { + return err + } + for _, p := range allEthPorts { _, _, err := i.client.DevicePorts.Bond(p, false) if err != nil { return err @@ -256,66 +309,31 @@ func (i *DevicePortServiceOp) Convert2BondDevice(d *Device, targetType string) e return nil } -func (i *DevicePortServiceOp) Convert1BondDevice(d *Device, targetType string) error { - bond0, err := d.GetPortByName("bond0") - if err != nil { - return err - } - bond0ports := d.GetPortsInBond("bond0") - - if targetType == "layer3" { - for _, p := range bond0ports { - _, _, err = i.client.DevicePorts.Bond(p, false) +// waitDeviceNetworkType waits for a device's computed network type (as +// determined by GetNetworkType()) to reach the specified state. An error will +// be returned if the device does not attain the desired network type state when +// the timeout is reached without +func waitDeviceNetworkType(id, networkType string, c *Client) (*Device, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(15)*time.Minute) + defer cancel() + + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + d, _, err := c.Devices.Get(id, nil) if err != nil { - return err + return nil, err } - } - _, _, err = i.client.DevicePorts.PortToLayerThree(d.ID, "bond0") - if err != nil { - return err - } - } - if targetType == "hybrid" { - _, _, err = i.client.DevicePorts.Bond(bond0, false) - if err != nil { - return err - } - _, _, err = i.client.DevicePorts.PortToLayerThree(d.ID, "bond0") - if err != nil { - return err - } - eth1, err := i.client.DevicePorts.GetPortByName(d.ID, "eth1") - if err != nil { - return err - } - _, _, err = i.client.DevicePorts.Disbond(eth1, false) - if err != nil { - return err - } - } - if targetType == "layer2-individual" { - bond0, _, err = i.client.DevicePorts.PortToLayerTwo(d.ID, "bond0") - if err != nil { - return err - } - _, _, err = i.client.DevicePorts.Disbond(bond0, true) - if err != nil { - return err - } - } - if targetType == "layer2-bonded" { - for _, p := range bond0ports { - _, _, err = i.client.DevicePorts.Bond(p, false) - if err != nil { - return err + if d.GetNetworkType() == networkType { + return d, nil } - } - _, _, err = i.client.DevicePorts.PortToLayerTwo(d.ID, "bond0") - if err != nil { - return err + case <-ctx.Done(): + return nil, fmt.Errorf("device %s is still not in state %s after timeout", id, networkType) } } - return nil } func (i *DevicePortServiceOp) DeviceToNetworkType(deviceID string, targetType string) (*Device, error) { @@ -325,38 +343,23 @@ func (i *DevicePortServiceOp) DeviceToNetworkType(deviceID string, targetType st return nil, err } - curType, err := d.GetNetworkType() - if err != nil { - return nil, err - } + curType := d.GetNetworkType() if curType == targetType { return nil, fmt.Errorf("Device already is in state %s", targetType) } - - numOfBonds := d.NumOfBonds() - if (numOfBonds < 1) || (numOfBonds > 2) { - return nil, fmt.Errorf("Strange number of bonds: %d", numOfBonds) - } - - if numOfBonds == 1 { - err = i.client.DevicePorts.Convert1BondDevice(d, targetType) - } else { - err = i.client.DevicePorts.Convert2BondDevice(d, targetType) - } + err = i.client.DevicePorts.ConvertDevice(d, targetType) if err != nil { return nil, err } d, _, err = i.client.Devices.Get(deviceID, nil) + //d, err = waitDeviceNetworkType(deviceID, targetType, i.client) if err != nil { return nil, err } - finalType, err := d.GetNetworkType() - if err != nil { - return nil, err - } + finalType := d.GetNetworkType() if finalType != targetType { return nil, fmt.Errorf( diff --git a/vendor/modules.txt b/vendor/modules.txt index 2db4b58e..46eacfd8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -200,7 +200,7 @@ github.com/mitchellh/mapstructure github.com/mitchellh/reflectwalk # github.com/oklog/run v1.0.0 github.com/oklog/run -# github.com/packethost/packngo v0.4.1 +# github.com/packethost/packngo v0.5.0 github.com/packethost/packngo # github.com/posener/complete v1.2.1 github.com/posener/complete