├── .go-version
├── version
└── version.go
├── .github
├── CODE_OF_CONDUCT.md
├── SUPPORT.md
├── workflows
│ ├── test.yml
│ ├── release.yml
│ └── acctest.yml
└── ISSUE_TEMPLATE.md
├── scripts
├── gogetcookie.sh
├── gofmtcheck.sh
├── errcheck.sh
└── changelog-links.sh
├── OWNERS.md
├── .gitignore
├── docs
├── resources
│ ├── volume.md
│ ├── volume_attachment.md
│ ├── user_api_key.md
│ ├── project_api_key.md
│ ├── vlan.md
│ ├── organization.md
│ ├── device_network_type.md
│ ├── ssh_key.md
│ ├── gateway.md
│ ├── port.md
│ ├── ip_attachment.md
│ ├── project_ssh_key.md
│ ├── connection.md
│ ├── spot_market_request.md
│ └── vrf.md
├── data-sources
│ ├── volume.md
│ ├── spot_market_price.md
│ ├── operating_system.md
│ ├── gateway.md
│ ├── vrf.md
│ ├── organization.md
│ ├── metro.md
│ ├── project_ssh_key.md
│ ├── facility.md
│ ├── port.md
│ ├── reserved_ip_block.md
│ ├── hardware_reservation.md
│ ├── vlan.md
│ ├── project.md
│ ├── device_bgp_neighbors.md
│ ├── ip_block_ranges.md
│ ├── precreated_ip_block.md
│ ├── spot_market_request.md
│ ├── virtual_circuit.md
│ ├── connection.md
│ └── device.md
└── index.md
├── main.go
├── metal
├── resource_metal_user_api_key.go
├── sweeper_test.go
├── resource_metal_project_ssh_key.go
├── volume_stub.go
├── datasource_metal_plans_test.go
├── provider_test.go
├── datasource_metal_spot_market_price_test.go
├── resource_metal_volume_attachment.go
├── datasource_metal_gateway_test.go
├── mutexkv.go
├── utils.go
├── datasource_metal_project_test.go
├── resource_metal_project_api_key_test.go
├── datasource_metal_reserved_ip_block_test.go
├── datasource_metal_vrf.go
├── datasource_metal_gateway.go
├── datasource_metal_operating_system_test.go
├── datasource_metal_ip_block_ranges_test.go
├── datasource_metal_precreated_ip_block_test.go
├── datasource_metal_metro.go
├── datasource_metal_spot_market_price.go
├── datasource_metal_organization_test.go
├── datasource_metal_metro_test.go
├── datasource_metal_volume.go
├── internal
│ └── datalist
│ │ ├── sort.go
│ │ └── values.go
├── resource_metal_user_api_key_test.go
├── datasource_metal_port.go
├── datasource_metal_port_test.go
├── resource_metal_project_ssh_key_test.go
├── resource_metal_ip_attachment.go
├── resource_metal_volume.go
├── datasource_metal_operating_system.go
├── datasource_metal_facility_test.go
├── datasource_metal_spot_market_request_test.go
├── resource_metal_bgp_session.go
├── config.go
├── resource_metal_bgp_setup_test.go
├── datasource_metal_project_ssh_key.go
├── datasource_metal_spot_market_request.go
├── datasource_metal_hardware_reservation.go
├── resource_metal_gateway_test.go
└── resource_metal_device_network_type.go
├── .goreleaser.yml
├── README.md
├── GNUmakefile
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
└── go.mod
/.go-version:
--------------------------------------------------------------------------------
1 | 1.17.7
2 |
--------------------------------------------------------------------------------
/version/version.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | var (
4 | // ProviderVersion is set at build-time in the release process
5 | ProviderVersion = "dev"
6 | )
7 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | HashiCorp Community Guidelines apply to you when interacting with the community here on GitHub and contributing code.
4 |
5 | Please read the full text at https://www.hashicorp.com/community-guidelines
6 |
--------------------------------------------------------------------------------
/.github/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # Support
2 |
3 | Terraform is a mature project with a growing community. There are active, dedicated people willing to help you through various mediums.
4 |
5 | Take a look at those mediums listed at https://www.terraform.io/community.html
6 |
--------------------------------------------------------------------------------
/scripts/gogetcookie.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | touch ~/.gitcookies
4 | chmod 0600 ~/.gitcookies
5 |
6 | git config --global http.cookiefile ~/.gitcookies
7 |
8 | tr , \\t <<\__END__ >>~/.gitcookies
9 | .googlesource.com,TRUE,/,TRUE,2147483647,o,git-paul.hashicorp.com=1/z7s05EYPudQ9qoe6dMVfmAVwgZopEkZBb1a2mA5QtHE
10 | __END__
11 |
--------------------------------------------------------------------------------
/scripts/gofmtcheck.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Check gofmt
4 | echo "==> Checking that code complies with gofmt requirements..."
5 | gofmt_files=$(gofmt -l `find . -name '*.go' | grep -v vendor`)
6 | if [[ -n ${gofmt_files} ]]; then
7 | echo 'gofmt needs running on the following files:'
8 | echo "${gofmt_files}"
9 | echo "You can use the command: \`make fmt\` to reformat code."
10 | exit 1
11 | fi
12 |
13 | exit 0
14 |
--------------------------------------------------------------------------------
/OWNERS.md:
--------------------------------------------------------------------------------
1 | # Owners
2 |
3 | This project is governed by [Equinix Metal](https://metal.equinix.com) and benefits from a community of users that collaborate and contribute to its use in Kubernetes on Equinix Metal.
4 |
5 | Members of the Equinix Metal Github organization will strive to triage issues in a timely manner, see [SUPPORT.md](.github/SUPPORT.md) for details.
6 |
7 | See the [packethost/standards glossary](https://github.com/packethost/standards/blob/master/glossary.md#ownersmd) for more details about this file.
8 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Go Tests
2 | on:
3 | pull_request:
4 | jobs:
5 | test:
6 | runs-on: ubuntu-latest
7 | timeout-minutes: 10
8 | steps:
9 | - name: Set up Go
10 | uses: actions/setup-go@v2
11 | with:
12 | go-version: '1.17.7'
13 | - name: Check out code into the Go module directory
14 | uses: actions/checkout@v2
15 | - name: Get dependencies
16 | run: go mod download
17 | - name: Build
18 | run: go build -v .
19 | - name: TF tests
20 | run: go test -v -cover -parallel 4 ./metal
21 |
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.dll
2 | *.exe
3 | .DS_Store
4 | example.tf
5 | terraform.tfplan
6 | terraform.tfstate
7 | terraform-provider-metal
8 | bin/
9 | modules-dev/
10 | /pkg/
11 | website/.vagrant
12 | website/.bundle
13 | website/build
14 | website/node_modules
15 | .vagrant/
16 | *.backup
17 | ./*.tfstate
18 | .terraform/
19 | *.log
20 | *.bak
21 | *~
22 | .*.swp
23 | .idea
24 | .vscode
25 | *.iml
26 | *.test
27 | *.iml
28 |
29 | vendor
30 | website/vendor
31 |
32 | # Test exclusions
33 | !command/test-fixtures/**/*.tfstate
34 | !command/test-fixtures/**/.terraform/
35 |
36 | # build binary exclusion
37 | terraform-provider-metal
38 |
--------------------------------------------------------------------------------
/docs/resources/volume.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_volume"
3 | subcategory: ""
4 | description: |-
5 | (Removed) Provides an Equinix Metal Block Storage Volume Resource.
6 | ---
7 |
8 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
9 |
10 | Resource `metal_volume` was removed in version 3.0.0, and the API support was deprecated on June 1st 2021. See https://metal.equinix.com/developers/docs/storage/elastic-block-storage/#elastic-block-storage for more details.
11 |
--------------------------------------------------------------------------------
/docs/data-sources/volume.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_volume"
3 | subcategory: ""
4 | description: |-
5 | (Removed) Provides an Equinix Metal Block Storage Volume Datasource.
6 | ---
7 |
8 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
9 |
10 | Datasource `metal_volume` was removed in version 3.0.0, and the API support was deprecated on June 1st 2021. See https://metal.equinix.com/developers/docs/storage/elastic-block-storage/#elastic-block-storage for more details.
11 |
--------------------------------------------------------------------------------
/docs/resources/volume_attachment.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_volume_attachment"
3 | subcategory: ""
4 | description: |-
5 | (Removed) Provides attachment of volumes to devices in the Equinix Metal Host.
6 | ---
7 |
8 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
9 |
10 | Resource `metal_volume_attachment` was removed in version 3.0.0, and the API support was deprecated on June 1st 2021. See https://metal.equinix.com/developers/docs/storage/elastic-block-storage/#elastic-block-storage for more details.
11 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "flag"
6 | "log"
7 |
8 | "github.com/equinix/terraform-provider-metal/metal"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
10 | )
11 |
12 | func main() {
13 | var debugMode bool
14 |
15 | flag.BoolVar(&debugMode, "debug", false, "set to true to run the provider with support for debuggers like delve")
16 | flag.Parse()
17 | opts := &plugin.ServeOpts{ProviderFunc: metal.Provider}
18 |
19 | if debugMode {
20 | err := plugin.Debug(context.Background(), "registry.terraform.io/equinix/metal", opts)
21 | if err != nil {
22 | log.Fatal(err.Error())
23 | }
24 | return
25 | }
26 |
27 | plugin.Serve(opts)
28 | }
29 |
--------------------------------------------------------------------------------
/metal/resource_metal_user_api_key.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | )
6 |
7 | func resourceMetalUserAPIKey() *schema.Resource {
8 | userKeySchema := schemaMetalAPIKey()
9 | userKeySchema["user_id"] = &schema.Schema{
10 | Type: schema.TypeString,
11 | Computed: true,
12 | Description: "UUID of user owning this key",
13 | }
14 | return &schema.Resource{
15 | DeprecationMessage: deprecatedProviderMsg,
16 | Create: resourceMetalAPIKeyCreate,
17 | Read: resourceMetalAPIKeyRead,
18 | Delete: resourceMetalAPIKeyDelete,
19 | Importer: &schema.ResourceImporter{
20 | State: schema.ImportStatePassthrough,
21 | },
22 |
23 | Schema: userKeySchema,
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/scripts/errcheck.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Check gofmt
4 | echo "==> Checking for unchecked errors..."
5 |
6 | if ! which errcheck > /dev/null; then
7 | echo "==> Installing errcheck..."
8 | go get -u github.com/kisielk/errcheck
9 | fi
10 |
11 | err_files=$(errcheck -ignoretests \
12 | -ignore 'github.com/hashicorp/terraform/helper/schema:Set' \
13 | -ignore 'bytes:.*' \
14 | -ignore 'io:Close|Write' \
15 | $(go list ./...| grep -v /vendor/))
16 |
17 | if [[ -n ${err_files} ]]; then
18 | echo 'Unchecked errors found in the following places:'
19 | echo "${err_files}"
20 | echo "Please handle returned errors. You can check directly with \`make errcheck\`"
21 | exit 1
22 | fi
23 |
24 | exit 0
25 |
--------------------------------------------------------------------------------
/metal/sweeper_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 | "testing"
8 |
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10 | )
11 |
12 | const tstResourcePrefix = "tfacc"
13 |
14 | func TestMain(m *testing.M) {
15 | resource.TestMain(m)
16 | }
17 |
18 | func sharedConfigForRegion(region string) (interface{}, error) {
19 | token := os.Getenv("METAL_AUTH_TOKEN")
20 |
21 | if token == "" {
22 | token = os.Getenv("PACKET_AUTH_TOKEN")
23 | }
24 |
25 | if token == "" {
26 | return nil, fmt.Errorf("you must set METAL_AUTH_TOKEN")
27 | }
28 |
29 | config := Config{
30 | AuthToken: token,
31 | }
32 |
33 | return config.Client(), nil
34 | }
35 |
36 | func isSweepableTestResource(namePrefix string) bool {
37 | return strings.HasPrefix(namePrefix, tstResourcePrefix)
38 | }
39 |
--------------------------------------------------------------------------------
/metal/resource_metal_project_ssh_key.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | )
6 |
7 | func resourceMetalProjectSSHKey() *schema.Resource {
8 | pkeySchema := metalSSHKeyCommonFields()
9 | pkeySchema["project_id"] = &schema.Schema{
10 | Type: schema.TypeString,
11 | Description: "The ID of parent project",
12 | ForceNew: true,
13 | Required: true,
14 | }
15 | return &schema.Resource{
16 | DeprecationMessage: deprecatedProviderMsg,
17 | Create: resourceMetalSSHKeyCreate,
18 | Read: resourceMetalSSHKeyRead,
19 | Update: resourceMetalSSHKeyUpdate,
20 | Delete: resourceMetalSSHKeyDelete,
21 | Importer: &schema.ResourceImporter{
22 | State: schema.ImportStatePassthrough,
23 | },
24 | Schema: pkeySchema,
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/metal/volume_stub.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8 | )
9 |
10 | const volumeRemovedMsgSuffix = "was removed in version 3.0.0, see https://metal.equinix.com/developers/docs/storage/elastic-block-storage/#elastic-block-storage"
11 |
12 | var (
13 | resourceVolumeRemovedMsg = fmt.Sprintf("resource metal_volume %s", volumeRemovedMsgSuffix)
14 | dataSourceVolumeRemovedMsg = fmt.Sprintf("datasource metal_volume %s", volumeRemovedMsgSuffix)
15 | resourceVolumeAttachmentRemovedMsg = fmt.Sprintf("resource metal_volume_attachment %s", volumeRemovedMsgSuffix)
16 | )
17 |
18 | func removedResourceOp(message string) func(d *schema.ResourceData, meta interface{}) error {
19 | return func(d *schema.ResourceData, meta interface{}) error {
20 | return errors.New(message)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/metal/datasource_metal_plans_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8 | )
9 |
10 | func TestAccDataSourcePlans_Basic(t *testing.T) {
11 | testSlug := "m2.xlarge.x86"
12 | resource.Test(t, resource.TestCase{
13 | PreCheck: func() { testAccPreCheck(t) },
14 | Providers: testAccProviders,
15 | Steps: []resource.TestStep{
16 | {
17 | Config: testAccDataSourcePlansConfigBasic(testSlug),
18 | Check: resource.ComposeTestCheckFunc(
19 | resource.TestCheckResourceAttr(
20 | "data.metal_plans.test", "plans.0.slug", testSlug),
21 | ),
22 | },
23 | },
24 | })
25 | }
26 |
27 | func testAccDataSourcePlansConfigBasic(slug string) string {
28 | return fmt.Sprintf(`
29 | data "metal_plans" "test" {
30 | filter {
31 | attribute = "slug"
32 | values = ["%s"]
33 | }
34 | }
35 |
36 | output "test" {
37 | value = data.metal_plans.test
38 | }
39 | `, slug)
40 | }
41 |
--------------------------------------------------------------------------------
/scripts/changelog-links.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script rewrites [GH-nnnn]-style references in the CHANGELOG.md file to
4 | # be Markdown links to the given github issues.
5 | #
6 | # This is run during releases so that the issue references in all of the
7 | # released items are presented as clickable links, but we can just use the
8 | # easy [GH-nnnn] shorthand for quickly adding items to the "Unrelease" section
9 | # while merging things between releases.
10 |
11 | set -e
12 |
13 | if [[ ! -f CHANGELOG.md ]]; then
14 | echo "ERROR: CHANGELOG.md not found in pwd."
15 | echo "Please run this from the root of the terraform provider repository"
16 | exit 1
17 | fi
18 |
19 | if [[ `uname` == "Darwin" ]]; then
20 | echo "Using BSD sed"
21 | SED="sed -i.bak -E -e"
22 | else
23 | echo "Using GNU sed"
24 | SED="sed -i.bak -r -e"
25 | fi
26 |
27 | PROVIDER_URL="https:\/\/github.com\/equinix\/terraform-provider-metal\/issues"
28 |
29 | $SED "s/GH-([0-9]+)/\[#\1\]\($PROVIDER_URL\/\1\)/g" -e 's/\[\[#(.+)([0-9])\)]$/(\[#\1\2))/g' CHANGELOG.md
30 |
31 | rm CHANGELOG.md.bak
32 |
--------------------------------------------------------------------------------
/metal/provider_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "os"
5 | "testing"
6 | "time"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9 | )
10 |
11 | var testAccProviders map[string]*schema.Provider
12 | var testAccProvider *schema.Provider
13 |
14 | func init() {
15 | testAccProvider = Provider()
16 | testAccProviders = map[string]*schema.Provider{
17 | "metal": testAccProvider,
18 | }
19 | }
20 |
21 | func TestProvider(t *testing.T) {
22 | if err := Provider().InternalValidate(); err != nil {
23 | t.Fatalf("err: %s", err)
24 | }
25 | }
26 |
27 | /*
28 | func TestProvider_impl(t *testing.T) {
29 | var _ terraform.ResourceProvider = Provider()
30 | }
31 | */
32 |
33 | func testAccPreCheck(t *testing.T) {
34 | v := os.Getenv("METAL_AUTH_TOKEN")
35 |
36 | if v == "" {
37 | v = os.Getenv("PACKET_AUTH_TOKEN")
38 | }
39 |
40 | if v == "" {
41 | t.Fatal("METAL_AUTH_TOKEN must be set for acceptance tests")
42 | }
43 | }
44 |
45 | func testDeviceTerminationTime() string {
46 | return time.Now().UTC().Add(60 * time.Minute).Format(time.RFC3339)
47 | }
48 |
--------------------------------------------------------------------------------
/metal/datasource_metal_spot_market_price_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8 | )
9 |
10 | func TestAccDataSourceMetalSpotPrice_Basic(t *testing.T) {
11 | resource.ParallelTest(t, resource.TestCase{
12 | PreCheck: func() { testAccPreCheck(t) },
13 | Providers: testAccProviders,
14 | CheckDestroy: testAccCheckMetalSpotMarketRequestDestroy,
15 | Steps: []resource.TestStep{
16 | {
17 | Config: testDataSourceMetalSpotMarketPrice(),
18 | Check: resource.ComposeTestCheckFunc(
19 | resource.TestCheckResourceAttrSet(
20 | "data.metal_spot_market_price.metro", "price"),
21 | resource.TestCheckResourceAttrSet(
22 | "data.metal_spot_market_price.facility", "price"),
23 | ),
24 | },
25 | },
26 | })
27 | }
28 |
29 | func testDataSourceMetalSpotMarketPrice() string {
30 | return fmt.Sprintf(`
31 | data "metal_spot_market_price" "metro" {
32 | metro = "da"
33 | plan = "c3.medium.x86"
34 | }
35 |
36 | data "metal_spot_market_price" "facility" {
37 | facility = "da11"
38 | plan = "c3.medium.x86"
39 | }
40 | `)
41 | }
42 |
--------------------------------------------------------------------------------
/metal/resource_metal_volume_attachment.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | "github.com/packethost/packngo"
6 | )
7 |
8 | func resourceMetalVolumeAttachment() *schema.Resource {
9 | return &schema.Resource{
10 | Create: removedResourceOp(resourceVolumeAttachmentRemovedMsg),
11 | Read: removedResourceOp(resourceVolumeAttachmentRemovedMsg),
12 | DeprecationMessage: "Volumes are deprecated, see https://metal.equinix.com/developers/docs/resilience-recovery/elastic-block-storage/#elastic-block-storage",
13 | Delete: resourceMetalVolumeAttachmentDelete,
14 | Importer: &schema.ResourceImporter{
15 | State: schema.ImportStatePassthrough,
16 | },
17 |
18 | Schema: map[string]*schema.Schema{
19 | "device_id": {
20 | Type: schema.TypeString,
21 | Required: true,
22 | ForceNew: true,
23 | },
24 |
25 | "volume_id": {
26 | Type: schema.TypeString,
27 | Required: true,
28 | ForceNew: true,
29 | },
30 | },
31 | }
32 | }
33 |
34 | func resourceMetalVolumeAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
35 | client := meta.(*packngo.Client)
36 | resp, err := client.VolumeAttachments.Delete(d.Id())
37 | return ignoreResponseErrors(httpForbidden, httpNotFound)(resp, err)
38 | }
39 |
--------------------------------------------------------------------------------
/docs/data-sources/spot_market_price.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: spot_market_price"
3 | subcategory: ""
4 | description: |-
5 | Get an Equinix Metal Spot Market Price
6 | ---
7 |
8 | # metal_operating_system (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_operating_system`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_operating_system) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_operating_system`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to get Equinix Metal Spot Market Price for a plan.
13 |
14 | ## Example Usage
15 |
16 | Lookup by facility:
17 |
18 | ```hcl
19 | data "metal_spot_market_price" "example" {
20 | facility = "ny5"
21 | plan = "c3.small.x86"
22 | }
23 | ```
24 |
25 | Lookup by metro:
26 |
27 | ```hcl
28 | data "metal_spot_market_price" "example" {
29 | metro = "sv"
30 | plan = "c3.small.x86"
31 | }
32 | ```
33 |
34 | ## Argument Reference
35 |
36 | * `plan` - (Required) Name of the plan.
37 | * `facility` - (Optional) Name of the facility.
38 | * `metro` - (Optional) Name of the metro.
39 |
40 | ## Attributes Reference
41 |
42 | * `price` - Current spot market price for given plan in given facility.
43 |
--------------------------------------------------------------------------------
/metal/datasource_metal_gateway_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8 | )
9 |
10 | func testAccDataSourceMetalGatewayConfig_PrivateIPv4() string {
11 | return fmt.Sprintf(`
12 | resource "metal_project" "test" {
13 | name = "tfacc-pro-gateway-test"
14 | }
15 |
16 | resource "metal_vlan" "test" {
17 | description = "%s-vlan in SV"
18 | metro = "sv"
19 | project_id = metal_project.test.id
20 | }
21 |
22 | resource "metal_gateway" "test" {
23 | project_id = metal_project.test.id
24 | vlan_id = metal_vlan.test.id
25 | private_ipv4_subnet_size = 8
26 | }
27 |
28 | data "metal_gateway" "test" {
29 | gateway_id = metal_gateway.test.id
30 | }
31 | `, tstResourcePrefix)
32 | }
33 |
34 | func TestAccDataSourceMetalGateway_PrivateIPv4(t *testing.T) {
35 | resource.ParallelTest(t, resource.TestCase{
36 | PreCheck: func() { testAccPreCheck(t) },
37 | Providers: testAccProviders,
38 | CheckDestroy: testAccCheckMetalGatewayDestroyed,
39 | Steps: []resource.TestStep{
40 | {
41 | Config: testAccDataSourceMetalGatewayConfig_PrivateIPv4(),
42 | Check: resource.ComposeTestCheckFunc(
43 | resource.TestCheckResourceAttrPair(
44 | "data.metal_gateway.test", "project_id",
45 | "metal_project.test", "id"),
46 | resource.TestCheckResourceAttr(
47 | "data.metal_gateway.test", "private_ipv4_subnet_size", "8"),
48 | ),
49 | },
50 | },
51 | })
52 | }
53 |
--------------------------------------------------------------------------------
/metal/mutexkv.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "log"
5 | "sync"
6 | )
7 |
8 | // MutexKV is a simple key/value store for arbitrary mutexes. It can be used to
9 | // serialize changes across arbitrary collaborators that share knowledge of the
10 | // keys they must serialize on.
11 | //
12 | // The initial use case is to let aws_security_group_rule resources serialize
13 | // their access to individual security groups based on SG ID.
14 | type MutexKV struct {
15 | lock sync.Mutex
16 | store map[string]*sync.Mutex
17 | }
18 |
19 | // Locks the mutex for the given key. Caller is responsible for calling Unlock
20 | // for the same key
21 | func (m *MutexKV) Lock(key string) {
22 | log.Printf("[DEBUG] Locking %q", key)
23 | m.get(key).Lock()
24 | log.Printf("[DEBUG] Locked %q", key)
25 | }
26 |
27 | // Unlock the mutex for the given key. Caller must have called Lock for the same key first
28 | func (m *MutexKV) Unlock(key string) {
29 | log.Printf("[DEBUG] Unlocking %q", key)
30 | m.get(key).Unlock()
31 | log.Printf("[DEBUG] Unlocked %q", key)
32 | }
33 |
34 | // Returns a mutex for the given key, no guarantee of its lock status
35 | func (m *MutexKV) get(key string) *sync.Mutex {
36 | m.lock.Lock()
37 | defer m.lock.Unlock()
38 | mutex, ok := m.store[key]
39 | if !ok {
40 | mutex = &sync.Mutex{}
41 | m.store[key] = mutex
42 | }
43 | return mutex
44 | }
45 |
46 | // Returns a properly initalized MutexKV
47 | func NewMutexKV() *MutexKV {
48 | return &MutexKV{
49 | store: make(map[string]*sync.Mutex),
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/metal/utils.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 | )
7 |
8 | func contains(s []string, e string) bool {
9 | for _, a := range s {
10 | if a == e {
11 | return true
12 | }
13 | }
14 | return false
15 | }
16 |
17 | func stringArrToIfArr(sli []string) []interface{} {
18 | var arr []interface{}
19 | for _, v := range sli {
20 | arr = append(arr, v)
21 | }
22 | return arr
23 | }
24 |
25 | func convertStringArr(ifaceArr []interface{}) []string {
26 | var arr []string
27 | for _, v := range ifaceArr {
28 | if v == nil {
29 | continue
30 | }
31 | arr = append(arr, v.(string))
32 | }
33 | return arr
34 | }
35 |
36 | func convertIntArr(ifaceArr []interface{}) []string {
37 | var arr []string
38 | for _, v := range ifaceArr {
39 | if v == nil {
40 | continue
41 | }
42 | arr = append(arr, strconv.Itoa(v.(int)))
43 | }
44 | return arr
45 | }
46 |
47 | func convertIntArr2(ifaceArr []interface{}) []int {
48 | var arr []int
49 | for _, v := range ifaceArr {
50 | if v == nil {
51 | continue
52 | }
53 | arr = append(arr, v.(int))
54 | }
55 | return arr
56 | }
57 |
58 | func toLower(v interface{}) string {
59 | return strings.ToLower(v.(string))
60 | }
61 |
62 | // from https://stackoverflow.com/a/45428032
63 | func difference(a, b []string) []string {
64 | mb := make(map[string]struct{}, len(b))
65 | for _, x := range b {
66 | mb[x] = struct{}{}
67 | }
68 | var diff []string
69 | for _, x := range a {
70 | if _, found := mb[x]; !found {
71 | diff = append(diff, x)
72 | }
73 | }
74 | return diff
75 | }
76 |
--------------------------------------------------------------------------------
/docs/resources/user_api_key.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: Metal User API Key"
3 | subcategory: ""
4 | description: |-
5 | Create Equinix Metal User API Keys
6 | ---
7 |
8 | # metal_user_api_key (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_user_api_key`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_user_api_key) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_user_api_key`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this resource to create Metal User API Key resources in Equinix Metal. Each API key contains a token which can be used for authentication in Equinix Metal HTTP API (in HTTP request header `X-Auth-Token`).
13 |
14 | Read-only keys only allow to list and view existing resources, read-write keys can also be used to create resources.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 |
20 | # Create a new read-only API key
21 |
22 | resource "metal_user_api_key" "test" {
23 | description = "Read-only user key"
24 | read_only = true
25 | }
26 | ```
27 |
28 | ## Argument Reference
29 |
30 | * `description` - Description string for the User API Key resource
31 | * `read-only` - Flag indicating whether the API key shoud be read-only
32 |
33 | ## Attributes Reference
34 |
35 | * `user_id` - UUID of the owner of the API key
36 | * `token` - API token which can be used in Equinix Metal API clients
37 |
--------------------------------------------------------------------------------
/metal/datasource_metal_project_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | "github.com/packethost/packngo"
10 | )
11 |
12 | func testAccCheckMetalDataSourceProject_Basic(r string) string {
13 | return fmt.Sprintf(`
14 | resource "metal_project" "foobar" {
15 | name = "tfacc-pro-%s"
16 | bgp_config {
17 | deployment_type = "local"
18 | md5 = "2SFsdfsg43"
19 | asn = 65000
20 | }
21 | }
22 |
23 | data metal_project "test" {
24 | project_id = metal_project.foobar.id
25 | }
26 |
27 | `, r)
28 | }
29 |
30 | func TestAccMetalDataSourceProject_Basic(t *testing.T) {
31 | var project packngo.Project
32 | rn := acctest.RandStringFromCharSet(12, "abcdef0123456789")
33 |
34 | resource.ParallelTest(t, resource.TestCase{
35 | PreCheck: func() { testAccPreCheck(t) },
36 | Providers: testAccProviders,
37 | CheckDestroy: testAccCheckMetalProjectDestroy,
38 | Steps: []resource.TestStep{
39 | {
40 | Config: testAccCheckMetalDataSourceProject_Basic(rn),
41 | Check: resource.ComposeTestCheckFunc(
42 | testAccCheckMetalProjectExists("metal_project.foobar", &project),
43 | resource.TestCheckResourceAttr(
44 | "metal_project.foobar", "name", fmt.Sprintf("tfacc-pro-%s", rn)),
45 | resource.TestCheckResourceAttr(
46 | "metal_project.foobar", "bgp_config.0.md5",
47 | "2SFsdfsg43"),
48 | resource.TestCheckResourceAttrPair(
49 | "metal_project.foobar", "id",
50 | "data.metal_project.test", "id"),
51 | ),
52 | },
53 | },
54 | })
55 | }
56 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | # This GitHub action can publish assets for release when a tag is created.
2 | # Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0).
3 | #
4 | # This uses an action (paultyng/ghaction-import-gpg) that assumes you set your
5 | # private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE`
6 | # secret. If you would rather own your own GPG handling, please fork this action
7 | # or use an alternative one for key handling.
8 | #
9 | # You will need to pass the `--batch` flag to `gpg` in your signing step
10 | # in `goreleaser` to indicate this is being used in a non-interactive mode.
11 | #
12 | name: release
13 | on:
14 | push:
15 | tags:
16 | - 'v*'
17 | jobs:
18 | goreleaser:
19 | runs-on: ubuntu-latest
20 | steps:
21 | -
22 | name: Checkout
23 | uses: actions/checkout@v2
24 | -
25 | name: Unshallow
26 | run: git fetch --prune --unshallow
27 | -
28 | name: Set up Go
29 | uses: actions/setup-go@v2
30 | with:
31 | go-version: 1.17.7
32 | -
33 | name: Import GPG key
34 | id: import_gpg
35 | uses: paultyng/ghaction-import-gpg@v2.1.0
36 | env:
37 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
38 | PASSPHRASE: ${{ secrets.PASSPHRASE }}
39 | -
40 | name: Run GoReleaser
41 | uses: goreleaser/goreleaser-action@v2
42 | with:
43 | version: latest
44 | args: release --rm-dist
45 | env:
46 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | # Visit https://goreleaser.com for documentation on how to customize this
2 | # behavior.
3 | before:
4 | hooks:
5 | # this is just an example and not a requirement for provider building/publishing
6 | - go mod tidy
7 | builds:
8 | - env:
9 | # goreleaser does not work with CGO, it could also complicate
10 | # usage by users in CI/CD systems like Terraform Cloud where
11 | # they are unable to install libraries.
12 | - CGO_ENABLED=0
13 | mod_timestamp: '{{ .CommitTimestamp }}'
14 | flags:
15 | - -trimpath
16 | ldflags:
17 | - -s -w -X version.ProviderVersion={{.Version}}
18 | goos:
19 | - freebsd
20 | - windows
21 | - linux
22 | - darwin
23 | goarch:
24 | - amd64
25 | - '386'
26 | - arm
27 | - arm64
28 | ignore:
29 | - goos: darwin
30 | goarch: '386'
31 | binary: '{{ .ProjectName }}_v{{ .Version }}'
32 | archives:
33 | - format: zip
34 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
35 | checksum:
36 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
37 | algorithm: sha256
38 | signs:
39 | - artifacts: checksum
40 | args:
41 | # if you are using this is a GitHub action or some other automated pipeline, you
42 | # need to pass the batch flag to indicate its not interactive.
43 | - "--batch"
44 | - "--local-user"
45 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key
46 | - "--output"
47 | - "${signature}"
48 | - "--detach-sign"
49 | - "${artifact}"
50 | release:
51 | # If you want to manually examine the release before its live, uncomment this line:
52 | # draft: true
53 | changelog:
54 | skip: true
55 |
--------------------------------------------------------------------------------
/docs/data-sources/operating_system.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: operating_system"
3 | subcategory: ""
4 | description: |-
5 | Get an Equinix Metal operating system image
6 | ---
7 |
8 | # metal_operating_system (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_operating_system`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_operating_system) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_operating_system`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to get Equinix Metal Operating System image.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | data "metal_operating_system" "example" {
18 | distro = "ubuntu"
19 | version = "20.04"
20 | provisionable_on = "c3.medium.x86"
21 | }
22 |
23 | resource "metal_device" "server" {
24 | hostname = "tf.ubuntu"
25 | plan = "c3.medium.x86"
26 | facilities = ["ny5"]
27 | operating_system = data.metal_operating_system.example.id
28 | billing_cycle = "hourly"
29 | project_id = local.project_id
30 | }
31 | ```
32 |
33 | ## Argument Reference
34 |
35 | * `distro` - (Optional) Name of the OS distribution.
36 | * `name` - (Optional) Name or part of the name of the distribution. Case insensitive.
37 | * `provisionable_on` - (Optional) Plan name.
38 | * `version` - (Optional) Version of the distribution
39 |
40 | ## Attributes Reference
41 |
42 | * `id` - Operating system slug
43 | * `slug` - Operating system slug (same as `id`)
44 |
--------------------------------------------------------------------------------
/metal/resource_metal_project_api_key_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
9 | "github.com/packethost/packngo"
10 | )
11 |
12 | func testAccMetalProjectAPIKeyDestroy(s *terraform.State) error {
13 | client := testAccProvider.Meta().(*packngo.Client)
14 | for _, rs := range s.RootModule().Resources {
15 | if rs.Type != "metal_project_api_key" {
16 | continue
17 | }
18 | if _, err := client.APIKeys.ProjectGet(rs.Primary.ID, rs.Primary.Attributes["project_id"], nil); err == nil {
19 | return fmt.Errorf("ProjectAPI key still exists")
20 | }
21 | }
22 | return nil
23 | }
24 |
25 | func testAccMetalProjectAPIKeyConfig_Basic() string {
26 | return fmt.Sprintf(`
27 |
28 | resource "metal_project" "test" {
29 | name = "tfacc-pro-key-test"
30 | }
31 |
32 | resource "metal_project_api_key" "test" {
33 | project_id = metal_project.test.id
34 | description = "tfacc-pro-key"
35 | read_only = true
36 | }`)
37 | }
38 |
39 | func TestAccMetalProjectAPIKey_Basic(t *testing.T) {
40 | resource.ParallelTest(t, resource.TestCase{
41 | PreCheck: func() { testAccPreCheck(t) },
42 | Providers: testAccProviders,
43 | CheckDestroy: testAccMetalProjectAPIKeyDestroy,
44 | Steps: []resource.TestStep{
45 | {
46 | Config: testAccMetalProjectAPIKeyConfig_Basic(),
47 | Check: resource.ComposeTestCheckFunc(
48 | resource.TestCheckResourceAttrSet(
49 | "metal_project_api_key.test", "token"),
50 | resource.TestCheckResourceAttrPair(
51 | "metal_project_api_key.test", "project_id",
52 | "metal_project.test", "id"),
53 | ),
54 | },
55 | },
56 | })
57 | }
58 |
--------------------------------------------------------------------------------
/metal/datasource_metal_reserved_ip_block_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | )
10 |
11 | func testAccDataSourceMetalReservedIPBlockConfig_Basic(name string) string {
12 | return fmt.Sprintf(`
13 | resource "metal_project" "foobar" {
14 | name = "tfacc-pro-reserved_ip_block-%s"
15 | }
16 |
17 | resource "metal_reserved_ip_block" "test" {
18 | project_id = metal_project.foobar.id
19 | metro = "sv"
20 | type = "public_ipv4"
21 | quantity = 2
22 | }
23 |
24 | data "metal_reserved_ip_block" "test" {
25 | project_id = metal_project.foobar.id
26 | ip_address = cidrhost(metal_reserved_ip_block.test.cidr_notation,1)
27 | }
28 |
29 | data "metal_reserved_ip_block" "test_id" {
30 | id = metal_reserved_ip_block.test.id
31 | }
32 |
33 | `, name)
34 | }
35 |
36 | func TestAccDataSourceMetalReservedIPBlock_Basic(t *testing.T) {
37 |
38 | rs := acctest.RandString(10)
39 |
40 | resource.ParallelTest(t, resource.TestCase{
41 | PreCheck: func() { testAccPreCheck(t) },
42 | Providers: testAccProviders,
43 | CheckDestroy: testAccCheckMetalReservedIPBlockDestroy,
44 | Steps: []resource.TestStep{
45 | {
46 | Config: testAccDataSourceMetalReservedIPBlockConfig_Basic(rs),
47 | Check: resource.ComposeTestCheckFunc(
48 | resource.TestCheckResourceAttrPair(
49 | "metal_reserved_ip_block.test", "id",
50 | "data.metal_reserved_ip_block.test", "id",
51 | ),
52 | resource.TestCheckResourceAttrPair(
53 | "metal_reserved_ip_block.test", "cidr_notation",
54 | "data.metal_reserved_ip_block.test_id", "cidr_notation",
55 | ),
56 | ),
57 | },
58 | },
59 | })
60 | }
61 |
--------------------------------------------------------------------------------
/docs/resources/project_api_key.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: Metal Project API Key"
3 | subcategory: ""
4 | description: |-
5 | Create Equinix Metal Project API Keys
6 | ---
7 |
8 | # metal_project_api_key (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_project_api_key`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_project_api_key) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_project_api_key`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this resource to create Metal Project API Key resources in Equinix Metal. Project API keys can be used to create and read resources in a single project. Each API key contains a token which can be used for authentication in Equinix Metal HTTP API (in HTTP request header `X-Auth-Token`).
13 |
14 | Read-only keys only allow to list and view existing resources, read-write keys can also be used to create resources.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 |
20 | # Create a new read-only API key in existing project
21 |
22 | resource "metal_project_api_key" "test" {
23 | project_id = local.existing_project_id
24 | description = "Read-only key scoped to a projct"
25 | read_only = true
26 | }
27 | ```
28 |
29 | ## Argument Reference
30 |
31 | * `project_id` - UUID of the project where the API key is scoped to
32 | * `description` - Description string for the Project API Key resource
33 | * `read-only` - Flag indicating whether the API key shoud be read-only
34 |
35 | ## Attributes Reference
36 |
37 | * `token` - API token which can be used in Equinix Metal API clients
38 |
--------------------------------------------------------------------------------
/metal/datasource_metal_vrf.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | )
6 |
7 | func dataSourceMetalVRF() *schema.Resource {
8 | return &schema.Resource{
9 | DeprecationMessage: deprecatedProviderMsg,
10 | Read: dataSourceMetalVRFRead,
11 | Schema: map[string]*schema.Schema{
12 | "vrf_id": {
13 | Required: true,
14 | Type: schema.TypeString,
15 | Description: "ID of the VRF to lookup",
16 | },
17 | "name": {
18 | Type: schema.TypeString,
19 | Computed: true,
20 | Description: "User-supplied name of the VRF, unique to the project",
21 | },
22 | "description": {
23 | Type: schema.TypeString,
24 | Computed: true,
25 | Description: "Description of the VRF",
26 | },
27 | "metro": {
28 | Type: schema.TypeString,
29 | Computed: true,
30 | Description: "Metro Code",
31 | },
32 | "local_asn": {
33 | Type: schema.TypeInt,
34 | Computed: true,
35 | Description: "The 4-byte ASN set on the VRF.",
36 | },
37 | "ip_ranges": {
38 | Type: schema.TypeSet,
39 | Computed: true,
40 | Description: "All IPv4 and IPv6 Ranges that will be available to BGP Peers. IPv4 addresses must be /8 or smaller with a minimum size of /29. IPv6 must be /56 or smaller with a minimum size of /64. Ranges must not overlap other ranges within the VRF.",
41 | Elem: &schema.Schema{Type: schema.TypeString},
42 | },
43 | "project_id": {
44 | Type: schema.TypeString,
45 | Computed: true,
46 | Description: "Project ID",
47 | },
48 | },
49 | }
50 | }
51 |
52 | func dataSourceMetalVRFRead(d *schema.ResourceData, meta interface{}) error {
53 | vrfId, _ := d.Get("vrf_id").(string)
54 |
55 | d.SetId(vrfId)
56 | return resourceMetalVRFRead(d, meta)
57 | }
58 |
--------------------------------------------------------------------------------
/docs/data-sources/gateway.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: Metal Gateway"
3 | subcategory: ""
4 | description: |-
5 | Retrieve Equinix Metal Gateways
6 | ---
7 |
8 | # metal_gateway (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_gateway`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_gateway) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_gateway`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this datasource to retrieve Metal Gateway resources in Equinix Metal.
13 |
14 | ~> VRF features are not generally available. The interfaces related to VRF resources may change ahead of general availability.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 | # Create Metal Gateway for a VLAN with a private IPv4 block with 8 IP addresses
20 |
21 | resource "metal_vlan" "test" {
22 | description = "test VLAN in SV"
23 | metro = "sv"
24 | project_id = local.project_id
25 | }
26 |
27 | data "metal_gateway" "test" {
28 | gateway_id = local.gateway_id
29 | }
30 | ```
31 |
32 | ## Argument Reference
33 |
34 | * `gateway_id` - (Required) UUID of the metal gateway resource to retrieve
35 |
36 | ## Attributes Reference
37 |
38 | * `project_id` - UUID of the project where the gateway is scoped to
39 | * `vlan_id` - UUID of the VLAN where the gateway is scoped to
40 | * `ip_reservation_id` - UUID of IP reservation block bound to the gateway
41 | * `private_ipv4_subnet_size` - Size of the private IPv4 subnet bound to this metal gateway, one of (8, 16, 32, 64, 128)`
42 | * `state` - Status of the gateway resource
43 | * `vrf_id` - UUID of the VRF associated with the IP Reservation.
44 |
--------------------------------------------------------------------------------
/docs/data-sources/vrf.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_vrf"
3 | subcategory: ""
4 | description: |-
5 | (not-GA) Provides a datasource for Equinix Metal VRF.
6 | ---
7 |
8 | # metal_virtual_circuit (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_virtual_circuit`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_virtual_circuit) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_virtual_circuit`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to retrieve a VRF resource.
13 |
14 | ~> VRF features are not generally available. The interfaces related to VRF resources may change ahead of general availability.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 | data "metal_vrf" "example_vrf" {
20 | vrf_id = "48630899-9ff2-4ce6-a93f-50ff4ebcdf6e"
21 | }
22 | ```
23 |
24 | ## Argument Reference
25 |
26 | The following arguments are supported:
27 |
28 | * `vrf_id` - (Required) ID of the VRF resource
29 |
30 | ## Attributes Reference
31 |
32 | In addition to all arguments above, the following attributes are exported:
33 |
34 | * `name` - User-supplied name of the VRF, unique to the project
35 | * `metro` - Metro ID or Code where the VRF will be deployed.
36 | * `project_id` - Project ID where the VRF will be deployed.
37 | * `description` - Description of the VRF.
38 | * `local_asn` - The 4-byte ASN set on the VRF.
39 | * `ip_ranges` - All IPv4 and IPv6 Ranges that will be available to BGP Peers. IPv4 addresses must be /8 or smaller with a minimum size of /29. IPv6 must be /56 or smaller with a minimum size of /64. Ranges must not overlap other ranges within the VRF.
40 |
--------------------------------------------------------------------------------
/metal/datasource_metal_gateway.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7 | )
8 |
9 | func dataSourceMetalGateway() *schema.Resource {
10 | return &schema.Resource{
11 | DeprecationMessage: deprecatedProviderMsg,
12 | Read: dataSourceMetalGatewayRead,
13 | Schema: map[string]*schema.Schema{
14 | "gateway_id": {
15 | Required: true,
16 | Type: schema.TypeString,
17 | Description: "UUID of the Metal Gateway to fetch",
18 | },
19 | "project_id": {
20 | Computed: true,
21 | Type: schema.TypeString,
22 | Description: "UUID of the Project where the Gateway is scoped to",
23 | },
24 | "vlan_id": {
25 | Computed: true,
26 | Type: schema.TypeString,
27 | Description: "UUID of the VLAN to associate",
28 | },
29 | "vrf_id": {
30 | Computed: true,
31 | Type: schema.TypeString,
32 | Description: "UUID of the VRF associated with the IP Reservation",
33 | },
34 | "ip_reservation_id": {
35 | Computed: true,
36 | Type: schema.TypeString,
37 | Description: "UUID of the IP Reservation to associate, must be in the same metro as the VLAN",
38 | },
39 | "private_ipv4_subnet_size": {
40 | Computed: true,
41 | Type: schema.TypeInt,
42 | Description: fmt.Sprintf("Size of the private IPv4 subnet to create for this gateway, one of %v", subnetSizes),
43 | },
44 | "state": {
45 | Type: schema.TypeString,
46 | Computed: true,
47 | Description: "Status of the virtual circuit resource",
48 | },
49 | },
50 | }
51 | }
52 |
53 | func dataSourceMetalGatewayRead(d *schema.ResourceData, meta interface{}) error {
54 | gatewayId, _ := d.Get("gateway_id").(string)
55 |
56 | d.SetId(gatewayId)
57 | return resourceMetalGatewayRead(d, meta)
58 | }
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Equinix Metal Terraform Provider
2 |
3 | [](end-of-life-statement.md#end-of-life-statements)
4 | [](https://github.com/equinix/terraform-provider-metal/releases)
5 | [](https://goreportcard.com/report/github.com/equinix/terraform-provider-metal)
6 |
7 | [](https://slack.equinixmetal.com)
8 | [](https://twitter.com/intent/follow?screen_name=equinixmetal)
9 |
10 |
11 |
12 | This repository is now [End of Life](https://github.com/equinix-labs/equinix-labs/blob/main/end-of-life-statement.md) meaning that this software is no longer supported nor maintained by Equinix Metal or its community.
13 |
14 | [Please review the Metal to Equinix provider migration guide](https://registry.terraform.io/providers/equinix/equinix/latest/docs/guides/migration_guide_equinix_metal). A guide is also available for [migrating from the Packet provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs/guides/migration_guide_packet).
15 |
16 | The [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) has full support for existing Terraform managed Metal resources once Terraform configuration and state are adapted. The Equinix provider manages resources including Network Edge and Fabric in addition to Metal.
17 |
18 | See for documentation on the resources included in this deprecated provider.
19 |
--------------------------------------------------------------------------------
/docs/data-sources/organization.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_organization"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal Organization datasource. This can be used to read existing Organizations.
6 | ---
7 |
8 | # metal_organization (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_organization`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_organization) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_organization`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal organization datasource.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | # Fetch a organization data and show projects which belong to it
18 | data "metal_organization" "test" {
19 | organization_id = local.org_id
20 | }
21 |
22 | output "projects_in_the_org" {
23 | value = data.metal_organization.test.project_ids
24 | }
25 | ```
26 |
27 | ## Argument Reference
28 |
29 | The following arguments are supported:
30 |
31 | * `name` - The organization name
32 | * `organization_id` - The UUID of the organization resource
33 |
34 | Exactly one of `name` or `organization_id` must be given.
35 |
36 | ## Attributes Reference
37 |
38 | The following attributes are exported:
39 |
40 | * `project_ids` - UUIDs of project resources which belong to this organization
41 | * `description` - Description string
42 | * `website` - Website link
43 | * `twitter` - Twitter handle
44 | * `logo` - Logo URL
45 | * `address` - Address information
46 | * `address` - Postal address.
47 | * `city` - City name.
48 | * `country` - Two letter country code (ISO 3166-1 alpha-2), e.g. US.
49 | * `zip_code` - Zip Code.
50 | * `state` - State name.
51 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Hi there,
2 |
3 | Thank you for opening an issue. Please note that we try to keep the Terraform issue tracker reserved for bug reports and feature requests. For general usage questions, please see: https://www.terraform.io/community.html.
4 |
5 | ### Terraform Version
6 | Run `terraform -v` to show the version. If you are not running the latest version of Terraform, please upgrade because your issue may have already been fixed.
7 |
8 | ### Affected Resource(s)
9 | Please list the resources as a list, for example:
10 | - metal_device
11 | - metal_spot_market_request
12 |
13 | If this issue appears to affect multiple resources, it may be an issue with Terraform's core, so please mention this.
14 |
15 | ### Terraform Configuration Files
16 | ```hcl
17 | # Copy-paste your Terraform configurations here - for large Terraform configs,
18 | # please use a service like Dropbox and share a link to the ZIP file.
19 | ```
20 |
21 | ### Debug Output
22 | Please provider a link to a GitHub Gist containing the complete debug output: https://www.terraform.io/docs/internals/debugging.html. Please do NOT paste the debug output in the issue; just paste a link to the Gist. Note: the debug log will contain your API key, please search the log for `X-Auth-Token` (HTTP request header holding the API token) and remove it.
23 |
24 | ### Panic Output
25 | If Terraform produced a panic, please provide a link to a GitHub Gist containing the output of the `crash.log`.
26 |
27 | ### Expected Behavior
28 | What should have happened?
29 |
30 | ### Actual Behavior
31 | What actually happened?
32 |
33 | ### Steps to Reproduce
34 | Please list the steps required to reproduce the issue, for example:
35 | 1. `terraform apply`
36 |
37 | ### Important Factoids
38 | Are there anything atypical about your accounts that we should know?
39 |
40 | ### References
41 | Are there any other GitHub issues (open or closed) or Pull Requests that should be linked here? For example:
42 | - #1234
43 |
--------------------------------------------------------------------------------
/docs/data-sources/metro.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_metro"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal metro datasource. This can be used to read metros.
6 | ---
7 |
8 | # metal_metro (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_metro`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_metro) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_metro`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal metro datasource.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | # Fetch a metro by code and show its ID
18 |
19 | data "metal_metro" "sv" {
20 | code = "sv"
21 | }
22 |
23 | output "id" {
24 | value = data.metal_metro.sv.id
25 | }
26 | ```
27 |
28 |
29 | ```hcl
30 | # Verify that metro "sv" has capacity for provisioning 2 c3.small.x86
31 | devices and 1 c3.medium.x86 device
32 |
33 | data "metal_facility" "test" {
34 | code = "dc13"
35 | capacity {
36 | plan = "c3.small.x86"
37 | quantity = 2
38 | }
39 | capacity {
40 | plan = "c3.medium.x86"
41 | quantity = 1
42 | }
43 | }
44 |
45 | ```
46 |
47 | ## Argument Reference
48 |
49 | The following arguments are supported:
50 |
51 | * `code` - The metro code
52 |
53 | Metros can be looked up by `code`.
54 |
55 | ## Attributes Reference
56 |
57 | The following attributes are exported:
58 |
59 | * `id` - The ID of the metro
60 | * `code` - The code of the metro
61 | * `country` - The country of the metro
62 | * `name` - The name of the metro
63 | * `capacity` - (Optional) Ensure that queried metro has capacity for specified number of given plans
64 | - `plan` - device plan to check
65 | - `quantity` - number of device to check
66 |
--------------------------------------------------------------------------------
/docs/data-sources/project_ssh_key.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_project_ssh_key"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal Project SSH Key datasource.
6 | ---
7 |
8 | # metal_project_ssh_key (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_project_ssh_key`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_project_ssh_key) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_project_ssh_key`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this datasource to retrieve attributes of a Project SSH Key API resource.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | # Get Project SSH Key by name
18 | data "metal_project_ssh_key" "my_key" {
19 | search = "username@hostname"
20 | project_id = local.project_id
21 | }
22 | ```
23 |
24 | ## Argument Reference
25 |
26 | The following arguments are supported:
27 |
28 | * `search` - (Optional) The name, fingerprint, or public_key of the SSH Key to search for
29 | in the Equinix Metal project
30 | * `id` - (Optional) The id of the SSH Key to search for in the Equinix Metal project
31 | * `project_id` - The Equinix Metal project id of the Equinix Metal SSH Key
32 |
33 | One of either `search` or `id` must be provided along with `project_id`.
34 |
35 | ## Attributes Reference
36 |
37 | The following attributes are exported:
38 |
39 | * `id` - The unique ID of the key
40 | * `name` - The name of the SSH key
41 | * `public_key` - The text of the public key
42 | * `project_id` - The ID of parent project
43 | * `owner_id` - The ID of parent project (same as project_id)
44 | * `fingerprint` - The fingerprint of the SSH key
45 | * `created` - The timestamp for when the SSH key was created
46 | * `updated` - The timestamp for the last time the SSH key was updated
47 |
--------------------------------------------------------------------------------
/docs/resources/vlan.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_vlan"
3 | subcategory: ""
4 | description: |-
5 | Provides a resource for Equinix Metal Virtual Network.
6 | ---
7 |
8 | # metal_vlan (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_vlan`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_vlan) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_vlan`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides a resource to allow users to manage Virtual Networks in their projects.
13 |
14 | To learn more about Layer 2 networking in Equinix Metal, refer to
15 |
16 | *
17 | *
18 |
19 | ## Example Usage
20 |
21 | ```hcl
22 | # Create a new VLAN in facility "sv15"
23 | resource "metal_vlan" "vlan1" {
24 | description = "VLAN in New Jersey"
25 | facility = "sv15"
26 | project_id = local.project_id
27 | }
28 |
29 | # Create a new VLAN in metro "esv"
30 | resource "metal_vlan" "vlan1" {
31 | description = "VLAN in New Jersey"
32 | metro = "sv"
33 | project_id = local.project_id
34 | vxlan = 1040
35 | }
36 | ```
37 |
38 | ## Argument Reference
39 |
40 | The following arguments are supported:
41 |
42 | * `project_id` - (Required) ID of parent project
43 | * `facility` - (Required) Facility where to create the VLAN
44 | * `description` - Description string
45 | * `vxlan` - VLAN ID, must be unique in metro
46 |
47 | ## Attributes Reference
48 |
49 | The following attributes are exported:
50 |
51 | * `vxlan` - VXLAN segment ID
52 |
53 | ## Import
54 |
55 | This resource can be imported using an existing VLAN ID (UUID):
56 |
57 | ```sh
58 | terraform import metal_vlan {existing_vlan_id}
59 | ```
60 |
--------------------------------------------------------------------------------
/metal/datasource_metal_operating_system_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8 | )
9 |
10 | func TestAccMetalOperatingSystem_Basic(t *testing.T) {
11 |
12 | resource.ParallelTest(t, resource.TestCase{
13 | PreCheck: func() { testAccPreCheck(t) },
14 | Providers: testAccProviders,
15 | Steps: []resource.TestStep{
16 | {Config: testOperatingSystemConfig_Basic,
17 | Check: resource.ComposeTestCheckFunc(
18 | resource.TestCheckResourceAttr("data.metal_operating_system.example", "slug", "ubuntu_20_04"),
19 | ),
20 | },
21 | },
22 | })
23 | }
24 |
25 | const testOperatingSystemConfig_Basic = `
26 | data "metal_operating_system" "example" {
27 | distro = "ubuntu"
28 | version = "20.04"
29 | }`
30 |
31 | var matchErrOSNotFound = regexp.MustCompile(".*There are no operating systems*")
32 |
33 | func TestAccMetalOperatingSystem_NotFound(t *testing.T) {
34 |
35 | resource.ParallelTest(t, resource.TestCase{
36 | PreCheck: func() { testAccPreCheck(t) },
37 | Providers: testAccProviders,
38 | Steps: []resource.TestStep{
39 | {Config: testOperatingSystemConfig_NotFound,
40 | ExpectError: matchErrOSNotFound,
41 | },
42 | },
43 | })
44 | }
45 |
46 | const testOperatingSystemConfig_NotFound = `
47 | data "metal_operating_system" "example" {
48 | distro = "NOTEXISTS"
49 | version = "alpha"
50 | }`
51 |
52 | var matchErrOSAmbiguous = regexp.MustCompile(".*There is more than one operating system.*")
53 |
54 | func TestAccMetalOperatingSystem_Ambiguous(t *testing.T) {
55 |
56 | resource.ParallelTest(t, resource.TestCase{
57 | PreCheck: func() { testAccPreCheck(t) },
58 | Providers: testAccProviders,
59 | Steps: []resource.TestStep{
60 | {Config: testOperatingSystemConfig_Ambiguous,
61 | ExpectError: matchErrOSAmbiguous,
62 | },
63 | },
64 | })
65 | }
66 |
67 | const testOperatingSystemConfig_Ambiguous = `
68 | data "metal_operating_system" "example" {
69 | distro = "ubuntu"
70 | }`
71 |
--------------------------------------------------------------------------------
/metal/datasource_metal_ip_block_ranges_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | )
10 |
11 | func TestAccMetalIPBlockRanges_Basic(t *testing.T) {
12 |
13 | rs := acctest.RandString(10)
14 |
15 | resource.ParallelTest(t, resource.TestCase{
16 | PreCheck: func() { testAccPreCheck(t) },
17 | Providers: testAccProviders,
18 | Steps: []resource.TestStep{
19 | {
20 | Config: testIPBlockRangesConfig_Basic(rs),
21 | Check: resource.ComposeTestCheckFunc(
22 | resource.TestCheckResourceAttrSet(
23 | "data.metal_ip_block_ranges.test", "ipv6.0"),
24 | resource.TestCheckResourceAttrPair(
25 | "metal_ip_attachment.test", "device_id",
26 | "metal_device.test", "id"),
27 | ),
28 | },
29 | {
30 | ResourceName: "metal_ip_attachment.test",
31 | ImportState: true,
32 | ImportStateVerify: true,
33 | },
34 | },
35 | })
36 | }
37 |
38 | func testIPBlockRangesConfig_Basic(name string) string {
39 | return fmt.Sprintf(`
40 | %s
41 |
42 | resource "metal_project" "test" {
43 | name = "tfacc-pro-precreated_ip_block-%s"
44 | }
45 |
46 | resource "metal_device" "test" {
47 | hostname = "tfacc-device-test-ip"
48 | plan = local.plan
49 | facilities = local.facilities
50 | operating_system = "ubuntu_16_04"
51 | billing_cycle = "hourly"
52 | project_id = metal_project.test.id
53 |
54 | lifecycle {
55 | ignore_changes = [
56 | plan,
57 | facilities,
58 | ]
59 | }
60 | }
61 |
62 | data "metal_ip_block_ranges" "test" {
63 | facility = metal_device.test.deployed_facility
64 | project_id = metal_device.test.project_id
65 | }
66 |
67 | resource "metal_ip_attachment" "test" {
68 | device_id = metal_device.test.id
69 | cidr_notation = cidrsubnet(data.metal_ip_block_ranges.test.ipv6.0, 8,2)
70 | }`, confAccMetalDevice_base(preferable_plans, preferable_metros), name)
71 | }
72 |
--------------------------------------------------------------------------------
/docs/data-sources/facility.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_facility"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal facility datasource. This can be used to read facilities.
6 | ---
7 |
8 | # metal_facility (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_facility`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_facility) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_facility`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal facility datasource.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | # Fetch a facility by code and show its ID
18 |
19 | data "metal_facility" "ny5" {
20 | code = "ny5"
21 | }
22 |
23 | output "id" {
24 | value = data.metal_facility.ny5.id
25 | }
26 | ```
27 |
28 | ```hcl
29 | # Verify that facility "dc13" has capacity for provisioning 2 c3.small.x86
30 | devices and 1 c3.medium.x86 device
31 |
32 | data "metal_facility" "test" {
33 | code = "dc13"
34 | capacity {
35 | plan = "c3.small.x86"
36 | quantity = 2
37 | }
38 | capacity {
39 | plan = "c3.medium.x86"
40 | quantity = 1
41 | }
42 | }
43 |
44 | ```
45 |
46 | ## Argument Reference
47 |
48 | The following arguments are supported:
49 |
50 | * `code` - The facility code
51 | * `features_required` - Set of feature strings that the facility must have
52 |
53 | Facilities can be looked up by `code`.
54 |
55 | ## Attributes Reference
56 |
57 | The following attributes are exported:
58 |
59 | * `id` - The ID of the facility
60 | * `name` - The name of the facility
61 | * `features` - The features of the facility
62 | * `metro` - The metro code the facility is part of
63 | * `capacity` - (Optional) Ensure that queried facility has capacity for specified number of given plans
64 | - `plan` - device plan to check
65 | - `quantity` - number of device to check
66 |
67 |
--------------------------------------------------------------------------------
/metal/datasource_metal_precreated_ip_block_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | )
10 |
11 | func TestAccMetalDatasourcePreCreatedIPBlock_Basic(t *testing.T) {
12 |
13 | rs := acctest.RandString(10)
14 |
15 | resource.ParallelTest(t, resource.TestCase{
16 | PreCheck: func() { testAccPreCheck(t) },
17 | Providers: testAccProviders,
18 | Steps: []resource.TestStep{
19 | {
20 | Config: testDatasourcePreCreatedIPBlockConfig_Basic(rs),
21 | Check: resource.ComposeTestCheckFunc(
22 | resource.TestCheckResourceAttrSet(
23 | "data.metal_precreated_ip_block.test", "cidr_notation"),
24 | resource.TestCheckResourceAttrPair(
25 | "metal_ip_attachment.test", "device_id",
26 | "metal_device.test", "id"),
27 | ),
28 | },
29 | {
30 | ResourceName: "metal_ip_attachment.test",
31 | ImportState: true,
32 | ImportStateVerify: true,
33 | },
34 | },
35 | })
36 | }
37 |
38 | func testDatasourcePreCreatedIPBlockConfig_Basic(name string) string {
39 | return fmt.Sprintf(`
40 | %s
41 |
42 | resource "metal_project" "test" {
43 | name = "tfacc-pro-recreated_ip_block-%s"
44 | }
45 |
46 | resource "metal_device" "test" {
47 | hostname = "tfacc-device-test-ip-blockt"
48 | plan = local.plan
49 | metro = local.metro
50 | operating_system = "ubuntu_16_04"
51 | billing_cycle = "hourly"
52 | project_id = metal_project.test.id
53 |
54 | lifecycle {
55 | ignore_changes = [
56 | plan,
57 | metro,
58 | ]
59 | }
60 | }
61 |
62 | data "metal_precreated_ip_block" "test" {
63 | facility = metal_device.test.deployed_facility
64 | project_id = metal_device.test.project_id
65 | address_family = 6
66 | public = true
67 | }
68 |
69 | resource "metal_ip_attachment" "test" {
70 | device_id = metal_device.test.id
71 | cidr_notation = cidrsubnet(data.metal_precreated_ip_block.test.cidr_notation,8,2)
72 | }
73 | `, confAccMetalDevice_base(preferable_plans, preferable_metros), name)
74 | }
75 |
--------------------------------------------------------------------------------
/docs/resources/organization.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_organization"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal Organization resource.
6 | ---
7 |
8 | # metal_organization (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_organization`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_organization) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_organization`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides a resource to manage organization resource in Equinix Metal.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | # Create a new Project
18 | resource "metal_organization" "tf_organization_1" {
19 | name = "foobar"
20 | description = "quux"
21 | }
22 | ```
23 |
24 | ## Argument Reference
25 |
26 | The following arguments are supported:
27 |
28 | * `name` - (Required) The name of the Organization
29 | * `address` - (Required) An object that has the address information. See [Address](#address)
30 | below for more details.
31 | * `description` - (Optional) Description string
32 | * `website` - (Optional) Website link
33 | * `twitter` - (Optional) Twitter handle
34 | * `logo` - (Optional) Logo URL
35 |
36 | ### Address
37 |
38 | The `address` block contains:
39 |
40 | * `address` - (Required) Postal address.
41 | * `city` - (Required) City name.
42 | * `country` - (Required) Two letter country code (ISO 3166-1 alpha-2), e.g. US.
43 | * `zip_code` - (Required) Zip Code.
44 | * `state` - (Optional) State name.
45 |
46 | ## Attributes Reference
47 |
48 | The following attributes are exported:
49 |
50 | * `id` - The unique ID of the organization
51 | * `name` - The name of the Organization
52 | * `description` - Description string
53 | * `website` - Website link
54 | * `twitter` - Twitter handle
55 | * `logo` - Logo URL
56 |
57 | ## Import
58 |
59 | This resource can be imported using an existing organization ID:
60 |
61 | ```sh
62 | terraform import metal_organization {existing_organization_id}
63 | ```
64 |
--------------------------------------------------------------------------------
/metal/datasource_metal_metro.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7 | "github.com/packethost/packngo"
8 | )
9 |
10 | func dataSourceMetalMetro() *schema.Resource {
11 | return &schema.Resource{
12 | DeprecationMessage: deprecatedProviderMsg,
13 | Read: dataSourceMetalMetroRead,
14 | Schema: map[string]*schema.Schema{
15 | "id": {
16 | Type: schema.TypeString,
17 | Description: "The ID of this Metro.",
18 | Computed: true,
19 | },
20 | "code": {
21 | Type: schema.TypeString,
22 | Description: "The code of the Metro to match",
23 | Required: true,
24 | },
25 | "country": {
26 | Type: schema.TypeString,
27 | Description: "The country of this Metro.",
28 | Computed: true,
29 | },
30 | "name": {
31 | Type: schema.TypeString,
32 | Description: "The name of this Metro.",
33 | Computed: true,
34 | },
35 | "capacity": capacitySchema(),
36 | },
37 | }
38 | }
39 |
40 | func dataSourceMetalMetroRead(d *schema.ResourceData, meta interface{}) error {
41 | client := meta.(*packngo.Client)
42 | code := d.Get("code").(string)
43 |
44 | _, capacityOk := d.GetOk("capacity")
45 | if capacityOk {
46 | ci := getCapacityInput(
47 | d.Get("capacity").([]interface{}),
48 | packngo.ServerInfo{Metro: code},
49 | )
50 | res, _, err := client.CapacityService.CheckMetros(ci)
51 | if err != nil {
52 | return err
53 | }
54 | for _, s := range res.Servers {
55 | if !s.Available {
56 | return fmt.Errorf("Not enough capacity in metro %s for %d device(s) of plan %s", s.Facility, s.Quantity, s.Plan)
57 | }
58 | }
59 | if err != nil {
60 | return err
61 | }
62 | }
63 |
64 | metros, _, err := client.Metros.List(nil)
65 | if err != nil {
66 | return fmt.Errorf("Error listing Metros: %s", err)
67 | }
68 |
69 | for _, m := range metros {
70 | if m.Code == code {
71 | d.SetId(m.ID)
72 | return setMap(d, map[string]interface{}{
73 | "id": m.ID,
74 | "code": m.Code,
75 | "name": m.Name,
76 | "country": m.Country,
77 | })
78 | }
79 | }
80 |
81 | return fmt.Errorf("Metro %s was not found", code)
82 | }
83 |
--------------------------------------------------------------------------------
/docs/data-sources/port.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: precreated_port"
3 | subcategory: ""
4 | description: |-
5 | Fetch device ports
6 | ---
7 |
8 | # metal_port (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_port`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_port) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_port`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to read ports of existing devices. You can read port by either its UUID, or by a device UUID and port name.
13 |
14 | ## Example Usage
15 |
16 | Create a device and read it's eth0 port to the datasource.
17 |
18 | ```hcl
19 | locals {
20 | project_id = ""
21 | }
22 |
23 | resource "metal_device" "test" {
24 | hostname = "tfacc-test-device-port"
25 | plan = "c3.medium.x86"
26 | facilities = ["sv15"]
27 | operating_system = "ubuntu_20_04"
28 | billing_cycle = "hourly"
29 | project_id = local.project_id
30 | }
31 |
32 | data "metal_port" "test" {
33 | device_id = metal_device.test.id
34 | name = "eth0"
35 | }
36 | ```
37 |
38 | ## Argument Reference
39 |
40 | * `id` - (Required) ID of the port to read, conflicts with device_id.
41 | * `device_id` - (Required)
42 | * `name` - (Required) Whether to look for public or private block.
43 |
44 | ## Attributes Reference
45 |
46 | * `network_type` - One of layer2-bonded, layer2-individual, layer3, hybrid, hybrid-bonded
47 | * `type` - Type is either "NetworkBondPort" for bond ports or "NetworkPort" for bondable ethernet ports
48 | * `mac` - MAC address of the port
49 | * `bond_id` - UUID of the bond port"
50 | * `bond_name` - Name of the bond port
51 | * `bonded` - Flag indicating whether the port is bonded
52 | * `disbond_supported` - Flag indicating whether the port can be removed from a bond
53 | * `native_vlan_id` - UUID of native VLAN of the port
54 | * `vlan_ids` - UUIDs of attached VLANs
55 | * `vxlan_ids` - VXLAN ids of attached VLANs
56 |
57 |
--------------------------------------------------------------------------------
/.github/workflows/acctest.yml:
--------------------------------------------------------------------------------
1 | name: Acceptance Tests
2 | on:
3 | push:
4 | paths-ignore:
5 | - 'LICENSE'
6 | - '**.md'
7 | - 'website/**'
8 | - 'docs/**'
9 | jobs:
10 |
11 | build:
12 | name: Build
13 | runs-on: ubuntu-latest
14 | timeout-minutes: 10
15 | steps:
16 |
17 | - name: Set up Go
18 | uses: actions/setup-go@v2.2.0
19 | with:
20 | go-version: '1.17.7'
21 | id: go
22 |
23 | - name: Check out code into the Go module directory
24 | uses: actions/checkout@v2.3.4
25 |
26 | - name: Get dependencies
27 | run: |
28 | go mod download
29 | - name: Build
30 | run: |
31 | go build -v .
32 | test:
33 | name: Matrix Test
34 | needs: build
35 | runs-on: ubuntu-latest
36 | timeout-minutes: 240
37 | strategy:
38 | fail-fast: false
39 | matrix:
40 | version:
41 | - stable
42 | terraform:
43 | - '1.1.6'
44 | steps:
45 |
46 | - name: Set up Go
47 | uses: actions/setup-go@v2.2.0
48 | with:
49 | go-version: '1.17.7'
50 | id: go
51 |
52 | - name: Check out code into the Go module directory
53 | uses: actions/checkout@v2.3.4
54 |
55 | - name: Get dependencies
56 | run: |
57 | go mod download
58 |
59 | - name: TF acceptance tests
60 | timeout-minutes: 180
61 | env:
62 | TF_ACC: "1"
63 | TF_ACC_TERRAFORM_VERSION: ${{ matrix.terraform }}
64 | # TF_SCHEMA_PANIC_ON_ERROR: "1"
65 | # TF_LOG: "DEBUG"
66 | #
67 |
68 | METAL_AUTH_TOKEN: ${{ secrets.PACKET_AUTH_TOKEN }}
69 | TF_ACC_METAL_DEDICATED_CONNECTION_ID: ${{ secrets.TF_ACC_METAL_DEDICATED_CONNECTION_ID }}
70 | run: |
71 | go test -v -coverprofile coverage.txt -covermode=atomic -parallel 8 -timeout 180m ./metal
72 | - name: Sweeper
73 | if: ${{ always() }}
74 | env:
75 | METAL_AUTH_TOKEN: ${{ secrets.PACKET_AUTH_TOKEN }}
76 | run: |
77 | go test ./metal -v -sweep="tf_test"
78 | - name: Upload coverage to Codecov
79 | if: ${{ always() }}
80 | uses: codecov/codecov-action@v2
81 | with:
82 | token: ${{ secrets.CODECOV_TOKEN }}
83 | files: ./coverage.txt
84 |
--------------------------------------------------------------------------------
/docs/data-sources/reserved_ip_block.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: reserved_ip_block"
3 | subcategory: ""
4 | description: |-
5 | Look up an IP address block
6 | ---
7 |
8 | # metal_reserved_ip_block (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_reserved_ip_block`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_reserved_ip_block) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_reserved_ip_block`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to find IP address blocks in Equinix Metal. You can use IP address or a block ID for lookup.
13 |
14 | ~> VRF features are not generally available. The interfaces related to VRF resources may change ahead of general availability.
15 |
16 | ## Example Usage
17 |
18 | Look up an IP address for a domain name, then use the IP to look up the containing IP block and run a device with IP address from the block:
19 |
20 | ```hcl
21 | data "dns_a_record_set" "www" {
22 | host = "www.example.com"
23 | }
24 |
25 | data "metal_reserved_ip_block" "www" {
26 | project_id = local.my_project_id
27 | address = data.dns_a_record_set.www.addrs[0]
28 | }
29 |
30 | resource "metal_device" "www" {
31 | project_id = local.my_project_id
32 | [...]
33 | ip_address {
34 | type = "public_ipv4"
35 | reservation_ids = [data.metal_reserved_ip_block.www.id]
36 | }
37 | }
38 | ```
39 |
40 | ## Argument Reference
41 |
42 | * `id` - (Optional) UUID of the IP address block to look up
43 | * `project_id` - (Optional) UUID of the project where the searched block should be
44 | * `ip_address` - (Optional) Block containing this IP address will be returned
45 |
46 | -> **NOTE:** You should pass either `id`, or both `project_id` and `ip_address`.
47 |
48 | ## Attributes Reference
49 |
50 | This datasource exposes the same attributes as the [metal_reserved_ip_block resource](../resources/reserved_ip_block.md), with the following differences:
51 |
52 | * `type` - One of `global_ipv4`, `public_ipv4`, `private_ipv4`, `public_ipv6`,or `vrf`
53 |
--------------------------------------------------------------------------------
/docs/data-sources/hardware_reservation.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_hardware_reservation"
3 | subcategory: ""
4 | description: |-
5 | Retrieve Equinix Metal Hardware Reservation
6 | ---
7 |
8 | # metal_hardware_reservation (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_hardware_reservation`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_hardware_reservation) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_hardware_reservation`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to retrieve a [hardware reservation resource from Equinix Metal](https://metal.equinix.com/developers/docs/deploy/reserved/).
13 |
14 | You can look up hardware reservation by its ID or by ID of device which occupies it.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 | // lookup by ID
20 | data "hardware_reservation" "example" {
21 | id = "4347e805-eb46-4699-9eb9-5c116e6a0172"
22 | }
23 |
24 | // lookup by device ID
25 | data "hardware_reservation" "example_by_device_id" {
26 | device_id = "ff85aa58-c106-4624-8f1c-7c64554047ea"
27 | }
28 | ```
29 |
30 | ## Argument Reference
31 |
32 | * `id` - ID of the hardware reservation
33 | * `device_id` - UUID of device occupying the reservation
34 |
35 | ## Attributes Reference
36 |
37 | * `id` - ID of the hardware reservation to look up
38 | * `short_id` - Reservation short ID
39 | * `project_id` - UUID of project this reservation is scoped to
40 | * `device_id` - UUID of device occupying the reservation
41 | * `plan` - Plan type for the reservation
42 | * `facility` - Plan type for the reservation
43 | * `provisionable` - Flag indicating whether the reserved server is provisionable or not. Spare devices can't be provisioned unless they are activated first
44 | * `spare` - Flag indicating whether the Hardware Reservation is a spare. Spare Hardware Reservations are used when a Hardware Reservations requires service from Metal Equinix
45 | * `switch_uuid` - Switch short ID, can be used to determine if two devices are connected to the same switch
46 |
--------------------------------------------------------------------------------
/docs/data-sources/vlan.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_vlan"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal Virtual Network datasource. This can be used to read the attributes of existing VLANs.
6 | ---
7 |
8 | # metal_vlan (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_vlan`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_vlan) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_vlan`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal Virtual Network datasource. VLANs data sources can be
13 | searched by VLAN UUID, or project UUID and vxlan number.
14 |
15 | ## Example Usage
16 |
17 | Fetch a vlan by ID:
18 |
19 | ```hcl
20 | resource "metal_vlan" "foovlan" {
21 | project_id = local.project_id
22 | metro = "sv"
23 | vxlan = 5
24 | }
25 |
26 | data "metal_vlan" "dsvlan" {
27 | vlan_id = metal_vlan.foovlan.id
28 | }
29 | ```
30 |
31 | Fetch a vlan by project ID, vxlan and metro
32 |
33 | ```hcl
34 | resource "metal_vlan" "foovlan" {
35 | project_id = local.project_id
36 | metro = "sv"
37 | vxlan = 5
38 | }
39 |
40 | data "metal_vlan" "dsvlan" {
41 | project_id = local.project_id
42 | vxlan = 5
43 | metro = "sv"
44 | }
45 | ```
46 |
47 | ## Argument Reference
48 |
49 | The following arguments are supported:
50 |
51 | * `vlan_id` - Metal UUID of the VLAN resource to look up
52 | * `project_id` - UUID of parent project of the VLAN. Use together with the vxlan number and metro or facility
53 | * `vxlan` - vxlan number of the VLAN to look up. Use together with the project_id and metro or facility
54 | * `facility` - Facility where the VLAN is deployed
55 | * `metro` - Metro where the VLAN is deployed
56 |
57 | ## Attributes Reference
58 |
59 | The following attributes are exported, in addition to any unspecified arguments.
60 |
61 | * `description` - Description text of the VLAN resource
62 | * `assigned_devices_ids` - List of device ID to which this VLAN is assigned
63 |
--------------------------------------------------------------------------------
/metal/datasource_metal_spot_market_price.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7 | "github.com/packethost/packngo"
8 | )
9 |
10 | func dataSourceSpotMarketPrice() *schema.Resource {
11 | return &schema.Resource{
12 | DeprecationMessage: deprecatedProviderMsg,
13 | Read: dataSourceMetalSpotMarketPriceRead,
14 | Schema: map[string]*schema.Schema{
15 | "facility": {
16 | Type: schema.TypeString,
17 | Description: "Name of the facility",
18 | ConflictsWith: []string{"metro"},
19 | Optional: true,
20 | },
21 | "metro": {
22 | Type: schema.TypeString,
23 | Description: "Name of the metro",
24 | ConflictsWith: []string{"facility"},
25 | Optional: true,
26 | StateFunc: toLower,
27 | },
28 | "plan": {
29 | Type: schema.TypeString,
30 | Description: "Name of the plan",
31 | Required: true,
32 | },
33 | "price": {
34 | Type: schema.TypeFloat,
35 | Description: "Current spot market price for given plan in given facility",
36 | Computed: true,
37 | },
38 | },
39 | }
40 | }
41 |
42 | func dataSourceMetalSpotMarketPriceRead(d *schema.ResourceData, meta interface{}) error {
43 | client := meta.(*packngo.Client)
44 | sms := client.SpotMarket.(*packngo.SpotMarketServiceOp)
45 | facility := d.Get("facility").(string)
46 | metro := d.Get("metro").(string)
47 | plan := d.Get("plan").(string)
48 |
49 | if facility != "" && metro != "" {
50 | return fmt.Errorf("Parameters facility and metro cannot be used together")
51 | }
52 |
53 | filter := facility
54 | fn := sms.PricesByFacility
55 | filterType := "facility"
56 |
57 | if metro != "" {
58 | filter = metro
59 | fn = sms.PricesByMetro
60 | filterType = "metro"
61 | }
62 |
63 | prices, _, err := fn()
64 | if err != nil {
65 | return err
66 | }
67 |
68 | match, ok := prices[filter]
69 | if !ok {
70 | return fmt.Errorf("Cannot find %s %s", filterType, filter)
71 | }
72 |
73 | price, ok := match[plan]
74 | if !ok {
75 | return fmt.Errorf("Cannot find price for plan %s in %s %s", plan, filterType, filter)
76 | }
77 |
78 | d.Set("price", price)
79 | d.SetId(fmt.Sprintf("%s-%s-%s", filterType, filter, plan))
80 | return nil
81 | }
82 |
--------------------------------------------------------------------------------
/metal/datasource_metal_organization_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | "github.com/packethost/packngo"
10 | )
11 |
12 | func TestAccOrgDataSource_Basic(t *testing.T) {
13 | var org packngo.Organization
14 | rInt := acctest.RandInt()
15 |
16 | resource.ParallelTest(t, resource.TestCase{
17 | PreCheck: func() { testAccPreCheck(t) },
18 | Providers: testAccProviders,
19 | CheckDestroy: testAccCheckMetalOrgDestroy,
20 | Steps: []resource.TestStep{
21 | {
22 | Config: testAccCheckMetalOrgDataSourceConfigBasic(rInt),
23 | Check: resource.ComposeTestCheckFunc(
24 | testAccCheckMetalOrgExists("metal_organization.test", &org),
25 | resource.TestCheckResourceAttr(
26 | "metal_organization.test", "name",
27 | fmt.Sprintf("tfacc-org-datasource-%d", rInt)),
28 | resource.TestCheckResourceAttr(
29 | "metal_organization.test", "description", "quux"),
30 | resource.TestCheckResourceAttr(
31 | "data.metal_organization.test", "name",
32 | fmt.Sprintf("tfacc-org-datasource-%d", rInt)),
33 | resource.TestCheckResourceAttrPair(
34 | "metal_organization.test", "address.0.address",
35 | "data.metal_organization.test", "address.0.address",
36 | ),
37 | resource.TestCheckResourceAttrPair(
38 | "metal_organization.test", "address.0.city",
39 | "data.metal_organization.test", "address.0.city",
40 | ),
41 | resource.TestCheckResourceAttrPair(
42 | "metal_organization.test", "address.0.country",
43 | "data.metal_organization.test", "address.0.country",
44 | ),
45 | resource.TestCheckResourceAttrPair(
46 | "metal_organization.test", "address.0.zip_code",
47 | "data.metal_organization.test", "address.0.zip_code",
48 | ),
49 | ),
50 | },
51 | },
52 | })
53 | }
54 |
55 | func testAccCheckMetalOrgDataSourceConfigBasic(r int) string {
56 | return fmt.Sprintf(`
57 | resource "metal_organization" "test" {
58 | name = "tfacc-org-datasource-%d"
59 | description = "quux"
60 | address {
61 | address = "tfacc org street"
62 | city = "london"
63 | zip_code = "12345"
64 | country = "GB"
65 | }
66 | }
67 |
68 | data "metal_organization" "test" {
69 | organization_id = metal_organization.test.id
70 | }
71 |
72 | `, r)
73 | }
74 |
--------------------------------------------------------------------------------
/docs/data-sources/project.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_project"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal Project datasource.
6 | ---
7 |
8 | # metal_project (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_project`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_project) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_project`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this datasource to retrieve attributes of the Project API resource.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | # Get Project by name and print UUIDs of its users
18 | data "metal_project" "tf_project_1" {
19 | name = "Terraform Fun"
20 | }
21 |
22 | output "users_of_Terraform_Fun" {
23 | value = data.metal_project.tf_project_1.user_ids
24 | }
25 | ```
26 |
27 | ## Argument Reference
28 |
29 | The following arguments are supported:
30 |
31 | * `name` - The name which is used to look up the project
32 | * `project_id` - The UUID by which to look up the project
33 |
34 | ## Attributes Reference
35 |
36 | The following attributes are exported:
37 |
38 | * `payment_method_id` - The UUID of payment method for this project
39 | * `organization_id` - The UUID of this project's parent organization
40 | * `backend_transfer` - Whether Backend Transfer is enabled for this project
41 | * `created` - The timestamp for when the project was created
42 | * `updated` - The timestamp for the last time the project was updated
43 | * `user_ids` - List of UUIDs of user accounts which belong to this project
44 | * `bgp_config` - Optional BGP settings. Refer to [Equinix Metal guide for BGP](https://metal.equinix.com/developers/docs/networking/local-global-bgp/).
45 |
46 | The `bgp_config` block contains:
47 |
48 | * `asn` - Autonomous System Number for local BGP deployment
49 | * `md5` - Password for BGP session in plaintext (not a checksum)
50 | * `deployment_type` - `private` or `public`, the `private` is likely to be usable immediately, the `public` will need to be review by Equinix Metal engineers
51 | * `status` - status of BGP configuration in the project
52 | * `max_prefix` - The maximum number of route filters allowed per server
53 |
--------------------------------------------------------------------------------
/docs/resources/device_network_type.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: "metal"
3 | page_title: "Equinix Metal: metal_device_network_type"
4 | sidebar_current: "docs-metal-resource-device-network-type"
5 | description: |-
6 | Provides a resource to manage network type of Equinix Metal devices.
7 | ---
8 |
9 | # metal_device_network_type (Resource)
10 |
11 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_device_network_type`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_device_network_type) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_device_network_type`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
12 |
13 | This resource controls network type of Equinix Metal devices.
14 |
15 | To learn more about Layer 2 networking in Equinix Metal, refer to
16 |
17 | *
18 | *
19 |
20 | If you are attaching VLAN to a device (i.e. using metal_port_vlan_attachment), link the device ID from this resource, in order to make the port attachment implicitly dependent on the state of the network type. If you link the device ID from the metal_device resource, Terraform will not wait for the network type change. See examples in [metal_port_vlan_attachment](port_vlan_attachment).
21 |
22 | ## Example Usage
23 |
24 | See the [Network Types Guide](../guides/network_types.md) for examples of this resource and to learn about the recommended `metal_port` alternative.
25 |
26 | ## Import
27 |
28 | This resource can also be imported using existing device ID:
29 |
30 | ```sh
31 | terraform import metal_device_network_type {existing device_id}
32 | ```
33 |
34 | ## Argument Reference
35 |
36 | The following arguments are supported:
37 |
38 | * `device_id` - (Required) The ID of the device on which the network type should be set.
39 | * `type` - (Required) Network type to set. Must be one of `layer3`, `hybrid`, `layer2-individual` and `layer2-bonded`.
40 |
41 | ## Attributes Reference
42 |
43 | The following attributes are exported:
44 |
45 | * `id` - ID of the controlled device. Use this in linked resources, if you need to wait for the network type change. It is the same as `device_id`.
46 |
--------------------------------------------------------------------------------
/metal/datasource_metal_metro_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8 | )
9 |
10 | func TestAccDataSourceMetro_Basic(t *testing.T) {
11 | testMetro := "da"
12 | resource.ParallelTest(t, resource.TestCase{
13 | PreCheck: func() { testAccPreCheck(t) },
14 | Providers: testAccProviders,
15 | Steps: []resource.TestStep{
16 | {
17 | Config: testAccDataSourceMetroConfigBasic(testMetro),
18 | Check: resource.ComposeTestCheckFunc(
19 | resource.TestCheckResourceAttr(
20 | "data.metal_metro.test", "code", testMetro),
21 | ),
22 | },
23 | {
24 | Config: testAccDataSourceMetroConfigCapacityReasonable(testMetro),
25 | Check: resource.ComposeTestCheckFunc(
26 | resource.TestCheckResourceAttr(
27 | "data.metal_metro.test", "code", testMetro),
28 | ),
29 | },
30 | {
31 | Config: testAccDataSourceMetroConfigCapacityUnreasonable(testMetro),
32 | ExpectError: matchErrNoCapacity,
33 | },
34 | {
35 | Config: testAccDataSourceMetroConfigCapacityUnreasonableMultiple(testMetro),
36 | ExpectError: matchErrNoCapacity,
37 | },
38 | },
39 | })
40 | }
41 |
42 | func testAccDataSourceMetroConfigBasic(facCode string) string {
43 | return fmt.Sprintf(`
44 | data "metal_metro" "test" {
45 | code = "%s"
46 | }
47 | `, facCode)
48 | }
49 |
50 | func testAccDataSourceMetroConfigCapacityUnreasonable(facCode string) string {
51 | return fmt.Sprintf(`
52 | data "metal_metro" "test" {
53 | code = "%s"
54 | capacity {
55 | plan = "c3.small.x86"
56 | quantity = 1000
57 | }
58 | }
59 | `, facCode)
60 | }
61 |
62 | func testAccDataSourceMetroConfigCapacityReasonable(facCode string) string {
63 | return fmt.Sprintf(`
64 | data "metal_metro" "test" {
65 | code = "%s"
66 | capacity {
67 | plan = "c3.small.x86"
68 | quantity = 1
69 | }
70 | capacity {
71 | plan = "c3.medium.x86"
72 | quantity = 1
73 | }
74 | }
75 | `, facCode)
76 | }
77 |
78 | func testAccDataSourceMetroConfigCapacityUnreasonableMultiple(facCode string) string {
79 | return fmt.Sprintf(`
80 | data "metal_metro" "test" {
81 | code = "%s"
82 | capacity {
83 | plan = "c3.small.x86"
84 | quantity = 1
85 | }
86 | capacity {
87 | plan = "c3.medium.x86"
88 | quantity = 1000
89 | }
90 | }
91 | `, facCode)
92 | }
93 |
--------------------------------------------------------------------------------
/metal/datasource_metal_volume.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | )
6 |
7 | func dataSourceMetalVolume() *schema.Resource {
8 | return &schema.Resource{
9 | Read: removedResourceOp(dataSourceVolumeRemovedMsg),
10 | DeprecationMessage: "Volumes are deprecated, see https://metal.equinix.com/developers/docs/resilience-recovery/elastic-block-storage/#elastic-block-storage",
11 | Schema: map[string]*schema.Schema{
12 | "name": {
13 | Type: schema.TypeString,
14 | Optional: true,
15 | Computed: true,
16 | ConflictsWith: []string{"volume_id"},
17 | },
18 | "project_id": {
19 | Type: schema.TypeString,
20 | Optional: true,
21 | Computed: true,
22 | ConflictsWith: []string{"volume_id"},
23 | },
24 | "volume_id": {
25 | Type: schema.TypeString,
26 | Optional: true,
27 | Computed: true,
28 | ConflictsWith: []string{"project_id", "name"},
29 | },
30 | "description": {
31 | Type: schema.TypeString,
32 | Computed: true,
33 | },
34 | "size": {
35 | Type: schema.TypeInt,
36 | Computed: true,
37 | },
38 |
39 | "facility": {
40 | Type: schema.TypeString,
41 | Computed: true,
42 | },
43 |
44 | "plan": {
45 | Type: schema.TypeString,
46 | Computed: true,
47 | },
48 |
49 | "billing_cycle": {
50 | Type: schema.TypeString,
51 | Computed: true,
52 | },
53 |
54 | "state": {
55 | Type: schema.TypeString,
56 | Computed: true,
57 | },
58 |
59 | "locked": {
60 | Type: schema.TypeBool,
61 | Computed: true,
62 | },
63 |
64 | "snapshot_policies": {
65 | Type: schema.TypeList,
66 | Computed: true,
67 | Elem: &schema.Resource{
68 | Schema: map[string]*schema.Schema{
69 | "snapshot_frequency": {
70 | Type: schema.TypeString,
71 | Computed: true,
72 | },
73 | "snapshot_count": {
74 | Type: schema.TypeInt,
75 | Computed: true,
76 | },
77 | },
78 | },
79 | },
80 |
81 | "device_ids": {
82 | Type: schema.TypeList,
83 | Computed: true,
84 | Elem: &schema.Schema{Type: schema.TypeString},
85 | },
86 |
87 | "created": {
88 | Type: schema.TypeString,
89 | Computed: true,
90 | },
91 |
92 | "updated": {
93 | Type: schema.TypeString,
94 | Computed: true,
95 | },
96 | },
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/metal/internal/datalist/sort.go:
--------------------------------------------------------------------------------
1 | package datalist
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
6 | "sort"
7 | "strings"
8 | )
9 |
10 | var (
11 | sortAttributes = []string{"asc", "desc"}
12 | )
13 |
14 | type commonSort struct {
15 | attribute string
16 | direction string
17 | }
18 |
19 | func sortSchema(allowedAttributes []string) *schema.Schema {
20 | return &schema.Schema{
21 | Type: schema.TypeList,
22 | Elem: &schema.Resource{
23 | Schema: map[string]*schema.Schema{
24 | "attribute": {
25 | Type: schema.TypeString,
26 | Description: "The attribute used to sort the results. Sort attributes are case-sensitive",
27 | Required: true,
28 | ValidateFunc: validation.StringInSlice(allowedAttributes, false),
29 | },
30 | "direction": {
31 | Type: schema.TypeString,
32 | Description: "Sort results in ascending or descending order. Strings are sorted in alphabetical order. One of: asc, desc",
33 | Optional: true,
34 | ValidateFunc: validation.StringInSlice(sortAttributes, false),
35 | },
36 | },
37 | },
38 | Optional: true,
39 | Description: "One or more attribute/direction pairs on which to sort results. If multiple sorts are provided, they will be applied in order",
40 | }
41 | }
42 |
43 | func expandSorts(rawSorts []interface{}) []commonSort {
44 | expandedSorts := make([]commonSort, len(rawSorts))
45 | for i, rawSort := range rawSorts {
46 | f := rawSort.(map[string]interface{})
47 |
48 | expandedSort := commonSort{
49 | attribute: f["attribute"].(string),
50 | direction: f["direction"].(string),
51 | }
52 |
53 | expandedSorts[i] = expandedSort
54 | }
55 | return expandedSorts
56 | }
57 |
58 | func applySorts(recordSchema map[string]*schema.Schema, records []map[string]interface{}, sorts []commonSort) []map[string]interface{} {
59 | sort.Slice(records, func(_i, _j int) bool {
60 | for _, s := range sorts {
61 | // Handle multiple sorts by applying them in order
62 | i := _i
63 | j := _j
64 | if strings.EqualFold(s.direction, "desc") {
65 | // If the direction is desc, reverse index to compare
66 | i = _j
67 | j = _i
68 | }
69 |
70 | value1 := records[i]
71 | value2 := records[j]
72 | cmp := compareValues(recordSchema[s.attribute], value1[s.attribute], value2[s.attribute])
73 | if cmp != 0 {
74 | return cmp < 0
75 | }
76 | }
77 |
78 | return true
79 | })
80 |
81 | return records
82 | }
83 |
--------------------------------------------------------------------------------
/docs/data-sources/device_bgp_neighbors.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_device_bgp_neighbors"
3 | subcategory: ""
4 | description: |-
5 | Provides a datasource for listing BGP neighbors of an Equinix Metal device
6 | ---
7 |
8 | # metal_device_bgp_neighbors (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_device_bgp_neighbors`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_device_bgp_neighbors) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_device_bgp_neighbors`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this datasource to retrieve list of BGP neighbors of a device in the Equinix Metal host.
13 |
14 | To have any BGP neighbors listed, the device must be in [BGP-enabled project](../r/project.html) and have a [BGP session](../r/bgp_session.html) assigned.
15 |
16 | To learn more about using BGP in Equinix Metal, see the [metal_bgp_session](../r/bgp_session.html) resource documentation.
17 |
18 | ## Example Usage
19 |
20 | ```hcl
21 | # Get Project by name and print UUIDs of its users
22 |
23 | data "metal_device_bgp_neighbors" "test" {
24 | device_id = "4c641195-25e5-4c3c-b2b7-4cd7a42c7b40"
25 | }
26 |
27 | output "bgp_neighbors_listing" {
28 | value = data.metal_device_bgp_neighbors.test.bgp_neighbors
29 | }
30 | ```
31 |
32 | ## Argument Reference
33 |
34 | The following arguments are supported:
35 |
36 | * `device_id` - UUID of BGP-enabled device whose neighbors to list
37 |
38 | ## Attributes Reference
39 |
40 | The following attributes are exported:
41 |
42 | * `bgp_neighbors` - array of BGP neighbor records with attributes:
43 | * `address_family` - IP address version, 4 or 6
44 | * `customer_as` - Local autonomous system number
45 | * `customer_ip` - Local used peer IP address
46 | * `md5_enabled` - Whether BGP session is password enabled
47 | * `md5_password` - BGP session password in plaintext (not a checksum)
48 | * `multihop` - Whether the neighbor is in EBGP multihop session
49 | * `peer_as` - Peer AS number (different than customer_as for EBGP)
50 | * `peer_ips` - Array of IP addresses of this neighbor's peers
51 | * `routes_in` - Array of incoming routes. Each route has attributes:
52 | * `route` - CIDR expression of route (IP/mask)
53 | * `exact` - (bool) Whether the route is exact
54 | * `routes_out` - Array of outgoing routes in the same format
55 |
--------------------------------------------------------------------------------
/docs/resources/ssh_key.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_ssh_key"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal SSH key resource.
6 | ---
7 |
8 | # metal_ssh_key (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_ssh_key`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_ssh_key) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_ssh_key`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides a resource to manage User SSH keys on your Equinix Metal user account. If you create a new device in a project, all the keys of the project's collaborators will be injected to the device.
13 |
14 | The link between User SSH key and device is implicit. If you want to make sure that a key will be copied to a device, you must ensure that the device resource `depends_on` the key resource.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 | # Create a new SSH key
20 | resource "metal_ssh_key" "key1" {
21 | name = "terraform-1"
22 | public_key = file("/home/terraform/.ssh/id_rsa.pub")
23 | }
24 |
25 | # Create new device with "key1" included. The device resource "depends_on" the
26 | # key, in order to make sure the key is created before the device.
27 | resource "metal_device" "test" {
28 | hostname = "test-device"
29 | plan = "c3.small.x86"
30 | metro = "sv"
31 | operating_system = "ubuntu_20_04"
32 | billing_cycle = "hourly"
33 | project_id = local.project_id
34 | depends_on = ["metal_ssh_key.key1"]
35 | }
36 | ```
37 |
38 | ## Argument Reference
39 |
40 | The following arguments are supported:
41 |
42 | * `name` - (Required) The name of the SSH key for identification
43 | * `public_key` - (Required) The public key. If this is a file, it
44 | can be read using the file interpolation function
45 |
46 | ## Attributes Reference
47 |
48 | In addition to all arguments above, the following attributes are exported:
49 |
50 | * `id` - The unique ID of the key
51 | * `fingerprint` - The fingerprint of the SSH key
52 | * `owner_id` - The UUID of the Equinix Metal API User who owns this key
53 | * `created` - The timestamp for when the SSH key was created
54 | * `updated` - The timestamp for the last time the SSH key was updated
55 |
56 | ## Import
57 |
58 | This resource can be imported using an existing SSH Key ID:
59 |
60 | ```sh
61 | terraform import metal_ssh_key {existing_sshkey_id}
62 | ```
63 |
--------------------------------------------------------------------------------
/docs/resources/gateway.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: Metal Gateway"
3 | subcategory: ""
4 | description: |-
5 | Create Equinix Metal Gateways
6 | ---
7 |
8 | # metal_gateway (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_gateway`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_gateway) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_gateway`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this resource to create Metal Gateway resources in Equinix Metal.
13 |
14 | ~> VRF features are not generally available. The interfaces related to VRF resources may change ahead of general availability.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 | # Create Metal Gateway for a VLAN with a private IPv4 block with 8 IP addresses
20 |
21 | resource "metal_vlan" "test" {
22 | description = "test VLAN in SV"
23 | metro = "sv"
24 | project_id = local.project_id
25 | }
26 |
27 | resource "metal_gateway" "test" {
28 | project_id = local.project_id
29 | vlan_id = metal_vlan.test.id
30 | private_ipv4_subnet_size = 8
31 | }
32 | ```
33 |
34 | ```hcl
35 | # Create Metal Gateway for a VLAN and reserved IP address block
36 |
37 | resource "metal_vlan" "test" {
38 | description = "test VLAN in SV"
39 | metro = "sv"
40 | project_id = local.project_id
41 | }
42 |
43 | resource "metal_reserved_ip_block" "test" {
44 | project_id = local.project_id
45 | metro = "sv"
46 | quantity = 2
47 | }
48 |
49 | resource "metal_gateway" "test" {
50 | project_id = local.project_id
51 | vlan_id = metal_vlan.test.id
52 | ip_reservation_id = metal_reserved_ip_block.test.id
53 | }
54 | ```
55 |
56 | ## Argument Reference
57 |
58 | * `project_id` - (Required) UUID of the project where the gateway is scoped to.
59 | * `vlan_id` - (Required) UUID of the VLAN where the gateway is scoped to.
60 | * `ip_reservation_id` - (Optional) UUID of Public or VRF IP Reservation to associate with the gateway, the reservation must be in the same metro as the VLAN, conflicts with `private_ipv4_subnet_size`.
61 | * `private_ipv4_subnet_size` - (Optional) Size of the private IPv4 subnet to create for this metal gateway, must be one of (8, 16, 32, 64, 128), conflicts with `ip_reservation_id`.
62 |
63 | ## Attributes Reference
64 |
65 | * `state` - Status of the gateway resource.
66 | * `vrf_id` - UUID of the VRF associated with the IP Reservation.
67 |
--------------------------------------------------------------------------------
/docs/data-sources/ip_block_ranges.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: ip_block_ranges"
3 | subcategory: ""
4 | description: |-
5 | List IP address ranges allocated to a project
6 | ---
7 |
8 | # metal_ip_block_ranges (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_ip_block_ranges`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_ip_block_ranges) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_ip_block_ranges`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this datasource to get CIDR expressions for allocated IP blocks of all the types in a project, optionally filtered by facility or metro.
13 |
14 | There are four types of IP blocks in Equinix Metal: global IPv4, public IPv4, private IPv4 and IPv6. Both global and public IPv4 are routable from the Internet. Public IPv4 blocks are allocated in a facility or metro, and addresses from it can only be assigned to devices in that location. Addresses from Global IPv4 block can be assigned to a device in any metro.
15 |
16 | The datasource has 4 list attributes: `global_ipv4`, `public_ipv4`, `private_ipv4` and `ipv6`, each listing CIDR notation (`/`) of respective blocks from the project.
17 |
18 | ## Example Usage
19 |
20 | ```hcl
21 | # List CIDR expressions of all the allocated IP block in you project.
22 |
23 | # Declare your project ID
24 | locals {
25 | project_id = ""
26 | }
27 |
28 | data "metal_ip_block_ranges" "test" {
29 | project_id = local.project_id
30 | }
31 |
32 | output "out" {
33 | value = data.metal_ip_block_ranges.test
34 | }
35 | ```
36 |
37 | ## Argument Reference
38 |
39 | * `project_id` - (Required) ID of the project from which to list the blocks.
40 | * `facility` - (Optional) Facility code filtering the IP blocks. Global IPv4 blcoks will be listed anyway. If you omit this and metro, all the block from the project will be listed.
41 | * `metro` - (Optional) Metro code filtering the IP blocks. Global IPv4 blcoks will be listed anyway. If you omit this and facility, all the block from the project will be listed.
42 |
43 | ## Attributes Reference
44 |
45 | * `global_ipv4` - list of CIDR expressions for Global IPv4 blocks in the project
46 | * `public_ipv4` - list of CIDR expressions for Public IPv4 blocks in the project
47 | * `private_ipv4` - list of CIDR expressions for Private IPv4 blocks in the project
48 | * `ipv6` - list of CIDR expressions for IPv6 blocks in the project
49 |
--------------------------------------------------------------------------------
/docs/data-sources/precreated_ip_block.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: precreated_ip_block"
3 | subcategory: ""
4 | description: |-
5 | Load automatically created IP blocks from your Equinix Metal project
6 | ---
7 |
8 | # metal_precreated_ip_block (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_precreated_ip_block`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_precreated_ip_block) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_precreated_ip_block`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to get CIDR expression for precreated IPv6 and IPv4 blocks in Equinix Metal.
13 | You can then use the cidrsubnet TF builtin function to derive subnets.
14 |
15 | ## Example Usage
16 |
17 | ```hcl
18 | # Create device in your project and then assign /64 subnet from precreated block
19 | # to the new device
20 |
21 | # Declare your project ID
22 | locals {
23 | project_id = ""
24 | }
25 |
26 | resource "metal_device" "web1" {
27 | hostname = "web1"
28 | plan = "c3.small.x86"
29 | metro = "sv"
30 | operating_system = "ubuntu_20_04"
31 | billing_cycle = "hourly"
32 | project_id = local.project_id
33 |
34 | }
35 |
36 | data "metal_precreated_ip_block" "test" {
37 | metro = "sv"
38 | project_id = local.project_id
39 | address_family = 6
40 | public = true
41 | }
42 |
43 | # The precreated IPv6 blocks are /56, so to get /64, we specify 8 more bits for network.
44 | # The cirdsubnet interpolation will pick second /64 subnet from the precreated block.
45 |
46 | resource "metal_ip_attachment" "from_ipv6_block" {
47 | device_id = metal_device.web1.id
48 | cidr_notation = cidrsubnet(data.metal_precreated_ip_block.test.cidr_notation, 8, 2)
49 | }
50 | ```
51 |
52 | ## Argument Reference
53 |
54 | * `project_id` - (Required) ID of the project where the searched block should be.
55 | * `address_family` - (Required) 4 or 6, depending on which block you are looking for.
56 | * `public` - (Required) Whether to look for public or private block.
57 | * `global` - (Optional) Whether to look for global block. Default is false for backward compatibility.
58 | * `facility` - (Optional) Facility of the searched block. (for non-global blocks).
59 | * `metro` - (Optional) Metro of the searched block (for non-global blocks).
60 |
61 | ## Attributes Reference
62 |
63 | * `cidr_notation` - CIDR notation of the looked up block.
64 |
--------------------------------------------------------------------------------
/docs/resources/port.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_port"
3 | subcategory: ""
4 | description: |-
5 | Manipulate device ports
6 | ---
7 |
8 | # metal_port (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_port`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_port) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_port`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this resource to set up network ports on an Equnix Metal device. This resource can control both physical and bond ports.
13 |
14 | This Terraform resource doesn't create an API resource in Equinix Metal, but rather provides finer control for [`Layer 2 networking`](https://metal.equinix.com/developers/docs/layer2-networking/).
15 |
16 | The port resource referred is created together with device and accessible either via the device resource or over `/port/` API path.
17 |
18 | ## Example Usage
19 |
20 | See the [Network Types Guide](../guides/network_types.md) for examples of this resource.
21 |
22 | ## Argument Reference
23 |
24 | * `port_id` - (Required) ID of the port to read
25 | * `bonded` - (Required) Whether the port should be bonded
26 | * `layer2` - (Optional) Whether to put the port to Layer 2 mode, valid only for bond ports
27 | * `vlan_ids` - (Optional) List of VLAN UUIDs to attach to the port, valid only for L2 and Hybrid ports
28 | * `vxlan_ids` - (Optional) List of VXLAN IDs to attach to the port, valid only for L2 and Hybrid ports
29 | * `native_vlan_id` - (Optional) UUID of a VLAN to assign as a native VLAN. It must be one of attached VLANs (from `vlan_ids` parameter), valid only for physical (non-bond) ports
30 | * `reset_on_delete` - (Optional) Behavioral setting to reset the port to default settings. For a bond port it means layer3 without vlans attached, eth ports will be bonded without native vlan and vlans attached
31 |
32 | ## Attributes Reference
33 |
34 | * `name` - Name of the port, e.g. `bond0` or `eth0`
35 | * `network_type` - One of layer2-bonded, layer2-individual, layer3, hybrid and hybrid-bonded. This attribute is only set on bond ports.
36 | * `type` - Type is either "NetworkBondPort" for bond ports or "NetworkPort" for bondable ethernet ports
37 | * `mac` - MAC address of the port
38 | * `bond_id` - UUID of the bond port
39 | * `bond_name` - Name of the bond port
40 | * `bonded` - Flag indicating whether the port is bonded
41 | * `disbond_supported` - Flag indicating whether the port can be removed from a bond
42 | * `vlan_ids` - List of VLAN UUIDs to attach to the port
43 | * `vxlan_ids` - List of VXLAN IDs to attach to the port
44 |
45 |
--------------------------------------------------------------------------------
/metal/resource_metal_user_api_key_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "strings"
8 |
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
11 | "github.com/packethost/packngo"
12 | )
13 |
14 | func init() {
15 | resource.AddTestSweepers("metal_user_api_key", &resource.Sweeper{
16 | Name: "metal_user_api_key",
17 | F: testSweepUserAPIKeys,
18 | })
19 | }
20 |
21 | // Will remove all User API keys with Description starting with "tfacc-"
22 | func testSweepUserAPIKeys(region string) error {
23 | log.Printf("[DEBUG] Sweeping user_api keys")
24 | meta, err := sharedConfigForRegion(region)
25 | if err != nil {
26 | return fmt.Errorf("Error getting client for sweeping user_api keys: %s", err)
27 | }
28 | client := meta.(*packngo.Client)
29 |
30 | userApiKeys, _, err := client.APIKeys.UserList(nil)
31 | if err != nil {
32 | return fmt.Errorf("Error getting list for sweeping user_api keys: %s", err)
33 | }
34 | ids := []string{}
35 | for _, k := range userApiKeys {
36 | if strings.HasPrefix(k.Description, "tfacc-") {
37 | ids = append(ids, k.ID)
38 | }
39 | }
40 | for _, id := range ids {
41 | log.Printf("Removing user api key %s", id)
42 | resp, err := client.APIKeys.Delete(id)
43 | if err != nil && resp.StatusCode != http.StatusNotFound {
44 | return fmt.Errorf("Error deleting user_api key %s", err)
45 | }
46 | }
47 | return nil
48 | }
49 |
50 | func testAccMetalUserAPIKeyDestroy(s *terraform.State) error {
51 | client := testAccProvider.Meta().(*packngo.Client)
52 | for _, rs := range s.RootModule().Resources {
53 | if rs.Type != "metal_user_api_key" {
54 | continue
55 | }
56 | if _, err := client.APIKeys.UserGet(rs.Primary.ID, nil); err == nil {
57 | return fmt.Errorf("UserAPI key still exists")
58 | }
59 | }
60 | return nil
61 | }
62 |
63 | func testAccMetalUserAPIKeyConfig_Basic() string {
64 | return fmt.Sprintf(`
65 | resource "metal_user_api_key" "test" {
66 | description = "tfacc-user-key"
67 | read_only = true
68 | }`)
69 | }
70 |
71 | // Commented out because it lists existing user API keys in debug log
72 |
73 | /*
74 |
75 | func TestAccMetalUserAPIKey_Basic(t *testing.T) {
76 | resource.ParallelTest(t, resource.TestCase{
77 | PreCheck: func() { testAccPreCheck(t) },
78 | Providers: testAccProviders,
79 | CheckDestroy: testAccMetalUserAPIKeyDestroy,
80 | Steps: []resource.TestStep{
81 | {
82 | Config: testAccMetalUserAPIKeyConfig_Basic(),
83 | Check: resource.ComposeTestCheckFunc(
84 | resource.TestCheckResourceAttrSet(
85 | "metal_user_api_key.test", "token"),
86 | resource.TestCheckResourceAttrSet(
87 | "metal_user_api_key.test", "user_id"),
88 | ),
89 | },
90 | },
91 | })
92 | }
93 |
94 | */
95 |
--------------------------------------------------------------------------------
/metal/datasource_metal_port.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | )
6 |
7 | func dataSourceMetalPort() *schema.Resource {
8 | return &schema.Resource{
9 | DeprecationMessage: deprecatedProviderMsg,
10 | Read: resourceMetalPortRead,
11 | Schema: map[string]*schema.Schema{
12 | "port_id": {
13 | Type: schema.TypeString,
14 | Optional: true,
15 | Description: "UUID of the port to lookup",
16 | ConflictsWith: []string{"device_id", "name"},
17 | },
18 | "device_id": {
19 | Type: schema.TypeString,
20 | Optional: true,
21 | Description: "Device UUID where to lookup the port",
22 | ConflictsWith: []string{"port_id"},
23 | },
24 | "name": {
25 | Type: schema.TypeString,
26 | Optional: true,
27 | Computed: true,
28 | Description: "Name of the port to look up, e.g. bond0, eth1",
29 | ConflictsWith: []string{"port_id"},
30 | },
31 | "network_type": {
32 | Type: schema.TypeString,
33 | Computed: true,
34 | Description: "One of " + NetworkTypeListHB,
35 | },
36 | "type": {
37 | Type: schema.TypeString,
38 | Computed: true,
39 | Description: "Port type",
40 | },
41 | "mac": {
42 | Type: schema.TypeString,
43 | Computed: true,
44 | Description: "MAC address of the port",
45 | },
46 | "bond_id": {
47 | Type: schema.TypeString,
48 | Computed: true,
49 | Description: "UUID of the bond port",
50 | },
51 | "bond_name": {
52 | Type: schema.TypeString,
53 | Computed: true,
54 | Description: "Name of the bond port",
55 | },
56 | "bonded": {
57 | Type: schema.TypeBool,
58 | Computed: true,
59 | Description: "Flag indicating whether the port is bonded",
60 | },
61 | "disbond_supported": {
62 | Type: schema.TypeBool,
63 | Computed: true,
64 | Description: "Flag indicating whether the port can be removed from a bond",
65 | },
66 | "native_vlan_id": {
67 | Type: schema.TypeString,
68 | Computed: true,
69 | Description: "UUID of native VLAN of the port",
70 | },
71 | "vlan_ids": {
72 | Type: schema.TypeList,
73 | Computed: true,
74 | Description: "UUIDs of attached VLANs",
75 | Elem: &schema.Schema{Type: schema.TypeString},
76 | },
77 | "vxlan_ids": {
78 | Type: schema.TypeList,
79 | Computed: true,
80 | Description: "UUIDs of attached VLANs",
81 | Elem: &schema.Schema{Type: schema.TypeInt},
82 | },
83 | "layer2": {
84 | Type: schema.TypeBool,
85 | Computed: true,
86 | Description: "Flag indicating whether the port is in layer2 (or layer3) mode",
87 | },
88 | },
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/metal/datasource_metal_port_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | )
10 |
11 | func TestAccMetalPort_ByName(t *testing.T) {
12 |
13 | rs := acctest.RandString(10)
14 |
15 | resource.ParallelTest(t, resource.TestCase{
16 | PreCheck: func() { testAccPreCheck(t) },
17 | Providers: testAccProviders,
18 | Steps: []resource.TestStep{
19 | {
20 | Config: testPortConfig_ByName(rs),
21 | Check: resource.ComposeTestCheckFunc(
22 | resource.TestCheckResourceAttr(
23 | "data.metal_port.test", "bond_name", "bond0"),
24 | ),
25 | },
26 | },
27 | })
28 | }
29 |
30 | func testPortConfig_ByName(name string) string {
31 | return fmt.Sprintf(`
32 | %s
33 |
34 | resource "metal_project" "test" {
35 | name = "tfacc-pro-port-%s"
36 | }
37 |
38 | resource "metal_device" "test" {
39 | hostname = "tfacc-device-test-port"
40 | plan = local.plan
41 | metro = local.metro
42 | operating_system = "ubuntu_20_04"
43 | billing_cycle = "hourly"
44 | project_id = metal_project.test.id
45 |
46 | lifecycle {
47 | ignore_changes = [
48 | plan,
49 | metro,
50 | ]
51 | }
52 | }
53 |
54 | data "metal_port" "test" {
55 | device_id = metal_device.test.id
56 | name = "eth0"
57 | }`, confAccMetalDevice_base(preferable_plans, preferable_metros), name)
58 | }
59 |
60 | func TestAccMetalPort_ById(t *testing.T) {
61 |
62 | rs := acctest.RandString(10)
63 |
64 | resource.ParallelTest(t, resource.TestCase{
65 | PreCheck: func() { testAccPreCheck(t) },
66 | Providers: testAccProviders,
67 | Steps: []resource.TestStep{
68 | {
69 | Config: testPortConfig_ById(rs),
70 | Check: resource.ComposeTestCheckFunc(
71 | resource.TestCheckResourceAttrSet(
72 | "data.metal_port.test", "name"),
73 | ),
74 | },
75 | },
76 | })
77 | }
78 |
79 | func testPortConfig_ById(name string) string {
80 | return fmt.Sprintf(`
81 | %s
82 |
83 | resource "metal_project" "test" {
84 | name = "tfacc-pro-port-%s"
85 | }
86 |
87 | resource "metal_device" "test" {
88 | hostname = "tfacc-device-test-port"
89 | plan = local.plan
90 | metro = local.metro
91 | operating_system = "ubuntu_20_04"
92 | billing_cycle = "hourly"
93 | project_id = metal_project.test.id
94 |
95 | lifecycle {
96 | ignore_changes = [
97 | plan,
98 | metro,
99 | ]
100 | }
101 | }
102 |
103 | data "metal_port" "test" {
104 | port_id = metal_device.test.ports[0].id
105 | }
106 |
107 | `, confAccMetalDevice_base(preferable_plans, preferable_metros), name)
108 | }
109 |
--------------------------------------------------------------------------------
/metal/resource_metal_project_ssh_key_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10 | "github.com/packethost/packngo"
11 | )
12 |
13 | func metalProjectSSHKeyConfig_Basic(name, publicSshKey string) string {
14 | return fmt.Sprintf(`
15 | %s
16 |
17 | resource "metal_project" "test" {
18 | name = "tfacc-pro-project_ssh_key-%s"
19 | }
20 |
21 | resource "metal_project_ssh_key" "test" {
22 | name = "tfacc-pro-key-test"
23 | public_key = "%s"
24 | project_id = "${metal_project.test.id}"
25 | }
26 |
27 | resource "metal_device" "test" {
28 | hostname = "tfacc-device-test-key"
29 | plan = local.plan
30 | facilities = local.facilities
31 | operating_system = "ubuntu_16_04"
32 | billing_cycle = "hourly"
33 | project_ssh_key_ids = ["${metal_project_ssh_key.test.id}"]
34 | project_id = "${metal_project.test.id}"
35 |
36 | lifecycle {
37 | ignore_changes = [
38 | plan,
39 | facilities,
40 | ]
41 | }
42 | }
43 |
44 | `, confAccMetalDevice_base(preferable_plans, preferable_metros), name, publicSshKey)
45 | }
46 |
47 | func TestAccMetalProjectSSHKey_Basic(t *testing.T) {
48 | rs := acctest.RandString(10)
49 | var key packngo.SSHKey
50 | publicKeyMaterial, _, err := acctest.RandSSHKeyPair("")
51 | if err != nil {
52 | t.Fatalf("Cannot generate test SSH key pair: %s", err)
53 | }
54 | cfg := metalProjectSSHKeyConfig_Basic(rs, publicKeyMaterial)
55 |
56 | resource.ParallelTest(t, resource.TestCase{
57 | PreCheck: func() { testAccPreCheck(t) },
58 | Providers: testAccProviders,
59 | CheckDestroy: testAccCheckMetalProjectSSHKeyDestroy,
60 | Steps: []resource.TestStep{
61 | {
62 | Config: cfg,
63 | Check: resource.ComposeTestCheckFunc(
64 | testAccCheckMetalSSHKeyExists("metal_project_ssh_key.test", &key),
65 | resource.TestCheckResourceAttr(
66 | "metal_project_ssh_key.test", "public_key", publicKeyMaterial),
67 | resource.TestCheckResourceAttrPair(
68 | "metal_device.test", "ssh_key_ids.0",
69 | "metal_project_ssh_key.test", "id",
70 | ),
71 | resource.TestCheckResourceAttrPair(
72 | "metal_project.test", "id",
73 | "metal_project_ssh_key.test", "project_id",
74 | ),
75 | ),
76 | },
77 | },
78 | })
79 | }
80 |
81 | func testAccCheckMetalProjectSSHKeyDestroy(s *terraform.State) error {
82 | client := testAccProvider.Meta().(*packngo.Client)
83 |
84 | for _, rs := range s.RootModule().Resources {
85 | if rs.Type != "metal_project_ssh_key" {
86 | continue
87 | }
88 | if _, _, err := client.SSHKeys.Get(rs.Primary.ID, nil); err == nil {
89 | return fmt.Errorf("SSH key still exists")
90 | }
91 | }
92 |
93 | return nil
94 | }
95 |
--------------------------------------------------------------------------------
/docs/resources/ip_attachment.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_ip_attachment"
3 | subcategory: ""
4 | description: |-
5 | Provides a Resource for Attaching IP Subnets from a Reserved Block to a Device
6 | ---
7 |
8 | # metal_ip_attachment (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_ip_attachment`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_ip_attachment) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_ip_attachment`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides a resource to attach elastic IP subnets to devices.
13 |
14 | To attach an IP subnet from a reserved block to a provisioned device, you must derive a subnet CIDR belonging to
15 | one of your reserved blocks in the same project and facility as the target device.
16 |
17 | For example, you have reserved IPv4 address block 147.229.10.152/30, you can choose to assign either the whole
18 | block as one subnet to a device; or 2 subnets with CIDRs 147.229.10.152/31' and 147.229.10.154/31; or 4 subnets
19 | with mask prefix length 32. More about the elastic IP subnets is [here](https://metal.equinix.com/developers/docs/networking/elastic-ips/).
20 |
21 | Device and reserved block must be in the same facility.
22 |
23 | ## Example Usage
24 |
25 | ```hcl
26 | # Reserve /30 block of max 2 public IPv4 addresses in Parsippany, NJ (ny5) for myproject
27 | resource "metal_reserved_ip_block" "myblock" {
28 | project_id = local.project_id
29 | facility = "ny5"
30 | quantity = 2
31 | }
32 |
33 | # Assign /32 subnet (single address) from reserved block to a device
34 | resource "metal_ip_attachment" "first_address_assignment" {
35 | device_id = metal_device.mydevice.id
36 | # following expression will result to sth like "147.229.10.152/32"
37 | cidr_notation = join("/", [cidrhost(metal_reserved_ip_block.myblock.cidr_notation, 0), "32"])
38 | }
39 | ```
40 |
41 | ## Argument Reference
42 |
43 | The following arguments are supported:
44 |
45 | * `device_id` - (Required) ID of device to which to assign the subnet
46 | * `cidr_notation` - (Required) CIDR notation of subnet from block reserved in the same
47 | project and facility as the device
48 |
49 | ## Attributes Reference
50 |
51 | The following attributes are exported:
52 |
53 | * `id` - The unique ID of the assignment
54 | * `device_id` - ID of device to which subnet is assigned
55 | * `cidr_notation` - Assigned subnet in CIDR notation, e.g. "147.229.15.30/31"
56 | * `gateway` - IP address of gateway for the subnet
57 | * `network` - Subnet network address
58 | * `netmask` - Subnet mask in decimal notation, e.g. "255.255.255.0"
59 | * `cidr` - length of CIDR prefix of the subnet as integer
60 | * `address_family` - Address family as integer (4 or 6)
61 | * `public` - boolean flag whether subnet is reachable from the Internet
62 |
--------------------------------------------------------------------------------
/GNUmakefile:
--------------------------------------------------------------------------------
1 | ACCTEST_PARALLELISM ?= 8
2 | TEST?=$$(go list ./... |grep -v 'vendor')
3 | GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
4 | WEBSITE_REPO=github.com/hashicorp/terraform-website
5 | PKG_NAME=metal
6 | GOPATH?=$(HOME)/go
7 |
8 | default: build
9 |
10 | build: fmtcheck
11 | go install
12 |
13 | sweep:
14 | @echo "WARNING: This will destroy infrastructure. Use only in development accounts."
15 | go test $(TEST) -v -sweep=$(SWEEP) $(SWEEPARGS)
16 |
17 | test: fmtcheck
18 | go test $(TEST) -v $(TESTARGS) -timeout=30s -parallel=10
19 |
20 | testacc: fmtcheck
21 | TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout=120m -parallel=$(ACCTEST_PARALLELISM)
22 |
23 | vet:
24 | @echo "go vet ."
25 | @go vet $$(go list ./... | grep -v vendor/) ; if [ $$? -eq 1 ]; then \
26 | echo ""; \
27 | echo "Vet found suspicious constructs. Please check the reported constructs"; \
28 | echo "and fix them if necessary before submitting the code for review."; \
29 | exit 1; \
30 | fi
31 |
32 | fmt:
33 | gofmt -w $(GOFMT_FILES)
34 |
35 | fmtcheck:
36 | @sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'"
37 |
38 | errcheck:
39 | @sh -c "'$(CURDIR)/scripts/errcheck.sh'"
40 |
41 |
42 | test-compile:
43 | @if [ "$(TEST)" = "./..." ]; then \
44 | echo "ERROR: Set TEST to a specific package. For example,"; \
45 | echo " make test-compile TEST=./$(PKG_NAME)"; \
46 | exit 1; \
47 | fi
48 | go test -c $(TEST) $(TESTARGS)
49 |
50 | docs-lint:
51 | @echo "==> Checking docs against linters..."
52 | @misspell -error -source=text docs/ || (echo; \
53 | echo "Unexpected misspelling found in docs files."; \
54 | echo "To automatically fix the misspelling, run 'make docs-lint-fix' and commit the changes."; \
55 | exit 1)
56 | @docker run -v $(PWD):/markdown 06kellyjac/markdownlint-cli docs/ || (echo; \
57 | echo "Unexpected issues found in docs Markdown files."; \
58 | echo "To apply any automatic fixes, run 'make docs-lint-fix' and commit the changes."; \
59 | exit 1)
60 |
61 | docs-lint-fix:
62 | @echo "==> Applying automatic docs linter fixes..."
63 | @misspell -w -source=text docs/
64 | @docker run -v $(PWD):/markdown 06kellyjac/markdownlint-cli --fix docs/
65 |
66 | tfproviderlint:
67 | @echo "==> Checking provider code against bflad/tfproviderlint..."
68 | @docker run -v $(PWD):/src bflad/tfproviderlint ./... || (echo; \
69 | echo "Unexpected issues found in code with bflad/tfproviderlint."; \
70 | echo "To apply automated fixes for check that support them, run 'make tfproviderlint-fix'."; \
71 | exit 1)
72 |
73 | tfproviderlint-fix:
74 | @echo "==> Applying fixes with bflad/tfproviderlint..."
75 | @docker run -v $(PWD):/src bflad/tfproviderlint -fix ./...
76 |
77 | tfproviderdocs-check:
78 | @echo "==> Check provider docs with bflad/tfproviderdocs..."
79 | @docker run -v $(PWD):/src bflad/tfproviderdocs check -provider-name=metal || (echo; \
80 | echo "Unexpected issues found in code with bflad/tfproviderdocs."; \
81 | exit 1)
82 |
83 | .PHONY: build test testacc vet fmt fmtcheck errcheck test-compile docs-lint docs-lint-fix tfproviderlint tfproviderlint-fix tfproviderdocs-check
84 |
85 |
--------------------------------------------------------------------------------
/docs/resources/project_ssh_key.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_project_ssh_key"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal Project SSH key resource.
6 | ---
7 |
8 | # metal_project_ssh_key (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_project_ssh_key`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_project_ssh_key) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_project_ssh_key`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal project SSH key resource to manage project-specific SSH keys.
13 | Project SSH keys will only be populated onto servers that belong to that project, in contrast to User SSH Keys.
14 |
15 | ## Example Usage
16 |
17 | ```hcl
18 | locals {
19 | project_id = ""
20 | }
21 |
22 | resource "metal_project_ssh_key" "test" {
23 | name = "test"
24 | public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDM/unxJeFqxsTJcu6mhqsMHSaVlpu+Jj/P+44zrm6X/MAoHSX3X9oLgujEjjZ74yLfdfe0bJrbL2YgJzNaEkIQQ1VPMHB5EhTKUBGnzlPP0hHTnxsjAm9qDHgUPgvgFDQSAMzdJRJ0Cexo16Ph9VxCoLh3dxiE7s2gaM2FdVg7P8aSxKypsxAhYV3D0AwqzoOyT6WWhBoQ0xZ85XevOTnJCpImSemEGs6nVGEsWcEc1d1YvdxFjAK4SdsKUMkj4Dsy/leKsdi/DEAf356vbMT1UHsXXvy5TlHu/Pa6qF53v32Enz+nhKy7/8W2Yt2yWx8HnQcT2rug9lvCXagJO6oauqRTO77C4QZn13ZLMZgLT66S/tNh2EX0gi6vmIs5dth8uF+K6nxIyKJXbcA4ASg7F1OJrHKFZdTc5v1cPeq6PcbqGgc+8SrPYQmzvQqLoMBuxyos2hUkYOmw3aeWJj9nFa8Wu5WaN89mUeOqSkU4S5cgUzWUOmKey56B/j/s1sVys9rMhZapVs0wL4L9GBBM48N5jAQZnnpo85A8KsZq5ME22bTLqnxsDXqDYZvS7PSI6Dxi7eleOFE/NYYDkrgDLHTQri8ucDMVeVWHgoMY2bPXdn7KKy5jW5jKsf8EPARXg77A4gRYmgKrcwIKqJEUPqyxJBe0CPoGTqgXPRsUiQ== tomk@hp2"
25 | project_id = local.project_id
26 | }
27 |
28 | resource "metal_device" "test" {
29 | hostname = "test"
30 | plan = "c3.medium.x86"
31 | facilities = ["ny5"]
32 | operating_system = "ubuntu_20_04"
33 | billing_cycle = "hourly"
34 | project_ssh_key_ids = [metal_project_ssh_key.test.id]
35 | project_id = local.project_id
36 | }
37 | ```
38 |
39 | ## Argument Reference
40 |
41 | The following arguments are supported:
42 |
43 | * `name` - (Required) The name of the SSH key for identification
44 | * `public_key` - (Required) The public key. If this is a file, it can be read using the file interpolation function
45 | * `project_id` - (Required) The ID of parent project
46 |
47 | ## Attributes Reference
48 |
49 | The following attributes are exported:
50 |
51 | * `id` - The unique ID of the key
52 | * `name` - The name of the SSH key
53 | * `public_key` - The text of the public key
54 | * `project_id` - The ID of parent project
55 | * `owner_id` - The ID of parent project (same as project_id)
56 | * `fingerprint` - The fingerprint of the SSH key
57 | * `created` - The timestamp for when the SSH key was created
58 | * `updated` - The timestamp for the last time the SSH key was updated
59 |
--------------------------------------------------------------------------------
/docs/resources/connection.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: connection"
3 | subcategory: ""
4 | description: |-
5 | Request/Create Equinix Fabric Connection
6 | ---
7 |
8 | # metal_connection (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_connection`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_connection) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_connection`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this resource to request of create an Interconnection from [Equinix Fabric - software-defined interconnections](https://metal.equinix.com/developers/docs/networking/fabric/)
13 |
14 | ~> Equinix Metal connection with service_token_type `a_side` is not generally available and may not be enabled yet for your organization.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 |
20 | resource "metal_connection" "test" {
21 | name = "My Interconnection"
22 | project_id = metal_project.test.id
23 | type = "shared"
24 | redundancy = "redundant"
25 | metro = "sv"
26 | speed = "50Mbps"
27 | service_token_type = "a_side"
28 | }
29 | ```
30 |
31 | ## Argument Reference
32 |
33 | * `name` - (Required) Name of the connection resource
34 | * `metro` - (Optional) Metro where the connection will be created
35 | * `facility` - (Optional) Facility where the connection will be created
36 | * `redundancy` - (Required) Connection redundancy - redundant or primary
37 | * `type` - (Required) Connection type - dedicated or shared
38 | * `project_id` - (Required) ID of the project where the connection is scoped to, must be set for shared connection
39 | * `speed` - (Required) Connection speed - one of 50Mbps, 200Mbps, 500Mbps, 1Gbps, 2Gbps, 5Gbps, 10Gbps
40 | * `description` - (Optional) Description for the connection resource
41 | * `mode` - (Optional) Mode for connections in IBX facilities with the dedicated type - standard or tunnel. Default is standard
42 | * `tags` - (Optional) String list of tags
43 | * `vlans` - (Optional) Only used with shared connection. Vlans to attach. Pass one vlan for Primary/Single connection and two vlans for Redundant connection
44 | * `service_token_type` - (Optional) Only used with shared connection. Type of service token to use for the connection, a_side or z_side
45 |
46 | ## Attributes Reference
47 |
48 | * `organization_id` - ID of the organization where the connection is scoped to
49 | * `status` - Status of the connection resource
50 | * `ports` - List of connection ports - primary (`ports[0]`) and secondary (`ports[1]`). Schema of port is described in documentation of the [metal_connection datasource](../data-sources/connection.md).
51 | * `service_tokens` - List of connection service tokens with attributes. Scehma of service_token is described in documentation of the [metal_connection datasource](../data-sources/connection.md).
52 |
--------------------------------------------------------------------------------
/metal/resource_metal_ip_attachment.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "path"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9 | "github.com/packethost/packngo"
10 | )
11 |
12 | func resourceMetalIPAttachment() *schema.Resource {
13 | ipAttachmentSchema := metalIPResourceComputedFields()
14 | ipAttachmentSchema["device_id"] = &schema.Schema{
15 | Type: schema.TypeString,
16 | ForceNew: true,
17 | Required: true,
18 | }
19 | ipAttachmentSchema["cidr_notation"] = &schema.Schema{
20 | Type: schema.TypeString,
21 | ForceNew: true,
22 | Required: true,
23 | }
24 | return &schema.Resource{
25 | DeprecationMessage: deprecatedProviderMsg,
26 | Create: resourceMetalIPAttachmentCreate,
27 | Read: resourceMetalIPAttachmentRead,
28 | Delete: resourceMetalIPAttachmentDelete,
29 | Importer: &schema.ResourceImporter{
30 | State: schema.ImportStatePassthrough,
31 | },
32 |
33 | Schema: ipAttachmentSchema,
34 | }
35 | }
36 |
37 | func resourceMetalIPAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
38 | client := meta.(*packngo.Client)
39 | deviceID := d.Get("device_id").(string)
40 | ipa := d.Get("cidr_notation").(string)
41 |
42 | req := packngo.AddressStruct{Address: ipa}
43 |
44 | assignment, _, err := client.DeviceIPs.Assign(deviceID, &req)
45 | if err != nil {
46 | return fmt.Errorf("error assigning address %s to device %s: %s", ipa, deviceID, err)
47 | }
48 |
49 | d.SetId(assignment.ID)
50 |
51 | return resourceMetalIPAttachmentRead(d, meta)
52 | }
53 |
54 | func resourceMetalIPAttachmentRead(d *schema.ResourceData, meta interface{}) error {
55 | client := meta.(*packngo.Client)
56 | assignment, _, err := client.DeviceIPs.Get(d.Id(), nil)
57 | if err != nil {
58 | err = friendlyError(err)
59 |
60 | // If the IP attachment was already destroyed, mark as succesfully gone.
61 | if isNotFound(err) {
62 | log.Printf("[WARN] IP attachment (%q) not found, removing from state", d.Id())
63 | d.SetId("")
64 | return nil
65 | }
66 | return err
67 | }
68 |
69 | d.SetId(assignment.ID)
70 | d.Set("address", assignment.Address)
71 | d.Set("gateway", assignment.Gateway)
72 | d.Set("network", assignment.Network)
73 | d.Set("netmask", assignment.Netmask)
74 | d.Set("address_family", assignment.AddressFamily)
75 | d.Set("cidr", assignment.CIDR)
76 | d.Set("public", assignment.Public)
77 | d.Set("management", assignment.Management)
78 | d.Set("manageable", assignment.Manageable)
79 |
80 | d.Set("global", assignment.Global)
81 |
82 | d.Set("device_id", path.Base(assignment.AssignedTo.Href))
83 | d.Set("cidr_notation",
84 | fmt.Sprintf("%s/%d", assignment.Network, assignment.CIDR))
85 |
86 | return nil
87 | }
88 |
89 | func resourceMetalIPAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
90 | client := meta.(*packngo.Client)
91 |
92 | resp, err := client.DeviceIPs.Unassign(d.Id())
93 | if ignoreResponseErrors(httpForbidden, httpNotFound)(resp, err) != nil {
94 | return friendlyError(err)
95 | }
96 |
97 | d.SetId("")
98 | return nil
99 | }
100 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ""
3 | page_title: "Provider: Equinix Metal"
4 | description: |-
5 | The Equinix Metal provider is used to interact with the Equinix Metal Host API.
6 | ---
7 |
8 | # Equinix Metal Provider
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated (End-of-Life scheduled for July 1, 2023) meaning that this software is only supported or maintained by Equinix Metal and its community in a case-by-case basis. The [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) has full support for existing Terraform managed Metal resources once Terraform configuration and state are adapted. The Equinix provider manages resources including Network Edge and Fabric in addition to Metal. [Please review the Metal to Equinix provider migration guide](https://registry.terraform.io/providers/equinix/equinix/latest/docs/guides/migration_guide_equinix_metal). A guide is also available for [migrating from the Packet provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs/guides/migration_guide_packet).
11 |
12 | The Equinix Metal (`metal`) provider is used to interact with the resources supported by [Equinix Metal](https://metal.equinix.com/).
13 | The provider needs to be configured with the proper credentials before it can be used.
14 |
15 | Use the navigation to the left to read about the available resources.
16 |
17 | ## Example Usage
18 |
19 | ```hcl
20 | terraform {
21 | required_providers {
22 | metal = {
23 | source = "equinix/metal"
24 | # version = "1.0.0"
25 | }
26 | }
27 | }
28 |
29 | # Configure the Equinix Metal Provider.
30 | provider "metal" {
31 | auth_token = var.auth_token
32 | }
33 |
34 | data "metal_project" "project" {
35 | name = "My Project"
36 | }
37 |
38 | # If you want to create a fresh project, you can create one with metal_project
39 | #
40 | # resource "metal_project" "cool_project" {
41 | # name = "My First Terraform Project"
42 | # }
43 |
44 | # Create a device and add it to tf_project_1
45 | resource "metal_device" "web1" {
46 | hostname = "web1"
47 | plan = "c3.medium.x86"
48 | metro = "ny"
49 | operating_system = "ubuntu_20_04"
50 | billing_cycle = "hourly"
51 | project_id = data.metal_project.project.id
52 |
53 | # if you created a project with the metal_project resource, refer to its ID
54 | # project_id = metal_project.cool_project.id
55 |
56 | # You can find the ID of your project in the URL of the Equinix Metal console.
57 | # For example, if you see your devices listed at
58 | # https://console.equinix.com/projects/352000fb2-ee46-4673-93a8-de2c2bdba33b
59 | # .. then 352000fb2-ee46-4673-93a8-de2c2bdba33b is your project ID.
60 | }
61 | ```
62 |
63 | ## Argument Reference
64 |
65 | The following arguments are supported:
66 |
67 | * `auth_token` - (Required) This is your Equinix Metal API Auth token. This can
68 | also be specified with the `METAL_AUTH_TOKEN` environment variable.
69 |
70 | Use of the legacy `PACKET_AUTH_TOKEN` environment variable is deprecated.
71 | * `max_retries` - Maximum number of retries in case of network failure.
72 | * `max_retry_wait_seconds` - Maximum time to wait in case of network failure.
73 |
--------------------------------------------------------------------------------
/docs/data-sources/spot_market_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_spot_market_request"
3 | subcategory: ""
4 | description: |-
5 | Provides a datasource for existing Spot Market Requests in the Equinix Metal host.
6 | ---
7 |
8 | # metal_spot_market_request (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_spot_market_request`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_spot_market_request) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_spot_market_request`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal spot_market_request datasource. The datasource will contain list of device IDs created by referenced Spot Market Request.
13 |
14 | ## Example Usage
15 |
16 | ```hcl
17 | # Create a Spot Market Request, and print public IPv4 of the created devices, if any.
18 |
19 | resource "metal_spot_market_request" "req" {
20 | project_id = local.project_id
21 | max_bid_price = 0.1
22 | facilities = ["ny5"]
23 | devices_min = 2
24 | devices_max = 2
25 | wait_for_devices = true
26 |
27 | instance_parameters {
28 | hostname = "testspot"
29 | billing_cycle = "hourly"
30 | operating_system = "ubuntu_20_04"
31 | plan = "c3.small.x86"
32 | }
33 | }
34 |
35 | data "metal_spot_market_request" "dreq" {
36 | request_id = metal_spot_market_request.req.id
37 | }
38 |
39 | output "ids" {
40 | value = data.metal_spot_market_request.dreq.device_ids
41 | }
42 |
43 | data "metal_device" "devs" {
44 | count = length(data.metal_spot_market_request.dreq.device_ids)
45 | device_id = data.metal_spot_market_request.dreq.device_ids[count.index]
46 | }
47 |
48 | output "ips" {
49 | value = [for d in data.metal_device.devs : d.access_public_ipv4]
50 | }
51 | ```
52 |
53 | With the code as `main.tf`, first create the spot market request:
54 |
55 | ```
56 | terraform apply -target metal_spot_market_request.req
57 | ```
58 |
59 | When the terraform run ends, run a full apply, and the IPv4 addresses will be printed:
60 |
61 | ```
62 | $ terraform apply
63 |
64 | [...]
65 |
66 | ips = [
67 | "947.85.199.231",
68 | "947.85.194.181",
69 | ]
70 | ```
71 |
72 | ## Argument Reference
73 |
74 | The following arguments are supported:
75 |
76 | * `request_id` - (Required) The id of the Spot Market Request
77 |
78 | ## Attributes Reference
79 |
80 | The following attributes are exported:
81 |
82 | * `device_ids` - List of IDs of devices spawned by the referenced Spot Market Request
83 | * `devices_min` - Miniumum number devices to be created
84 | * `devices_max` - Maximum number devices to be created
85 | * `max_bid_price` - Maximum price user is willing to pay per hour per device
86 | * `facilities` - Facility IDs where devices should be created
87 | * `metro` - Metro where devices should be created.
88 | * `project_id` - Project ID
89 | * `plan` - The device plan slug.
90 | * `end_at` - Date and time When the spot market request will be ended.
91 |
--------------------------------------------------------------------------------
/metal/resource_metal_volume.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
5 | "github.com/packethost/packngo"
6 | )
7 |
8 | func resourceMetalVolume() *schema.Resource {
9 | return &schema.Resource{
10 | Create: removedResourceOp(resourceVolumeRemovedMsg),
11 | Read: removedResourceOp(resourceVolumeRemovedMsg),
12 | DeprecationMessage: "Volumes are deprecated, see https://metal.equinix.com/developers/docs/resilience-recovery/elastic-block-storage/#elastic-block-storage",
13 | Update: removedResourceOp(resourceVolumeRemovedMsg),
14 | Delete: resourceMetalVolumeDelete,
15 | Importer: &schema.ResourceImporter{
16 | State: schema.ImportStatePassthrough,
17 | },
18 |
19 | Schema: map[string]*schema.Schema{
20 | "project_id": {
21 | Type: schema.TypeString,
22 | Required: true,
23 | ForceNew: true,
24 | },
25 |
26 | "name": {
27 | Type: schema.TypeString,
28 | Computed: true,
29 | },
30 |
31 | "description": {
32 | Type: schema.TypeString,
33 | Required: false,
34 | Optional: true,
35 | },
36 |
37 | "size": {
38 | Type: schema.TypeInt,
39 | Required: true,
40 | },
41 |
42 | "facility": {
43 | Type: schema.TypeString,
44 | Required: true,
45 | ForceNew: true,
46 | },
47 |
48 | "plan": {
49 | Type: schema.TypeString,
50 | Required: true,
51 | },
52 |
53 | "billing_cycle": {
54 | Type: schema.TypeString,
55 | Computed: true,
56 | Optional: true,
57 | },
58 |
59 | "state": {
60 | Type: schema.TypeString,
61 | Computed: true,
62 | },
63 |
64 | "locked": {
65 | Type: schema.TypeBool,
66 | Optional: true,
67 | },
68 |
69 | "snapshot_policies": {
70 | Type: schema.TypeList,
71 | Optional: true,
72 | Elem: &schema.Resource{
73 | Schema: map[string]*schema.Schema{
74 | "snapshot_frequency": {
75 | Type: schema.TypeString,
76 | Required: true,
77 | ForceNew: true,
78 | },
79 | "snapshot_count": {
80 | Type: schema.TypeInt,
81 | Required: true,
82 | ForceNew: true,
83 | },
84 | },
85 | },
86 | },
87 |
88 | "attachments": {
89 | Type: schema.TypeList,
90 | Computed: true,
91 | Elem: &schema.Resource{
92 | Schema: map[string]*schema.Schema{
93 | "href": {
94 | Type: schema.TypeString,
95 | Computed: true,
96 | },
97 | },
98 | },
99 | },
100 |
101 | "created": {
102 | Type: schema.TypeString,
103 | Computed: true,
104 | },
105 |
106 | "updated": {
107 | Type: schema.TypeString,
108 | Computed: true,
109 | },
110 | },
111 | }
112 | }
113 |
114 | func resourceMetalVolumeDelete(d *schema.ResourceData, meta interface{}) error {
115 | client := meta.(*packngo.Client)
116 |
117 | resp, err := client.Volumes.Delete(d.Id())
118 | if ignoreResponseErrors(httpForbidden, httpNotFound)(resp, err) != nil {
119 | return friendlyError(err)
120 | }
121 |
122 | return nil
123 | }
124 |
--------------------------------------------------------------------------------
/docs/data-sources/virtual_circuit.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_virtual_circuit"
3 | subcategory: ""
4 | description: |-
5 | Retrieve Equinix Fabric Virtual Circuit
6 | ---
7 |
8 | # metal_virtual_circuit (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_virtual_circuit`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_virtual_circuit) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_virtual_circuit`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to retrieve a virtual circuit resource from [Equinix Fabric - software-defined interconnections](https://metal.equinix.com/developers/docs/networking/fabric/)
13 |
14 | -> **NOTE:** VRF features are not generally available. The interfaces related to VRF resources may change ahead of general availability.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 | data "metal_connection" "example_connection" {
20 | connection_id = "4347e805-eb46-4699-9eb9-5c116e6a017d"
21 | }
22 |
23 | data "metal_virtual_circuit" "example_vc" {
24 | virtual_circuit_id = data.metal_connection.example_connection.ports[1].virtual_circuit_ids[0]
25 | }
26 |
27 | ```
28 |
29 | ## Argument Reference
30 |
31 | The following arguments are supported:
32 |
33 | * `virtual_circuit_id` - (Required) ID of the virtual circuit resource
34 |
35 | ## Attributes Reference
36 |
37 | In addition to all arguments above, the following attributes are exported:
38 |
39 | * `name` - Name of the virtual circuit resource.
40 | * `status` - Status of the virtal circuit.
41 | * `port_id` - UUID of the Connection Port where the VC is scoped to.
42 | * `project_id` - ID of project to which the VC belongs.
43 | * `vnid`, `nni_vlan`, `nni_nvid` - VLAN parameters, see the [documentation for Equinix Fabric](https://metal.equinix.com/developers/docs/networking/fabric/).
44 | * `description` - Description for the Virtual Circuit resource.
45 | * `tags` - Tags for the Virtual Circuit resource.
46 | * `speed` - Speed of the Virtual Circuit resource.
47 | * `vrf_id` - UUID of the VLAN to associate.
48 | * `peer_asn` - The BGP ASN of the peer. The same ASN may be the used across several VCs, but it cannot be the same as the local_asn of the VRF.
49 | * `subnet` - A subnet from one of the IP
50 | blocks associated with the VRF that we will help create an IP reservation for. Can only be either a /30 or /31.
51 | * For a /31 block, it will only have two IP addresses, which will be used for
52 | the metal_ip and customer_ip.
53 | * For a /30 block, it will have four IP addresses, but the first and last IP addresses are not usable. We will default to the first usable IP address for the metal_ip.
54 | * `metal_ip` - The Metal IP address for the SVI (Switch Virtual Interface) of the VirtualCircuit. Will default to the first usable IP in the subnet.
55 | * `customer_ip` - The Customer IP address which the CSR switch will peer with. Will default to the other usable IP in the subnet.
56 | * `md5` - The password that can be set for the VRF BGP peer
57 |
--------------------------------------------------------------------------------
/docs/data-sources/connection.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: connection"
3 | subcategory: ""
4 | description: |-
5 | Retrieve Equinix Fabric Connection
6 | ---
7 |
8 | # metal_connection (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_connection`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_connection) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_connection`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this data source to retrieve a connection resource from [Equinix Fabric - software-defined interconnections](https://metal.equinix.com/developers/docs/networking/fabric/)
13 |
14 | ~> Equinix Metal connection with service_token_type `a_side` is not generally available and may not be enabled yet for your organization.
15 |
16 | ## Example Usage
17 |
18 | ```hcl
19 | data "metal_connection" "example" {
20 | connection_id = "4347e805-eb46-4699-9eb9-5c116e6a017d"
21 | }
22 | ```
23 |
24 | ## Argument Reference
25 |
26 | * `connection_id` - (Required) ID of the connection resource
27 |
28 | ## Attributes Reference
29 |
30 | * `name` - Name of the connection resource
31 | * `metro` - Slug of a metro to which the connection belongs
32 | * `facility` - Slug of a facility to which the connection belongs
33 | * `redundancy` - Connection redundancy, reduntant or primary
34 | * `type` - Connection type, dedicated or shared
35 | * `project_id` - ID of project to which the connection belongs
36 | * `speed` - Connection speed, one of 50Mbps, 200Mbps, 500Mbps, 1Gbps, 2Gbps, 5Gbps, 10Gbps
37 | * `description` - Description of the connection resource
38 | * `mode` - Mode for connections in IBX facilities with the dedicated type - standard or tunnel
39 | * `tags` - String list of tags
40 | * `vlans` - Attached VLANs. Only available in shared connection. One vlan for Primary/Single connection and two vlans for Redundant connection
41 | * `service_token_type` - Type of service token, a_side or z_side. One available in shared connection.
42 | * `organization_id` - ID of the organization where the connection is scoped to
43 | * `status` - Status of the connection resource
44 | * `service_tokens` - List of connection service tokens with attributes
45 | * `id` - UUID of the service token
46 | * `expires_at` - Expiration date of the service token
47 | * `max_allowed_speed` - Maximum allowed speed for the service token, string like in the `speed` attribute
48 | * `type` - Token type, `a_side` or `z_side`
49 | * `role` - Token role, `primary` or `secondary`
50 | * `ports` - List of connection ports - primary (`ports[0]`) and secondary (`ports[1]`)
51 | * `name` - Port name
52 | * `id` - Port UUID
53 | * `role` - Port role - primary or secondary
54 | * `speed` - Port speed in bits per second
55 | * `status` - Port status
56 | * `link_status` - Port link status
57 | * `virtual_circuit_ids` - List of IDs of virtual cicruits attached to this port
58 | * `token` - (Deprecated) Fabric Token from the [Equinix Fabric Portal](https://ecxfabric.equinix.com/dashboard)
59 |
--------------------------------------------------------------------------------
/metal/datasource_metal_operating_system.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8 | "github.com/packethost/packngo"
9 | )
10 |
11 | func dataSourceOperatingSystem() *schema.Resource {
12 | return &schema.Resource{
13 | DeprecationMessage: deprecatedProviderMsg,
14 | Read: dataSourceMetalOperatingSystemRead,
15 | Schema: map[string]*schema.Schema{
16 | "name": {
17 | Type: schema.TypeString,
18 | Description: "Name or part of the name of the distribution. Case insensitive",
19 | Optional: true,
20 | },
21 | "distro": {
22 | Type: schema.TypeString,
23 | Description: "Name of the OS distribution",
24 | Optional: true,
25 | },
26 | "version": {
27 | Type: schema.TypeString,
28 | Description: "Version of the distribution",
29 | Optional: true,
30 | },
31 | "provisionable_on": {
32 | Type: schema.TypeString,
33 | Description: "Plan name",
34 | Optional: true,
35 | },
36 | "slug": {
37 | Type: schema.TypeString,
38 | Description: "Operating system slug (same as id)",
39 | Computed: true,
40 | },
41 | },
42 | }
43 | }
44 |
45 | func dataSourceMetalOperatingSystemRead(d *schema.ResourceData, meta interface{}) error {
46 | client := meta.(*packngo.Client)
47 |
48 | name, nameOK := d.GetOk("name")
49 | distro, distroOK := d.GetOk("distro")
50 | version, versionOK := d.GetOk("version")
51 | provisionableOn, provisionableOnOK := d.GetOk("provisionable_on")
52 |
53 | if !nameOK && !distroOK && !versionOK && !provisionableOnOK {
54 | return fmt.Errorf("One of name, distro, version, or provisionable_on must be assigned")
55 | }
56 |
57 | oss, _, err := client.OperatingSystems.List()
58 | if err != nil {
59 | return err
60 | }
61 |
62 | if nameOK {
63 | temp := []packngo.OS{}
64 | for _, os := range oss {
65 | if strings.Contains(strings.ToLower(os.Name), strings.ToLower(name.(string))) {
66 | temp = append(temp, os)
67 | }
68 | }
69 | oss = temp
70 | }
71 |
72 | if distroOK && (len(oss) != 0) {
73 | temp := []packngo.OS{}
74 | for _, v := range oss {
75 | if v.Distro == distro.(string) {
76 | temp = append(temp, v)
77 | }
78 | }
79 | oss = temp
80 | }
81 |
82 | if versionOK && (len(oss) != 0) {
83 | temp := []packngo.OS{}
84 | for _, v := range oss {
85 | if v.Version == version.(string) {
86 | temp = append(temp, v)
87 | }
88 | }
89 | oss = temp
90 | }
91 |
92 | if provisionableOnOK && (len(oss) != 0) {
93 | temp := []packngo.OS{}
94 | for _, v := range oss {
95 | for _, po := range v.ProvisionableOn {
96 | if po == provisionableOn.(string) {
97 | temp = append(temp, v)
98 | }
99 | }
100 | }
101 | oss = temp
102 | }
103 |
104 | if len(oss) == 0 {
105 | return fmt.Errorf("There are no operating systems that match the search criteria")
106 | }
107 |
108 | if len(oss) > 1 {
109 | return fmt.Errorf("There is more than one operating system that matches the search criteria")
110 | }
111 | d.Set("name", oss[0].Name)
112 | d.Set("distro", oss[0].Distro)
113 | d.Set("version", oss[0].Version)
114 | d.Set("slug", oss[0].Slug)
115 | d.SetId(oss[0].Slug)
116 | return nil
117 | }
118 |
--------------------------------------------------------------------------------
/metal/datasource_metal_facility_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | "testing"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | )
10 |
11 | var (
12 | matchErrMissingFeature = regexp.MustCompile(`.*doesn't have feature.*`)
13 | matchErrNoCapacity = regexp.MustCompile(`Not enough capacity.*`)
14 | )
15 |
16 | func TestAccDataSourceFacility_Basic(t *testing.T) {
17 | testFac := "da11"
18 |
19 | resource.ParallelTest(t, resource.TestCase{
20 | PreCheck: func() { testAccPreCheck(t) },
21 | Providers: testAccProviders,
22 | Steps: []resource.TestStep{
23 | {
24 | Config: testAccDataSourceFacilityConfigBasic(testFac),
25 | Check: resource.ComposeTestCheckFunc(
26 | resource.TestCheckResourceAttr(
27 | "data.metal_facility.test", "code", testFac),
28 | ),
29 | },
30 | {
31 | Config: testAccDataSourceFacilityConfigCapacityReasonable(testFac),
32 | Check: resource.ComposeTestCheckFunc(
33 | resource.TestCheckResourceAttr(
34 | "data.metal_facility.test", "code", testFac),
35 | ),
36 | },
37 | {
38 | Config: testAccDataSourceFacilityConfigCapacityUnreasonable(testFac),
39 | ExpectError: matchErrNoCapacity,
40 | },
41 | {
42 | Config: testAccDataSourceFacilityConfigCapacityUnreasonableMultiple(testFac),
43 | ExpectError: matchErrNoCapacity,
44 | },
45 | },
46 | })
47 | }
48 |
49 | func TestAccDataSourceFacility_Features(t *testing.T) {
50 | resource.ParallelTest(t, resource.TestCase{
51 | PreCheck: func() { testAccPreCheck(t) },
52 | Providers: testAccProviders,
53 | Steps: []resource.TestStep{
54 | {
55 | Config: testAccDataSourceFacilityConfigFeatures(),
56 | ExpectError: matchErrMissingFeature,
57 | },
58 | },
59 | })
60 | }
61 |
62 | func testAccDataSourceFacilityConfigFeatures() string {
63 | return `
64 | data "metal_facility" "test" {
65 | code = "da11"
66 | features_required = ["baremetal", "ibx", "missingFeature"]
67 | }
68 | `
69 | }
70 |
71 | func testAccDataSourceFacilityConfigBasic(facCode string) string {
72 | return fmt.Sprintf(`
73 | data "metal_facility" "test" {
74 | code = "%s"
75 | }
76 | `, facCode)
77 | }
78 |
79 | func testAccDataSourceFacilityConfigCapacityUnreasonable(facCode string) string {
80 | return fmt.Sprintf(`
81 | data "metal_facility" "test" {
82 | code = "%s"
83 | capacity {
84 | plan = "c3.small.x86"
85 | quantity = 1000
86 | }
87 | }
88 | `, facCode)
89 | }
90 |
91 | func testAccDataSourceFacilityConfigCapacityReasonable(facCode string) string {
92 | return fmt.Sprintf(`
93 | data "metal_facility" "test" {
94 | code = "%s"
95 | capacity {
96 | plan = "c3.small.x86"
97 | quantity = 1
98 | }
99 | capacity {
100 | plan = "c3.medium.x86"
101 | quantity = 1
102 | }
103 | }
104 | `, facCode)
105 | }
106 |
107 | func testAccDataSourceFacilityConfigCapacityUnreasonableMultiple(facCode string) string {
108 | return fmt.Sprintf(`
109 | data "metal_facility" "test" {
110 | code = "%s"
111 | capacity {
112 | plan = "c3.small.x86"
113 | quantity = 1
114 | }
115 | capacity {
116 | plan = "c3.medium.x86"
117 | quantity = 1000
118 | }
119 | }
120 | `, facCode)
121 | }
122 |
--------------------------------------------------------------------------------
/metal/datasource_metal_spot_market_request_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10 | "github.com/packethost/packngo"
11 | )
12 |
13 | func TestAccDataSourceMetalSpotMarketRequest_Basic(t *testing.T) {
14 | projectName := fmt.Sprintf("ds-device-%s", acctest.RandString(10))
15 | var (
16 | facKey packngo.SpotMarketRequest
17 | metKey packngo.SpotMarketRequest
18 | )
19 | resource.ParallelTest(t, resource.TestCase{
20 | PreCheck: func() { testAccPreCheck(t) },
21 | Providers: testAccProviders,
22 | CheckDestroy: testAccCheckMetalSpotMarketRequestDestroy,
23 | Steps: []resource.TestStep{
24 | {
25 | Config: testDataSourceMetalSpotMarketRequestConfig_Basic(projectName),
26 | Check: resource.ComposeTestCheckFunc(
27 | testAccCheckMetalSpotMarketRequestExists("metal_spot_market_request.req", &facKey),
28 | ),
29 | },
30 | {
31 | Config: testDataSourceMetalSpotMarketRequestConfig_Metro(projectName),
32 | PlanOnly: true,
33 | ExpectNonEmptyPlan: true,
34 | },
35 | {
36 | Config: testDataSourceMetalSpotMarketRequestConfig_Metro(projectName),
37 | Check: resource.ComposeTestCheckFunc(
38 | testAccCheckMetalSpotMarketRequestExists("metal_spot_market_request.req", &metKey),
39 | func(_ *terraform.State) error {
40 | if metKey.ID == facKey.ID {
41 | return fmt.Errorf("Expected a new spot_market_request")
42 | }
43 | return nil
44 | },
45 | ),
46 | },
47 | },
48 | })
49 | }
50 |
51 | func testDataSourceMetalSpotMarketRequestConfig_Basic(projSuffix string) string {
52 | return fmt.Sprintf(`
53 |
54 | resource "metal_project" "test" {
55 | name = "tfacc-pro-spot_market_request-%s"
56 | }
57 |
58 | resource "metal_spot_market_request" "req" {
59 | project_id = "${metal_project.test.id}"
60 | max_bid_price = 0.01
61 | facilities = ["da11"]
62 | devices_min = 1
63 | devices_max = 1
64 | wait_for_devices = false
65 |
66 | instance_parameters {
67 | hostname = "tfacc-spot-test"
68 | billing_cycle = "hourly"
69 | operating_system = "ubuntu_20_04"
70 | plan = "c3.medium.x86"
71 | }
72 | }
73 |
74 | data "metal_spot_market_request" "dreq" {
75 | request_id = metal_spot_market_request.req.id
76 | }
77 | `, projSuffix)
78 | }
79 |
80 | func testDataSourceMetalSpotMarketRequestConfig_Metro(projSuffix string) string {
81 | return fmt.Sprintf(`
82 |
83 | resource "metal_project" "test" {
84 | name = "tfacc-pro-spot_market_request-%s"
85 | }
86 |
87 | resource "metal_spot_market_request" "req" {
88 | project_id = "${metal_project.test.id}"
89 | max_bid_price = 0.01
90 | metro = "da"
91 | devices_min = 1
92 | devices_max = 1
93 | wait_for_devices = false
94 |
95 | instance_parameters {
96 | hostname = "tfacc-spot-test"
97 | billing_cycle = "hourly"
98 | operating_system = "ubuntu_20_04"
99 | plan = "c3.medium.x86"
100 | }
101 | }
102 |
103 | data "metal_spot_market_request" "dreq" {
104 | request_id = metal_spot_market_request.req.id
105 | }
106 | `, projSuffix)
107 | }
108 |
--------------------------------------------------------------------------------
/metal/resource_metal_bgp_session.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
8 | "github.com/packethost/packngo"
9 | )
10 |
11 | func resourceMetalBGPSession() *schema.Resource {
12 | return &schema.Resource{
13 | DeprecationMessage: deprecatedProviderMsg,
14 | Create: resourceMetalBGPSessionCreate,
15 | Read: resourceMetalBGPSessionRead,
16 | Delete: resourceMetalBGPSessionDelete,
17 | Importer: &schema.ResourceImporter{
18 | State: schema.ImportStatePassthrough,
19 | },
20 |
21 | Schema: map[string]*schema.Schema{
22 | "device_id": {
23 | Type: schema.TypeString,
24 | Description: "ID of device",
25 | Required: true,
26 | ForceNew: true,
27 | },
28 | "address_family": {
29 | Type: schema.TypeString,
30 | Description: "ipv4 or ipv6",
31 | Required: true,
32 | ForceNew: true,
33 | ValidateFunc: validation.StringInSlice([]string{"ipv4", "ipv6"}, false),
34 | },
35 | "default_route": {
36 | Type: schema.TypeBool,
37 | Description: "Boolean flag to set the default route policy. False by default",
38 | Optional: true,
39 | Default: false,
40 | ForceNew: true,
41 | },
42 |
43 | "status": {
44 | Type: schema.TypeString,
45 | Description: "Status of the session - up or down",
46 | Computed: true,
47 | },
48 | },
49 | }
50 | }
51 |
52 | func resourceMetalBGPSessionCreate(d *schema.ResourceData, meta interface{}) error {
53 | client := meta.(*packngo.Client)
54 | dID := d.Get("device_id").(string)
55 | addressFamily := d.Get("address_family").(string)
56 | defaultRoute := d.Get("default_route").(bool)
57 | log.Printf("[DEBUG] creating %s BGP session to device (%s)\n", addressFamily, dID)
58 | bgpSession, _, err := client.BGPSessions.Create(
59 | dID, packngo.CreateBGPSessionRequest{
60 | AddressFamily: addressFamily,
61 | DefaultRoute: &defaultRoute})
62 | if err != nil {
63 | return friendlyError(err)
64 | }
65 |
66 | d.SetId(bgpSession.ID)
67 | return resourceMetalBGPSessionRead(d, meta)
68 | }
69 |
70 | func resourceMetalBGPSessionRead(d *schema.ResourceData, meta interface{}) error {
71 | client := meta.(*packngo.Client)
72 | bgpSession, _, err := client.BGPSessions.Get(d.Id(),
73 | &packngo.GetOptions{Includes: []string{"device"}})
74 | if err != nil {
75 | err = friendlyError(err)
76 | if isNotFound(err) {
77 | log.Printf("[WARN] BGP Session (%s) not found, removing from state", d.Id())
78 |
79 | d.SetId("")
80 | return nil
81 | }
82 | return err
83 | }
84 | defaultRoute := false
85 | if bgpSession.DefaultRoute != nil {
86 | if *(bgpSession.DefaultRoute) {
87 | defaultRoute = true
88 | }
89 | }
90 | d.Set("device_id", bgpSession.Device.ID)
91 | d.Set("address_family", bgpSession.AddressFamily)
92 | d.Set("status", bgpSession.Status)
93 | d.Set("default_route", defaultRoute)
94 | d.SetId(bgpSession.ID)
95 | return nil
96 | }
97 |
98 | func resourceMetalBGPSessionDelete(d *schema.ResourceData, meta interface{}) error {
99 | client := meta.(*packngo.Client)
100 | resp, err := client.BGPSessions.Delete(d.Id())
101 | return ignoreResponseErrors(httpForbidden, httpNotFound)(resp, err)
102 | }
103 |
--------------------------------------------------------------------------------
/metal/config.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "context"
5 | "crypto/x509"
6 | "fmt"
7 | "log"
8 | "net/http"
9 | "net/http/httputil"
10 | "net/url"
11 | "os"
12 | "regexp"
13 | "strings"
14 | "time"
15 |
16 | "github.com/equinix/terraform-provider-metal/version"
17 | "github.com/hashicorp/go-retryablehttp"
18 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
19 | "github.com/hashicorp/terraform-plugin-sdk/v2/meta"
20 | "github.com/packethost/packngo"
21 | )
22 |
23 | type DumpTransport struct {
24 | r http.RoundTripper
25 | }
26 |
27 | func (d *DumpTransport) RoundTrip(h *http.Request) (*http.Response, error) {
28 | dump, _ := httputil.DumpRequestOut(h, true)
29 | fmt.Printf("****REQUEST****\n%q\n", dump)
30 | resp, err := d.r.RoundTrip(h)
31 | dump, _ = httputil.DumpResponse(resp, true)
32 | fmt.Printf("****RESPONSE****\n%q\n****************\n\n", dump)
33 | return resp, err
34 | }
35 |
36 | const (
37 | consumerToken = "aZ9GmqHTPtxevvFq9SK3Pi2yr9YCbRzduCSXF2SNem5sjB91mDq7Th3ZwTtRqMWZ"
38 | uaEnvVar = "TF_APPEND_USER_AGENT"
39 | )
40 |
41 | type Config struct {
42 | terraformVersion string
43 | AuthToken string
44 | MaxRetries int
45 | MaxRetryWait time.Duration
46 | }
47 |
48 | var redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`)
49 |
50 | func MetalRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
51 | if ctx.Err() != nil {
52 | return false, ctx.Err()
53 | }
54 |
55 | if err != nil {
56 | if v, ok := err.(*url.Error); ok {
57 | // Don't retry if the error was due to too many redirects.
58 | if redirectsErrorRe.MatchString(v.Error()) {
59 | return false, nil
60 | }
61 |
62 | // Don't retry if the error was due to TLS cert verification failure.
63 | if _, ok := v.Err.(x509.UnknownAuthorityError); ok {
64 | return false, nil
65 | }
66 | }
67 |
68 | // The error is likely recoverable so retry.
69 | return true, nil
70 | }
71 | return false, nil
72 | }
73 |
74 | func terraformUserAgent(version string) string {
75 | ua := fmt.Sprintf("HashiCorp Terraform/%s (+https://www.terraform.io) Terraform Plugin SDK/%s",
76 | version, meta.SDKVersionString())
77 |
78 | if add := os.Getenv(uaEnvVar); add != "" {
79 | add = strings.TrimSpace(add)
80 | if len(add) > 0 {
81 | ua += " " + add
82 | log.Printf("[DEBUG] Using modified User-Agent: %s", ua)
83 | }
84 | }
85 |
86 | return ua
87 | }
88 |
89 | // Client returns a new client for accessing Equinix Metal's API.
90 | func (c *Config) Client() *packngo.Client {
91 | transport := http.DefaultTransport
92 | // transport = &DumpTransport{http.DefaultTransport} // Debug only
93 | transport = logging.NewTransport("Equinix Metal", transport)
94 | retryClient := retryablehttp.NewClient()
95 | retryClient.HTTPClient.Transport = transport
96 | retryClient.RetryMax = c.MaxRetries
97 | retryClient.RetryWaitMin = time.Second
98 | retryClient.RetryWaitMax = c.MaxRetryWait
99 | retryClient.CheckRetry = MetalRetryPolicy
100 | standardClient := retryClient.StandardClient()
101 |
102 | client := packngo.NewClientWithAuth(consumerToken, c.AuthToken, standardClient)
103 | tfUserAgent := terraformUserAgent(c.terraformVersion)
104 | userAgent := fmt.Sprintf("%s terraform-provider-metal/%s %s",
105 | tfUserAgent, version.ProviderVersion, client.UserAgent)
106 |
107 | client.UserAgent = strings.TrimSpace(userAgent)
108 |
109 | return client
110 | }
111 |
--------------------------------------------------------------------------------
/metal/resource_metal_bgp_setup_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10 | "github.com/packethost/packngo"
11 | )
12 |
13 | func TestAccMetalBGPSetup_Basic(t *testing.T) {
14 | rs := acctest.RandString(10)
15 |
16 | resource.ParallelTest(t, resource.TestCase{
17 | PreCheck: func() { testAccPreCheck(t) },
18 | Providers: testAccProviders,
19 | CheckDestroy: testAccCheckMetalBGPSetupDestroy,
20 | Steps: []resource.TestStep{
21 | {
22 | Config: testAccCheckMetalBGPSetupConfig_basic(rs),
23 | Check: resource.ComposeTestCheckFunc(
24 | resource.TestCheckResourceAttrPair(
25 | "metal_device.test", "id",
26 | "metal_bgp_session.test4", "device_id"),
27 | resource.TestCheckResourceAttrPair(
28 | "metal_device.test", "id",
29 | "metal_bgp_session.test6", "device_id"),
30 | resource.TestCheckResourceAttr(
31 | "metal_bgp_session.test4", "default_route", "true"),
32 | resource.TestCheckResourceAttr(
33 | "metal_bgp_session.test6", "default_route", "true"),
34 | resource.TestCheckResourceAttr(
35 | "metal_bgp_session.test4", "address_family", "ipv4"),
36 | resource.TestCheckResourceAttr(
37 | "metal_bgp_session.test6", "address_family", "ipv6"),
38 | // there will be 2 BGP neighbors, for IPv4 and IPv6
39 | resource.TestCheckResourceAttr(
40 | "data.metal_device_bgp_neighbors.test", "bgp_neighbors.#", "2"),
41 | ),
42 | },
43 | {
44 | ResourceName: "metal_bgp_session.test4",
45 | ImportState: true,
46 | ImportStateVerify: true,
47 | },
48 | },
49 | })
50 | }
51 |
52 | func testAccCheckMetalBGPSetupDestroy(s *terraform.State) error {
53 | client := testAccProvider.Meta().(*packngo.Client)
54 |
55 | for _, rs := range s.RootModule().Resources {
56 | if rs.Type != "metal_bgp_session" {
57 | continue
58 | }
59 | if _, _, err := client.BGPSessions.Get(rs.Primary.ID, nil); err == nil {
60 | return fmt.Errorf("BGPSession still exists")
61 | }
62 | }
63 |
64 | return nil
65 | }
66 |
67 | func testAccCheckMetalBGPSetupConfig_basic(name string) string {
68 | return fmt.Sprintf(`
69 | %s
70 |
71 | resource "metal_project" "test" {
72 | name = "tfacc-pro-bgp_session-%s"
73 | bgp_config {
74 | deployment_type = "local"
75 | md5 = "C179c28c41a85b"
76 | asn = 65000
77 | }
78 | }
79 |
80 | resource "metal_device" "test" {
81 | hostname = "tfacc-test-bgp-sesh"
82 | plan = local.plan
83 | facilities = local.facilities
84 | operating_system = "ubuntu_16_04"
85 | billing_cycle = "hourly"
86 | project_id = "${metal_project.test.id}"
87 |
88 | lifecycle {
89 | ignore_changes = [
90 | plan,
91 | facilities,
92 | ]
93 | }
94 | }
95 |
96 | resource "metal_bgp_session" "test4" {
97 | device_id = "${metal_device.test.id}"
98 | address_family = "ipv4"
99 | default_route = true
100 | }
101 |
102 | resource "metal_bgp_session" "test6" {
103 | device_id = "${metal_device.test.id}"
104 | address_family = "ipv6"
105 | default_route = true
106 | }
107 |
108 | data "metal_device_bgp_neighbors" "test" {
109 | device_id = metal_bgp_session.test4.device_id
110 | }
111 | `, confAccMetalDevice_base(preferable_plans, preferable_metros), name)
112 | }
113 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at support@equinixmetal.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/metal/internal/datalist/values.go:
--------------------------------------------------------------------------------
1 | package datalist
2 |
3 | import (
4 | "math"
5 | "regexp"
6 | "strings"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9 | )
10 |
11 | func floatApproxEquals(a, b float64) bool {
12 | return math.Abs(a-b) < 0.000001
13 | }
14 |
15 | func valueMatches(s *schema.Schema, value interface{}, filterValue interface{}, matchBy string) bool {
16 | switch s.Type {
17 | case schema.TypeString:
18 | switch matchBy {
19 | case "substring":
20 | return strings.Contains(value.(string), filterValue.(string))
21 | case "re":
22 | return filterValue.(*regexp.Regexp).MatchString(value.(string))
23 | }
24 | return strings.EqualFold(filterValue.(string), value.(string))
25 |
26 | case schema.TypeBool:
27 | return filterValue.(bool) == value.(bool)
28 |
29 | case schema.TypeInt:
30 | val := value.(int)
31 | filter := filterValue.(int)
32 | switch matchBy {
33 | case "less_than":
34 | return val < filter
35 | case "less_than_or_equal":
36 | return val <= filter
37 | case "greater_than":
38 | return val > filter
39 | case "greater_than_or_equal":
40 | return val >= filter
41 | }
42 | return val == filter
43 |
44 | case schema.TypeFloat:
45 | val := value.(float64)
46 | filter := filterValue.(float64)
47 | switch matchBy {
48 | case "less_than":
49 | return val != 0. && (val < filter)
50 | case "less_than_or_equal":
51 | return val != 0. && ((val < filter) || floatApproxEquals(filter, val))
52 | case "greater_than":
53 | return val != 0. && (val > filter)
54 | case "greater_than_or_equal":
55 | return val != 0. && ((val > filter) || floatApproxEquals(filter, val))
56 | }
57 | return floatApproxEquals(filter, val)
58 |
59 | case schema.TypeList:
60 | listValues := value.([]interface{})
61 | result := false
62 | for _, listValue := range listValues {
63 | valueDoesMatch := valueMatches(s.Elem.(*schema.Schema), listValue, filterValue, matchBy)
64 | result = result || valueDoesMatch
65 | }
66 | return result
67 |
68 | case schema.TypeSet:
69 | setValue := value.(*schema.Set)
70 | listValues := setValue.List()
71 | result := false
72 | for _, listValue := range listValues {
73 | valueDoesMatch := valueMatches(s.Elem.(*schema.Schema), listValue, filterValue, matchBy)
74 | result = result || valueDoesMatch
75 | }
76 | return result
77 | }
78 |
79 | return false
80 | }
81 |
82 | func compareValues(s *schema.Schema, value1 interface{}, value2 interface{}) int {
83 | switch s.Type {
84 | case schema.TypeString:
85 | return strings.Compare(value1.(string), value2.(string))
86 |
87 | case schema.TypeBool:
88 | boolValue1 := value1.(bool)
89 | boolValue2 := value2.(bool)
90 | if boolValue1 == boolValue2 {
91 | return 0
92 | } else if !boolValue1 {
93 | return -1
94 | } else {
95 | return 1
96 | }
97 |
98 | case schema.TypeInt:
99 | intValue1 := value1.(int)
100 | intValue2 := value2.(int)
101 | if intValue1 < intValue2 {
102 | return -1
103 | } else if intValue1 > intValue2 {
104 | return 1
105 | } else {
106 | return 0
107 | }
108 |
109 | case schema.TypeFloat:
110 | floatValue1 := value1.(float64)
111 | floatValue2 := value2.(float64)
112 | if floatApproxEquals(floatValue1, floatValue2) {
113 | return 0
114 | } else if floatValue1 < floatValue2 {
115 | return -1
116 | } else if floatValue1 > floatValue2 {
117 | return 1
118 | } else {
119 | return 0
120 | }
121 |
122 | default:
123 | panic("Illegal state: Unsupported value type for sort")
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/docs/resources/spot_market_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_spot_market_request"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal Spot Market Request Resource.
6 | ---
7 |
8 | # metal_spot_market_request (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_spot_market_request`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_spot_market_request) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_spot_market_request`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal Spot Market Request resource to allow you to
13 | manage spot market requests on your account. For more detail on Spot Market, see [this article in Equinix Metal documentation](https://metal.equinix.com/developers/docs/deploy/spot-market/).
14 |
15 | ## Example Usage
16 |
17 | ```hcl
18 | # Create a spot market request
19 | resource "metal_spot_market_request" "req" {
20 | project_id = local.project_id
21 | max_bid_price = 0.03
22 | facilities = ["ny5"]
23 | devices_min = 1
24 | devices_max = 1
25 |
26 | instance_parameters {
27 | hostname = "testspot"
28 | billing_cycle = "hourly"
29 | operating_system = "ubuntu_20_04"
30 | plan = "c3.small.x86"
31 | }
32 | }
33 | ```
34 |
35 | ## Argument Reference
36 |
37 | The following arguments are supported:
38 |
39 | * `devices_max` - (Required) Maximum number devices to be created
40 | * `devices_min` - (Required) Miniumum number devices to be created
41 | * `max_bid_price` - (Required) Maximum price user is willing to pay per hour per device
42 | * `project_id` - (Required) Project ID
43 | * `wait_for_devices` - (Optional) On resource creation - wait until all desired devices are active, on resource destruction - wait until devices are removed
44 | * `facilities` - (Optional) Facility IDs where devices should be created
45 | * `metro` - (Optional) Metro where devices should be created
46 | * `locked` - (Optional) Blocks deletion of the SpotMarketRequest device until the lock is disabled
47 | * `instance_parameters` - (Required) Parameters for devices provisioned from this request. You can find the parameter description from the [metal_device doc](device.md).
48 | * `billing_cycle`
49 | * `plan`
50 | * `operating_system`
51 | * `hostname`
52 | * `termintation_time`
53 | * `always_pxe`
54 | * `description`
55 | * `features`
56 | * `locked`
57 | * `project_ssh_keys`
58 | * `user_ssh_keys`
59 | * `userdata`
60 | * `customdata`
61 | * `ipxe_script_url`
62 | * `tags`
63 |
64 | ### Timeouts
65 |
66 | The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/configuration/resources#operation-timeouts) for certain actions:
67 |
68 | * `create` - (Defaults to 60 mins) Used when creating the Spot Market Request and `wait_for_devices == true`)
69 | * `delete` - (Defaults to 60 mins) Used when destroying the Spot Market Request and `wait for devices == true`
70 |
71 | ## Attributes Reference
72 |
73 | The following attributes are exported:
74 |
75 | * `id` - The ID of the Spot Market Request
76 | * `facilities` - The facilities where the Spot Market Request is applied. This is computed when `metro` is set or no specific location was requested.
77 |
78 | ## Import
79 |
80 | This resource can be imported using an existing spot market request ID:
81 |
82 | ```sh
83 | terraform import metal_spot_market_request {existing_spot_market_request_id}
84 | ```
85 |
--------------------------------------------------------------------------------
/metal/datasource_metal_project_ssh_key.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "path"
6 | "strings"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
10 | "github.com/packethost/packngo"
11 | )
12 |
13 | func dataSourceMetalProjectSSHKey() *schema.Resource {
14 | return &schema.Resource{
15 | DeprecationMessage: deprecatedProviderMsg,
16 | Read: dataSourceMetalProjectSSHKeyRead,
17 | Schema: map[string]*schema.Schema{
18 | "search": {
19 | Type: schema.TypeString,
20 | Description: "The name, fingerprint, id, or public_key of the SSH Key to search for in the Equinix Metal project",
21 | Optional: true,
22 | ValidateFunc: validation.NoZeroValues,
23 | },
24 | "id": {
25 | Type: schema.TypeString,
26 | Description: "The id of the SSH Key",
27 | Optional: true,
28 | ValidateFunc: validation.NoZeroValues,
29 | Computed: true,
30 | },
31 | "project_id": {
32 | Type: schema.TypeString,
33 | Description: "The Equinix Metal project id of the Equinix Metal SSH Key",
34 | Required: true,
35 | ValidateFunc: validation.NoZeroValues,
36 | },
37 | "name": {
38 | Type: schema.TypeString,
39 | Description: "The label of the Equinix Metal SSH Key",
40 | Computed: true,
41 | },
42 | "public_key": {
43 | Type: schema.TypeString,
44 | Description: "The public SSH key that will be authorized for SSH access on Equinix Metal devices provisioned with this key",
45 | Computed: true,
46 | },
47 | "fingerprint": {
48 | Type: schema.TypeString,
49 | Computed: true,
50 | },
51 | "created": {
52 | Type: schema.TypeString,
53 | Computed: true,
54 | },
55 | "updated": {
56 | Type: schema.TypeString,
57 | Computed: true,
58 | },
59 | "owner_id": {
60 | Type: schema.TypeString,
61 | Computed: true,
62 | },
63 | },
64 | }
65 | }
66 |
67 | func dataSourceMetalProjectSSHKeyRead(d *schema.ResourceData, meta interface{}) error {
68 | client := meta.(*packngo.Client)
69 |
70 | search := d.Get("search").(string)
71 | id := d.Get("id").(string)
72 | projectID := d.Get("project_id").(string)
73 |
74 | if id == "" && search == "" {
75 | return fmt.Errorf("You must supply either search or id")
76 | }
77 |
78 | var (
79 | key packngo.SSHKey
80 | searchOpts *packngo.SearchOptions
81 | )
82 |
83 | if search != "" {
84 | searchOpts = &packngo.SearchOptions{Search: search}
85 | }
86 | keys, _, err := client.Projects.ListSSHKeys(projectID, searchOpts)
87 |
88 | if err != nil {
89 | err = fmt.Errorf("Error listing project ssh keys: %s", friendlyError(err))
90 | return err
91 | }
92 |
93 | for i := range keys {
94 | // use the first match for searches
95 | if search != "" {
96 | key = keys[i]
97 | break
98 | }
99 |
100 | // otherwise find the matching ID
101 | if keys[i].ID == id {
102 | key = keys[i]
103 | break
104 | }
105 | }
106 |
107 | if key.ID == "" {
108 | // Not Found
109 | return fmt.Errorf("Project %q SSH Key matching %q was not found", projectID, search)
110 | }
111 |
112 | ownerID := path.Base(key.Owner.Href)
113 |
114 | d.SetId(key.ID)
115 | d.Set("name", key.Label)
116 | d.Set("public_key", key.Key)
117 | d.Set("fingerprint", key.FingerPrint)
118 | d.Set("owner_id", ownerID)
119 | d.Set("created", key.Created)
120 | d.Set("updated", key.Updated)
121 |
122 | if strings.Contains(key.Owner.Href, "/projects/") {
123 | d.Set("project_id", ownerID)
124 | }
125 |
126 | return nil
127 | }
128 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Hello Contributors
2 |
3 | Thx for your interest! We're so glad you're here.
4 |
5 | Before continuing, please note that this project is deprecated and all new work should be started in the [Equinix Terraform Provider](https://github.com/equinix/terraform-provider-equinix). See the [README.md](README.md) for more details.
6 |
7 | ## Contributing
8 | ### Important Resources
9 |
10 | - bugs: [https://github.com/equinix/terraform-provider-metal/issues](https://github.com/equinix/terraform-provider-metal/issues)
11 | - features: [https://github.com/equinix/terraform-provider-metal/issues](https://github.com/equinix/terraform-provider-metal/issues)
12 |
13 | ### Code of Conduct
14 |
15 | Available via [https://github.com/equinix/terraform-provider-metal/blob/main/.github/CODE_OF_CONDUCT.md](https://github.com/equinix/terraform-provider-metal/blob/main/.github/CODE_OF_CONDUCT.md)
16 |
17 | ### Environment Details
18 |
19 | [https://github.com/equinix/terraform-provider-metal/blob/main/GNUmakefile](https://github.com/equinix/terraform-provider-metal/blob/main/GNUmakefile)
20 |
21 | ### How to Submit Change Requests
22 |
23 | Please submit change requests and / or features via [Issues](https://github.com/equinix/terraform-provider-metal/issues). There's no guarantee it'll be changed, but you never know until you try. We'll try to add comments as soon as possible, though.
24 |
25 | ### How to Report a Bug
26 |
27 | Bugs are problems in code, in the functionality of an application or in its UI design; you can submit them through [Issues/(https://github.com/equinix/terraform-provider-metal/issues) as well.
28 |
29 | ## Development
30 | ### Requirements
31 |
32 | - [Terraform 0.12+](https://www.terraform.io/downloads.html) (for v1.0.0 of this provider and newer)
33 | - [Go](https://golang.org/doc/install) 1.13 (to build the provider plugin)
34 |
35 | ### Building the provider
36 |
37 | Clone the repository, enter the provider directory, and build the provider.
38 |
39 | ```sh
40 | git clone git@github.com:equinix/terraform-provider-metal
41 | cd terraform-provider-metal
42 | make build
43 | ```
44 |
45 | ### Developing the provider
46 |
47 | If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (version 1.13+ is *required*). You'll also need to correctly setup a [GOPATH](http://golang.org/doc/code.html#GOPATH), as well as adding `$GOPATH/bin` to your `$PATH`.
48 |
49 | To compile the provider, run `make build`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
50 |
51 | ```sh
52 | $ make bin
53 | ...
54 | $ $GOPATH/bin/terraform-provider-metal
55 | ...
56 | ```
57 |
58 | ### Testing provider code
59 |
60 | We have mostly acceptance tests in the provider. There's no point for you to run them all, but you should run the one covering the functionality which you change. The acceptance test run will cost you some money, so feel free to abstain. The acceptance test suite will be run for your PR during the review process.
61 |
62 | To run an acceptance test, find the relevant test function in `*_test.go` (for example TestAccMetalDevice_Basic), and run it as
63 |
64 | ```sh
65 | TF_ACC=1 go test -v -timeout=20m ./... -run=TestAccMetalDevice_Basic
66 | ```
67 |
68 | If you want to see HTTP traffic, set `TF_LOG=DEBUG`, i.e.
69 |
70 | ```sh
71 | TF_LOG=DEBUG TF_ACC=1 go test -v -timeout=20m ./... -run=TestAccMetalDevice_Basic
72 | ```
73 |
74 | ### Testing the provider with Terraform
75 |
76 | Once you've built the plugin binary (see [Developing the provider](#developing-the-provider) above), it can be incorporated within your Terraform environment using the `-plugin-dir` option. Subsequent runs of Terraform will then use the plugin from your development environment.
77 |
78 | ```sh
79 | terraform init -plugin-dir $GOPATH/bin
80 | ```
81 |
--------------------------------------------------------------------------------
/metal/datasource_metal_spot_market_request.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "strings"
5 | "time"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8 | "github.com/packethost/packngo"
9 | )
10 |
11 | func dataSourceMetalSpotMarketRequest() *schema.Resource {
12 | return &schema.Resource{
13 | DeprecationMessage: deprecatedProviderMsg,
14 | Read: dataSourceMetalSpotMarketRequestRead,
15 | Schema: map[string]*schema.Schema{
16 | "request_id": {
17 | Type: schema.TypeString,
18 | Description: "The id of the Spot Market Request",
19 | Required: true,
20 | },
21 | "device_ids": {
22 | Type: schema.TypeList,
23 | Description: "List of IDs of devices spawned by the referenced Spot Market Request",
24 | Computed: true,
25 | Elem: &schema.Schema{Type: schema.TypeString},
26 | },
27 | "devices_min": {
28 | Type: schema.TypeInt,
29 | Description: "Miniumum number devices to be created",
30 | Computed: true,
31 | },
32 | "devices_max": {
33 | Type: schema.TypeInt,
34 | Description: "Maximum number devices to be created",
35 | Computed: true,
36 | },
37 | "max_bid_price": {
38 | Type: schema.TypeFloat,
39 | Description: "Maximum price user is willing to pay per hour per device",
40 | Computed: true,
41 | },
42 | "facilities": {
43 | Type: schema.TypeList,
44 | Elem: &schema.Schema{Type: schema.TypeString},
45 | Description: "Facility IDs where devices should be created",
46 | Computed: true,
47 | },
48 | "metro": {
49 | Type: schema.TypeString,
50 | Description: "Metro where devices should be created.",
51 | Computed: true,
52 | },
53 | "project_id": {
54 | Type: schema.TypeString,
55 | Description: "Project ID",
56 | Computed: true,
57 | },
58 | "plan": {
59 | Type: schema.TypeString,
60 | Description: "The device plan slug.",
61 | Computed: true,
62 | },
63 | "end_at": {
64 | Type: schema.TypeString,
65 | Description: "Date and time When the spot market request will be ended.",
66 | Computed: true,
67 | },
68 | },
69 | Timeouts: resourceDefaultTimeouts,
70 | }
71 | }
72 | func dataSourceMetalSpotMarketRequestRead(d *schema.ResourceData, meta interface{}) error {
73 | client := meta.(*packngo.Client)
74 | id := d.Get("request_id").(string)
75 |
76 | smr, _, err := client.SpotMarketRequests.Get(id, &packngo.GetOptions{Includes: []string{"project", "devices", "facilities", "metro"}})
77 | if err != nil {
78 | err = friendlyError(err)
79 | if isNotFound(err) {
80 | d.SetId("")
81 | return nil
82 | }
83 | return err
84 | }
85 |
86 | deviceIDs := make([]string, len(smr.Devices))
87 | for i, d := range smr.Devices {
88 | deviceIDs[i] = d.ID
89 |
90 | }
91 |
92 | facs := smr.Facilities
93 | facCodes := []string{}
94 |
95 | for _, f := range facs {
96 | facCodes = append(facCodes, f.Code)
97 | }
98 |
99 | d.SetId(id)
100 |
101 | return setMap(d, map[string]interface{}{
102 | "device_ids": deviceIDs,
103 | "end_at": func(d *schema.ResourceData, k string) error {
104 | if smr.EndAt != nil {
105 | return d.Set(k, smr.EndAt.Format(time.RFC3339))
106 | }
107 | return nil
108 | },
109 | "devices_max": smr.DevicesMax,
110 | "devices_min": smr.DevicesMin,
111 | "facilities": facCodes,
112 | "metro": func(d *schema.ResourceData, k string) error {
113 | if smr.Metro != nil {
114 | return d.Set(k, strings.ToLower(smr.Metro.Code))
115 | }
116 | return nil
117 | },
118 | "max_bid_price": smr.MaxBidPrice,
119 | "plan": smr.Plan.Slug,
120 | "project_id": smr.Project.ID,
121 | // TODO: created_at is not in packngo
122 | })
123 | }
124 |
--------------------------------------------------------------------------------
/metal/datasource_metal_hardware_reservation.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7 | "github.com/packethost/packngo"
8 | )
9 |
10 | func dataSourceMetalHardwareReservation() *schema.Resource {
11 | return &schema.Resource{
12 | DeprecationMessage: deprecatedProviderMsg,
13 | Read: dataSourceMetalHardwareReservationRead,
14 | Schema: map[string]*schema.Schema{
15 | "id": {
16 | Type: schema.TypeString,
17 | Optional: true,
18 | Computed: true,
19 | Description: "ID of the hardware reservation to look up",
20 | },
21 | "device_id": {
22 | Type: schema.TypeString,
23 | Optional: true,
24 | Computed: true,
25 | Description: "UUID of device occupying the reservation",
26 | },
27 | "short_id": {
28 | Type: schema.TypeString,
29 | Computed: true,
30 | Description: "Reservation short ID",
31 | },
32 | "project_id": {
33 | Type: schema.TypeString,
34 | Computed: true,
35 | Description: "UUID of project this reservation is scoped to",
36 | },
37 | "plan": {
38 | Type: schema.TypeString,
39 | Computed: true,
40 | Description: "Plan type for the reservation",
41 | },
42 | "facility": {
43 | Type: schema.TypeString,
44 | Computed: true,
45 | Description: "Plan type for the reservation",
46 | },
47 | "provisionable": {
48 | Type: schema.TypeBool,
49 | Computed: true,
50 | Description: "Flag indicating whether the reserved server is provisionable or not. Spare devices can't be provisioned unless they are activated first",
51 | },
52 | "spare": {
53 | Type: schema.TypeBool,
54 | Computed: true,
55 | Description: "Flag indicating whether the Hardware Reservation is a spare. Spare Hardware Reservations are used when a Hardware Reservations requires service from Metal Equinix",
56 | },
57 | "switch_uuid": {
58 | Type: schema.TypeString,
59 | Computed: true,
60 | Description: "Switch short ID, can be used to determine if two devices are connected to the same switch",
61 | },
62 | },
63 | }
64 | }
65 |
66 | func dataSourceMetalHardwareReservationRead(d *schema.ResourceData, meta interface{}) error {
67 | client := meta.(*packngo.Client)
68 | hrIdRaw, hrIdOk := d.GetOk("id")
69 | dIdRaw, dIdOk := d.GetOk("device_id")
70 |
71 | if dIdOk == hrIdOk {
72 | return fmt.Errorf("You must set one of id and device_id")
73 | }
74 |
75 | var deviceId string
76 | var hr *packngo.HardwareReservation
77 |
78 | if dIdOk {
79 | deviceId = dIdRaw.(string)
80 | includes := []string{
81 | "hardware_reservation.project",
82 | "hardware_reservation.facility",
83 | }
84 | d, _, err := client.Devices.Get(deviceId, &packngo.GetOptions{Includes: includes})
85 | if err != nil {
86 | return err
87 | }
88 | if d.HardwareReservation == nil {
89 | return fmt.Errorf("Device %s is not in a hardware reservation", deviceId)
90 | }
91 | hr = d.HardwareReservation
92 |
93 | } else {
94 | var err error
95 | hr, _, err = client.HardwareReservations.Get(
96 | hrIdRaw.(string),
97 | &packngo.GetOptions{Includes: []string{"project", "facility", "device"}})
98 | if err != nil {
99 | return err
100 | }
101 | if hr.Device != nil {
102 | deviceId = hr.Device.ID
103 | }
104 | }
105 |
106 | m := map[string]interface{}{
107 | "short_id": hr.ShortID,
108 | "project_id": hr.Project.ID,
109 | "device_id": deviceId,
110 | "plan": hr.Plan.Slug,
111 | "facility": hr.Facility.Code,
112 | "provisionable": hr.Provisionable,
113 | "spare": hr.Spare,
114 | "switch_uuid": hr.SwitchUUID,
115 | }
116 |
117 | d.SetId(hr.ID)
118 | return setMap(d, m)
119 | }
120 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/equinix/terraform-provider-metal
2 |
3 | require (
4 | github.com/hashicorp/errwrap v1.0.0
5 | github.com/hashicorp/go-multierror v1.0.0
6 | github.com/hashicorp/go-retryablehttp v0.6.6
7 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.9.0
8 | github.com/packethost/packngo v0.25.0
9 | github.com/stretchr/testify v1.7.0
10 | )
11 |
12 | require (
13 | cloud.google.com/go v0.61.0 // indirect
14 | cloud.google.com/go/storage v1.10.0 // indirect
15 | github.com/agext/levenshtein v1.2.2 // indirect
16 | github.com/apparentlymart/go-cidr v1.0.1 // indirect
17 | github.com/apparentlymart/go-textseg v1.0.0 // indirect
18 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
19 | github.com/aws/aws-sdk-go v1.25.3 // indirect
20 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
21 | github.com/davecgh/go-spew v1.1.1 // indirect
22 | github.com/fatih/color v1.7.0 // indirect
23 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
24 | github.com/golang/protobuf v1.4.2 // indirect
25 | github.com/google/go-cmp v0.5.6 // indirect
26 | github.com/googleapis/gax-go/v2 v2.0.5 // indirect
27 | github.com/hashicorp/go-checkpoint v0.5.0 // indirect
28 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
29 | github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
30 | github.com/hashicorp/go-getter v1.5.3 // indirect
31 | github.com/hashicorp/go-hclog v0.15.0 // indirect
32 | github.com/hashicorp/go-plugin v1.4.1 // indirect
33 | github.com/hashicorp/go-safetemp v1.0.0 // indirect
34 | github.com/hashicorp/go-uuid v1.0.1 // indirect
35 | github.com/hashicorp/go-version v1.3.0 // indirect
36 | github.com/hashicorp/hcl/v2 v2.3.0 // indirect
37 | github.com/hashicorp/logutils v1.0.0 // indirect
38 | github.com/hashicorp/terraform-exec v0.15.0 // indirect
39 | github.com/hashicorp/terraform-json v0.13.0 // indirect
40 | github.com/hashicorp/terraform-plugin-go v0.4.0 // indirect
41 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
42 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
43 | github.com/jstemmer/go-junit-report v0.9.1 // indirect
44 | github.com/klauspost/compress v1.11.2 // indirect
45 | github.com/mattn/go-colorable v0.1.4 // indirect
46 | github.com/mattn/go-isatty v0.0.10 // indirect
47 | github.com/mitchellh/copystructure v1.2.0 // indirect
48 | github.com/mitchellh/go-homedir v1.1.0 // indirect
49 | github.com/mitchellh/go-testing-interface v1.0.4 // indirect
50 | github.com/mitchellh/go-wordwrap v1.0.0 // indirect
51 | github.com/mitchellh/mapstructure v1.1.2 // indirect
52 | github.com/mitchellh/reflectwalk v1.0.2 // indirect
53 | github.com/oklog/run v1.0.0 // indirect
54 | github.com/pmezard/go-difflib v1.0.0 // indirect
55 | github.com/ulikunitz/xz v0.5.8 // indirect
56 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
57 | github.com/zclconf/go-cty v1.9.1 // indirect
58 | go.opencensus.io v0.22.4 // indirect
59 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
60 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
61 | golang.org/x/mod v0.3.0 // indirect
62 | golang.org/x/net v0.0.0-20210326060303-6b1517762897 // indirect
63 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
64 | golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 // indirect
65 | golang.org/x/text v0.3.5 // indirect
66 | golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed // indirect
67 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
68 | google.golang.org/api v0.29.0 // indirect
69 | google.golang.org/appengine v1.6.6 // indirect
70 | google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect
71 | google.golang.org/grpc v1.32.0 // indirect
72 | google.golang.org/protobuf v1.25.0 // indirect
73 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
74 | )
75 |
76 | go 1.17
77 |
--------------------------------------------------------------------------------
/metal/resource_metal_gateway_test.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
9 | "github.com/packethost/packngo"
10 | )
11 |
12 | func testAccMetalGatewayConfig_PrivateIPv4() string {
13 | return fmt.Sprintf(`
14 | resource "metal_project" "test" {
15 | name = "%[1]s-pro-gateway-test"
16 | }
17 |
18 | resource "metal_vlan" "test" {
19 | description = "%[1]s-vlan in SV"
20 | metro = "sv"
21 | project_id = metal_project.test.id
22 | }
23 |
24 | resource "metal_gateway" "test" {
25 | project_id = metal_project.test.id
26 | vlan_id = metal_vlan.test.id
27 | private_ipv4_subnet_size = 8
28 | }
29 | `, tstResourcePrefix)
30 | }
31 |
32 | func TestAccMetalGateway_PrivateIPv4(t *testing.T) {
33 | resource.ParallelTest(t, resource.TestCase{
34 | PreCheck: func() { testAccPreCheck(t) },
35 | Providers: testAccProviders,
36 | CheckDestroy: testAccCheckMetalGatewayDestroyed,
37 | Steps: []resource.TestStep{
38 | {
39 | Config: testAccMetalGatewayConfig_PrivateIPv4(),
40 | Check: resource.ComposeTestCheckFunc(
41 | resource.TestCheckResourceAttrPair(
42 | "metal_gateway.test", "project_id",
43 | "metal_project.test", "id"),
44 | resource.TestCheckResourceAttr(
45 | "metal_gateway.test", "private_ipv4_subnet_size", "8"),
46 | ),
47 | },
48 | },
49 | })
50 | }
51 |
52 | func testAccMetalGatewayConfig_ExistingReservation() string {
53 | return fmt.Sprintf(`
54 | resource "metal_project" "test" {
55 | name = "%[1]s-pro-gateway-test"
56 | }
57 |
58 | resource "metal_vlan" "test" {
59 | description = "%[1]s-vlan in SV"
60 | metro = "sv"
61 | project_id = metal_project.test.id
62 | }
63 |
64 | resource "metal_reserved_ip_block" "test" {
65 | project_id = metal_project.test.id
66 | metro = "sv"
67 | quantity = 8
68 | }
69 |
70 | resource "metal_gateway" "test" {
71 | project_id = metal_project.test.id
72 | vlan_id = metal_vlan.test.id
73 | ip_reservation_id = metal_reserved_ip_block.test.id
74 | }
75 | `, tstResourcePrefix)
76 | }
77 |
78 | func TestAccMetalGateway_ExistingReservation(t *testing.T) {
79 | resource.ParallelTest(t, resource.TestCase{
80 | PreCheck: func() { testAccPreCheck(t) },
81 | Providers: testAccProviders,
82 | CheckDestroy: testAccCheckMetalGatewayDestroyed,
83 | Steps: []resource.TestStep{
84 | {
85 | Config: testAccMetalGatewayConfig_ExistingReservation(),
86 | Check: resource.ComposeTestCheckFunc(
87 | resource.TestCheckResourceAttrPair(
88 | "metal_gateway.test", "project_id",
89 | "metal_project.test", "id"),
90 | resource.TestCheckResourceAttrPair(
91 | "metal_gateway.test", "ip_reservation_id",
92 | "metal_reserved_ip_block.test", "id"),
93 | ),
94 | },
95 | },
96 | })
97 | }
98 |
99 | func testAccCheckMetalGatewayDestroyed(s *terraform.State) error {
100 | client := testAccProvider.Meta().(*packngo.Client)
101 |
102 | for _, rs := range s.RootModule().Resources {
103 | if rs.Type != "metal_gateway" {
104 | continue
105 | }
106 | if _, _, err := client.MetalGateways.Get(rs.Primary.ID, nil); err == nil {
107 | return fmt.Errorf("Gateway still exists")
108 | }
109 | }
110 |
111 | return nil
112 | }
113 |
114 | func TestAccMetalGateway_importBasic(t *testing.T) {
115 | resource.ParallelTest(t, resource.TestCase{
116 | PreCheck: func() { testAccPreCheck(t) },
117 | Providers: testAccProviders,
118 | CheckDestroy: testAccCheckMetalGatewayDestroyed,
119 | Steps: []resource.TestStep{
120 | {
121 | Config: testAccMetalGatewayConfig_PrivateIPv4(),
122 | },
123 | {
124 | ResourceName: "metal_gateway.test",
125 | ImportState: true,
126 | ImportStateVerify: true,
127 | },
128 | },
129 | })
130 | }
131 |
--------------------------------------------------------------------------------
/metal/resource_metal_device_network_type.go:
--------------------------------------------------------------------------------
1 | package metal
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
8 | "github.com/packethost/packngo"
9 | )
10 |
11 | func resourceMetalDeviceNetworkType() *schema.Resource {
12 | return &schema.Resource{
13 | DeprecationMessage: deprecatedProviderMsg,
14 | Create: resourceMetalDeviceNetworkTypeCreate,
15 | Read: resourceMetalDeviceNetworkTypeRead,
16 | Delete: resourceMetalDeviceNetworkTypeDelete,
17 | Update: resourceMetalDeviceNetworkTypeUpdate,
18 | Importer: &schema.ResourceImporter{
19 | State: schema.ImportStatePassthrough,
20 | },
21 |
22 | Schema: map[string]*schema.Schema{
23 | "device_id": {
24 | Type: schema.TypeString,
25 | Description: "The ID of the device on which the network type should be set",
26 | Required: true,
27 | ForceNew: true,
28 | },
29 | "type": {
30 | Type: schema.TypeString,
31 | Description: "Network type to set. Must be one of " + NetworkTypeListHB,
32 | Required: true,
33 | ValidateFunc: validation.StringInSlice(DeviceNetworkTypesHB, false),
34 | },
35 | },
36 | }
37 | }
38 |
39 | func getDevIDandNetworkType(d *schema.ResourceData, c *packngo.Client) (string, string, error) {
40 | deviceID := d.Id()
41 | if len(deviceID) == 0 {
42 | deviceID = d.Get("device_id").(string)
43 | }
44 |
45 | dev, _, err := c.Devices.Get(deviceID, nil)
46 | if err != nil {
47 | return "", "", err
48 | }
49 | devType := dev.GetNetworkType()
50 |
51 | return dev.ID, devType, nil
52 | }
53 |
54 | func getAndPossiblySetNetworkType(d *schema.ResourceData, c *packngo.Client, targetType string) error {
55 | // "hybrid-bonded" is an alias for "layer3" with VLAN(s) connected. We use
56 | // other resource for VLAN attachment, so we treat these two as equivalent
57 | if targetType == "hybrid-bonded" {
58 | targetType = "layer3"
59 | }
60 | devID, devType, err := getDevIDandNetworkType(d, c)
61 | if err != nil {
62 | return err
63 | }
64 |
65 | if devType != targetType {
66 | _, err := c.DevicePorts.DeviceToNetworkType(devID, targetType)
67 | if err != nil {
68 | return err
69 | }
70 | }
71 | return nil
72 | }
73 |
74 | func resourceMetalDeviceNetworkTypeCreate(d *schema.ResourceData, meta interface{}) error {
75 | client := meta.(*packngo.Client)
76 | ntype := d.Get("type").(string)
77 |
78 | err := getAndPossiblySetNetworkType(d, client, ntype)
79 | if err != nil {
80 | return err
81 | }
82 | d.SetId(d.Get("device_id").(string))
83 | return resourceMetalDeviceNetworkTypeRead(d, meta)
84 | }
85 |
86 | func resourceMetalDeviceNetworkTypeRead(d *schema.ResourceData, meta interface{}) error {
87 | client := meta.(*packngo.Client)
88 |
89 | _, devNType, err := getDevIDandNetworkType(d, client)
90 |
91 | if err != nil {
92 | err = friendlyError(err)
93 |
94 | if isNotFound(err) {
95 | log.Printf("[WARN] Device (%s) for Network Type request not found, removing from state", d.Id())
96 | d.SetId("")
97 | return nil
98 | }
99 |
100 | return err
101 | }
102 |
103 | // if "hybrid-bonded" is set as desired state and current state is "layer3",
104 | // keep the value in "hybrid-bonded"
105 | currentType := d.Get("type").(string)
106 | if currentType == "hybrid-bonded" && devNType == "layer3" {
107 | devNType = "hybrid-bonded"
108 | }
109 |
110 | d.Set("type", devNType)
111 |
112 | return nil
113 | }
114 |
115 | func resourceMetalDeviceNetworkTypeUpdate(d *schema.ResourceData, meta interface{}) error {
116 | client := meta.(*packngo.Client)
117 | ntype := d.Get("type").(string)
118 | if d.HasChange("type") {
119 | err := getAndPossiblySetNetworkType(d, client, ntype)
120 | if err != nil {
121 | return err
122 | }
123 | }
124 |
125 | return resourceMetalDeviceNetworkTypeRead(d, meta)
126 | }
127 |
128 | func resourceMetalDeviceNetworkTypeDelete(d *schema.ResourceData, meta interface{}) error {
129 | return nil
130 | }
131 |
--------------------------------------------------------------------------------
/docs/resources/vrf.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_vrf"
3 | subcategory: ""
4 | description: |-
5 | (not-GA) Provides a resource for Equinix Metal VRF.
6 | ---
7 |
8 | # metal_vrf (Resource)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_vrf`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/resources/equinix_metal_vrf) resource from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_vrf`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Use this resource to manage a VRF.
13 |
14 | ~> VRF features are not generally available. The interfaces related to VRF resources may change ahead of general availability.
15 |
16 | ## Example Usage
17 |
18 | Create a VRF in your desired metro and project with any IP ranges that you want the VRF to route and forward.
19 |
20 | ```hcl
21 | resource "metal_project" "example" {
22 | name = "example"
23 | }
24 |
25 | resource "metal_vrf" "example" {
26 | description = "VRF with ASN 65000 and a pool of address space that includes 192.168.100.0/25"
27 | name = "example-vrf"
28 | metro = "da"
29 | local_asn = "65000"
30 | ip_ranges = ["192.168.100.0/25", "192.168.200.0/25"]
31 | project_id = metal_project.example.id
32 | }
33 | ```
34 |
35 | Create IP reservations and assign them to a Metal Gateway resources. The Gateway will be assigned the first address in the block.
36 |
37 | ```hcl
38 | resource "metal_reserved_ip_block" "example" {
39 | description = "Reserved IP block (192.168.100.0/29) taken from on of the ranges in the VRF's pool of address space."
40 | project_id = metal_project.example.id
41 | metro = metal_vrf.example.metro
42 | type = "vrf"
43 | vrf_id = metal_vrf.example.id
44 | cidr = 29
45 | network = "192.168.100.0"
46 | }
47 |
48 | resource "metal_vlan" "example" {
49 | description = "A VLAN for Layer2 and Hybrid Metal devices"
50 | metro = metal_vrf.example.metro
51 | project_id = metal_project.example.id
52 | }
53 |
54 | resource "metal_gateway" "example" {
55 | description = "A Gateway on the VRF192.168.100.0/29
56 | project_id = metal_project.example.id
57 | vlan_id = metal_vlan.example.id
58 | ip_reservation_id = metal_reserved_ip_block.example.id
59 | }
60 | ```
61 |
62 | Attach a Virtual Circuit from a Dedicated Metal Connection to the Metal Gateway.
63 |
64 | ```hcl
65 | data "metal_connection" "example" {
66 | connection_id = var.metal_dedicated_connection_id
67 | }
68 |
69 | resource "metal_virtual_circuit" "example" {
70 | name = "example-vc"
71 | description = "Virtual Circuit"
72 | connection_id = data.metal_connection.example.id
73 | project_id = metal_project.example.id
74 | port_id = data.metal_connection.example.ports[0].id
75 | nni_vlan = 1024
76 | vrf_id = metal_vrf.example.id
77 | peer_asn = 65530
78 | subnet = "192.168.100.16/31"
79 | metal_ip = "192.168.100.16"
80 | customer_ip = "192.168.100.17"
81 | }
82 | ```
83 |
84 | ## Argument Reference
85 |
86 | The following arguments are supported:
87 |
88 | * `name` - (Required) User-supplied name of the VRF, unique to the project
89 | * `metro` - (Required) Metro ID or Code where the VRF will be deployed.
90 | * `project_id` - (Required) Project ID where the VRF will be deployed.
91 | * `description` - (Optional) Description of the VRF.
92 | * `local_asn` - (Optional) The 4-byte ASN set on the VRF.
93 | * `ip_ranges` - (Optional) All IPv4 and IPv6 Ranges that will be available to BGP Peers. IPv4 addresses must be /8 or smaller with a minimum size of /29. IPv6 must be /56 or smaller with a minimum size of /64. Ranges must not overlap other ranges within the VRF.
94 |
95 | ## Attributes Reference
96 |
97 | No additional attributes are exported.
98 |
99 | ## Import
100 |
101 | This resource can be imported using an existing VRF ID:
102 |
103 | ```sh
104 | terraform import metal_vrf {existing_id}
105 | ```
106 |
--------------------------------------------------------------------------------
/docs/data-sources/device.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "Equinix Metal: metal_device"
3 | subcategory: ""
4 | description: |-
5 | Provides an Equinix Metal device datasource. This can be used to read existing devices.
6 | ---
7 |
8 | # metal_device (Data Source)
9 |
10 | !> **PROVIDER DEPRECATED:** Equinix Metal Provider is now Deprecated. Please consider using [`equinix_metal_device`](https://registry.terraform.io/providers/equinix/equinix/latest/docs/data-sources/equinix_metal_device) data source from the [Equinix provider](https://registry.terraform.io/providers/equinix/equinix/latest/docs) instead of `metal_device`. [See the Metal provider section for more details](../index.md#equinix-metal-provider) on the new provider and available migration guides.
11 |
12 | Provides an Equinix Metal device datasource.
13 |
14 | ~> **Note:** All arguments including the `root_password` and `user_data` will be stored in
15 | the raw state as plain-text.
16 | [Read more about sensitive data in state](/docs/state/sensitive-data.html).
17 |
18 | ## Example Usage
19 |
20 | ```hcl
21 | # Fetch a device data by hostname and show it's ID
22 |
23 | data "metal_device" "test" {
24 | project_id = local.project_id
25 | hostname = "mydevice"
26 | }
27 |
28 | output "id" {
29 | value = data.metal_device.test.id
30 | }
31 | ```
32 |
33 | ```hcl
34 | # Fetch a device data by ID and show its public IPv4
35 | data "metal_device" "test" {}
36 |
37 | output "ipv4" {
38 | value = data.metal_device.test.access_public_ipv4
39 | }
40 | ```
41 |
42 | ## Argument Reference
43 |
44 | The following arguments are supported:
45 |
46 | * `hostname` - The device name
47 | * `project_id` - The id of the project in which the devices exists
48 | * `device_id` - Device ID
49 |
50 | User can lookup devices either by `device_id` or `project_id` and `hostname`.
51 |
52 | ## Attributes Reference
53 |
54 | The following attributes are exported:
55 |
56 | * `access_private_ipv4` - The ipv4 private IP assigned to the device
57 | * `access_public_ipv4` - The ipv4 management IP assigned to the device
58 | * `access_public_ipv6` - The ipv6 management IP assigned to the device
59 | * `billing_cycle` - The billing cycle of the device (monthly or hourly)
60 | * `facility` - The facility where the device is deployed.
61 | * `description` - Description string for the device
62 | * `hardware_reservation_id` - The id of hardware reservation which this device occupies
63 | * `id` - The ID of the device
64 | * `metro` - The metro where the device is deployed
65 | * `network` - The device's private and public IP (v4 and v6) network details. When a device is run without any special network configuration, it will have 3 networks:
66 | * Public IPv4 at `metal_device.name.network.0`
67 | * IPv6 at `metal_device.name.network.1`
68 | * Private IPv4 at `metal_device.name.network.2`
69 | Elastic addresses then stack by type - an assigned public IPv4 will go after the management public IPv4 (to index 1), and will then shift the indices of the IPv6 and private IPv4. Assigned private IPv4 will go after the management private IPv4 (to the end of the network list).
70 | The fields of the network attributes are:
71 | * `address` - IPv4 or IPv6 address string
72 | * `cidr` - Bit length of the network mask of the address
73 | * `gateway` - Address of router
74 | * `public` - Whether the address is routable from the Internet
75 | * `family` - IP version - "4" or "6"
76 | * `network_type` - L2 network type of the device, one of "layer3", "layer2-bonded", "layer2-individual", "hybrid"
77 | * `operating_system` - The operating system running on the device
78 | * `plan` - The hardware config of the device
79 | * `ports` - Ports assigned to the device
80 | * `name` - Name of the port (e.g. `eth0`, or `bond0`)
81 | * `id` - ID of the port
82 | * `type` - Type of the port (e.g. `NetworkPort` or `NetworkBondPort`)
83 | * `mac` - MAC address assigned to the port
84 | * `bonded` - Whether this port is part of a bond in bonded network setup
85 | * `root_password` - Root password to the server (if still available)
86 | * `ssh_key_ids` - List of IDs of SSH keys deployed in the device, can be both user or project SSH keys
87 | * `state` - The state of the device
88 | * `tags` - Tags attached to the device
89 |
--------------------------------------------------------------------------------