github.com/aavshr/aws-sdk-go@v1.41.3/aws/ec2metadata/api.go (about)

     1  package ec2metadata
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/aavshr/aws-sdk-go/aws"
    12  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    13  	"github.com/aavshr/aws-sdk-go/aws/request"
    14  	"github.com/aavshr/aws-sdk-go/internal/sdkuri"
    15  )
    16  
    17  // getToken uses the duration to return a token for EC2 metadata service,
    18  // or an error if the request failed.
    19  func (c *EC2Metadata) getToken(ctx aws.Context, duration time.Duration) (tokenOutput, error) {
    20  	op := &request.Operation{
    21  		Name:       "GetToken",
    22  		HTTPMethod: "PUT",
    23  		HTTPPath:   "/latest/api/token",
    24  	}
    25  
    26  	var output tokenOutput
    27  	req := c.NewRequest(op, nil, &output)
    28  	req.SetContext(ctx)
    29  
    30  	// remove the fetch token handler from the request handlers to avoid infinite recursion
    31  	req.Handlers.Sign.RemoveByName(fetchTokenHandlerName)
    32  
    33  	// Swap the unmarshalMetadataHandler with unmarshalTokenHandler on this request.
    34  	req.Handlers.Unmarshal.Swap(unmarshalMetadataHandlerName, unmarshalTokenHandler)
    35  
    36  	ttl := strconv.FormatInt(int64(duration/time.Second), 10)
    37  	req.HTTPRequest.Header.Set(ttlHeader, ttl)
    38  
    39  	err := req.Send()
    40  
    41  	// Errors with bad request status should be returned.
    42  	if err != nil {
    43  		err = awserr.NewRequestFailure(
    44  			awserr.New(req.HTTPResponse.Status, http.StatusText(req.HTTPResponse.StatusCode), err),
    45  			req.HTTPResponse.StatusCode, req.RequestID)
    46  	}
    47  
    48  	return output, err
    49  }
    50  
    51  // GetMetadata uses the path provided to request information from the EC2
    52  // instance metadata service. The content will be returned as a string, or
    53  // error if the request failed.
    54  func (c *EC2Metadata) GetMetadata(p string) (string, error) {
    55  	return c.GetMetadataWithContext(aws.BackgroundContext(), p)
    56  }
    57  
    58  // GetMetadataWithContext uses the path provided to request information from the EC2
    59  // instance metadata service. The content will be returned as a string, or
    60  // error if the request failed.
    61  func (c *EC2Metadata) GetMetadataWithContext(ctx aws.Context, p string) (string, error) {
    62  	op := &request.Operation{
    63  		Name:       "GetMetadata",
    64  		HTTPMethod: "GET",
    65  		HTTPPath:   sdkuri.PathJoin("/latest/meta-data", p),
    66  	}
    67  	output := &metadataOutput{}
    68  
    69  	req := c.NewRequest(op, nil, output)
    70  
    71  	req.SetContext(ctx)
    72  
    73  	err := req.Send()
    74  	return output.Content, err
    75  }
    76  
    77  // GetUserData returns the userdata that was configured for the service. If
    78  // there is no user-data setup for the EC2 instance a "NotFoundError" error
    79  // code will be returned.
    80  func (c *EC2Metadata) GetUserData() (string, error) {
    81  	return c.GetUserDataWithContext(aws.BackgroundContext())
    82  }
    83  
    84  // GetUserDataWithContext returns the userdata that was configured for the service. If
    85  // there is no user-data setup for the EC2 instance a "NotFoundError" error
    86  // code will be returned.
    87  func (c *EC2Metadata) GetUserDataWithContext(ctx aws.Context) (string, error) {
    88  	op := &request.Operation{
    89  		Name:       "GetUserData",
    90  		HTTPMethod: "GET",
    91  		HTTPPath:   "/latest/user-data",
    92  	}
    93  
    94  	output := &metadataOutput{}
    95  	req := c.NewRequest(op, nil, output)
    96  	req.SetContext(ctx)
    97  
    98  	err := req.Send()
    99  	return output.Content, err
   100  }
   101  
   102  // GetDynamicData uses the path provided to request information from the EC2
   103  // instance metadata service for dynamic data. The content will be returned
   104  // as a string, or error if the request failed.
   105  func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
   106  	return c.GetDynamicDataWithContext(aws.BackgroundContext(), p)
   107  }
   108  
   109  // GetDynamicDataWithContext uses the path provided to request information from the EC2
   110  // instance metadata service for dynamic data. The content will be returned
   111  // as a string, or error if the request failed.
   112  func (c *EC2Metadata) GetDynamicDataWithContext(ctx aws.Context, p string) (string, error) {
   113  	op := &request.Operation{
   114  		Name:       "GetDynamicData",
   115  		HTTPMethod: "GET",
   116  		HTTPPath:   sdkuri.PathJoin("/latest/dynamic", p),
   117  	}
   118  
   119  	output := &metadataOutput{}
   120  	req := c.NewRequest(op, nil, output)
   121  	req.SetContext(ctx)
   122  
   123  	err := req.Send()
   124  	return output.Content, err
   125  }
   126  
   127  // GetInstanceIdentityDocument retrieves an identity document describing an
   128  // instance. Error is returned if the request fails or is unable to parse
   129  // the response.
   130  func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) {
   131  	return c.GetInstanceIdentityDocumentWithContext(aws.BackgroundContext())
   132  }
   133  
   134  // GetInstanceIdentityDocumentWithContext retrieves an identity document describing an
   135  // instance. Error is returned if the request fails or is unable to parse
   136  // the response.
   137  func (c *EC2Metadata) GetInstanceIdentityDocumentWithContext(ctx aws.Context) (EC2InstanceIdentityDocument, error) {
   138  	resp, err := c.GetDynamicDataWithContext(ctx, "instance-identity/document")
   139  	if err != nil {
   140  		return EC2InstanceIdentityDocument{},
   141  			awserr.New("EC2MetadataRequestError",
   142  				"failed to get EC2 instance identity document", err)
   143  	}
   144  
   145  	doc := EC2InstanceIdentityDocument{}
   146  	if err := json.NewDecoder(strings.NewReader(resp)).Decode(&doc); err != nil {
   147  		return EC2InstanceIdentityDocument{},
   148  			awserr.New(request.ErrCodeSerialization,
   149  				"failed to decode EC2 instance identity document", err)
   150  	}
   151  
   152  	return doc, nil
   153  }
   154  
   155  // IAMInfo retrieves IAM info from the metadata API
   156  func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
   157  	return c.IAMInfoWithContext(aws.BackgroundContext())
   158  }
   159  
   160  // IAMInfoWithContext retrieves IAM info from the metadata API
   161  func (c *EC2Metadata) IAMInfoWithContext(ctx aws.Context) (EC2IAMInfo, error) {
   162  	resp, err := c.GetMetadataWithContext(ctx, "iam/info")
   163  	if err != nil {
   164  		return EC2IAMInfo{},
   165  			awserr.New("EC2MetadataRequestError",
   166  				"failed to get EC2 IAM info", err)
   167  	}
   168  
   169  	info := EC2IAMInfo{}
   170  	if err := json.NewDecoder(strings.NewReader(resp)).Decode(&info); err != nil {
   171  		return EC2IAMInfo{},
   172  			awserr.New(request.ErrCodeSerialization,
   173  				"failed to decode EC2 IAM info", err)
   174  	}
   175  
   176  	if info.Code != "Success" {
   177  		errMsg := fmt.Sprintf("failed to get EC2 IAM Info (%s)", info.Code)
   178  		return EC2IAMInfo{},
   179  			awserr.New("EC2MetadataError", errMsg, nil)
   180  	}
   181  
   182  	return info, nil
   183  }
   184  
   185  // Region returns the region the instance is running in.
   186  func (c *EC2Metadata) Region() (string, error) {
   187  	return c.RegionWithContext(aws.BackgroundContext())
   188  }
   189  
   190  // RegionWithContext returns the region the instance is running in.
   191  func (c *EC2Metadata) RegionWithContext(ctx aws.Context) (string, error) {
   192  	ec2InstanceIdentityDocument, err := c.GetInstanceIdentityDocumentWithContext(ctx)
   193  	if err != nil {
   194  		return "", err
   195  	}
   196  	// extract region from the ec2InstanceIdentityDocument
   197  	region := ec2InstanceIdentityDocument.Region
   198  	if len(region) == 0 {
   199  		return "", awserr.New("EC2MetadataError", "invalid region received for ec2metadata instance", nil)
   200  	}
   201  	// returns region
   202  	return region, nil
   203  }
   204  
   205  // Available returns if the application has access to the EC2 Metadata service.
   206  // Can be used to determine if application is running within an EC2 Instance and
   207  // the metadata service is available.
   208  func (c *EC2Metadata) Available() bool {
   209  	return c.AvailableWithContext(aws.BackgroundContext())
   210  }
   211  
   212  // AvailableWithContext returns if the application has access to the EC2 Metadata service.
   213  // Can be used to determine if application is running within an EC2 Instance and
   214  // the metadata service is available.
   215  func (c *EC2Metadata) AvailableWithContext(ctx aws.Context) bool {
   216  	if _, err := c.GetMetadataWithContext(ctx, "instance-id"); err != nil {
   217  		return false
   218  	}
   219  
   220  	return true
   221  }
   222  
   223  // An EC2IAMInfo provides the shape for unmarshaling
   224  // an IAM info from the metadata API
   225  type EC2IAMInfo struct {
   226  	Code               string
   227  	LastUpdated        time.Time
   228  	InstanceProfileArn string
   229  	InstanceProfileID  string
   230  }
   231  
   232  // An EC2InstanceIdentityDocument provides the shape for unmarshaling
   233  // an instance identity document
   234  type EC2InstanceIdentityDocument struct {
   235  	DevpayProductCodes      []string  `json:"devpayProductCodes"`
   236  	MarketplaceProductCodes []string  `json:"marketplaceProductCodes"`
   237  	AvailabilityZone        string    `json:"availabilityZone"`
   238  	PrivateIP               string    `json:"privateIp"`
   239  	Version                 string    `json:"version"`
   240  	Region                  string    `json:"region"`
   241  	InstanceID              string    `json:"instanceId"`
   242  	BillingProducts         []string  `json:"billingProducts"`
   243  	InstanceType            string    `json:"instanceType"`
   244  	AccountID               string    `json:"accountId"`
   245  	PendingTime             time.Time `json:"pendingTime"`
   246  	ImageID                 string    `json:"imageId"`
   247  	KernelID                string    `json:"kernelId"`
   248  	RamdiskID               string    `json:"ramdiskId"`
   249  	Architecture            string    `json:"architecture"`
   250  }