Skip to content

Commit

Permalink
move device resource and datasource to separate package
Browse files Browse the repository at this point in the history
  • Loading branch information
ctreatma committed Sep 24, 2024
1 parent 2b12867 commit fddfc02
Show file tree
Hide file tree
Showing 13 changed files with 449 additions and 376 deletions.
120 changes: 120 additions & 0 deletions equinix/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package equinix

import (
"fmt"
"strings"
"time"
)

// list of plans and metros and os used as filter criteria to find available hardware to run tests
var (
preferable_plans = []string{"x1.small.x86", "t1.small.x86", "c2.medium.x86", "c3.small.x86", "c3.medium.x86", "m3.small.x86"}
preferable_metros = []string{"ch", "ny", "sv", "ty", "am"}
preferable_os = []string{"ubuntu_20_04"}
)

// Deprecated: use the identical TestDeviceTerminationTime from internal/acceptance instead
func testDeviceTerminationTime() string {
return time.Now().UTC().Add(60 * time.Minute).Format(time.RFC3339)
}

// This function should be used to find available plans in all test where a metal_device resource is needed.
//
// TODO consider adding a datasource for equinix_metal_operating_system and making the local.os conditional
//
// https://github.com/equinix/terraform-provider-equinix/pull/220#discussion_r915418418equinix_metal_operating_system
// https://github.com/equinix/terraform-provider-equinix/discussions/221
func confAccMetalDevice_base(plans, metros, os []string) string {
return fmt.Sprintf(`
data "equinix_metal_plans" "test" {
sort {
attribute = "id"
direction = "asc"
}
filter {
attribute = "name"
values = [%s]
}
filter {
attribute = "available_in_metros"
values = [%s]
}
filter {
attribute = "deployment_types"
values = ["on_demand", "spot_market"]
}
}
// Select a metal plan randomly and lock it in
// so that we don't pick a different one for
// every subsequent terraform plan
resource "random_integer" "plan_idx" {
min = 0
max = length(data.equinix_metal_plans.test.plans) - 1
}
resource "terraform_data" "plan" {
input = data.equinix_metal_plans.test.plans[random_integer.plan_idx.result]
lifecycle {
ignore_changes = ["input"]
}
}
resource "terraform_data" "facilities" {
input = sort(tolist(setsubtract(terraform_data.plan.output.available_in, ["nrt1", "dfw2", "ewr1", "ams1", "sjc1", "ld7", "sy4", "ny6"])))
lifecycle {
ignore_changes = ["input"]
}
}
// Select a metal facility randomly and lock it in
// so that we don't pick a different one for
// every subsequent terraform plan
resource "random_integer" "facility_idx" {
min = 0
max = length(local.facilities) - 1
}
resource "terraform_data" "facility" {
input = local.facilities[random_integer.facility_idx.result]
lifecycle {
ignore_changes = ["input"]
}
}
// Select a metal metro randomly and lock it in
// so that we don't pick a different one for
// every subsequent terraform plan
resource "random_integer" "metro_idx" {
min = 0
max = length(local.metros) - 1
}
resource "terraform_data" "metro" {
input = local.metros[random_integer.metro_idx.result]
lifecycle {
ignore_changes = ["input"]
}
}
locals {
// Select a random plan
plan = terraform_data.plan.output.slug
// Select a random facility from the facilities in which the selected plan is available, excluding decommed facilities
facilities = terraform_data.facilities.output
facility = terraform_data.facility.output
// Select a random metro from the metros in which the selected plan is available
metros = sort(tolist(terraform_data.plan.output.available_in_metros))
metro = terraform_data.metro.output
os = [%s][0]
}
`, fmt.Sprintf("\"%s\"", strings.Join(plans[:], `","`)), fmt.Sprintf("\"%s\"", strings.Join(metros[:], `","`)), fmt.Sprintf("\"%s\"", strings.Join(os[:], `","`)))
}
28 changes: 23 additions & 5 deletions equinix/data_source_metal_device_bgp_neighbors_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import (
)

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccDataSourceMetalDeviceBgpNeighborsConfig(projectName),
Config: testAccDataSourceMetalDeviceBgpNeighborsConfig(projSuffix),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
"data.equinix_metal_device_bgp_neighbors.test", "bgp_neighbors.#"),
Expand All @@ -27,16 +27,34 @@ func TestAccDataSourceMetalDeviceBgpNeighbors(t *testing.T) {
})
}

