Skip to content

chore: refactor networkedge to Internal/#622

Open
displague wants to merge 8 commits intomainfrom
internal_networkedge
Open

chore: refactor networkedge to Internal/#622
displague wants to merge 8 commits intomainfrom
internal_networkedge

Conversation

@displague
Copy link
Member

@displague displague commented Mar 14, 2024

This PR refactors Network Edge resources from the equinix package to dedicated packages under internal/resources/networkedge/, addressing part of issue #106. The refactoring reorganizes code structure while consolidating shared utilities like comparisons and nprintf helpers.

Key changes:

  • Network Edge resources split into individual packages (device, ssh_key, ssh_user, bgp, acl_template, etc.)
    • Resource/DataSource functions renamed from resourceNetworkX() to Resource() (exported)
    • NE Test sweepers moved from test files to dedicated sweeper.go files
  • Shared utilities consolidated (comparisons.IsEmpty, comparisons.SlicesMatch, nprintf.Nprintf)

Refactoring and modularization of shared utilities:

  • Moved shared comparison functions (stringsFound, isEmpty, slicesMatch) from equinix/provider.go and their tests from equinix/provider_test.go into the internal package internal/comparisons, removing deprecated code from the provider and test files. [1] [2]
  • Centralized the nprintf helper function into a new internal package internal/nprintf, updating documentation and function naming for clarity. [1] [2] [3]

Test and sweeper code cleanup:

  • Removed the resource_network_ssh_user_acc_test.go file, consolidating SSH user acceptance tests and sweepers, as these are now covered elsewhere or are redundant due to the new structure.
  • Removed redundant or unused helper functions and variables from equinix/equinix_sweeper_test.go and equinix/provider_test.go. [1] [2] [3]

Provider and resource mapping improvements:

  • Refactored network_edge_provider_maps.go to use resources and data sources from their respective internal packages, improving modularity and separation of concerns.

Acceptance test initialization refactor:

  • Moved acceptance test provider initialization logic from internal/acceptance/acceptance.go to a new file internal/acceptance/acceptance_acc_test.go, streamlining test setup and clarifying responsibilities. [1] [2] [3]

General codebase hygiene:

  • Cleaned up imports and variable declarations across multiple files for consistency and to remove unused dependencies. [1] [2] [3] [4] [5] [6] [7] [8] [9]

These changes collectively improve the structure and maintainability of the codebase, making shared logic easier to test and reuse, and laying the groundwork for further modularization and package separation.

@codecov-commenter
Copy link

codecov-commenter commented Mar 14, 2024

Codecov Report

❌ Patch coverage is 9.87654% with 219 lines in your changes missing coverage. Please review.
✅ Project coverage is 21.26%. Comparing base (a3d1850) to head (3b46f1d).

Files with missing lines Patch % Lines
internal/resources/networkedge/device/sweeper.go 0.00% 39 Missing ⚠️
...rnal/resources/networkedge/acl_template/sweeper.go 0.00% 28 Missing ⚠️
...ernal/resources/networkedge/device_link/sweeper.go 0.00% 28 Missing ⚠️
internal/resources/networkedge/ssh_key/sweeper.go 0.00% 28 Missing ⚠️
internal/resources/networkedge/device/resource.go 29.72% 21 Missing and 5 partials ⚠️
internal/resources/networkedge/ssh_user/sweeper.go 0.00% 24 Missing ⚠️
internal/sweep/sweep.go 0.00% 21 Missing ⚠️
internal/sweep/services/networkedge.go 0.00% 6 Missing ⚠️
...rnal/resources/networkedge/platform/data_source.go 0.00% 4 Missing ⚠️
internal/converters/converters.go 0.00% 3 Missing ⚠️
... and 10 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #622      +/-   ##
==========================================
- Coverage   29.42%   21.26%   -8.17%     
==========================================
  Files         246      252       +6     
  Lines       28407    28537     +130     
==========================================
- Hits         8360     6068    -2292     
- Misses      19893    22243    +2350     
- Partials      154      226      +72     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@displague
Copy link
Member Author

The best way to advance this PR will be to split out the helper refactorings into separate (easy to review) PRs. This will prevent the creeping in of new code with the patterns we want to move away from.

