Skip to content

Commit

Permalink
First draft of changes to separate a resource away from equinix pkg
Browse files Browse the repository at this point in the history
  • Loading branch information
t0mk committed Dec 12, 2023
1 parent 3dfe085 commit 9293144
Show file tree
Hide file tree
Showing 14 changed files with 361 additions and 139 deletions.
16 changes: 8 additions & 8 deletions equinix/equinix_sweeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ func TestMain(m *testing.M) {
}

func sharedConfigForRegion(region string) (*config.Config, error) {
endpoint := getFromEnvDefault(endpointEnvVar, config.DefaultBaseURL)
clientToken := getFromEnvDefault(clientTokenEnvVar, "")
clientID := getFromEnvDefault(clientIDEnvVar, "")
clientSecret := getFromEnvDefault(clientSecretEnvVar, "")
clientTimeout := getFromEnvDefault(clientTimeoutEnvVar, strconv.Itoa(config.DefaultTimeout))
endpoint := getFromEnvDefault(config.EndpointEnvVar, config.DefaultBaseURL)
clientToken := getFromEnvDefault(config.ClientTokenEnvVar, "")
clientID := getFromEnvDefault(config.ClientIDEnvVar, "")
clientSecret := getFromEnvDefault(config.ClientSecretEnvVar, "")
clientTimeout := getFromEnvDefault(config.ClientTimeoutEnvVar, strconv.Itoa(config.DefaultTimeout))
clientTimeoutInt, err := strconv.Atoi(clientTimeout)
if err != nil {
return nil, fmt.Errorf("cannot convert value of '%s' env variable to int", clientTimeoutEnvVar)
return nil, fmt.Errorf("cannot convert value of '%s' env variable to int", config.ClientTimeoutEnvVar)
}
metalAuthToken := getFromEnvDefault(metalAuthTokenEnvVar, "")
metalAuthToken := getFromEnvDefault(config.MetalAuthTokenEnvVar, "")

if clientToken == "" && (clientID == "" || clientSecret == "") && metalAuthToken == "" {
return nil, fmt.Errorf("To run acceptance tests sweeper, one of '%s' or pair '%s' - '%s' must be set for Equinix Fabric and Network Edge, and '%s' for Equinix Metal",
clientTokenEnvVar, clientIDEnvVar, clientSecretEnvVar, metalAuthTokenEnvVar)
config.ClientTokenEnvVar, config.ClientIDEnvVar, config.ClientSecretEnvVar, config.MetalAuthTokenEnvVar)
}

