Skip to content

Commit

Permalink
WIP start using metal-go
Browse files Browse the repository at this point in the history
  • Loading branch information
ctreatma committed Jun 5, 2023
1 parent 6dbd3d3 commit 43e0318
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 42 deletions.
43 changes: 36 additions & 7 deletions equinix/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"time"

v4 "github.com/equinix-labs/fabric-go/fabric/v4"
metalv1 "github.com/equinix-labs/metal-go/metal/v1"
"github.com/equinix/ecx-go/v2"
"github.com/equinix/ne-go"
"github.com/equinix/oauth2-go"
Expand Down Expand Up @@ -80,13 +81,15 @@ type Config struct {
PageSize int
Token string

ecx ecx.Client
ne ne.Client
metal *packngo.Client
ecx ecx.Client
ne ne.Client
metal *packngo.Client
metalgo *metalv1.APIClient

ecxUserAgent string
neUserAgent string
metalUserAgent string
ecxUserAgent string
neUserAgent string
metalUserAgent string
metalGoUserAgent string

terraformVersion string
fabricClient *v4.APIClient
Expand Down Expand Up @@ -158,6 +161,7 @@ func (c *Config) Load(ctx context.Context) error {
c.ecx = ecxClient
c.ne = neClient
c.metal = c.NewMetalClient()
c.metalgo = c.NewMetalGoClient()
c.fabricClient = c.NewFabricClient()
return nil
}
Expand All @@ -183,7 +187,7 @@ func (c *Config) NewFabricClient() *v4.APIClient {
return client
}

// NewMetalClient returns a new client for accessing Equinix Metal's API.
// NewMetalClient returns a new packngo client for accessing Equinix Metal's API.
func (c *Config) NewMetalClient() *packngo.Client {
transport := http.DefaultTransport
// transport = &DumpTransport{http.DefaultTransport} // Debug only
Expand All @@ -203,6 +207,27 @@ func (c *Config) NewMetalClient() *packngo.Client {
return client
}

// NewMetalGoClient returns a new metal-go client for accessing Equinix Metal's API.
func (c *Config) NewMetalGoClient() *metalv1.APIClient {
transport := http.DefaultTransport
transport = logging.NewTransport("Equinix Metal", transport)
retryClient := retryablehttp.NewClient()
retryClient.HTTPClient.Transport = transport
retryClient.RetryMax = c.MaxRetries
retryClient.RetryWaitMin = time.Second
retryClient.RetryWaitMax = c.MaxRetryWait
retryClient.CheckRetry = MetalRetryPolicy
standardClient := retryClient.StandardClient()

configuration := metalv1.NewConfiguration()
configuration.HTTPClient = standardClient
configuration.AddDefaultHeader("X-Auth-Token", os.Getenv("METAL_AUTH_TOKEN"))
configuration.UserAgent = c.fullUserAgent(configuration.UserAgent)
client := metalv1.NewAPIClient(configuration)
c.metalGoUserAgent = client.GetConfig().UserAgent
return client
}

func (c *Config) requestTimeout() time.Duration {
if c.RequestTimeout == 0 {
return 5 * time.Second
Expand Down Expand Up @@ -271,6 +296,10 @@ func (c *Config) addModuleToMetalUserAgent(d *schema.ResourceData) {
c.metal.UserAgent = generateModuleUserAgentString(d, c.metalUserAgent)
}

func (c *Config) addModuleToMetalGoUserAgent(d *schema.ResourceData) {
c.metalgo.GetConfig().UserAgent = generateModuleUserAgentString(d, c.metalUserAgent)
}

func generateModuleUserAgentString(d *schema.ResourceData, baseUserAgent string) string {
var m providerMeta
err := d.GetProviderMeta(&m)
Expand Down
59 changes: 32 additions & 27 deletions equinix/data_source_metal_device.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package equinix

import (
"context"
"encoding/json"
"fmt"
"path"
"sort"
"strings"

metalv1 "github.com/equinix-labs/metal-go/metal/v1"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/packethost/packngo"
)

func dataSourceMetalDevice() *schema.Resource {
Expand Down Expand Up @@ -202,7 +203,7 @@ func dataSourceMetalDevice() *schema.Resource {
}

func dataSourceMetalDeviceRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Config).metal
client := meta.(*Config).metalgo

hostnameRaw, hostnameOK := d.GetOk("hostname")
projectIdRaw, projectIdOK := d.GetOk("project_id")
Expand All @@ -211,17 +212,16 @@ func dataSourceMetalDeviceRead(d *schema.ResourceData, meta interface{}) error {
if !deviceIdOK && !hostnameOK {
return fmt.Errorf("You must supply device_id or hostname")
}
var device *packngo.Device
var device *metalv1.Device

if hostnameOK {
if !projectIdOK {
return fmt.Errorf("If you lookup via hostname, you must supply project_id")
}
hostname := hostnameRaw.(string)
projectId := projectIdRaw.(string)

ds, _, err := client.Devices.List(
projectId,
&packngo.ListOptions{Search: hostname, Includes: deviceCommonIncludes})
ds, _, err := client.DevicesApi.FindProjectDevices(context.Background(), projectId).Hostname(hostname).Include(deviceCommonIncludes).Execute()
if err != nil {
return err
}
Expand All @@ -233,26 +233,28 @@ func dataSourceMetalDeviceRead(d *schema.ResourceData, meta interface{}) error {
} else {
deviceId := deviceIdRaw.(string)
var err error
device, _, err = client.Devices.Get(deviceId, deviceReadOptions)
device, _, err = client.DevicesApi.FindDeviceById(context.Background(), deviceId).Include(deviceCommonIncludes).Execute()
if err != nil {
return err
}
}

d.Set("hostname", device.Hostname)
d.Set("project_id", device.Project.ID)
d.Set("device_id", device.ID)
d.Set("project_id", device.Project.Id)
d.Set("device_id", device.Id)
d.Set("plan", device.Plan.Slug)
d.Set("facility", device.Facility.Code)
if device.Metro != nil {
d.Set("metro", strings.ToLower(device.Metro.Code))
d.Set("metro", strings.ToLower(device.Metro.GetCode()))
}
d.Set("operating_system", device.OS.Slug)
d.Set("operating_system", device.OperatingSystem.Slug)
d.Set("state", device.State)
d.Set("billing_cycle", device.BillingCycle)
d.Set("ipxe_script_url", device.IPXEScriptURL)
d.Set("always_pxe", device.AlwaysPXE)
d.Set("ipxe_script_url", device.IpxeScriptUrl)
d.Set("always_pxe", device.AlwaysPxe)
d.Set("root_password", device.RootPassword)

// Device schema needs to be updated to define the `storage` field
if device.Storage != nil {
rawStorageBytes, err := json.Marshal(device.Storage)
if err != nil {
Expand All @@ -267,45 +269,48 @@ func dataSourceMetalDeviceRead(d *schema.ResourceData, meta interface{}) error {
}

if device.HardwareReservation != nil {
d.Set("hardware_reservation_id", device.HardwareReservation.ID)
d.Set("hardware_reservation_id", device.HardwareReservation.Id)
}
networkType, err := getMetalGoNetworkType(device)
if err != nil {
return fmt.Errorf("[ERR] Error computing network type for device (%s): %s", d.Id(), err)
}
networkType := device.GetNetworkType()

d.Set("network_type", networkType)

d.Set("tags", device.Tags)

keyIDs := []string{}
for _, k := range device.SSHKeys {
keyIDs = append(keyIDs, path.Base(k.URL))
for _, k := range device.SshKeys {
keyIDs = append(keyIDs, path.Base(k.Href))
}
d.Set("ssh_key_ids", keyIDs)
networkInfo := getNetworkInfo(device.Network)
networkInfo := getMetalGoNetworkInfo(device.IpAddresses)

sort.SliceStable(networkInfo.Networks, func(i, j int) bool {
famI := networkInfo.Networks[i]["family"].(int)
famJ := networkInfo.Networks[j]["family"].(int)
famI := networkInfo.Networks[i]["family"].(int32)
famJ := networkInfo.Networks[j]["family"].(int32)
pubI := networkInfo.Networks[i]["public"].(bool)
pubJ := networkInfo.Networks[j]["public"].(bool)
return getNetworkRank(famI, pubI) < getNetworkRank(famJ, pubJ)
return getNetworkRank(int(famI), pubI) < getNetworkRank(int(famJ), pubJ)
})

d.Set("network", networkInfo.Networks)
d.Set("access_public_ipv4", networkInfo.PublicIPv4)
d.Set("access_private_ipv4", networkInfo.PrivateIPv4)
d.Set("access_public_ipv6", networkInfo.PublicIPv6)

ports := getPorts(device.NetworkPorts)
ports := getMetalGoPorts(device.NetworkPorts)
d.Set("ports", ports)

d.SetId(device.ID)
d.SetId(*device.Id)
return nil
}

func findDeviceByHostname(devices []packngo.Device, hostname string) (*packngo.Device, error) {
results := make([]packngo.Device, 0)
for _, d := range devices {
if d.Hostname == hostname {
func findDeviceByHostname(devices *metalv1.DeviceList, hostname string) (*metalv1.Device, error) {
results := make([]metalv1.Device, 0)
for _, d := range devices.GetDevices() {
if *d.Hostname == hostname {
results = append(results, d)
}
}
Expand Down
14 changes: 7 additions & 7 deletions equinix/data_source_metal_device_bgp_neighbors.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package equinix

import (
metalv1 "github.com/equinix-labs/metal-go/metal/v1"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/packethost/packngo"
)

func bgpNeighborSchema() *schema.Resource {
Expand Down Expand Up @@ -103,10 +103,10 @@ func dataSourceMetalDeviceBGPNeighbors() *schema.Resource {
}

func dataSourceMetalDeviceBGPNeighborsRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*Config).metal
client := meta.(*Config).metalgo
deviceID := d.Get("device_id").(string)

bgpNeighborsRaw, _, err := client.Devices.ListBGPNeighbors(deviceID, nil)
bgpNeighborsRaw, _, err := client.DevicesApi.GetBgpNeighborData(nil, deviceID).Execute()
if err != nil {
return err
}
Expand All @@ -116,7 +116,7 @@ func dataSourceMetalDeviceBGPNeighborsRead(d *schema.ResourceData, meta interfac
return nil
}

func getRoutesSlice(routes []packngo.BGPRoute) []map[string]interface{} {
func getRoutesSlice(routes []metalv1.BgpRoute) []map[string]interface{} {
ret := []map[string]interface{}{}
for _, r := range routes {
ret = append(ret, map[string]interface{}{
Expand All @@ -126,13 +126,13 @@ func getRoutesSlice(routes []packngo.BGPRoute) []map[string]interface{} {
return ret
}

func getBgpNeighbors(ns []packngo.BGPNeighbor) []map[string]interface{} {
func getBgpNeighbors(ns *metalv1.BgpSessionNeighbors) []map[string]interface{} {
ret := make([]map[string]interface{}, 0, 1)
for _, n := range ns {
for _, n := range ns.BgpNeighbors {
neighbor := map[string]interface{}{
"address_family": n.AddressFamily,
"customer_as": n.CustomerAs,
"customer_ip": n.CustomerIP,
"customer_ip": n.CustomerIp,
"md5_enabled": n.Md5Enabled,
"md5_password": n.Md5Password,
"multihop": n.Multihop,
Expand Down
42 changes: 42 additions & 0 deletions equinix/data_source_metal_device_bgp_neighbors_acc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package equinix

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceMetalDeviceBgpNeighbors(t *testing.T) {
projectName := fmt.Sprintf("ds-device-%s", acctest.RandString(10))

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceMetalDeviceBgpNeighborsConfig(projectName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
"data.equinix_metal_device_bgp_neighbors.test", "bgp_neighbors.#"),
),
},
},
})
}

func testAccDataSourceMetalDeviceBgpNeighborsConfig(projectName string) string {
return fmt.Sprintf(`
%s
data "equinix_metal_device_bgp_neighbors" "test" {
device_id = equinix_metal_device.test.id
}
output "bgp_neighbors_listing" {
value = data.equinix_metal_device_bgp_neighbors.test.bgp_neighbors
}
`, testDataSourceMetalDeviceConfig_basic(projectName))
}
Loading

0 comments on commit 43e0318

Please sign in to comment.