func testAccDataSourceMetalDeviceBgpNeighborsConfig(projectName string) string {
func testAccDataSourceMetalDeviceBgpNeighborsConfig(projSuffix string) string {
return fmt.Sprintf(`
%s
resource "equinix_metal_project" "test" {
name = "tfacc-project-%s"
}
resource "equinix_metal_device" "test" {
hostname = "tfacc-test-device"
plan = local.plan
metro = local.metro
operating_system = local.os
billing_cycle = "hourly"
project_id = "${equinix_metal_project.test.id}"
termination_time = "%s"
}
data "equinix_metal_device" "test" {
project_id = equinix_metal_project.test.id
hostname = equinix_metal_device.test.hostname
}
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))
}`, confAccMetalDevice_base(preferable_plans, preferable_metros, preferable_os), projSuffix, testDeviceTerminationTime())
}
7 changes: 4 additions & 3 deletions equinix/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
fabric_connection "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/connection"
fabric_market_place_subscription "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/marketplace"
fabric_network "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/network"
metal_device "github.com/equinix/terraform-provider-equinix/internal/resources/metal/device"
metal_port "github.com/equinix/terraform-provider-equinix/internal/resources/metal/port"
"github.com/equinix/terraform-provider-equinix/internal/resources/metal/virtual_circuit"
"github.com/equinix/terraform-provider-equinix/internal/resources/metal/vrf"
Expand Down Expand Up @@ -104,8 +105,8 @@ func Provider() *schema.Provider {
"equinix_metal_precreated_ip_block": dataSourceMetalPreCreatedIPBlock(),
"equinix_metal_operating_system": dataSourceOperatingSystem(),
"equinix_metal_spot_market_price": dataSourceSpotMarketPrice(),
"equinix_metal_device": dataSourceMetalDevice(),
"equinix_metal_devices": dataSourceMetalDevices(),
"equinix_metal_device": metal_device.DataSource(),
"equinix_metal_devices": metal_device.ListDataSource(),
"equinix_metal_device_bgp_neighbors": dataSourceMetalDeviceBGPNeighbors(),
"equinix_metal_plans": dataSourceMetalPlans(),
"equinix_metal_port": metal_port.DataSource(),
Expand All @@ -129,7 +130,7 @@ func Provider() *schema.Provider {
"equinix_network_file": resourceNetworkFile(),
"equinix_metal_user_api_key": resourceMetalUserAPIKey(),
"equinix_metal_project_api_key": resourceMetalProjectAPIKey(),
"equinix_metal_device": resourceMetalDevice(),
"equinix_metal_device": metal_device.Resource(),
"equinix_metal_device_network_type": resourceMetalDeviceNetworkType(),
"equinix_metal_port": metal_port.Resource(),
"equinix_metal_reserved_ip_block": resourceMetalReservedIPBlock(),
Expand Down
10 changes: 6 additions & 4 deletions equinix/resource_metal_spot_market_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"reflect"
"regexp"
"sort"
"strconv"
"time"
Expand All @@ -22,6 +23,10 @@ import (
"github.com/packethost/packngo"
)

var (
matchIPXEScript = regexp.MustCompile(`(?i)^#![i]?pxe`)
)

func resourceMetalSpotMarketRequest() *schema.Resource {
return &schema.Resource{
CreateContext: resourceMetalSpotMarketRequestCreate,
Expand Down Expand Up @@ -62,10 +67,7 @@ func resourceMetalSpotMarketRequest() *schema.Resource {
diffThreshold := .02
priceDiff := oldF / newF

if diffThreshold < priceDiff {
return true
}
return false
return diffThreshold < priceDiff
},
},
"facilities": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package equinix
package device

import (
"context"
"encoding/json"
"errors"
"fmt"
"path"
"sort"
Expand All @@ -17,7 +18,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
)

func dataSourceMetalDevice() *schema.Resource {
func DataSource() *schema.Resource {
return &schema.Resource{
Description: `The datasource can be used to fetch a single device.
Expand Down Expand Up @@ -253,21 +254,23 @@ func dataSourceMetalDeviceRead(ctx context.Context, d *schema.ResourceData, meta
}
}

d.Set("hostname", device.GetHostname())
d.Set("project_id", device.Project.GetId())
d.Set("device_id", device.GetId())
d.Set("plan", device.Plan.Slug)
d.Set("facility", device.Facility.Code)
var errs []error

errs = append(errs, d.Set("hostname", device.GetHostname()))
errs = append(errs, d.Set("project_id", device.Project.GetId()))
errs = append(errs, d.Set("device_id", device.GetId()))
errs = append(errs, d.Set("plan", device.Plan.Slug))
errs = append(errs, d.Set("facility", device.Facility.Code))
if device.Metro != nil {
d.Set("metro", strings.ToLower(device.Metro.GetCode()))
errs = append(errs, d.Set("metro", strings.ToLower(device.Metro.GetCode())))
}
d.Set("operating_system", device.OperatingSystem.GetSlug())
d.Set("state", device.GetState())
d.Set("billing_cycle", device.GetBillingCycle())
d.Set("ipxe_script_url", device.GetIpxeScriptUrl())
d.Set("always_pxe", device.GetAlwaysPxe())
d.Set("root_password", device.GetRootPassword())
d.Set("sos_hostname", device.GetSos())
errs = append(errs, d.Set("operating_system", device.OperatingSystem.GetSlug()))
errs = append(errs, d.Set("state", device.GetState()))
errs = append(errs, d.Set("billing_cycle", device.GetBillingCycle()))
errs = append(errs, d.Set("ipxe_script_url", device.GetIpxeScriptUrl()))
errs = append(errs, d.Set("always_pxe", device.GetAlwaysPxe()))
errs = append(errs, d.Set("root_password", device.GetRootPassword()))
errs = append(errs, d.Set("sos_hostname", device.GetSos()))

if device.Storage != nil {
rawStorageBytes, err := json.Marshal(device.Storage)
Expand All @@ -279,26 +282,26 @@ func dataSourceMetalDeviceRead(ctx context.Context, d *schema.ResourceData, meta
if err != nil {
return diag.Errorf("[ERR] Error normalizing storage JSON string for device (%s): %s", d.Id(), err)
}
d.Set("storage", storageString)
errs = append(errs, d.Set("storage", storageString))
}

if device.HardwareReservation != nil {
d.Set("hardware_reservation_id", device.HardwareReservation.GetId())
errs = append(errs, d.Set("hardware_reservation_id", device.HardwareReservation.GetId()))
}
networkType, err := getNetworkType(device)
if err != nil {
return diag.Errorf("[ERR] Error computing network type for device (%s): %s", d.Id(), err)
}

d.Set("network_type", networkType)
errs = append(errs, d.Set("network_type", networkType))

d.Set("tags", device.Tags)
errs = append(errs, d.Set("tags", device.Tags))

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

sort.SliceStable(networkInfo.Networks, func(i, j int) bool {
Expand All @@ -309,15 +312,21 @@ func dataSourceMetalDeviceRead(ctx context.Context, d *schema.ResourceData, meta
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)
errs = append(errs, d.Set("network", networkInfo.Networks))
errs = append(errs, d.Set("access_public_ipv4", networkInfo.PublicIPv4))
errs = append(errs, d.Set("access_private_ipv4", networkInfo.PrivateIPv4))
errs = append(errs, d.Set("access_public_ipv6", networkInfo.PublicIPv6))

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

d.SetId(device.GetId())

err = errors.Join(errs...)
if err != nil {
return diag.FromErr(err)
}

return nil
}

Expand Down
Loading

0 comments on commit fddfc02

Please sign in to comment.