return &config.Config{
Expand Down
30 changes: 12 additions & 18 deletions equinix/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (
"strings"
"time"

"github.com/equinix/terraform-provider-equinix/internal/resources/metal/metal_project_ssh_key"
"github.com/equinix/terraform-provider-equinix/internal/resources/metal/metal_ssh_key"

v4 "github.com/equinix-labs/fabric-go/fabric/v4"
"github.com/equinix/ecx-go/v2"
"github.com/equinix/rest-go"
Expand All @@ -26,15 +29,6 @@ var (
NetworkTypeListHB = strings.Join(DeviceNetworkTypesHB, ", ")
)

const (
endpointEnvVar = "EQUINIX_API_ENDPOINT"
clientIDEnvVar = "EQUINIX_API_CLIENTID"
clientSecretEnvVar = "EQUINIX_API_CLIENTSECRET"
clientTokenEnvVar = "EQUINIX_API_TOKEN"
clientTimeoutEnvVar = "EQUINIX_API_TIMEOUT"
metalAuthTokenEnvVar = "METAL_AUTH_TOKEN"
)

// resourceDataProvider provies interface to schema.ResourceData
// for convenient mocking purposes
type resourceDataProvider interface {
Expand All @@ -51,38 +45,38 @@ func Provider() *schema.Provider {
"endpoint": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(endpointEnvVar, config.DefaultBaseURL),
DefaultFunc: schema.EnvDefaultFunc(config.EndpointEnvVar, config.DefaultBaseURL),
ValidateFunc: validation.IsURLWithHTTPorHTTPS,
Description: fmt.Sprintf("The Equinix API base URL to point out desired environment. Defaults to %s", config.DefaultBaseURL),
},
"client_id": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(clientIDEnvVar, ""),
DefaultFunc: schema.EnvDefaultFunc(config.ClientIDEnvVar, ""),
Description: "API Consumer Key available under My Apps section in developer portal",
},
"client_secret": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(clientSecretEnvVar, ""),
DefaultFunc: schema.EnvDefaultFunc(config.ClientSecretEnvVar, ""),
Description: "API Consumer secret available under My Apps section in developer portal",
},
"token": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(clientTokenEnvVar, ""),
DefaultFunc: schema.EnvDefaultFunc(config.ClientTokenEnvVar, ""),
Description: "API token from the developer sandbox",
},
"auth_token": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(metalAuthTokenEnvVar, ""),
DefaultFunc: schema.EnvDefaultFunc(config.MetalAuthTokenEnvVar, ""),
Description: "The Equinix Metal API auth key for API operations",
},
"request_timeout": {
Type: schema.TypeInt,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(clientTimeoutEnvVar, config.DefaultTimeout),
DefaultFunc: schema.EnvDefaultFunc(config.ClientTimeoutEnvVar, config.DefaultTimeout),
ValidateFunc: validation.IntAtLeast(1),
Description: fmt.Sprintf("The duration of time, in seconds, that the Equinix Platform API Client should wait before canceling an API request. Defaults to %d", config.DefaultTimeout),
},
Expand Down Expand Up @@ -135,7 +129,7 @@ func Provider() *schema.Provider {
"equinix_metal_plans": dataSourceMetalPlans(),
"equinix_metal_port": dataSourceMetalPort(),
"equinix_metal_project": dataSourceMetalProject(),
"equinix_metal_project_ssh_key": dataSourceMetalProjectSSHKey(),
"equinix_metal_project_ssh_key": metal_project_ssh_key.DataSource(),
"equinix_metal_reserved_ip_block": dataSourceMetalReservedIPBlock(),
"equinix_metal_spot_market_request": dataSourceMetalSpotMarketRequest(),
"equinix_metal_virtual_circuit": dataSourceMetalVirtualCircuit(),
Expand All @@ -162,10 +156,10 @@ func Provider() *schema.Provider {
"equinix_metal_connection": resourceMetalConnection(),
"equinix_metal_device": resourceMetalDevice(),
"equinix_metal_device_network_type": resourceMetalDeviceNetworkType(),
"equinix_metal_ssh_key": resourceMetalSSHKey(),
"equinix_metal_ssh_key": metal_ssh_key.Resource(),
"equinix_metal_organization_member": resourceMetalOrganizationMember(),
"equinix_metal_port": resourceMetalPort(),
"equinix_metal_project_ssh_key": resourceMetalProjectSSHKey(),
"equinix_metal_project_ssh_key": metal_project_ssh_key.Resource(),
"equinix_metal_project": resourceMetalProject(),
"equinix_metal_organization": resourceMetalOrganization(),
"equinix_metal_reserved_ip_block": resourceMetalReservedIPBlock(),
Expand Down
11 changes: 6 additions & 5 deletions equinix/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"testing"

"github.com/equinix/terraform-provider-equinix/internal/config"
"github.com/equinix/terraform-provider-equinix/internal/hashcode"

"github.com/equinix/ecx-go/v2"
Expand Down Expand Up @@ -403,20 +404,20 @@ func TestProvider_schemaSetToMap(t *testing.T) {
func testAccPreCheck(t *testing.T) {
var err error

if _, err = getFromEnv(clientTokenEnvVar); err != nil {
_, err = getFromEnv(clientIDEnvVar)
if _, err = getFromEnv(config.ClientTokenEnvVar); err != nil {
_, err = getFromEnv(config.ClientIDEnvVar)
if err == nil {
_, err = getFromEnv(clientSecretEnvVar)
_, err = getFromEnv(config.ClientSecretEnvVar)
}
}

if err == nil {
_, err = getFromEnv(metalAuthTokenEnvVar)
_, err = getFromEnv(config.MetalAuthTokenEnvVar)
}

if err != nil {
t.Fatalf("To run acceptance tests, one of '%s' or pair '%s' - '%s' must be set for Equinix Fabric and Network Edge, and '%s' for Equinix Metal",
clientTokenEnvVar, clientIDEnvVar, clientSecretEnvVar, metalAuthTokenEnvVar)
config.ClientTokenEnvVar, config.ClientIDEnvVar, config.ClientSecretEnvVar, config.MetalAuthTokenEnvVar)
}
}

Expand Down
25 changes: 0 additions & 25 deletions equinix/resource_metal_project_ssh_key.go

This file was deleted.

83 changes: 83 additions & 0 deletions internal/acceptance/acceptance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package acceptance

import (
"fmt"
"os"
"strconv"
"strings"
"testing"
"time"

"github.com/equinix/terraform-provider-equinix/equinix"
"github.com/equinix/terraform-provider-equinix/internal/config"

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

const (
// duplicated from equinix_sweeoer_test.go
tstResourcePrefix = "tfacc"
missingMetalToken = "To run acceptance tests of Equinix Metal Resources, you must set %s"
)

var (
TestAccProvider *schema.Provider
TestAccProviders map[string]*schema.Provider
TestAccProviderFactories map[string]func() (*schema.Provider, error)
TestExternalProviders map[string]resource.ExternalProvider
)

func init() {
TestAccProvider = equinix.Provider()
TestAccProviders = map[string]*schema.Provider{
"equinix": TestAccProvider,
}
TestAccProviderFactories = map[string]func() (*schema.Provider, error){
"equinix": func() (*schema.Provider, error) {
return TestAccProvider, nil
},
}
TestExternalProviders = map[string]resource.ExternalProvider{
"random": {
Source: "hashicorp/random",
},
}
}

func TestAccPreCheckMetal(t *testing.T) {
if os.Getenv(config.MetalAuthTokenEnvVar) == "" {
t.Fatalf(missingMetalToken, config.MetalAuthTokenEnvVar)
}
}

func IsSweepableTestResource(namePrefix string) bool {
return strings.HasPrefix(namePrefix, tstResourcePrefix)
}

func getFromEnvDefault(varName string, defaultValue string) string {
if v := os.Getenv(varName); v != "" {
return v
}
return defaultValue
}

func GetConfigForNonStandardMetalTest() (*config.Config, error) {
endpoint := getFromEnvDefault(config.EndpointEnvVar, config.DefaultBaseURL)
clientTimeout := getFromEnvDefault(config.ClientTimeoutEnvVar, strconv.Itoa(config.DefaultTimeout))
clientTimeoutInt, err := strconv.Atoi(clientTimeout)
if err != nil {
return nil, fmt.Errorf("cannot convert value of '%s' env variable to int", config.ClientTimeoutEnvVar)
}
metalAuthToken := getFromEnvDefault(config.MetalAuthTokenEnvVar, "")

if metalAuthToken == "" {
return nil, fmt.Errorf(missingMetalToken, config.MetalAuthTokenEnvVar)
}

return &config.Config{
AuthToken: metalAuthToken,
BaseURL: endpoint,
RequestTimeout: time.Duration(clientTimeoutInt) * time.Second,
}, nil
}
119 changes: 119 additions & 0 deletions internal/acceptance/device_helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package acceptance

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"}
)

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[:], `","`)))
}
Loading

0 comments on commit 9293144

Please sign in to comment.