text: // Package ec2metadata provides the client for making API calls to the
  // EC2 Metadata service.
  //
  // This package's client can be disabled completely by setting the environment
  // variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
  // true instructs the SDK to disable the EC2 Metadata client. The client cannot
  // be used while the environemnt variable is set to true, (case insensitive).
  package ec2metadata
  
  import (
  	"bytes"
  	"errors"
  	"io"
  	"net/http"
  	"os"
  	"strings"
  	"time"
  
  	"github.com/aws/aws-sdk-go/aws"
  	"github.com/aws/aws-sdk-go/aws/awserr"
  	"github.com/aws/aws-sdk-go/aws/client"
  	"github.com/aws/aws-sdk-go/aws/client/metadata"
  	"github.com/aws/aws-sdk-go/aws/corehandlers"
  	"github.com/aws/aws-sdk-go/aws/request"
  )
  
  // ServiceName is the name of the service.
  const ServiceName = "ec2metadata"
  const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
  
  // A EC2Metadata is an EC2 Metadata service Client.
  type EC2Metadata struct {
  	*client.Client
  }
  
  // New creates a new instance of the EC2Metadata client with a session.
  // This client is safe to use across multiple goroutines.
  //
  //
  // Example:
  //     // Create a EC2Metadata client from just a session.
  //     svc := ec2metadata.New(mySession)
  //
  //     // Create a EC2Metadata client with additional configuration
  //     svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
  func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
  	c := p.ClientConfig(ServiceName, cfgs...)
  	return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
  }
  
  // NewClient returns a new EC2Metadata client. Should be used to create
  // a client when not using a session. Generally using just New with a session
  // is preferred.
  //
  // If an unmodified HTTP client is provided from the stdlib default, or no client
  // the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened.
  // To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default.
  func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata {
  	if !aws.BoolValue(cfg.EC2MetadataDisableTimeoutOverride) && httpClientZero(cfg.HTTPClient) {
  		// If the http client is unmodified and this feature is not disabled
  		// set custom timeouts for EC2Metadata requests.
  		cfg.HTTPClient = &http.Client{
  			// use a shorter timeout than default because the metadata
  			// service is local if it is running, and to fail faster
  			// if not running on an ec2 instance.
  			Timeout: 5 * time.Second,
  		}
  	}
  
  	svc := &EC2Metadata{
  		Client: client.New(
  			cfg,
  			metadata.ClientInfo{
  				ServiceName: ServiceName,
  				Endpoint:    endpoint,
  				APIVersion:  "latest",
  			},
  			handlers,
  		),
  	}
  
  	svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
  	svc.Handlers.UnmarshalError.PushBack(unmarshalError)
  	svc.Handlers.Validate.Clear()
  	svc.Handlers.Validate.PushBack(validateEndpointHandler)
  
  	// Disable the EC2 Metadata service if the environment variable is set.
  	// This shortcirctes the service's functionality to always fail to send
  	// requests.
  	if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" {
  		svc.Handlers.Send.SwapNamed(request.NamedHandler{
  			Name: corehandlers.SendHandler.Name,
  			Fn: func(r *request.Request) {
  				r.Error = awserr.New(
  					request.CanceledErrorCode,
  					"EC2 IMDS access disabled via "+disableServiceEnvVar+" env var",
  					nil)
  			},
  		})
  	}
  
  	// Add additional options to the service config
  	for _, option := range opts {
  		option(svc.Client)
  	}
  
  	return svc
  }
  
  func httpClientZero(c *http.Client) bool {
  	return c == nil || (c.Transport == nil && c.CheckRedirect == nil && c.Jar == nil && c.Timeout == 0)
  }
  
  type metadataOutput struct {
  	Content string
  }
  
  func unmarshalHandler(r *request.Request) {
  	defer r.HTTPResponse.Body.Close()
  	b := &bytes.Buffer{}
  	if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
  		r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err)
  		return
  	}
  
  	if data, ok := r.Data.(*metadataOutput); ok {
  		data.Content = b.String()
  	}
  }
  
  func unmarshalError(r *request.Request) {
  	defer r.HTTPResponse.Body.Close()
  	b := &bytes.Buffer{}
  	if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
  		r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err)
  		return
  	}
  
  	// Response body format is not consistent between metadata endpoints.
  	// Grab the error message as a string and include that as the source error
  	r.Error = awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String()))
  }
  
  func validateEndpointHandler(r *request.Request) {
  	if r.ClientInfo.Endpoint == "" {
  		r.Error = aws.ErrMissingEndpoint
  	}
  }
  