diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 20c2d50..1d96707 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -34,7 +34,7 @@ jobs: build-mode: autobuild steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index c4c3d4b..448a613 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout repository' - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: 'Dependency Review' uses: actions/dependency-review-action@v4 with: diff --git a/.github/workflows/ensure-docs-compiled.yaml b/.github/workflows/ensure-docs-compiled.yaml index f51d5bc..c6bbc2e 100644 --- a/.github/workflows/ensure-docs-compiled.yaml +++ b/.github/workflows/ensure-docs-compiled.yaml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout 🛎 - uses: actions/checkout@v5 + uses: actions/checkout@v6 - uses: actions/setup-go@v6 - shell: bash run: make generate diff --git a/.github/workflows/go-test-multiplatform.yml b/.github/workflows/go-test-multiplatform.yml index d30c827..4356929 100644 --- a/.github/workflows/go-test-multiplatform.yml +++ b/.github/workflows/go-test-multiplatform.yml @@ -20,7 +20,7 @@ jobs: runs-on: macos-latest name: Darwin Go tests steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable @@ -31,7 +31,7 @@ jobs: runs-on: windows-latest name: Windows Go tests steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest name: Linux Go tests steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable diff --git a/.github/workflows/go-validate.yml b/.github/workflows/go-validate.yml index 3cfb7ce..b45030d 100644 --- a/.github/workflows/go-validate.yml +++ b/.github/workflows/go-validate.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest name: Go Mod Tidy steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest name: Lint check steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-latest name: Gofmt check steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable @@ -48,7 +48,7 @@ jobs: runs-on: ubuntu-latest name: Generate check steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: stable diff --git a/.github/workflows/integration-unit-test.yml b/.github/workflows/integration-unit-test.yml index d1572d5..34ed592 100644 --- a/.github/workflows/integration-unit-test.yml +++ b/.github/workflows/integration-unit-test.yml @@ -17,7 +17,7 @@ jobs: EXIT_STATUS: 0 steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Go uses: actions/setup-go@v6 @@ -39,7 +39,7 @@ jobs: - name: Upload test report as artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: test-report-file path: "${{ env.REPORT_FILENAME }}" @@ -51,13 +51,13 @@ jobs: - integration-and-unit-tests steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 submodules: 'recursive' - name: Download test report - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: test-report-file diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 7a3ee5f..843a41c 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Run Labeler uses: crazy-max/ghaction-github-labeler@24d110aa46a59976b8a7f35518cb7f14f434c916 diff --git a/.github/workflows/notify-integration-release-via-manual.yaml b/.github/workflows/notify-integration-release-via-manual.yaml index 36a4cb1..62b1940 100644 --- a/.github/workflows/notify-integration-release-via-manual.yaml +++ b/.github/workflows/notify-integration-release-via-manual.yaml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout this repo - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.event.inputs.branch }} # Ensure that Docs are Compiled @@ -35,7 +35,7 @@ jobs: fi # Perform the Release - name: Checkout integration-release-action - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: hashicorp/integration-release-action path: ./integration-release-action diff --git a/.github/workflows/notify-integration-release-via-tag.yaml b/.github/workflows/notify-integration-release-via-tag.yaml index 032e4bd..e7c003b 100644 --- a/.github/workflows/notify-integration-release-via-tag.yaml +++ b/.github/workflows/notify-integration-release-via-tag.yaml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout this repo - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.ref }} # Ensure that Docs are Compiled @@ -39,7 +39,7 @@ jobs: fi # Perform the Release - name: Checkout integration-release-action - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: hashicorp/integration-release-action path: ./integration-release-action diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e01af2b..a659a0b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Unshallow run: git fetch --prune --unshallow - name: Set up Go diff --git a/.github/workflows/test-plugin-example.yml b/.github/workflows/test-plugin-example.yml index bb0438d..c774ed8 100644 --- a/.github/workflows/test-plugin-example.yml +++ b/.github/workflows/test-plugin-example.yml @@ -22,7 +22,7 @@ jobs: name: init and build example steps: - name: Checkout Repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Init uses: hashicorp/packer-github-actions@master diff --git a/.web-docs/components/builder/linode/README.md b/.web-docs/components/builder/linode/README.md index 2654932..b9fffa9 100644 --- a/.web-docs/components/builder/linode/README.md +++ b/.web-docs/components/builder/linode/README.md @@ -75,9 +75,11 @@ can also be supplied to override the typical auto-generated key: -- `interface` ([]Interface) - Network Interfaces to add to this Linode’s Configuration Profile. Singular repeatable +- `interface` ([]Interface) - Legacy Config Network Interfaces to add to this Linode’s Configuration Profile. Singular repeatable block containing a `purpose`, a `label`, and an `ipam_address` field. +- `linode_interface` ([]LinodeInterface) - Newer Linode Network Interfaces to add to this Linode. + - `authorized_keys` ([]string) - Public SSH keys need to be appended to the Linode instance. - `authorized_users` ([]string) - Users whose SSH keys need to be appended to the Linode instance. @@ -125,14 +127,223 @@ can also be supplied to override the typical auto-generated key: - `image_regions` ([]string) - The regions where the outcome image will be replicated to. +- `interface_generation` (string) - Specifies the interface type for the Linode. The value can be either + `legacy_config` or `linode`. The default value is determined by the + `interfaces_for_new_linodes` setting in the account settings. + -#### Interface +#### Linode Interface + +This section outlines the fields configurable for a newer Linode interface object. + + + +- `firewall_id` (\*int) - The enabled firewall to secure a VPC or public interface. Not allowed for VLAN interfaces. + +- `default_route` (\*InterfaceDefaultRoute) - Indicates if the interface serves as the default route when multiple interfaces are + eligible for this role. + +- `public` (\*PublicInterface) - Public interface settings. A Linode can have only one public interface. + A public interface can have both IPv4 and IPv6 configurations. + +- `vpc` (\*VPCInterface) - VPC interface settings. + +- `vlan` (\*VLANInterface) - VLAN interface settings. + + + + +##### Linode Interface Default Route configuration object (InterfaceDefaultRoute) + +###### Optional + + + +- `ipv4` (\*bool) - Whether this interface is used for the IPv4 default route. + +- `ipv6` (\*bool) - Whether this interface is used for the IPv6 default route. + + + + +##### Public Linode Interface configuration object (PublicInterface) + +###### Optional + + + +- `ipv4` (\*PublicInterfaceIPv4) - IPv4 address settings for this public interface. If omitted, + a public IPv4 address is automatically allocated. + +- `ipv6` (\*PublicInterfaceIPv6) - IPv6 address settings for the public interface. + + + + +##### Public Linode Interface IPv4 configuration object (PublicInterfaceIPv4) + +###### Optional + + + +- `address` ([]PublicInterfaceIPv4Address) - Blocks of IPv4 addresses to assign to this interface. Setting any to auto + allocates a public IPv4 address. + + + + +##### Public Linode Interface IPv4 Address configuration object (PublicInterfaceIPv4Address) + +###### Required + + + +- `address` (\*string) - The interface's public IPv4 address. You can specify which public IPv4 + address to configure for the interface. Setting this to auto automatically + allocates a public address. + + + + +###### Optional + + + +- `primary` (\*bool) - The IPv4 primary address configures the source address for routes within + the Linode on the corresponding network interface. + + - Don't set this to false if there's only one address in the addresses array. + - If more than one address is provided, primary can be set to true for one address. + - If only one address is present in the addresses array, this address is automatically set as the primary address. + + + + +##### Public Linode Interface IPv6 configuration object (PublicInterfaceIPv6) + +###### Optional + + + +- `ranges` ([]PublicInterfaceIPv6Range) - IPv6 address ranges to assign to this interface. If omitted, no ranges are assigned. + + + + +##### Public Linode Interface IPv6 Range configuration object (PublicInterfaceIPv6Range) + +###### Required + + + +- `range` (string) - Your assigned IPv6 range in CIDR notation (2001:0db8::1/64) or prefix (/64). + + - The prefix of /64 or /56 block of IPv6 addresses. + - If provided in CIDR notation, the prefix must be within the assigned ranges for the Linode. + + + + +##### VPC Linode Interface configuration object (VPCInterface) + +###### Required + + + +- `subnet_id` (int) - The VPC subnet identifier for this interface. Your subnet’s VPC must be in + the same data center (region) as the Linode. + + + + +###### Optional + + + +- `ipv4` (\*VPCInterfaceIPv4) - Interfaces can be configured with IPv4 addresses or ranges. + + + + +##### VPC Linode Interface IPv4 configuration object (VPCInterfaceIPv4) + +###### Optional + + + +- `addresses` ([]VPCInterfaceIPv4Address) - IPv4 address settings for this VPC interface. + +- `ranges` ([]VPCInterfaceIPv4Range) - VPC IPv4 ranges. + + + + +##### VPC Linode Interface IPv4 Address configuration object (VPCInterfaceIPv4Address) + +###### Required -This section outlines the fields configurable for a single interface object. + -##### Required Interface Common Attributes +- `address` (\*string) - Specifies which IPv4 address to use in the VPC subnet. You can specify which + VPC Ipv4 address in the subnet to configure for the interface. You can't use + an IPv4 address taken from another Linode or interface, or the first two or + last two addresses in the VPC subnet. When address is set to `auto`, an IP + address from the subnet is automatically assigned. + + + + +###### Optional + + + +- `primary` (\*bool) - The IPv4 primary address is used to configure the source address for routes + within the Linode on the corresponding network interface. + +- `nat_1_1_address` (\*string) - The 1:1 NAT IPv4 address used to associate a public IPv4 address with the + interface's VPC subnet IPv4 address. + + + + +##### VPC Linode Interface IPv4 Range configuration object (VPCInterfaceIPv4Range) + +###### Required + + + +- `range` (string) - VPC IPv4 ranges. + + + + +##### VLAN Linode Interface configuration object (VLANInterface) + +###### Required + + + +- `vlan_label` (string) - The VLAN's unique label. VLAN interfaces on the same Linode must have a unique `vlan_label`. + + + + +###### Optional + + + +- `ipam_address` (\*string) - This VLAN interface's private IPv4 address in classless inter-domain routing (CIDR) notation. + + + + +#### Legacy Config Interface + +This section outlines the fields configurable for a single legacy config interface object. + +##### Required Config Interface Common Attributes @@ -141,7 +352,7 @@ This section outlines the fields configurable for a single interface object. -##### Optional Interface Common Attributes +##### Optional Config Interface Common Attributes @@ -174,7 +385,7 @@ This section outlines the fields configurable for a single interface object. -###### VPC Interface IPv4 configuration object +###### VPC Config Interface IPv4 configuration object (InterfaceIPv4) @@ -369,3 +580,78 @@ build { } } ``` + +## Linode Interface Example + +**HCL2** + +```hcl +locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") } + +source "linode" "example" { + image = "linode/ubuntu24.04" + image_description = "My Private Image" + image_label = "private-image-${local.timestamp}" + instance_label = "temporary-linode-${local.timestamp}" + instance_type = "g6-standard-1" + region = "us-mia" + ssh_username = "root" + interface_generation = "linode" + + linode_interface { + firewall_id = 12345 + public { + ipv4 { + address { + address = "auto" + primary = true + } + } + } + } +} + +build { + sources = ["source.linode.example"] +} +``` + +**JSON** + +```json +{ + "source": { + "linode": { + "example": { + "image": "linode/ubuntu24.04", + "linode_token": "YOUR API TOKEN", + "region": "us-mia", + "instance_type": "g6-nanode-1", + "instance_label": "temporary-linode-{{timestamp}}", + "image_label": "private-image-{{timestamp}}", + "image_description": "My Private Image", + "ssh_username": "root", + "interface_generation": "linode", + "linode_interface": { + "firewall_id": 2930969, + "public": { + "ipv4": { + "addresses": [ + { + "address": "auto", + "primary": true + } + ] + } + } + } + } + } + }, + "build": { + "sources": [ + "source.linode.example" + ] + } +} +``` diff --git a/builder/linode/builder_test.go b/builder/linode/builder_test.go index c3621de..592bbc4 100644 --- a/builder/linode/builder_test.go +++ b/builder/linode/builder_test.go @@ -7,6 +7,7 @@ import ( "time" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/linode/linodego" ) func testConfig() map[string]any { @@ -453,7 +454,7 @@ func TestBuilderPrepare_StackScripts(t *testing.T) { } } -func TestBuilderPrepare_NetworkInterfaces(t *testing.T) { +func TestBuilderPrepare_ConfigNetworkInterfaces(t *testing.T) { var b Builder config := testConfig() @@ -514,6 +515,93 @@ func TestBuilderPrepare_NetworkInterfaces(t *testing.T) { } } +func TestBuilderPrepare_LinodeNetworkInterfaces(t *testing.T) { + var b Builder + config := testConfig() + + // Test optional + delete(config, "linode_interface") + + _, warnings, err := b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + expectedLinodeInterfaces := []LinodeInterface{ + { + FirewallID: linodego.Pointer(123), + DefaultRoute: &InterfaceDefaultRoute{ + IPv4: linodego.Pointer(true), + IPv6: linodego.Pointer(true), + }, + Public: &PublicInterface{ + IPv4: &PublicInterfaceIPv4{ + Addresses: []PublicInterfaceIPv4Address{ + { + Address: linodego.Pointer("auto"), + Primary: linodego.Pointer(true), + }, + }, + }, + IPv6: &PublicInterfaceIPv6{ + Ranges: []PublicInterfaceIPv6Range{ + { + Range: "/64", + }, + }, + }, + }, + }, + { + FirewallID: linodego.Pointer(123), + DefaultRoute: &InterfaceDefaultRoute{ + IPv4: linodego.Pointer(false), + IPv6: linodego.Pointer(false), + }, + VPC: &VPCInterface{ + SubnetID: 12345, + IPv4: &VPCInterfaceIPv4{ + Addresses: []VPCInterfaceIPv4Address{ + { + Address: linodego.Pointer("auto"), + Primary: linodego.Pointer(false), + NAT1To1Address: linodego.Pointer("auto"), + }, + }, + }, + }, + }, + { + DefaultRoute: &InterfaceDefaultRoute{ + IPv4: linodego.Pointer(false), + IPv6: linodego.Pointer(false), + }, + VLAN: &VLANInterface{ + VLANLabel: "vlan-1", + IPAMAddress: linodego.Pointer("10.0.0.1/24"), + }, + }, + } + + // Test set + config["linode_interface"] = expectedLinodeInterfaces + b = Builder{} + _, warnings, err = b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatalf("should not have error: %s", err) + } + + if !reflect.DeepEqual(b.config.LinodeInterfaces, expectedLinodeInterfaces) { + t.Errorf("got %v, expected %v", b.config.LinodeInterfaces, expectedLinodeInterfaces) + } +} + func TestBuilderPrepare_CloudInit(t *testing.T) { var b Builder config := testConfig() diff --git a/builder/linode/config.go b/builder/linode/config.go index 6670dff..0c0c3ff 100644 --- a/builder/linode/config.go +++ b/builder/linode/config.go @@ -69,10 +69,13 @@ type Config struct { ctx interpolate.Context Comm communicator.Config `mapstructure:",squash"` - // Network Interfaces to add to this Linode’s Configuration Profile. Singular repeatable + // Legacy Config Network Interfaces to add to this Linode’s Configuration Profile. Singular repeatable // block containing a `purpose`, a `label`, and an `ipam_address` field. Interfaces []Interface `mapstructure:"interface" required:"false"` + // Newer Linode Network Interfaces to add to this Linode. + LinodeInterfaces []LinodeInterface `mapstructure:"linode_interface" required:"false"` + // The id of the region to launch the Linode instance in. Images are available in all // regions, but there will be less delay when deploying from the region where the image // was taken. See [regions](https://api.linode.com/v4/regions) for more information on @@ -155,6 +158,11 @@ type Config struct { // The regions where the outcome image will be replicated to. ImageRegions []string `mapstructure:"image_regions" required:"false"` + + // Specifies the interface type for the Linode. The value can be either + // `legacy_config` or `linode`. The default value is determined by the + // `interfaces_for_new_linodes` setting in the account settings. + InterfaceGeneration string `mapstructure:"interface_generation" required:"false"` } func createRandomRootPassword() (string, error) { diff --git a/builder/linode/config.hcl2spec.go b/builder/linode/config.hcl2spec.go index f0e4dca..1291ee9 100644 --- a/builder/linode/config.hcl2spec.go +++ b/builder/linode/config.hcl2spec.go @@ -10,86 +10,88 @@ import ( // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - PersonalAccessToken *string `mapstructure:"linode_token" cty:"linode_token" hcl:"linode_token"` - APICAPath *string `mapstructure:"api_ca_path" cty:"api_ca_path" hcl:"api_ca_path"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` - SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - Interfaces []FlatInterface `mapstructure:"interface" required:"false" cty:"interface" hcl:"interface"` - Region *string `mapstructure:"region" required:"true" cty:"region" hcl:"region"` - AuthorizedKeys []string `mapstructure:"authorized_keys" required:"false" cty:"authorized_keys" hcl:"authorized_keys"` - AuthorizedUsers []string `mapstructure:"authorized_users" required:"false" cty:"authorized_users" hcl:"authorized_users"` - InstanceType *string `mapstructure:"instance_type" required:"true" cty:"instance_type" hcl:"instance_type"` - Label *string `mapstructure:"instance_label" required:"false" cty:"instance_label" hcl:"instance_label"` - Tags []string `mapstructure:"instance_tags" required:"false" cty:"instance_tags" hcl:"instance_tags"` - Image *string `mapstructure:"image" required:"true" cty:"image" hcl:"image"` - SwapSize *int `mapstructure:"swap_size" required:"false" cty:"swap_size" hcl:"swap_size"` - PrivateIP *bool `mapstructure:"private_ip" required:"false" cty:"private_ip" hcl:"private_ip"` - RootPass *string `mapstructure:"root_pass" required:"false" cty:"root_pass" hcl:"root_pass"` - ImageLabel *string `mapstructure:"image_label" required:"false" cty:"image_label" hcl:"image_label"` - Description *string `mapstructure:"image_description" required:"false" cty:"image_description" hcl:"image_description"` - StateTimeout *string `mapstructure:"state_timeout" required:"false" cty:"state_timeout" hcl:"state_timeout"` - StackScriptData map[string]string `mapstructure:"stackscript_data" required:"false" cty:"stackscript_data" hcl:"stackscript_data"` - StackScriptID *int `mapstructure:"stackscript_id" required:"false" cty:"stackscript_id" hcl:"stackscript_id"` - ImageCreateTimeout *string `mapstructure:"image_create_timeout" required:"false" cty:"image_create_timeout" hcl:"image_create_timeout"` - CloudInit *bool `mapstructure:"cloud_init" required:"false" cty:"cloud_init" hcl:"cloud_init"` - Metadata *FlatMetadata `mapstructure:"metadata" required:"false" cty:"metadata" hcl:"metadata"` - FirewallID *int `mapstructure:"firewall_id" required:"false" cty:"firewall_id" hcl:"firewall_id"` - ImageRegions []string `mapstructure:"image_regions" required:"false" cty:"image_regions" hcl:"image_regions"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + PersonalAccessToken *string `mapstructure:"linode_token" cty:"linode_token" hcl:"linode_token"` + APICAPath *string `mapstructure:"api_ca_path" cty:"api_ca_path" hcl:"api_ca_path"` + Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` + SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` + SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` + SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` + SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` + SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` + SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` + SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` + WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` + Interfaces []FlatInterface `mapstructure:"interface" required:"false" cty:"interface" hcl:"interface"` + LinodeInterfaces []FlatLinodeInterface `mapstructure:"linode_interface" required:"false" cty:"linode_interface" hcl:"linode_interface"` + Region *string `mapstructure:"region" required:"true" cty:"region" hcl:"region"` + AuthorizedKeys []string `mapstructure:"authorized_keys" required:"false" cty:"authorized_keys" hcl:"authorized_keys"` + AuthorizedUsers []string `mapstructure:"authorized_users" required:"false" cty:"authorized_users" hcl:"authorized_users"` + InstanceType *string `mapstructure:"instance_type" required:"true" cty:"instance_type" hcl:"instance_type"` + Label *string `mapstructure:"instance_label" required:"false" cty:"instance_label" hcl:"instance_label"` + Tags []string `mapstructure:"instance_tags" required:"false" cty:"instance_tags" hcl:"instance_tags"` + Image *string `mapstructure:"image" required:"true" cty:"image" hcl:"image"` + SwapSize *int `mapstructure:"swap_size" required:"false" cty:"swap_size" hcl:"swap_size"` + PrivateIP *bool `mapstructure:"private_ip" required:"false" cty:"private_ip" hcl:"private_ip"` + RootPass *string `mapstructure:"root_pass" required:"false" cty:"root_pass" hcl:"root_pass"` + ImageLabel *string `mapstructure:"image_label" required:"false" cty:"image_label" hcl:"image_label"` + Description *string `mapstructure:"image_description" required:"false" cty:"image_description" hcl:"image_description"` + StateTimeout *string `mapstructure:"state_timeout" required:"false" cty:"state_timeout" hcl:"state_timeout"` + StackScriptData map[string]string `mapstructure:"stackscript_data" required:"false" cty:"stackscript_data" hcl:"stackscript_data"` + StackScriptID *int `mapstructure:"stackscript_id" required:"false" cty:"stackscript_id" hcl:"stackscript_id"` + ImageCreateTimeout *string `mapstructure:"image_create_timeout" required:"false" cty:"image_create_timeout" hcl:"image_create_timeout"` + CloudInit *bool `mapstructure:"cloud_init" required:"false" cty:"cloud_init" hcl:"cloud_init"` + Metadata *FlatMetadata `mapstructure:"metadata" required:"false" cty:"metadata" hcl:"metadata"` + FirewallID *int `mapstructure:"firewall_id" required:"false" cty:"firewall_id" hcl:"firewall_id"` + ImageRegions []string `mapstructure:"image_regions" required:"false" cty:"image_regions" hcl:"image_regions"` + InterfaceGeneration *string `mapstructure:"interface_generation" required:"false" cty:"interface_generation" hcl:"interface_generation"` } // FlatMapstructure returns a new FlatConfig. @@ -164,6 +166,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, "interface": &hcldec.BlockListSpec{TypeName: "interface", Nested: hcldec.ObjectSpec((*FlatInterface)(nil).HCL2Spec())}, + "linode_interface": &hcldec.BlockListSpec{TypeName: "linode_interface", Nested: hcldec.ObjectSpec((*FlatLinodeInterface)(nil).HCL2Spec())}, "region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false}, "authorized_keys": &hcldec.AttrSpec{Name: "authorized_keys", Type: cty.List(cty.String), Required: false}, "authorized_users": &hcldec.AttrSpec{Name: "authorized_users", Type: cty.List(cty.String), Required: false}, @@ -184,6 +187,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "metadata": &hcldec.BlockSpec{TypeName: "metadata", Nested: hcldec.ObjectSpec((*FlatMetadata)(nil).HCL2Spec())}, "firewall_id": &hcldec.AttrSpec{Name: "firewall_id", Type: cty.Number, Required: false}, "image_regions": &hcldec.AttrSpec{Name: "image_regions", Type: cty.List(cty.String), Required: false}, + "interface_generation": &hcldec.AttrSpec{Name: "interface_generation", Type: cty.String, Required: false}, } return s } diff --git a/builder/linode/linode_interfaces.go b/builder/linode/linode_interfaces.go new file mode 100644 index 0000000..9281aee --- /dev/null +++ b/builder/linode/linode_interfaces.go @@ -0,0 +1,119 @@ +//go:generate packer-sdc struct-markdown +//go:generate packer-sdc mapstructure-to-hcl2 -type LinodeInterface,InterfaceDefaultRoute,PublicInterface,PublicInterfaceIPv4,PublicInterfaceIPv6,PublicInterfaceIPv4Address,PublicInterfaceIPv6Range,VPCInterface,VPCInterfaceIPv4,VPCInterfaceIPv4Address,VPCInterfaceIPv4Range,VLANInterface +package linode + +type LinodeInterface struct { + // The enabled firewall to secure a VPC or public interface. Not allowed for VLAN interfaces. + FirewallID *int `mapstructure:"firewall_id" required:"false"` + + // Indicates if the interface serves as the default route when multiple interfaces are + // eligible for this role. + DefaultRoute *InterfaceDefaultRoute `mapstructure:"default_route" required:"false"` + + // Public interface settings. A Linode can have only one public interface. + // A public interface can have both IPv4 and IPv6 configurations. + Public *PublicInterface `mapstructure:"public" required:"false"` + + // VPC interface settings. + VPC *VPCInterface `mapstructure:"vpc" required:"false"` + + // VLAN interface settings. + VLAN *VLANInterface `mapstructure:"vlan" required:"false"` +} + +type InterfaceDefaultRoute struct { + // Whether this interface is used for the IPv4 default route. + IPv4 *bool `mapstructure:"ipv4" required:"false"` + + // Whether this interface is used for the IPv6 default route. + IPv6 *bool `mapstructure:"ipv6" required:"false"` +} + +type PublicInterface struct { + // IPv4 address settings for this public interface. If omitted, + // a public IPv4 address is automatically allocated. + IPv4 *PublicInterfaceIPv4 `mapstructure:"ipv4" required:"false"` + + // IPv6 address settings for the public interface. + IPv6 *PublicInterfaceIPv6 `mapstructure:"ipv6" required:"false"` +} + +type PublicInterfaceIPv4 struct { + // Blocks of IPv4 addresses to assign to this interface. Setting any to auto + // allocates a public IPv4 address. + Addresses []PublicInterfaceIPv4Address `mapstructure:"address" required:"false"` +} + +type PublicInterfaceIPv4Address struct { + // The interface's public IPv4 address. You can specify which public IPv4 + // address to configure for the interface. Setting this to auto automatically + // allocates a public address. + Address *string `mapstructure:"address" required:"true"` + + // The IPv4 primary address configures the source address for routes within + // the Linode on the corresponding network interface. + // + // - Don't set this to false if there's only one address in the addresses array. + // - If more than one address is provided, primary can be set to true for one address. + // - If only one address is present in the addresses array, this address is automatically set as the primary address. + Primary *bool `mapstructure:"primary" required:"false"` +} + +type PublicInterfaceIPv6 struct { + // IPv6 address ranges to assign to this interface. If omitted, no ranges are assigned. + Ranges []PublicInterfaceIPv6Range `mapstructure:"ranges" required:"false"` +} + +type PublicInterfaceIPv6Range struct { + // Your assigned IPv6 range in CIDR notation (2001:0db8::1/64) or prefix (/64). + // + // - The prefix of /64 or /56 block of IPv6 addresses. + // - If provided in CIDR notation, the prefix must be within the assigned ranges for the Linode. + Range string `mapstructure:"range" required:"true"` +} + +type VPCInterface struct { + // The VPC subnet identifier for this interface. Your subnet’s VPC must be in + // the same data center (region) as the Linode. + SubnetID int `mapstructure:"subnet_id" required:"true"` + + // Interfaces can be configured with IPv4 addresses or ranges. + IPv4 *VPCInterfaceIPv4 `mapstructure:"ipv4" required:"false"` +} +type VPCInterfaceIPv4 struct { + // IPv4 address settings for this VPC interface. + Addresses []VPCInterfaceIPv4Address `mapstructure:"addresses" required:"false"` + + // VPC IPv4 ranges. + Ranges []VPCInterfaceIPv4Range `mapstructure:"ranges" required:"false"` +} + +type VPCInterfaceIPv4Address struct { + // Specifies which IPv4 address to use in the VPC subnet. You can specify which + // VPC Ipv4 address in the subnet to configure for the interface. You can't use + // an IPv4 address taken from another Linode or interface, or the first two or + // last two addresses in the VPC subnet. When address is set to `auto`, an IP + // address from the subnet is automatically assigned. + Address *string `mapstructure:"address" required:"true"` + + // The IPv4 primary address is used to configure the source address for routes + // within the Linode on the corresponding network interface. + Primary *bool `mapstructure:"primary" required:"false"` + + // The 1:1 NAT IPv4 address used to associate a public IPv4 address with the + // interface's VPC subnet IPv4 address. + NAT1To1Address *string `mapstructure:"nat_1_1_address" required:"false"` +} + +type VPCInterfaceIPv4Range struct { + // VPC IPv4 ranges. + Range string `mapstructure:"range" required:"true"` +} + +type VLANInterface struct { + // The VLAN's unique label. VLAN interfaces on the same Linode must have a unique `vlan_label`. + VLANLabel string `mapstructure:"vlan_label" required:"true"` + + // This VLAN interface's private IPv4 address in classless inter-domain routing (CIDR) notation. + IPAMAddress *string `mapstructure:"ipam_address" required:"false"` +} diff --git a/builder/linode/linode_interfaces.hcl2spec.go b/builder/linode/linode_interfaces.hcl2spec.go new file mode 100644 index 0000000..24ac5f7 --- /dev/null +++ b/builder/linode/linode_interfaces.hcl2spec.go @@ -0,0 +1,308 @@ +// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. + +package linode + +import ( + "github.com/hashicorp/hcl/v2/hcldec" + "github.com/zclconf/go-cty/cty" +) + +// FlatInterfaceDefaultRoute is an auto-generated flat version of InterfaceDefaultRoute. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatInterfaceDefaultRoute struct { + IPv4 *bool `mapstructure:"ipv4" required:"false" cty:"ipv4" hcl:"ipv4"` + IPv6 *bool `mapstructure:"ipv6" required:"false" cty:"ipv6" hcl:"ipv6"` +} + +// FlatMapstructure returns a new FlatInterfaceDefaultRoute. +// FlatInterfaceDefaultRoute is an auto-generated flat version of InterfaceDefaultRoute. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*InterfaceDefaultRoute) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatInterfaceDefaultRoute) +} + +// HCL2Spec returns the hcl spec of a InterfaceDefaultRoute. +// This spec is used by HCL to read the fields of InterfaceDefaultRoute. +// The decoded values from this spec will then be applied to a FlatInterfaceDefaultRoute. +func (*FlatInterfaceDefaultRoute) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "ipv4": &hcldec.AttrSpec{Name: "ipv4", Type: cty.Bool, Required: false}, + "ipv6": &hcldec.AttrSpec{Name: "ipv6", Type: cty.Bool, Required: false}, + } + return s +} + +// FlatLinodeInterface is an auto-generated flat version of LinodeInterface. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatLinodeInterface struct { + FirewallID *int `mapstructure:"firewall_id" required:"false" cty:"firewall_id" hcl:"firewall_id"` + DefaultRoute *FlatInterfaceDefaultRoute `mapstructure:"default_route" required:"false" cty:"default_route" hcl:"default_route"` + Public *FlatPublicInterface `mapstructure:"public" required:"false" cty:"public" hcl:"public"` + VPC *FlatVPCInterface `mapstructure:"vpc" required:"false" cty:"vpc" hcl:"vpc"` + VLAN *FlatVLANInterface `mapstructure:"vlan" required:"false" cty:"vlan" hcl:"vlan"` +} + +// FlatMapstructure returns a new FlatLinodeInterface. +// FlatLinodeInterface is an auto-generated flat version of LinodeInterface. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*LinodeInterface) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatLinodeInterface) +} + +// HCL2Spec returns the hcl spec of a LinodeInterface. +// This spec is used by HCL to read the fields of LinodeInterface. +// The decoded values from this spec will then be applied to a FlatLinodeInterface. +func (*FlatLinodeInterface) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "firewall_id": &hcldec.AttrSpec{Name: "firewall_id", Type: cty.Number, Required: false}, + "default_route": &hcldec.BlockSpec{TypeName: "default_route", Nested: hcldec.ObjectSpec((*FlatInterfaceDefaultRoute)(nil).HCL2Spec())}, + "public": &hcldec.BlockSpec{TypeName: "public", Nested: hcldec.ObjectSpec((*FlatPublicInterface)(nil).HCL2Spec())}, + "vpc": &hcldec.BlockSpec{TypeName: "vpc", Nested: hcldec.ObjectSpec((*FlatVPCInterface)(nil).HCL2Spec())}, + "vlan": &hcldec.BlockSpec{TypeName: "vlan", Nested: hcldec.ObjectSpec((*FlatVLANInterface)(nil).HCL2Spec())}, + } + return s +} + +// FlatPublicInterface is an auto-generated flat version of PublicInterface. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatPublicInterface struct { + IPv4 *FlatPublicInterfaceIPv4 `mapstructure:"ipv4" required:"false" cty:"ipv4" hcl:"ipv4"` + IPv6 *FlatPublicInterfaceIPv6 `mapstructure:"ipv6" required:"false" cty:"ipv6" hcl:"ipv6"` +} + +// FlatMapstructure returns a new FlatPublicInterface. +// FlatPublicInterface is an auto-generated flat version of PublicInterface. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*PublicInterface) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatPublicInterface) +} + +// HCL2Spec returns the hcl spec of a PublicInterface. +// This spec is used by HCL to read the fields of PublicInterface. +// The decoded values from this spec will then be applied to a FlatPublicInterface. +func (*FlatPublicInterface) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "ipv4": &hcldec.BlockSpec{TypeName: "ipv4", Nested: hcldec.ObjectSpec((*FlatPublicInterfaceIPv4)(nil).HCL2Spec())}, + "ipv6": &hcldec.BlockSpec{TypeName: "ipv6", Nested: hcldec.ObjectSpec((*FlatPublicInterfaceIPv6)(nil).HCL2Spec())}, + } + return s +} + +// FlatPublicInterfaceIPv4 is an auto-generated flat version of PublicInterfaceIPv4. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatPublicInterfaceIPv4 struct { + Addresses []FlatPublicInterfaceIPv4Address `mapstructure:"address" required:"false" cty:"address" hcl:"address"` +} + +// FlatMapstructure returns a new FlatPublicInterfaceIPv4. +// FlatPublicInterfaceIPv4 is an auto-generated flat version of PublicInterfaceIPv4. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*PublicInterfaceIPv4) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatPublicInterfaceIPv4) +} + +// HCL2Spec returns the hcl spec of a PublicInterfaceIPv4. +// This spec is used by HCL to read the fields of PublicInterfaceIPv4. +// The decoded values from this spec will then be applied to a FlatPublicInterfaceIPv4. +func (*FlatPublicInterfaceIPv4) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "address": &hcldec.BlockListSpec{TypeName: "address", Nested: hcldec.ObjectSpec((*FlatPublicInterfaceIPv4Address)(nil).HCL2Spec())}, + } + return s +} + +// FlatPublicInterfaceIPv4Address is an auto-generated flat version of PublicInterfaceIPv4Address. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatPublicInterfaceIPv4Address struct { + Address *string `mapstructure:"address" required:"true" cty:"address" hcl:"address"` + Primary *bool `mapstructure:"primary" required:"false" cty:"primary" hcl:"primary"` +} + +// FlatMapstructure returns a new FlatPublicInterfaceIPv4Address. +// FlatPublicInterfaceIPv4Address is an auto-generated flat version of PublicInterfaceIPv4Address. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*PublicInterfaceIPv4Address) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatPublicInterfaceIPv4Address) +} + +// HCL2Spec returns the hcl spec of a PublicInterfaceIPv4Address. +// This spec is used by HCL to read the fields of PublicInterfaceIPv4Address. +// The decoded values from this spec will then be applied to a FlatPublicInterfaceIPv4Address. +func (*FlatPublicInterfaceIPv4Address) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "address": &hcldec.AttrSpec{Name: "address", Type: cty.String, Required: false}, + "primary": &hcldec.AttrSpec{Name: "primary", Type: cty.Bool, Required: false}, + } + return s +} + +// FlatPublicInterfaceIPv6 is an auto-generated flat version of PublicInterfaceIPv6. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatPublicInterfaceIPv6 struct { + Ranges []FlatPublicInterfaceIPv6Range `mapstructure:"ranges" required:"false" cty:"ranges" hcl:"ranges"` +} + +// FlatMapstructure returns a new FlatPublicInterfaceIPv6. +// FlatPublicInterfaceIPv6 is an auto-generated flat version of PublicInterfaceIPv6. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*PublicInterfaceIPv6) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatPublicInterfaceIPv6) +} + +// HCL2Spec returns the hcl spec of a PublicInterfaceIPv6. +// This spec is used by HCL to read the fields of PublicInterfaceIPv6. +// The decoded values from this spec will then be applied to a FlatPublicInterfaceIPv6. +func (*FlatPublicInterfaceIPv6) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "ranges": &hcldec.BlockListSpec{TypeName: "ranges", Nested: hcldec.ObjectSpec((*FlatPublicInterfaceIPv6Range)(nil).HCL2Spec())}, + } + return s +} + +// FlatPublicInterfaceIPv6Range is an auto-generated flat version of PublicInterfaceIPv6Range. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatPublicInterfaceIPv6Range struct { + Range *string `mapstructure:"range" required:"true" cty:"range" hcl:"range"` +} + +// FlatMapstructure returns a new FlatPublicInterfaceIPv6Range. +// FlatPublicInterfaceIPv6Range is an auto-generated flat version of PublicInterfaceIPv6Range. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*PublicInterfaceIPv6Range) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatPublicInterfaceIPv6Range) +} + +// HCL2Spec returns the hcl spec of a PublicInterfaceIPv6Range. +// This spec is used by HCL to read the fields of PublicInterfaceIPv6Range. +// The decoded values from this spec will then be applied to a FlatPublicInterfaceIPv6Range. +func (*FlatPublicInterfaceIPv6Range) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "range": &hcldec.AttrSpec{Name: "range", Type: cty.String, Required: false}, + } + return s +} + +// FlatVLANInterface is an auto-generated flat version of VLANInterface. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatVLANInterface struct { + VLANLabel *string `mapstructure:"vlan_label" required:"true" cty:"vlan_label" hcl:"vlan_label"` + IPAMAddress *string `mapstructure:"ipam_address" required:"false" cty:"ipam_address" hcl:"ipam_address"` +} + +// FlatMapstructure returns a new FlatVLANInterface. +// FlatVLANInterface is an auto-generated flat version of VLANInterface. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*VLANInterface) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatVLANInterface) +} + +// HCL2Spec returns the hcl spec of a VLANInterface. +// This spec is used by HCL to read the fields of VLANInterface. +// The decoded values from this spec will then be applied to a FlatVLANInterface. +func (*FlatVLANInterface) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "vlan_label": &hcldec.AttrSpec{Name: "vlan_label", Type: cty.String, Required: false}, + "ipam_address": &hcldec.AttrSpec{Name: "ipam_address", Type: cty.String, Required: false}, + } + return s +} + +// FlatVPCInterface is an auto-generated flat version of VPCInterface. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatVPCInterface struct { + SubnetID *int `mapstructure:"subnet_id" required:"true" cty:"subnet_id" hcl:"subnet_id"` + IPv4 *FlatVPCInterfaceIPv4 `mapstructure:"ipv4" required:"false" cty:"ipv4" hcl:"ipv4"` +} + +// FlatMapstructure returns a new FlatVPCInterface. +// FlatVPCInterface is an auto-generated flat version of VPCInterface. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*VPCInterface) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatVPCInterface) +} + +// HCL2Spec returns the hcl spec of a VPCInterface. +// This spec is used by HCL to read the fields of VPCInterface. +// The decoded values from this spec will then be applied to a FlatVPCInterface. +func (*FlatVPCInterface) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.Number, Required: false}, + "ipv4": &hcldec.BlockSpec{TypeName: "ipv4", Nested: hcldec.ObjectSpec((*FlatVPCInterfaceIPv4)(nil).HCL2Spec())}, + } + return s +} + +// FlatVPCInterfaceIPv4 is an auto-generated flat version of VPCInterfaceIPv4. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatVPCInterfaceIPv4 struct { + Addresses []FlatVPCInterfaceIPv4Address `mapstructure:"addresses" required:"false" cty:"addresses" hcl:"addresses"` + Ranges []FlatVPCInterfaceIPv4Range `mapstructure:"ranges" required:"false" cty:"ranges" hcl:"ranges"` +} + +// FlatMapstructure returns a new FlatVPCInterfaceIPv4. +// FlatVPCInterfaceIPv4 is an auto-generated flat version of VPCInterfaceIPv4. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*VPCInterfaceIPv4) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatVPCInterfaceIPv4) +} + +// HCL2Spec returns the hcl spec of a VPCInterfaceIPv4. +// This spec is used by HCL to read the fields of VPCInterfaceIPv4. +// The decoded values from this spec will then be applied to a FlatVPCInterfaceIPv4. +func (*FlatVPCInterfaceIPv4) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "addresses": &hcldec.BlockListSpec{TypeName: "addresses", Nested: hcldec.ObjectSpec((*FlatVPCInterfaceIPv4Address)(nil).HCL2Spec())}, + "ranges": &hcldec.BlockListSpec{TypeName: "ranges", Nested: hcldec.ObjectSpec((*FlatVPCInterfaceIPv4Range)(nil).HCL2Spec())}, + } + return s +} + +// FlatVPCInterfaceIPv4Address is an auto-generated flat version of VPCInterfaceIPv4Address. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatVPCInterfaceIPv4Address struct { + Address *string `mapstructure:"address" required:"true" cty:"address" hcl:"address"` + Primary *bool `mapstructure:"primary" required:"false" cty:"primary" hcl:"primary"` + NAT1To1Address *string `mapstructure:"nat_1_1_address" required:"false" cty:"nat_1_1_address" hcl:"nat_1_1_address"` +} + +// FlatMapstructure returns a new FlatVPCInterfaceIPv4Address. +// FlatVPCInterfaceIPv4Address is an auto-generated flat version of VPCInterfaceIPv4Address. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*VPCInterfaceIPv4Address) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatVPCInterfaceIPv4Address) +} + +// HCL2Spec returns the hcl spec of a VPCInterfaceIPv4Address. +// This spec is used by HCL to read the fields of VPCInterfaceIPv4Address. +// The decoded values from this spec will then be applied to a FlatVPCInterfaceIPv4Address. +func (*FlatVPCInterfaceIPv4Address) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "address": &hcldec.AttrSpec{Name: "address", Type: cty.String, Required: false}, + "primary": &hcldec.AttrSpec{Name: "primary", Type: cty.Bool, Required: false}, + "nat_1_1_address": &hcldec.AttrSpec{Name: "nat_1_1_address", Type: cty.String, Required: false}, + } + return s +} + +// FlatVPCInterfaceIPv4Range is an auto-generated flat version of VPCInterfaceIPv4Range. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatVPCInterfaceIPv4Range struct { + Range *string `mapstructure:"range" required:"true" cty:"range" hcl:"range"` +} + +// FlatMapstructure returns a new FlatVPCInterfaceIPv4Range. +// FlatVPCInterfaceIPv4Range is an auto-generated flat version of VPCInterfaceIPv4Range. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*VPCInterfaceIPv4Range) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatVPCInterfaceIPv4Range) +} + +// HCL2Spec returns the hcl spec of a VPCInterfaceIPv4Range. +// This spec is used by HCL to read the fields of VPCInterfaceIPv4Range. +// The decoded values from this spec will then be applied to a FlatVPCInterfaceIPv4Range. +func (*FlatVPCInterfaceIPv4Range) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "range": &hcldec.AttrSpec{Name: "range", Type: cty.String, Required: false}, + } + return s +} diff --git a/builder/linode/step_create_linode.go b/builder/linode/step_create_linode.go index 44deff4..8f936a3 100644 --- a/builder/linode/step_create_linode.go +++ b/builder/linode/step_create_linode.go @@ -37,6 +37,95 @@ func flattenConfigInterface(i Interface) linodego.InstanceConfigInterfaceCreateO } } +func flattenPublicInterface(public *PublicInterface) *linodego.PublicInterfaceCreateOptions { + if public == nil { + return nil + } + result := &linodego.PublicInterfaceCreateOptions{} + if public.IPv4 != nil { + addresses := make([]linodego.PublicInterfaceIPv4AddressCreateOptions, len(public.IPv4.Addresses)) + for i, addr := range public.IPv4.Addresses { + addresses[i] = linodego.PublicInterfaceIPv4AddressCreateOptions{ + Address: addr.Address, + Primary: addr.Primary, + } + } + result.IPv4 = &linodego.PublicInterfaceIPv4CreateOptions{ + Addresses: linodego.Pointer(addresses), + } + } + if public.IPv6 != nil { + ranges := make([]linodego.PublicInterfaceIPv6RangeCreateOptions, len(public.IPv6.Ranges)) + for i, r := range public.IPv6.Ranges { + ranges[i] = linodego.PublicInterfaceIPv6RangeCreateOptions{ + Range: r.Range, + } + } + result.IPv6 = &linodego.PublicInterfaceIPv6CreateOptions{ + Ranges: linodego.Pointer(ranges), + } + } + return result +} + +func flattenVPCInterface(vpc *VPCInterface) *linodego.VPCInterfaceCreateOptions { + if vpc == nil { + return nil + } + result := &linodego.VPCInterfaceCreateOptions{ + SubnetID: vpc.SubnetID, + } + if vpc.IPv4 != nil { + addresses := make([]linodego.VPCInterfaceIPv4AddressCreateOptions, len(vpc.IPv4.Addresses)) + ranges := make([]linodego.VPCInterfaceIPv4RangeCreateOptions, len(vpc.IPv4.Ranges)) + for i, addr := range vpc.IPv4.Addresses { + addresses[i] = linodego.VPCInterfaceIPv4AddressCreateOptions{ + Address: addr.Address, + } + } + for i, r := range vpc.IPv4.Ranges { + ranges[i] = linodego.VPCInterfaceIPv4RangeCreateOptions{ + Range: r.Range, + } + } + result.IPv4 = &linodego.VPCInterfaceIPv4CreateOptions{ + Addresses: linodego.Pointer(addresses), + Ranges: linodego.Pointer(ranges), + } + } + return result +} + +func flattenVLANInterface(vlan *VLANInterface) *linodego.VLANInterface { + if vlan == nil { + return nil + } + result := &linodego.VLANInterface{ + VLANLabel: vlan.VLANLabel, + } + if vlan.IPAMAddress != nil { + result.IPAMAddress = vlan.IPAMAddress + } + return result +} + +func flattenLinodeInterface(li LinodeInterface) (opts linodego.LinodeInterfaceCreateOptions) { + opts.FirewallID = linodego.Pointer(li.FirewallID) + + if li.DefaultRoute != nil { + opts.DefaultRoute = &linodego.InterfaceDefaultRoute{ + IPv4: li.DefaultRoute.IPv4, + IPv6: li.DefaultRoute.IPv6, + } + } + + opts.Public = flattenPublicInterface(li.Public) + opts.VPC = flattenVPCInterface(li.VPC) + opts.VLAN = flattenVLANInterface(li.VLAN) + + return +} + func flattenMetadata(m Metadata) *linodego.InstanceMetadataOptions { if m.UserData == "" { return nil @@ -57,27 +146,40 @@ func (s *stepCreateLinode) Run(ctx context.Context, state multistep.StateBag) mu ui.Say("Creating Linode...") + createOpts := linodego.InstanceCreateOptions{ + RootPass: c.Comm.Password(), + AuthorizedKeys: []string{}, + AuthorizedUsers: []string{}, + PrivateIP: c.PrivateIP, + Region: c.Region, + StackScriptID: c.StackScriptID, + StackScriptData: c.StackScriptData, + Type: c.InstanceType, + Label: c.Label, + Image: c.Image, + SwapSize: &c.SwapSize, + Tags: c.Tags, + FirewallID: c.FirewallID, + Metadata: flattenMetadata(c.Metadata), + InterfaceGeneration: linodego.InterfaceGeneration(c.InterfaceGeneration), + } + interfaces := make([]linodego.InstanceConfigInterfaceCreateOptions, len(c.Interfaces)) for i, v := range c.Interfaces { interfaces[i] = flattenConfigInterface(v) } - createOpts := linodego.InstanceCreateOptions{ - RootPass: c.Comm.Password(), - AuthorizedKeys: []string{}, - AuthorizedUsers: []string{}, - Interfaces: interfaces, - PrivateIP: c.PrivateIP, - Region: c.Region, - StackScriptID: c.StackScriptID, - StackScriptData: c.StackScriptData, - Type: c.InstanceType, - Label: c.Label, - Image: c.Image, - SwapSize: &c.SwapSize, - Tags: c.Tags, - FirewallID: c.FirewallID, - Metadata: flattenMetadata(c.Metadata), + linodeInterfaces := make([]linodego.LinodeInterfaceCreateOptions, len(c.LinodeInterfaces)) + for i, v := range c.LinodeInterfaces { + linodeInterfaces[i] = flattenLinodeInterface(v) + } + + if len(interfaces) > 0 { + createOpts.Interfaces = interfaces + } + + if len(linodeInterfaces) > 0 { + createOpts.LinodeInterfaces = linodeInterfaces } if pubKey := string(c.Comm.SSHPublicKey); pubKey != "" { diff --git a/docs/builders/linode.mdx b/docs/builders/linode.mdx index 07c0039..8bc5142 100644 --- a/docs/builders/linode.mdx +++ b/docs/builders/linode.mdx @@ -49,15 +49,103 @@ can also be supplied to override the typical auto-generated key: @include 'builder/linode/Config-not-required.mdx' -#### Interface +#### Linode Interface -This section outlines the fields configurable for a single interface object. +This section outlines the fields configurable for a newer Linode interface object. -##### Required Interface Common Attributes +@include 'builder/linode/LinodeInterface-not-required.mdx' + +##### Linode Interface Default Route configuration object (InterfaceDefaultRoute) + +###### Optional + +@include 'builder/linode/InterfaceDefaultRoute-not-required.mdx' + +##### Public Linode Interface configuration object (PublicInterface) + +###### Optional + +@include 'builder/linode/PublicInterface-not-required.mdx' + +##### Public Linode Interface IPv4 configuration object (PublicInterfaceIPv4) + +###### Optional + +@include 'builder/linode/PublicInterfaceIPv4-not-required.mdx' + +##### Public Linode Interface IPv4 Address configuration object (PublicInterfaceIPv4Address) + +###### Required + +@include 'builder/linode/PublicInterfaceIPv4Address-required.mdx' + +###### Optional + +@include 'builder/linode/PublicInterfaceIPv4Address-not-required.mdx' + +##### Public Linode Interface IPv6 configuration object (PublicInterfaceIPv6) + +###### Optional + +@include 'builder/linode/PublicInterfaceIPv6-not-required.mdx' + +##### Public Linode Interface IPv6 Range configuration object (PublicInterfaceIPv6Range) + +###### Required + +@include 'builder/linode/PublicInterfaceIPv6Range-required.mdx' + +##### VPC Linode Interface configuration object (VPCInterface) + +###### Required + +@include 'builder/linode/VPCInterface-required.mdx' + +###### Optional + +@include 'builder/linode/VPCInterface-not-required.mdx' + +##### VPC Linode Interface IPv4 configuration object (VPCInterfaceIPv4) + +###### Optional + +@include 'builder/linode/VPCInterfaceIPv4-not-required.mdx' + +##### VPC Linode Interface IPv4 Address configuration object (VPCInterfaceIPv4Address) + +###### Required + +@include 'builder/linode/VPCInterfaceIPv4Address-required.mdx' + +###### Optional + +@include 'builder/linode/VPCInterfaceIPv4Address-not-required.mdx' + +##### VPC Linode Interface IPv4 Range configuration object (VPCInterfaceIPv4Range) + +###### Required + +@include 'builder/linode/VPCInterfaceIPv4Range-required.mdx' + +##### VLAN Linode Interface configuration object (VLANInterface) + +###### Required + +@include 'builder/linode/VLANInterface-required.mdx' + +###### Optional + +@include 'builder/linode/VLANInterface-not-required.mdx' + +#### Legacy Config Interface + +This section outlines the fields configurable for a single legacy config interface object. + +##### Required Config Interface Common Attributes @include 'builder/linode/Interface-required.mdx' -##### Optional Interface Common Attributes +##### Optional Config Interface Common Attributes @include 'builder/linode/Interface-not-required.mdx' @@ -69,7 +157,7 @@ This section outlines the fields configurable for a single interface object. @include 'builder/linode/VPCInterfaceAttributes-not-required.mdx' -###### VPC Interface IPv4 configuration object +###### VPC Config Interface IPv4 configuration object (InterfaceIPv4) @include 'builder/linode/InterfaceIPv4-not-required.mdx' @@ -253,3 +341,77 @@ build { } ``` +## Linode Interface Example + +**HCL2** + +```hcl +locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") } + +source "linode" "example" { + image = "linode/ubuntu24.04" + image_description = "My Private Image" + image_label = "private-image-${local.timestamp}" + instance_label = "temporary-linode-${local.timestamp}" + instance_type = "g6-standard-1" + region = "us-mia" + ssh_username = "root" + interface_generation = "linode" + + linode_interface { + firewall_id = 12345 + public { + ipv4 { + address { + address = "auto" + primary = true + } + } + } + } +} + +build { + sources = ["source.linode.example"] +} +``` + +**JSON** + +```json +{ + "source": { + "linode": { + "example": { + "image": "linode/ubuntu24.04", + "linode_token": "YOUR API TOKEN", + "region": "us-mia", + "instance_type": "g6-nanode-1", + "instance_label": "temporary-linode-{{timestamp}}", + "image_label": "private-image-{{timestamp}}", + "image_description": "My Private Image", + "ssh_username": "root", + "interface_generation": "linode", + "linode_interface": { + "firewall_id": 2930969, + "public": { + "ipv4": { + "addresses": [ + { + "address": "auto", + "primary": true + } + ] + } + } + } + } + } + }, + "build": { + "sources": [ + "source.linode.example" + ] + } +} +``` \ No newline at end of file diff --git a/go.mod b/go.mod index f4aa7de..37c2eb2 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,8 @@ require ( github.com/linode/linodego v1.61.0 github.com/mitchellh/mapstructure v1.5.0 github.com/zclconf/go-cty v1.16.3 - golang.org/x/crypto v0.43.0 - golang.org/x/oauth2 v0.33.0 + golang.org/x/crypto v0.46.0 + golang.org/x/oauth2 v0.34.0 ) require ( @@ -98,14 +98,14 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect go.opencensus.io v0.24.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/mod v0.28.0 // indirect - golang.org/x/net v0.46.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.36.0 // indirect - golang.org/x/text v0.30.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/tools v0.39.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.150.0 // indirect google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect diff --git a/go.sum b/go.sum index b7d6529..0e19436 100644 --- a/go.sum +++ b/go.sum @@ -373,8 +373,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= @@ -382,8 +382,8 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -401,11 +401,11 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -413,8 +413,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -445,21 +445,21 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -470,8 +470,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=