displague added a commit that referenced this pull request May 10, 2024
Extracted from #622

Also ran goimports for clean up (triggered by stray imports based test
failure)
ctreatma pushed a commit that referenced this pull request May 20, 2024
Remove isStringInSlice in favor of slices.Contains.

Extracted from #622 
Related to #665

Signed-off-by: Marques Johansson <mjohansson@equinix.com>
@displague displague force-pushed the internal_networkedge branch from d6b13e7 to f3b96d7 Compare May 22, 2024 13:19
ctreatma pushed a commit that referenced this pull request Jul 11, 2024
This PR moves the helper functions from provider.go to a new comparisons
package. This package will be used by provider, tests, and resources.
The refactoring will assist with splitting resources into resource
specific packages. #106

The previous helper functions have been deprecated and will be removed
in a future commit.

Extracted from #622 (PR grew to large to maintain. Refactoring is not a
priority and rebasing gets hard as the underlying code changes)

Related to #674
Related to #654

Signed-off-by: Marques Johansson <mjohansson@equinix.com>
@displague displague force-pushed the internal_networkedge branch from f3b96d7 to 20a6b6b Compare July 16, 2024 21:33
@displague
Copy link
Member Author

displague commented Jul 16, 2024

@ctreatma @equinix/governor-ne-network-edge-engineering

I updated this refactor branch andgo test -v ./... is no longer complaining! (no more import cycles in the branch. this was not blocking go build ./... )

The biggest trick was moving the init function in internal/acceptance/acceptance.go to {same}_acc_test.go.

There are a few more rounds of cleanup that could happen to make this PR easier to review:

  • removing/replacing the deprecated helpers in a separate PR
  • unifying the template_acc_test.go helpers which were copy/pasted around to avoid needing a separate package of helpers (or further polluting acceptance as we have done with one or two shared Metal config templates)
  • removing the unused code (this is now required by the linter, along with other linting changes). In particular, the template_acc_test.go copy/paste has unused functions copied around for the previously mentioned reasons.
  • revisiting the commit log (I expected after a rebase that some of the commits would have been removed entirely, this was not the case)
  • the templates_acc_test.go helpers would be better designed as Go templates, or entirely different styles of templating could be introduced. I don't see that as necessary or in scope for this PR.

// from https://stackoverflow.com/a/45428032
func Difference(a, b []string) []string {
mb := make(map[string]struct{}, len(b))
// Difference returns the elements in `a` that aren't in `b`.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

making Difference use generics doesn't have to be done in this PR.

@displague
Copy link
Member Author

#720 should be merged ahead of this so this PR can rebase and apply the sweeper related changes from that PR

@displague
Copy link
Member Author

displague commented Sep 25, 2024

After the latest rebase to pickup sweeper changes, and some changes to use SetMap (and a diag equivalent) for which more will be needed, there are new errors:

data_source_acc_test.go:25: Test validation error: TestStep 1/1 validation error: Providers must be specified at the TestCase level, or in all TestStep, or in TestStep.ConfigDirectory or TestStep.ConfigFile

I'm wondering if the init() calls in acceptance_test.go are not initializing the provider list correctly for cross-package testing.

kpdhulipala pushed a commit to kpdhulipala/terraform-provider-equinix that referenced this pull request Mar 24, 2025
Remove isStringInSlice in favor of slices.Contains.

Extracted from equinix#622 
Related to equinix#665

Signed-off-by: Marques Johansson <mjohansson@equinix.com>
kpdhulipala pushed a commit to kpdhulipala/terraform-provider-equinix that referenced this pull request Mar 24, 2025
This PR moves the helper functions from provider.go to a new comparisons
package. This package will be used by provider, tests, and resources.
The refactoring will assist with splitting resources into resource
specific packages. equinix#106

The previous helper functions have been deprecated and will be removed
in a future commit.

Extracted from equinix#622 (PR grew to large to maintain. Refactoring is not a
priority and rebasing gets hard as the underlying code changes)

Related to equinix#674
Related to equinix#654

