Skip to content

Commit

Permalink
Merge pull request #255 from displague/ua_module_name
Browse files Browse the repository at this point in the history
add module_name provider metadata
  • Loading branch information
ocobles authored Nov 22, 2022
2 parents 39f6656 + 957a460 commit b582b09
Show file tree
Hide file tree
Showing 33 changed files with 390 additions and 224 deletions.
96 changes: 69 additions & 27 deletions equinix/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/equinix/terraform-provider-equinix/version"
"github.com/hashicorp/go-retryablehttp"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/meta"
"github.com/packethost/packngo"
xoauth2 "golang.org/x/oauth2"
Expand Down Expand Up @@ -62,8 +63,9 @@ Original Error:`
)

var (
DefaultBaseURL = "https://api.equinix.com"
DefaultTimeout = 30
DefaultBaseURL = "https://api.equinix.com"
DefaultTimeout = 30
redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`)
)

// Config is the configuration structure used to instantiate the Equinix
Expand All @@ -83,6 +85,10 @@ type Config struct {
ne ne.Client
metal *packngo.Client

ecxUserAgent string
neUserAgent string
metalUserAgent string

terraformVersion string
}

Expand Down Expand Up @@ -122,11 +128,13 @@ func (c *Config) Load(ctx context.Context) error {
ecxClient.SetPageSize(c.PageSize)
neClient.SetPageSize(c.PageSize)
}
c.ecxUserAgent = c.fullUserAgent("equinix/ecx-go")
ecxClient.SetHeaders(map[string]string{
"User-agent": c.fullUserAgent("equinix/ecx-go"),
"User-agent": c.ecxUserAgent,
})
c.neUserAgent = c.fullUserAgent("equinix/ecx-go")
neClient.SetHeaders(map[string]string{
"User-agent": c.fullUserAgent("equinix/ne-go"),
"User-agent": c.neUserAgent,
})

c.ecx = ecxClient
Expand All @@ -136,15 +144,33 @@ func (c *Config) Load(ctx context.Context) error {
return nil
}

// NewMetalClient returns a new client for accessing Equinix Metal's API.
func (c *Config) NewMetalClient() *packngo.Client {
transport := http.DefaultTransport
// transport = &DumpTransport{http.DefaultTransport} // Debug only
transport = logging.NewTransport("Equinix Metal", transport)
retryClient := retryablehttp.NewClient()
retryClient.HTTPClient.Transport = transport
retryClient.RetryMax = c.MaxRetries
retryClient.RetryWaitMin = time.Second
retryClient.RetryWaitMax = c.MaxRetryWait
retryClient.CheckRetry = MetalRetryPolicy
standardClient := retryClient.StandardClient()
baseURL, _ := url.Parse(c.BaseURL)
baseURL.Path = path.Join(baseURL.Path, metalBasePath) + "/"
client, _ := packngo.NewClientWithBaseURL(consumerToken, c.AuthToken, standardClient, baseURL.String())
client.UserAgent = c.fullUserAgent(client.UserAgent)
c.metalUserAgent = client.UserAgent
return client
}

func (c *Config) requestTimeout() time.Duration {
if c.RequestTimeout == 0 {
return 5 * time.Second
}
return c.RequestTimeout
}

var redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`)

func MetalRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
if ctx.Err() != nil {
return false, ctx.Err()
Expand All @@ -162,7 +188,6 @@ func MetalRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool
return false, nil
}
}

// The error is likely recoverable so retry.
return true, nil
}
Expand All @@ -184,28 +209,45 @@ func terraformUserAgent(version string) string {
return ua
}

func (c *Config) addModuleToECXUserAgent(client *ecx.Client, d *schema.ResourceData) {
cli := *client
rc := cli.(*ecx.RestClient)
rc.SetHeader("User-agent", generateModuleUserAgentString(d, c.ecxUserAgent))
*client = rc
}

func (c *Config) addModuleToNEUserAgent(client *ne.Client, d *schema.ResourceData) {
cli := *client
rc := cli.(*ne.RestClient)
rc.SetHeader("User-agent", generateModuleUserAgentString(d, c.neUserAgent))
*client = rc
}

// TODO (ocobleseqx) - known issue, Metal services are initialized using the metal client pointer
// if two or more modules in same project interact with metal resources they will override
// the UserAgent resulting in swapped UserAgent.
// This can be fixed by letting the headers be overwritten on the initialized Packngo ServiceOp
// clients on a query-by-query basis.
func (c *Config) addModuleToMetalUserAgent(d *schema.ResourceData) {
c.metal.UserAgent = generateModuleUserAgentString(d, c.metalUserAgent)
}

func generateModuleUserAgentString(d *schema.ResourceData, baseUserAgent string) string {
var m providerMeta
err := d.GetProviderMeta(&m)
if err != nil {
log.Printf("[WARN] error retrieving provider_meta")
return baseUserAgent
}

if m.ModuleName != "" {
return strings.Join([]string{m.ModuleName, baseUserAgent}, " ")
}
return baseUserAgent
}

func (c *Config) fullUserAgent(suffix string) string {
tfUserAgent := terraformUserAgent(c.terraformVersion)
userAgent := fmt.Sprintf("%s terraform-provider-equinix/%s %s", tfUserAgent, version.ProviderVersion, suffix)
return strings.TrimSpace(userAgent)
}

// NewMetalClient returns a new client for accessing Equinix Metal's API.
func (c *Config) NewMetalClient() *packngo.Client {
transport := http.DefaultTransport
// transport = &DumpTransport{http.DefaultTransport} // Debug only
transport = logging.NewTransport("Equinix Metal", transport)
retryClient := retryablehttp.NewClient()
retryClient.HTTPClient.Transport = transport
retryClient.RetryMax = c.MaxRetries
retryClient.RetryWaitMin = time.Second
retryClient.RetryWaitMax = c.MaxRetryWait
retryClient.CheckRetry = MetalRetryPolicy
standardClient := retryClient.StandardClient()
baseURL, _ := url.Parse(c.BaseURL)
baseURL.Path = path.Join(baseURL.Path, metalBasePath) + "/"
client, _ := packngo.NewClientWithBaseURL(consumerToken, c.AuthToken, standardClient, baseURL.String())
client.UserAgent = c.fullUserAgent(client.UserAgent)

return client
}
2 changes: 1 addition & 1 deletion equinix/data_source_ecx_l2_sellerprofile.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func dataSourceECXL2SellerProfile() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceECXL2SellerProfileRead,
Description: "Use this data source to get details of Equinix Fabric layer 2 seller profile with a given name and / or organization",
Schema: createECXL2SellerProfileSchema(),
Schema: createECXL2SellerProfileSchema(),
}
}

Expand Down
6 changes: 6 additions & 0 deletions equinix/data_source_metal_project_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ func TestAccDataSourceMetalProject_basic(t *testing.T) {

func testAccDataSourceMetalProject_basic(r string) string {
return fmt.Sprintf(`
terraform {
provider_meta "equinix" {
module_name = "test"
}
}
resource "equinix_metal_project" "foobar" {
name = "tfacc-project-%s"
bgp_config {
Expand Down
4 changes: 4 additions & 0 deletions equinix/helpers_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ func waitForDeviceAttribute(d *schema.ResourceData, targets []string, pending []
Target: targets,
Refresh: func() (interface{}, string, error) {
client := meta.(*Config).metal
client.UserAgent = generateModuleUserAgentString(d, client.UserAgent)

device, _, err := client.Devices.Get(d.Id(), &packngo.GetOptions{Includes: []string{"project"}})
if err == nil {
retAttrVal := device.State
Expand Down Expand Up @@ -215,7 +217,9 @@ func waitForDeviceAttribute(d *schema.ResourceData, targets []string, pending []

// powerOnAndWait Powers on the device and waits for it to be active.
func powerOnAndWait(d *schema.ResourceData, meta interface{}) error {
meta.(*Config).addModuleToMetalUserAgent(d)
client := meta.(*Config).metal

_, err := client.Devices.PowerOn(d.Id())
if err != nil {
return friendlyError(err)
Expand Down
1 change: 1 addition & 0 deletions equinix/port_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type ClientPortResource struct {
}

func getClientPortResource(d *schema.ResourceData, meta interface{}) (*ClientPortResource, *packngo.Response, error) {
meta.(*Config).addModuleToMetalUserAgent(d)
client := meta.(*Config).metal

port_id := d.Get("port_id").(string)
Expand Down
14 changes: 14 additions & 0 deletions equinix/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ func Provider() *schema.Provider {
"equinix_metal_port_vlan_attachment": resourceMetalPortVlanAttachment(),
"equinix_metal_gateway": resourceMetalGateway(),
},
ProviderMetaSchema: map[string]*schema.Schema{
"module_name": {
Type: schema.TypeString,
Optional: true,
},
},
}

provider.ConfigureContextFunc = func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
Expand All @@ -171,6 +177,10 @@ func Provider() *schema.Provider {
return provider
}

type providerMeta struct {
ModuleName string `cty:"module_name"`
}

func configureProvider(ctx context.Context, d *schema.ResourceData, p *schema.Provider) (interface{}, diag.Diagnostics) {
mrws := d.Get("max_retry_wait_seconds").(int)
rt := d.Get("request_timeout").(int)
Expand All @@ -186,7 +196,11 @@ func configureProvider(ctx context.Context, d *schema.ResourceData, p *schema.Pr
MaxRetries: d.Get("max_retries").(int),
MaxRetryWait: time.Duration(mrws) * time.Second,
}
meta := providerMeta{}

if err := d.GetProviderMeta(&meta); err != nil {
return nil, diag.FromErr(err)
}
config.terraformVersion = p.TerraformVersion
if config.terraformVersion == "" {
// Terraform 0.12 introduced this field to the protocol
Expand Down
Loading

0 comments on commit b582b09

Please sign in to comment.