Signed-off-by: Marques Johansson <mjohansson@equinix.com>
Signed-off-by: Marques Johansson <mjohansson@equinix.com>
Signed-off-by: Marques Johansson <mjohansson@equinix.com>
Signed-off-by: Marques Johansson <mjohansson@equinix.com>
@displague displague force-pushed the internal_networkedge branch from 921c699 to 0b8fe98 Compare December 9, 2025 14:27
@displague displague force-pushed the internal_networkedge branch from 0b8fe98 to 3d0de0f Compare December 9, 2025 14:33
@displague
Copy link
Member Author

displague commented Dec 9, 2025

Rebased to latest

I suspect the sweeper shared config may be able to find a better home, sweeper/services/networkedge.go ?)
Perhaps there is a better approach (the other sweepers don't use this function or pattern). @ctreatma

@displague displague force-pushed the internal_networkedge branch from 3d0de0f to 0a88969 Compare December 9, 2025 14:42
@displague displague marked this pull request as ready for review December 9, 2025 14:42
@displague displague requested review from a team as code owners December 9, 2025 14:42
Copilot AI review requested due to automatic review settings December 9, 2025 14:42
@displague displague requested a review from a team as a code owner December 9, 2025 14:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors Network Edge resources from the equinix package to dedicated packages under internal/resources/networkedge/, addressing part of issue #106. The refactoring reorganizes code structure while consolidating shared utilities like comparisons and nprintf helpers.

Key changes:

  • Network Edge resources split into individual packages (device, ssh_key, ssh_user, bgp, acl_template, etc.)
  • Resource/DataSource functions renamed from resourceNetworkX() to Resource() (exported)
  • Shared utilities consolidated (comparisons.IsEmpty, comparisons.SlicesMatch, nprintf.Nprintf)
  • Test sweepers moved from test files to dedicated sweeper.go files

Reviewed changes

Copilot reviewed 56 out of 56 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/resources/networkedge/*/resource.go Refactored resources with package name changes and exported Resource() functions
internal/resources/networkedge/*/sweeper.go New sweeper files extracted from test init() functions
internal/resources/networkedge/*/templates_acc_test.go Test template helpers (duplicated across device, device_link, bgp packages)
internal/acceptance/acceptance*.go Test provider initialization split into separate _test.go file
internal/sweep/sweep.go New SharedConfigForRegion() function for test sweepers
internal/comparisons/comparisons.go Utility functions consolidated from equinix package
internal/nprintf/nprintf.go String formatting helper renamed from NPrintf to Nprintf
equinix/network_edge_provider_maps.go Updated to use new package imports and exported functions
equinix/provider.go Removed deprecated utility functions moved to internal packages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +9 to +21
)

func init() {
TestAccProvider = equinix.Provider()
TestAccProviders = map[string]*schema.Provider{
"equinix": TestAccProvider,
}
TestExternalProviders = map[string]resource.ExternalProvider{
"random": {
Source: "hashicorp/random",
},
}
TestAccFrameworkProvider = provider.CreateFrameworkProvider(version.ProviderVersion).(*provider.FrameworkProvider)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The init() function has been moved from internal/acceptance/acceptance.go to this new file. However, the init() function will now run twice if both files are imported - once from acceptance.go and once from acceptance_acc_test.go. Since acceptance_acc_test.go has the _test.go suffix, it's only included in test builds, but acceptance.go is always included. This could cause issues if the package is imported in non-test code. Consider keeping the init() only in acceptance.go or using sync.Once to ensure single initialization.

Suggested change
)
func init() {
TestAccProvider = equinix.Provider()
TestAccProviders = map[string]*schema.Provider{
"equinix": TestAccProvider,
}
TestExternalProviders = map[string]resource.ExternalProvider{
"random": {
Source: "hashicorp/random",
},
}
TestAccFrameworkProvider = provider.CreateFrameworkProvider(version.ProviderVersion).(*provider.FrameworkProvider)
"sync"
)
var initOnce sync.Once
func init() {
initOnce.Do(func() {
TestAccProvider = equinix.Provider()
TestAccProviders = map[string]*schema.Provider{
"equinix": TestAccProvider,
}
TestExternalProviders = map[string]resource.ExternalProvider{
"random": {
Source: "hashicorp/random",
},
}
TestAccFrameworkProvider = provider.CreateFrameworkProvider(version.ProviderVersion).(*provider.FrameworkProvider)
})

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this is needed to prevent the problems I initially encountered with this PR, which left it in draft. I believe a better approach was found in other resource sets. ( @ctreatma )

Comment on lines +1 to +461
package device

import (
"github.com/equinix/terraform-provider-equinix/internal/comparisons"
"github.com/equinix/terraform-provider-equinix/internal/nprintf"
)

const (
tstResourcePrefix = "tfacc"

networkDeviceProjectId = "TF_ACC_NETWORK_DEVICE_PROJECT_ID"
networkDeviceAccountNameEnvVar = "TF_ACC_NETWORK_DEVICE_BILLING_ACCOUNT_NAME"
networkDeviceSecondaryAccountNameEnvVar = "TF_ACC_NETWORK_DEVICE_SECONDARY_BILLING_ACCOUNT_NAME"
networkDeviceMetroEnvVar = "TF_ACC_NETWORK_DEVICE_METRO"
networkDeviceSecondaryMetroEnvVar = "TF_ACC_NETWORK_DEVICE_SECONDARY_METRO"
networkDeviceCSRSDWANLicenseFileEnvVar = "TF_ACC_NETWORK_DEVICE_CSRSDWAN_LICENSE_FILE"
networkDeviceVSRXLicenseFileEnvVar = "TF_ACC_NETWORK_DEVICE_VSRX_LICENSE_FILE"
networkDeviceVersaController1EnvVar = "TF_ACC_NETWORK_DEVICE_VERSA_CONTROLLER1"
networkDeviceVersaController2EnvVar = "TF_ACC_NETWORK_DEVICE_VERSA_CONTROLLER2"
networkDeviceVersaLocalIDEnvVar = "TF_ACC_NETWORK_DEVICE_VERSA_LOCALID"
networkDeviceVersaRemoteIDEnvVar = "TF_ACC_NETWORK_DEVICE_VERSA_REMOTEID"
networkDeviceVersaSerialNumberEnvVar = "TF_ACC_NETWORK_DEVICE_VERSA_SERIAL"
networkDeviceCGENIXLicenseKeyEnvVar = "TF_ACC_NETWORK_DEVICE_CGENIX_LICENSE_KEY"
networkDeviceCGENIXLicenseSecretEnvVar = "TF_ACC_NETWORK_DEVICE_CGENIX_LICENSE_SECRET"
networkDevicePANWLicenseTokenEnvVar = "TF_ACC_NETWORK_DEVICE_PANW_LICENSE_TOKEN"
)

type testAccConfig struct {
ctx map[string]interface{}
config string
}

func newTestAccConfig(ctx map[string]interface{}) *testAccConfig {
return &testAccConfig{
ctx: ctx,
config: "",
}
}

func (t *testAccConfig) build() string {
return t.config
}

func (t *testAccConfig) withDevice() *testAccConfig {
t.config += testAccNetworkDevice(t.ctx)
return t
}

func copyMap(source map[string]interface{}) map[string]interface{} {
target := make(map[string]interface{})
for k, v := range source {
target[k] = v
}
return target
}

func testAccNetworkDeviceUser(ctx map[string]interface{}) string {
config := nprintf.Nprintf(`
resource "equinix_network_ssh_user" "%{user-resourceName}" {
username = "%{user-username}"
password = "%{user-password}"
device_ids = [
equinix_network_device.%{device-resourceName}.id`, ctx)
if _, ok := ctx["device-secondary_name"]; ok {
config += nprintf.Nprintf(`,
equinix_network_device.%{device-resourceName}.redundant_id`, ctx)
}
config += `
]
}`
return config
}

func testAccNetworkDevice(ctx map[string]interface{}) string {
var config string
config += nprintf.Nprintf(`
data "equinix_network_account" "test" {
metro_code = "%{device-metro_code}"
status = "Active"
project_id = "%{device-project_id}"`, ctx)
if v, ok := ctx["device-account_name"]; ok && !comparisons.IsEmpty(v) {
config += nprintf.Nprintf(`
name = "%{device-account_name}"`, ctx)
}
config += nprintf.Nprintf(`
}`, ctx)
if _, ok := ctx["device-secondary_metro_code"]; ok {
config += nprintf.Nprintf(`
data "equinix_network_account" "test-secondary" {
metro_code = "%{device-secondary_metro_code}"
status = "Active"`, ctx)
if v, ok := ctx["device-secondary_account_name"]; ok && !comparisons.IsEmpty(v) {
config += nprintf.Nprintf(`
name = "%{device-secondary_account_name}"`, ctx)
}
config += nprintf.Nprintf(`
}`, ctx)
}
config += nprintf.Nprintf(`
resource "equinix_network_device" "%{device-resourceName}" {
self_managed = %{device-self_managed}
byol = %{device-byol}
name = "%{device-name}"
metro_code = "%{device-metro_code}"
type_code = "%{device-type_code}"
project_id = "%{device-project_id}"
package_code = "%{device-package_code}"
notifications = %{device-notifications}
term_length = %{device-term_length}
account_number = data.equinix_network_account.test.number
version = "%{device-version}"
core_count = %{device-core_count}`, ctx)
if _, ok := ctx["device-purchase_order_number"]; ok {
config += nprintf.Nprintf(`
purchase_order_number = "%{device-purchase_order_number}"`, ctx)
}
if _, ok := ctx["device-purchase_order_number"]; ok {
config += nprintf.Nprintf(`
order_reference = "%{device-order_reference}"`, ctx)
}
if _, ok := ctx["device-additional_bandwidth"]; ok {
config += nprintf.Nprintf(`
additional_bandwidth = %{device-additional_bandwidth}`, ctx)
}
if _, ok := ctx["device-throughput"]; ok {
config += nprintf.Nprintf(`
throughput = %{device-throughput}
throughput_unit = "%{device-throughput_unit}"`, ctx)
}
if _, ok := ctx["device-hostname"]; ok {
config += nprintf.Nprintf(`
hostname = "%{device-hostname}"`, ctx)
}
if _, ok := ctx["device-interface_count"]; ok {
config += nprintf.Nprintf(`
interface_count = %{device-interface_count}`, ctx)
}
if _, ok := ctx["acl-resourceName"]; ok {
config += nprintf.Nprintf(`
acl_template_id = equinix_network_acl_template.%{acl-resourceName}.id`, ctx)
}
if _, ok := ctx["mgmtAcl-resourceName"]; ok {
config += nprintf.Nprintf(`
mgmt_acl_template_uuid = equinix_network_acl_template.%{mgmtAcl-resourceName}.id`, ctx)
}
if _, ok := ctx["sshkey-resourceName"]; ok {
config += nprintf.Nprintf(`
ssh_key {
username = "test"
key_name = equinix_network_ssh_key.%{sshkey-resourceName}.name
}`, ctx)
}
if _, ok := ctx["device-license_file"]; ok {
config += nprintf.Nprintf(`
license_file = "%{device-license_file}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_enabled"]; ok {
config += nprintf.Nprintf(`
vendor_configuration = {`, ctx)
if _, ok := ctx["device-vendorConfig_siteId"]; ok {
config += nprintf.Nprintf(`
siteId = "%{device-vendorConfig_siteId}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_systemIpAddress"]; ok {
config += nprintf.Nprintf(`
systemIpAddress = "%{device-vendorConfig_systemIpAddress}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_licenseKey"]; ok {
config += nprintf.Nprintf(`
licenseKey = "%{device-vendorConfig_licenseKey}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_licenseSecret"]; ok {
config += nprintf.Nprintf(`
licenseSecret = "%{device-vendorConfig_licenseSecret}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_controller1"]; ok {
config += nprintf.Nprintf(`
controller1 = "%{device-vendorConfig_controller1}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_controller2"]; ok {
config += nprintf.Nprintf(`
controller2 = "%{device-vendorConfig_controller2}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_localId"]; ok {
config += nprintf.Nprintf(`
localId = "%{device-vendorConfig_localId}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_remoteId"]; ok {
config += nprintf.Nprintf(`
remoteId = "%{device-vendorConfig_remoteId}"`, ctx)
}
if _, ok := ctx["device-vendorConfig_serialNumber"]; ok {
config += nprintf.Nprintf(`
serialNumber = "%{device-vendorConfig_serialNumber}"`, ctx)
}
config += nprintf.Nprintf(`
}`, ctx)
}
if _, ok := ctx["device-secondary_name"]; ok {
config += nprintf.Nprintf(`
secondary_device {
name = "%{device-secondary_name}"`, ctx)
if _, ok := ctx["device-secondary_metro_code"]; ok {
config += nprintf.Nprintf(`
metro_code = "%{device-secondary_metro_code}"
account_number = data.equinix_network_account.test-secondary.number`, ctx)
} else {
config += nprintf.Nprintf(`
metro_code = "%{device-metro_code}"
account_number = data.equinix_network_account.test.number`, ctx)
}
config += nprintf.Nprintf(`
notifications = %{device-secondary_notifications}`, ctx)
if _, ok := ctx["device-secondary_additional_bandwidth"]; ok {
config += nprintf.Nprintf(`
additional_bandwidth = %{device-secondary_additional_bandwidth}`, ctx)
}
if _, ok := ctx["device-secondary_hostname"]; ok {
config += nprintf.Nprintf(`
hostname = "%{device-secondary_hostname}"`, ctx)
}
if _, ok := ctx["acl-secondary_resourceName"]; ok {
config += nprintf.Nprintf(`
acl_template_id = equinix_network_acl_template.%{acl-secondary_resourceName}.id`, ctx)
}
if _, ok := ctx["mgmtAcl-secondary_resourceName"]; ok {
config += nprintf.Nprintf(`
mgmt_acl_template_uuid = equinix_network_acl_template.%{mgmtAcl-secondary_resourceName}.id`, ctx)
}
if _, ok := ctx["sshkey-resourceName"]; ok {
config += nprintf.Nprintf(`
ssh_key {
username = "test"
key_name = equinix_network_ssh_key.%{sshkey-resourceName}.name
}`, ctx)
}
if _, ok := ctx["device-secondary_license_file"]; ok {
config += nprintf.Nprintf(`
license_file = "%{device-secondary_license_file}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_enabled"]; ok {
config += nprintf.Nprintf(`
vendor_configuration = {`, ctx)
if _, ok := ctx["device-secondary_vendorConfig_siteId"]; ok {
config += nprintf.Nprintf(`
siteId = "%{device-secondary_vendorConfig_siteId}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_systemIpAddress"]; ok {
config += nprintf.Nprintf(`
systemIpAddress = "%{device-secondary_vendorConfig_systemIpAddress}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_licenseKey"]; ok {
config += nprintf.Nprintf(`
licenseKey = "%{device-secondary_vendorConfig_licenseKey}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_licenseSecret"]; ok {
config += nprintf.Nprintf(`
licenseSecret = "%{device-secondary_vendorConfig_licenseSecret}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_controller1"]; ok {
config += nprintf.Nprintf(`
controller1 = "%{device-secondary_vendorConfig_controller1}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_controller2"]; ok {
config += nprintf.Nprintf(`
controller2 = "%{device-secondary_vendorConfig_controller2}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_localId"]; ok {
config += nprintf.Nprintf(`
localId = "%{device-secondary_vendorConfig_localId}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_remoteId"]; ok {
config += nprintf.Nprintf(`
remoteId = "%{device-secondary_vendorConfig_remoteId}"`, ctx)
}
if _, ok := ctx["device-secondary_vendorConfig_serialNumber"]; ok {
config += nprintf.Nprintf(`
serialNumber = "%{device-secondary_vendorConfig_serialNumber}"`, ctx)
}
config += nprintf.Nprintf(`
}`, ctx)
}
config += `
}`
}
if _, ok := ctx["device-cluster_name"]; ok {
config += nprintf.Nprintf(`
cluster_details {
cluster_name = "%{device-cluster_name}"`, ctx)
config += `
node0 {`
if _, ok := ctx["device-node0_license_file_id"]; ok {
config += nprintf.Nprintf(`
license_file_id = "%{device-node0_license_file_id}"`, ctx)
}
if _, ok := ctx["device-node0_license_token"]; ok {
config += nprintf.Nprintf(`
license_token = "%{device-node0_license_token}"`, ctx)
}
if _, ok := ctx["device-node0_vendorConfig_enabled"]; ok {
config += nprintf.Nprintf(`
vendor_configuration {`, ctx)
if _, ok := ctx["device-node0_vendorConfig_hostname"]; ok {
config += nprintf.Nprintf(`
hostname = "%{device-node0_vendorConfig_hostname}"`, ctx)
}
if _, ok := ctx["device-node0_vendorConfig_adminPassword"]; ok {
config += nprintf.Nprintf(`
admin_password = "%{device-node0_vendorConfig_adminPassword}"`, ctx)
}
if _, ok := ctx["device-node0_vendorConfig_controller1"]; ok {
config += nprintf.Nprintf(`
controller1 = "%{device-node0_vendorConfig_controller1}"`, ctx)
}
if _, ok := ctx["device-node0_vendorConfig_activationKey"]; ok {
config += nprintf.Nprintf(`
activation_key = "%{device-node0_vendorConfig_activationKey}"`, ctx)
}
if _, ok := ctx["device-node0_vendorConfig_controllerFqdn"]; ok {
config += nprintf.Nprintf(`
controller_fqdn = "%{device-node0_vendorConfig_controllerFqdn}"`, ctx)
}
if _, ok := ctx["device-node0_vendorConfig_rootPassword"]; ok {
config += nprintf.Nprintf(`
root_password = "%{device-node0_vendorConfig_rootPassword}"`, ctx)
}
config += nprintf.Nprintf(`
}`, ctx)
}
config += `
}`
config += `
node1 {`
if _, ok := ctx["device-node1_license_file_id"]; ok {
config += nprintf.Nprintf(`
license_file_id = "%{device-node1_license_file_id}"`, ctx)
}
if _, ok := ctx["device-node1_license_token"]; ok {
config += nprintf.Nprintf(`
license_token = "%{device-node1_license_token}"`, ctx)
}
if _, ok := ctx["device-node1_vendorConfig_enabled"]; ok {
config += nprintf.Nprintf(`
vendor_configuration {`, ctx)
if _, ok := ctx["device-node1_vendorConfig_hostname"]; ok {
config += nprintf.Nprintf(`
hostname = "%{device-node1_vendorConfig_hostname}"`, ctx)
}
if _, ok := ctx["device-node1_vendorConfig_adminPassword"]; ok {
config += nprintf.Nprintf(`
admin_password = "%{device-node1_vendorConfig_adminPassword}"`, ctx)
}
if _, ok := ctx["device-node1_vendorConfig_controller1"]; ok {
config += nprintf.Nprintf(`
controller1 = "%{device-node1_vendorConfig_controller1}"`, ctx)
}
if _, ok := ctx["device-node1_vendorConfig_activationKey"]; ok {
config += nprintf.Nprintf(`
activation_key = "%{device-node1_vendorConfig_activationKey}"`, ctx)
}
if _, ok := ctx["device-node1_vendorConfig_controllerFqdn"]; ok {
config += nprintf.Nprintf(`
controller_fqdn = "%{device-node1_vendorConfig_controllerFqdn}"`, ctx)
}
if _, ok := ctx["device-node1_vendorConfig_rootPassword"]; ok {
config += nprintf.Nprintf(`
root_password = "%{device-node1_vendorConfig_rootPassword}"`, ctx)
}
config += nprintf.Nprintf(`
}`, ctx)
}
config += `
}`
config += `
}`
}
config += `
}`
return config
}

func testAccNetworkDeviceACL(ctx map[string]interface{}) string {
var config string
if _, ok := ctx["acl-name"]; ok {
config += nprintf.Nprintf(`
resource "equinix_network_acl_template" "%{acl-resourceName}" {
name = "%{acl-name}"
description = "%{acl-description}"
inbound_rule {
subnet = "10.0.0.0/24"
protocol = "IP"
src_port = "any"
dst_port = "any"
}
}`, ctx)
}
if _, ok := ctx["mgmtAcl-name"]; ok {
config += nprintf.Nprintf(`
resource "equinix_network_acl_template" "%{mgmtAcl-resourceName}" {
name = "%{mgmtAcl-name}"
description = "%{mgmtAcl-description}"
inbound_rule {
subnet = "11.0.0.0/24"
protocol = "IP"
src_port = "any"
dst_port = "any"
}
}`, ctx)
}
if _, ok := ctx["acl-secondary_name"]; ok {
config += nprintf.Nprintf(`
resource "equinix_network_acl_template" "%{acl-secondary_resourceName}" {
name = "%{acl-secondary_name}"
description = "%{acl-secondary_description}"
inbound_rule {
subnet = "192.0.0.0/24"
protocol = "IP"
src_port = "any"
dst_port = "any"
}
}`, ctx)
}
if _, ok := ctx["mgmtAcl-secondary_name"]; ok {
config += nprintf.Nprintf(`
resource "equinix_network_acl_template" "%{mgmtAcl-secondary_resourceName}" {
name = "%{mgmtAcl-secondary_name}"
description = "%{mgmtAcl-secondary_description}"
inbound_rule {
subnet = "193.0.0.0/24"
protocol = "IP"
src_port = "any"
dst_port = "any"
}
}`, ctx)
}
return config
}

func testAccNetworkDeviceSSHKey(ctx map[string]interface{}) string {
return nprintf.Nprintf(`
resource "equinix_network_ssh_key" "%{sshkey-resourceName}" {
name = "%{sshkey-name}"
public_key = "%{sshkey-public_key}"
}
`, ctx)
}

func (t *testAccConfig) withACL() *testAccConfig {
t.config += testAccNetworkDeviceACL(t.ctx)
return t
}

func (t *testAccConfig) withSSHKey() *testAccConfig {
t.config += testAccNetworkDeviceSSHKey(t.ctx)
return t
}

func (t *testAccConfig) withSSHUser() *testAccConfig {
t.config += testAccNetworkDeviceUser(t.ctx)
return t
}
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same test template code (testAccNetworkDevice, testAccNetworkDeviceACL, testAccNetworkDeviceSSHKey, copyMap, testAccNetworkDeviceUser, newTestAccConfig, testAccConfig struct, and related methods) is duplicated across three files:

  • internal/resources/networkedge/device/templates_acc_test.go (lines 1-461)
  • internal/resources/networkedge/device_link/templates_acc_test.go (lines 1-461)
  • internal/resources/networkedge/bgp/templates_acc_test.go (lines 1-461)

This violates the DRY principle and creates a maintenance burden. Consider:

  1. Moving this shared test infrastructure to a common package like internal/resources/networkedge/testutils or internal/acceptance
  2. Or creating a shared templates_test_common.go file that all three packages can import

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +119
if _, ok := ctx["device-purchase_order_number"]; ok {
config += nprintf.Nprintf(`
order_reference = "%{device-order_reference}"`, ctx)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition on line 117 checks for device-purchase_order_number but should likely check for device-order_reference instead. This is a copy-paste error that causes order_reference to only be added when purchase_order_number exists in the context, which may not be the intended behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +119
if _, ok := ctx["device-purchase_order_number"]; ok {
config += nprintf.Nprintf(`
order_reference = "%{device-order_reference}"`, ctx)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition on line 117 checks for device-purchase_order_number but should likely check for device-order_reference instead. This is a copy-paste error that causes order_reference to only be added when purchase_order_number exists in the context, which may not be the intended behavior.

Copilot uses AI. Check for mistakes.
config += nprintf.Nprintf(`
purchase_order_number = "%{device-purchase_order_number}"`, ctx)
}
if _, ok := ctx["device-purchase_order_number"]; ok {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition on line 117 checks for device-purchase_order_number but should likely check for device-order_reference instead. This is a copy-paste error that causes order_reference to only be added when purchase_order_number exists in the context, which may not be the intended behavior.

Suggested change
if _, ok := ctx["device-purchase_order_number"]; ok {
if _, ok := ctx["device-order_reference"]; ok {

Copilot uses AI. Check for mistakes.
Signed-off-by: Marques Johansson <mjohansson@equinix.com>
Signed-off-by: Marques Johansson <mjohansson@equinix.com>
Signed-off-by: Marques Johansson <mjohansson@equinix.com>
Signed-off-by: Marques Johansson <mjohansson@equinix.com>
…ovider-equinix on networkedge files

Signed-off-by: Marques Johansson <mjohansson@equinix.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants