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

     1  //go:build go1.7
     2  // +build go1.7
     3  
     4  package ec2metadata_test
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"path"
    14  	"reflect"
    15  	"strings"
    16  	"sync"
    17  	"sync/atomic"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/aavshr/aws-sdk-go/aws"
    22  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    23  	"github.com/aavshr/aws-sdk-go/aws/ec2metadata"
    24  	"github.com/aavshr/aws-sdk-go/aws/request"
    25  	"github.com/aavshr/aws-sdk-go/awstesting/unit"
    26  	"github.com/aavshr/aws-sdk-go/internal/sdktesting"
    27  )
    28  
    29  const instanceIdentityDocument = `{
    30    "devpayProductCodes" : null,
    31    "marketplaceProductCodes" : [ "1abc2defghijklm3nopqrs4tu" ], 
    32    "availabilityZone" : "us-east-1d",
    33    "privateIp" : "10.158.112.84",
    34    "version" : "2010-08-31",
    35    "region" : "us-east-1",
    36    "instanceId" : "i-1234567890abcdef0",
    37    "billingProducts" : null,
    38    "instanceType" : "t1.micro",
    39    "accountId" : "123456789012",
    40    "pendingTime" : "2015-11-19T16:32:11Z",
    41    "imageId" : "ami-5fb8c835",
    42    "kernelId" : "aki-919dcaf8",
    43    "ramdiskId" : null,
    44    "architecture" : "x86_64"
    45  }`
    46  
    47  const validIamInfo = `{
    48    "Code" : "Success",
    49    "LastUpdated" : "2016-03-17T12:27:32Z",
    50    "InstanceProfileArn" : "arn:aws:iam::123456789012:instance-profile/my-instance-profile",
    51    "InstanceProfileId" : "AIPAABCDEFGHIJKLMN123"
    52  }`
    53  
    54  const unsuccessfulIamInfo = `{
    55    "Code" : "Failed",
    56    "LastUpdated" : "2016-03-17T12:27:32Z",
    57    "InstanceProfileArn" : "arn:aws:iam::123456789012:instance-profile/my-instance-profile",
    58    "InstanceProfileId" : "AIPAABCDEFGHIJKLMN123"
    59  }`
    60  
    61  const (
    62  	ttlHeader   = "x-aws-ec2-metadata-token-ttl-seconds"
    63  	tokenHeader = "x-aws-ec2-metadata-token"
    64  )
    65  
    66  type testType int
    67  
    68  const (
    69  	SecureTestType testType = iota
    70  	InsecureTestType
    71  	BadRequestTestType
    72  	NotFoundRequestTestType
    73  	InvalidTokenRequestTestType
    74  	ServerErrorForTokenTestType
    75  	pageNotFoundForTokenTestType
    76  	pageNotFoundWith401TestType
    77  )
    78  
    79  type testServer struct {
    80  	t *testing.T
    81  
    82  	tokens      []string
    83  	activeToken atomic.Value
    84  	data        string
    85  }
    86  
    87  type operationListProvider struct {
    88  	operationsPerformed []string
    89  }
    90  
    91  func getTokenRequiredParams(t *testing.T, fn http.HandlerFunc) http.HandlerFunc {
    92  	return func(w http.ResponseWriter, r *http.Request) {
    93  		if e, a := "PUT", r.Method; e != a {
    94  			t.Errorf("expect %v, http method got %v", e, a)
    95  			http.Error(w, "wrong method", 400)
    96  			return
    97  		}
    98  		if len(r.Header.Get(ttlHeader)) == 0 {
    99  			t.Errorf("expect ttl header to be present in the request headers, got none")
   100  			http.Error(w, "wrong method", 400)
   101  			return
   102  		}
   103  
   104  		fn(w, r)
   105  	}
   106  }
   107  
   108  func newTestServer(t *testing.T, testType testType, testServer *testServer) *httptest.Server {
   109  	mux := http.NewServeMux()
   110  	switch testType {
   111  	case SecureTestType:
   112  		mux.HandleFunc("/latest/api/token", getTokenRequiredParams(t, testServer.secureGetTokenHandler))
   113  		mux.HandleFunc("/", testServer.secureGetLatestHandler)
   114  	case InsecureTestType:
   115  		mux.HandleFunc("/latest/api/token", testServer.insecureGetTokenHandler)
   116  		mux.HandleFunc("/", testServer.insecureGetLatestHandler)
   117  	case BadRequestTestType:
   118  		mux.HandleFunc("/latest/api/token", getTokenRequiredParams(t, testServer.badRequestGetTokenHandler))
   119  		mux.HandleFunc("/", testServer.badRequestGetLatestHandler)
   120  	case NotFoundRequestTestType:
   121  		mux.HandleFunc("/latest/api/token", getTokenRequiredParams(t, testServer.secureGetTokenHandler))
   122  		mux.HandleFunc("/", testServer.notFoundRequestGetLatestHandler)
   123  	case InvalidTokenRequestTestType:
   124  		mux.HandleFunc("/latest/api/token", getTokenRequiredParams(t, testServer.secureGetTokenHandler))
   125  		mux.HandleFunc("/", testServer.unauthorizedGetLatestHandler)
   126  	case ServerErrorForTokenTestType:
   127  		mux.HandleFunc("/latest/api/token", getTokenRequiredParams(t, testServer.serverErrorGetTokenHandler))
   128  		mux.HandleFunc("/", testServer.insecureGetLatestHandler)
   129  	case pageNotFoundForTokenTestType:
   130  		mux.HandleFunc("/latest/api/token", getTokenRequiredParams(t, testServer.pageNotFoundGetTokenHandler))
   131  		mux.HandleFunc("/", testServer.insecureGetLatestHandler)
   132  	case pageNotFoundWith401TestType:
   133  		mux.HandleFunc("/latest/api/token", getTokenRequiredParams(t, testServer.pageNotFoundGetTokenHandler))
   134  		mux.HandleFunc("/", testServer.unauthorizedGetLatestHandler)
   135  
   136  	}
   137  
   138  	return httptest.NewServer(mux)
   139  }
   140  
   141  func (s *testServer) secureGetTokenHandler(w http.ResponseWriter, r *http.Request) {
   142  	token := s.tokens[0]
   143  
   144  	// set the active token
   145  	s.activeToken.Store(token)
   146  
   147  	// rotate the token
   148  	if len(s.tokens) > 1 {
   149  		s.tokens = s.tokens[1:]
   150  	}
   151  
   152  	// set the header and response body
   153  	w.Header().Set(ttlHeader, r.Header.Get(ttlHeader))
   154  	if activeToken, ok := s.activeToken.Load().(string); ok {
   155  		w.Write([]byte(activeToken))
   156  	} else {
   157  		s.t.Fatalf("Expected activeToken to be of type string, got %v", activeToken)
   158  	}
   159  }
   160  
   161  func (s *testServer) secureGetLatestHandler(w http.ResponseWriter, r *http.Request) {
   162  	if s.activeToken.Load() == nil {
   163  		s.t.Errorf("expect token to have been requested, was not")
   164  		http.Error(w, "", 401)
   165  		return
   166  	}
   167  
   168  	if e, a := s.activeToken.Load(), r.Header.Get(tokenHeader); e != a {
   169  		s.t.Errorf("expect %v token, got %v", e, a)
   170  		http.Error(w, "", 401)
   171  		return
   172  	}
   173  
   174  	w.Header().Set(ttlHeader, r.Header.Get(ttlHeader))
   175  	w.Write([]byte(s.data))
   176  }
   177  
   178  func (s *testServer) insecureGetTokenHandler(w http.ResponseWriter, r *http.Request) {
   179  	http.Error(w, "", 404)
   180  }
   181  
   182  func (s *testServer) insecureGetLatestHandler(w http.ResponseWriter, r *http.Request) {
   183  	if len(r.Header.Get(tokenHeader)) != 0 {
   184  		s.t.Errorf("Request token found, expected none")
   185  		http.Error(w, "", 400)
   186  		return
   187  	}
   188  
   189  	w.Write([]byte(s.data))
   190  }
   191  
   192  func (s *testServer) badRequestGetTokenHandler(w http.ResponseWriter, r *http.Request) {
   193  	http.Error(w, "", 400)
   194  }
   195  
   196  func (s *testServer) badRequestGetLatestHandler(w http.ResponseWriter, r *http.Request) {
   197  	s.t.Errorf("Expected no call to this handler, incorrect behavior found")
   198  }
   199  
   200  func (s *testServer) notFoundRequestGetLatestHandler(w http.ResponseWriter, r *http.Request) {
   201  	http.Error(w, "not found error", 404)
   202  }
   203  
   204  func (s *testServer) serverErrorGetTokenHandler(w http.ResponseWriter, r *http.Request) {
   205  	http.Error(w, "", 403)
   206  }
   207  
   208  func (s *testServer) pageNotFoundGetTokenHandler(w http.ResponseWriter, r *http.Request) {
   209  	http.Error(w, "Page not found error", 404)
   210  }
   211  
   212  func (s *testServer) unauthorizedGetLatestHandler(w http.ResponseWriter, r *http.Request) {
   213  	http.Error(w, "", 401)
   214  }
   215  
   216  func (opListProvider *operationListProvider) addToOperationPerformedList(r *request.Request) {
   217  	opListProvider.operationsPerformed = append(opListProvider.operationsPerformed, r.Operation.Name)
   218  }
   219  
   220  func TestEndpoint(t *testing.T) {
   221  	restoreEnvFn := sdktesting.StashEnv()
   222  	defer restoreEnvFn()
   223  
   224  	c := ec2metadata.New(unit.Session)
   225  	op := &request.Operation{
   226  		Name:       "GetMetadata",
   227  		HTTPMethod: "GET",
   228  		HTTPPath:   path.Join("/latest", "meta-data", "testpath"),
   229  	}
   230  
   231  	req := c.NewRequest(op, nil, nil)
   232  	if e, a := "http://169.254.169.254/latest/meta-data/testpath", req.HTTPRequest.URL.String(); e != a {
   233  		t.Errorf("expect %v, got %v", e, a)
   234  	}
   235  }
   236  
   237  func TestGetMetadata(t *testing.T) {
   238  	cases := map[string]struct {
   239  		tokens                      []string
   240  		NewServer                   func(t *testing.T, tokens []string) *httptest.Server
   241  		expectedData                string
   242  		expectedError               string
   243  		expectedOperationsAttempted []string
   244  	}{
   245  		"Insecure server success case": {
   246  			NewServer: func(t *testing.T, tokens []string) *httptest.Server {
   247  				testType := InsecureTestType
   248  				Ts := &testServer{
   249  					t:      t,
   250  					tokens: tokens,
   251  					data:   "IMDSProfileForGoSDK",
   252  				}
   253  				return newTestServer(t, testType, Ts)
   254  			},
   255  			expectedData:                "IMDSProfileForGoSDK",
   256  			expectedOperationsAttempted: []string{"GetToken", "GetMetadata", "GetMetadata"},
   257  		},
   258  		"Secure server success case": {
   259  			tokens: []string{"firstToken", "secondToken", "thirdToken"},
   260  			NewServer: func(t *testing.T, tokens []string) *httptest.Server {
   261  				testType := SecureTestType
   262  				Ts := &testServer{
   263  					t:      t,
   264  					tokens: tokens,
   265  					data:   "IMDSProfileForGoSDK",
   266  				}
   267  				return newTestServer(t, testType, Ts)
   268  			},
   269  			expectedData:                "IMDSProfileForGoSDK",
   270  			expectedError:               "",
   271  			expectedOperationsAttempted: []string{"GetToken", "GetMetadata", "GetMetadata"},
   272  		},
   273  		"Bad token request case": {
   274  			tokens: []string{"firstToken", "secondToken", "thirdToken"},
   275  			NewServer: func(t *testing.T, tokens []string) *httptest.Server {
   276  				testType := BadRequestTestType
   277  				Ts := &testServer{
   278  					t:      t,
   279  					tokens: tokens,
   280  					data:   "IMDSProfileForGoSDK",
   281  				}
   282  				return newTestServer(t, testType, Ts)
   283  			},
   284  			expectedError:               "400",
   285  			expectedOperationsAttempted: []string{"GetToken", "GetToken"},
   286  		},
   287  		"Not found no retry request case": {
   288  			tokens: []string{"firstToken", "secondToken", "thirdToken"},
   289  			NewServer: func(t *testing.T, tokens []string) *httptest.Server {
   290  				testType := NotFoundRequestTestType
   291  				Ts := &testServer{
   292  					t:      t,
   293  					tokens: tokens,
   294  					data:   "IMDSProfileForGoSDK",
   295  				}
   296  				return newTestServer(t, testType, Ts)
   297  			},
   298  			expectedError:               "404",
   299  			expectedOperationsAttempted: []string{"GetToken", "GetMetadata", "GetMetadata"},
   300  		},
   301  		"invalid token request case": {
   302  			tokens: []string{"firstToken", "secondToken", "thirdToken"},
   303  			NewServer: func(t *testing.T, tokens []string) *httptest.Server {
   304  				testType := InvalidTokenRequestTestType
   305  				Ts := &testServer{
   306  					t:      t,
   307  					tokens: tokens,
   308  					data:   "IMDSProfileForGoSDK",
   309  				}
   310  				return newTestServer(t, testType, Ts)
   311  			},
   312  			expectedError:               "401",
   313  			expectedOperationsAttempted: []string{"GetToken", "GetMetadata", "GetToken", "GetMetadata"},
   314  		},
   315  		"ServerErrorForTokenTestType": {
   316  			NewServer: func(t *testing.T, tokens []string) *httptest.Server {
   317  				testType := ServerErrorForTokenTestType
   318  				Ts := &testServer{
   319  					t:      t,
   320  					tokens: []string{},
   321  					data:   "IMDSProfileForGoSDK",
   322  				}
   323  				return newTestServer(t, testType, Ts)
   324  			},
   325  			expectedData:                "IMDSProfileForGoSDK",
   326  			expectedOperationsAttempted: []string{"GetToken", "GetMetadata", "GetMetadata"},
   327  		},
   328  	}
   329  
   330  	for name, x := range cases {
   331  		t.Run(name, func(t *testing.T) {
   332  
   333  			server := x.NewServer(t, x.tokens)
   334  			defer server.Close()
   335  
   336  			op := &operationListProvider{}
   337  
   338  			c := ec2metadata.New(unit.Session, &aws.Config{
   339  				Endpoint: aws.String(server.URL),
   340  			})
   341  			c.Handlers.CompleteAttempt.PushBack(op.addToOperationPerformedList)
   342  
   343  			tokenCounter := -1
   344  			c.Handlers.Send.PushBack(func(r *request.Request) {
   345  				switch r.Operation.Name {
   346  				case "GetToken":
   347  					tokenCounter++
   348  
   349  				case "GetMetadata":
   350  					curToken := r.HTTPRequest.Header.Get("x-aws-ec2-metadata-token")
   351  					if len(curToken) != 0 && curToken != x.tokens[tokenCounter] {
   352  						t.Errorf("expect %v token, got %v", x.tokens[tokenCounter], curToken)
   353  					}
   354  				}
   355  			})
   356  
   357  			resp, err := c.GetMetadata("some/path")
   358  
   359  			// token should stay alive, since default duration is 26000 seconds
   360  			resp, err = c.GetMetadata("some/path")
   361  
   362  			if len(x.expectedError) != 0 {
   363  				if err == nil {
   364  					t.Fatalf("expect %v error, got none", x.expectedError)
   365  				}
   366  				if e, a := x.expectedError, err.Error(); !strings.Contains(a, e) {
   367  					t.Fatalf("expect %v error, got %v", e, a)
   368  				}
   369  			} else if err != nil {
   370  				t.Fatalf("expect no error, got %v", err)
   371  			}
   372  
   373  			if e, a := x.expectedData, resp; e != a {
   374  				t.Fatalf("expect %v, got %v", e, a)
   375  			}
   376  
   377  			if e, a := x.expectedOperationsAttempted, op.operationsPerformed; !reflect.DeepEqual(e, a) {
   378  				t.Errorf("expect %v operations, got %v", e, a)
   379  			}
   380  
   381  		})
   382  	}
   383  }
   384  
   385  func TestGetUserData_Error(t *testing.T) {
   386  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   387  		reader := strings.NewReader(`<?xml version="1.0" encoding="iso-8859-1"?>
   388  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   389           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   390  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
   391   <head>
   392    <title>404 - Not Found</title>
   393   </head>
   394   <body>
   395    <h1>404 - Not Found</h1>
   396   </body>
   397  </html>`)
   398  		w.Header().Set("Content-Type", "text/html")
   399  		w.Header().Set("Content-Length", fmt.Sprintf("%d", reader.Len()))
   400  		w.WriteHeader(http.StatusNotFound)
   401  		io.Copy(w, reader)
   402  	}))
   403  
   404  	defer server.Close()
   405  	c := ec2metadata.New(unit.Session, &aws.Config{
   406  		Endpoint: aws.String(server.URL),
   407  	})
   408  
   409  	resp, err := c.GetUserData()
   410  	if err == nil {
   411  		t.Fatalf("expect error")
   412  	}
   413  	if len(resp) != 0 {
   414  		t.Fatalf("expect empty, got %v", resp)
   415  	}
   416  
   417  	if requestFailedError, ok := err.(awserr.RequestFailure); ok {
   418  		if e, a := http.StatusNotFound, requestFailedError.StatusCode(); e != a {
   419  			t.Fatalf("expect %v, got %v", e, a)
   420  		}
   421  	}
   422  }
   423  
   424  func TestGetRegion(t *testing.T) {
   425  	cases := map[string]struct {
   426  		NewServer                   func(t *testing.T) *httptest.Server
   427  		expectedData                string
   428  		expectedError               string
   429  		expectedOperationsPerformed []string
   430  	}{
   431  		"Insecure server success case": {
   432  			NewServer: func(t *testing.T) *httptest.Server {
   433  				testType := InsecureTestType
   434  				Ts := &testServer{
   435  					t:    t,
   436  					data: instanceIdentityDocument,
   437  				}
   438  				return newTestServer(t, testType, Ts)
   439  			},
   440  			expectedData:                "us-east-1",
   441  			expectedOperationsPerformed: []string{"GetToken", "GetDynamicData"},
   442  		},
   443  		"Secure server success case": {
   444  			NewServer: func(t *testing.T) *httptest.Server {
   445  				testType := SecureTestType
   446  				Ts := &testServer{
   447  					t:      t,
   448  					tokens: []string{"firstToken", "secondToken", "thirdToken"},
   449  					data:   instanceIdentityDocument,
   450  				}
   451  				return newTestServer(t, testType, Ts)
   452  			},
   453  			expectedData:                "us-east-1",
   454  			expectedOperationsPerformed: []string{"GetToken", "GetDynamicData"},
   455  		},
   456  		"Bad request case": {
   457  			NewServer: func(t *testing.T) *httptest.Server {
   458  				testType := BadRequestTestType
   459  				Ts := &testServer{
   460  					t:      t,
   461  					tokens: []string{"firstToken", "secondToken", "thirdToken"},
   462  					data:   instanceIdentityDocument,
   463  				}
   464  				return newTestServer(t, testType, Ts)
   465  			},
   466  			expectedError:               "400",
   467  			expectedOperationsPerformed: []string{"GetToken", "GetDynamicData"},
   468  		},
   469  		"ServerErrorForTokenTestType": {
   470  			NewServer: func(t *testing.T) *httptest.Server {
   471  				testType := ServerErrorForTokenTestType
   472  				Ts := &testServer{
   473  					t:      t,
   474  					tokens: []string{},
   475  					data:   instanceIdentityDocument,
   476  				}
   477  				return newTestServer(t, testType, Ts)
   478  			},
   479  			expectedData:                "us-east-1",
   480  			expectedOperationsPerformed: []string{"GetToken", "GetDynamicData"},
   481  		},
   482  	}
   483  
   484  	for name, x := range cases {
   485  		t.Run(name, func(t *testing.T) {
   486  
   487  			server := x.NewServer(t)
   488  			defer server.Close()
   489  
   490  			op := &operationListProvider{}
   491  
   492  			c := ec2metadata.New(unit.Session, &aws.Config{
   493  				Endpoint: aws.String(server.URL),
   494  			})
   495  			c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
   496  
   497  			resp, err := c.Region()
   498  
   499  			if len(x.expectedError) != 0 {
   500  				if err == nil {
   501  					t.Fatalf("expect %v error, got none", x.expectedError)
   502  				}
   503  				if e, a := x.expectedError, err.Error(); !strings.Contains(a, e) {
   504  					t.Fatalf("expect %v error, got %v", e, a)
   505  				}
   506  			} else if err != nil {
   507  				t.Fatalf("expect no error, got %v", err)
   508  			}
   509  
   510  			if e, a := x.expectedData, resp; e != a {
   511  				t.Fatalf("expect %v, got %v", e, a)
   512  			}
   513  
   514  			if e, a := x.expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
   515  				t.Fatalf("expect %v operations, got %v", e, a)
   516  			}
   517  		})
   518  	}
   519  }
   520  
   521  func TestMetadataIAMInfo_success(t *testing.T) {
   522  	cases := map[string]struct {
   523  		NewServer                   func(t *testing.T) *httptest.Server
   524  		expectedData                string
   525  		expectedError               string
   526  		expectedOperationsPerformed []string
   527  	}{
   528  		"Insecure server success case": {
   529  			NewServer: func(t *testing.T) *httptest.Server {
   530  				testType := InsecureTestType
   531  				Ts := &testServer{
   532  					t:    t,
   533  					data: validIamInfo,
   534  				}
   535  				return newTestServer(t, testType, Ts)
   536  			},
   537  			expectedData:                validIamInfo,
   538  			expectedOperationsPerformed: []string{"GetToken", "GetMetadata"},
   539  		},
   540  		"Secure server success case": {
   541  			NewServer: func(t *testing.T) *httptest.Server {
   542  				testType := SecureTestType
   543  				Ts := &testServer{
   544  					t:      t,
   545  					tokens: []string{"firstToken", "secondToken", "thirdToken"},
   546  					data:   validIamInfo,
   547  				}
   548  				return newTestServer(t, testType, Ts)
   549  			},
   550  			expectedData:                validIamInfo,
   551  			expectedOperationsPerformed: []string{"GetToken", "GetMetadata"},
   552  		},
   553  	}
   554  
   555  	for name, x := range cases {
   556  		t.Run(name, func(t *testing.T) {
   557  
   558  			server := x.NewServer(t)
   559  			defer server.Close()
   560  
   561  			op := &operationListProvider{}
   562  
   563  			c := ec2metadata.New(unit.Session, &aws.Config{
   564  				Endpoint: aws.String(server.URL),
   565  			})
   566  			c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
   567  
   568  			iamInfo, err := c.IAMInfo()
   569  
   570  			if len(x.expectedError) != 0 {
   571  				if err == nil {
   572  					t.Fatalf("expect %v error, got none", x.expectedError)
   573  				}
   574  				if e, a := x.expectedError, err.Error(); !strings.Contains(a, e) {
   575  					t.Fatalf("expect %v error, got %v", e, a)
   576  				}
   577  			} else if err != nil {
   578  				t.Fatalf("expect no error, got %v", err)
   579  			}
   580  
   581  			if e, a := "Success", iamInfo.Code; e != a {
   582  				t.Fatalf("expect %v, got %v", e, a)
   583  			}
   584  			if e, a := "arn:aws:iam::123456789012:instance-profile/my-instance-profile", iamInfo.InstanceProfileArn; e != a {
   585  				t.Fatalf("expect %v, got %v", e, a)
   586  			}
   587  			if e, a := "AIPAABCDEFGHIJKLMN123", iamInfo.InstanceProfileID; e != a {
   588  				t.Fatalf("expect %v, got %v", e, a)
   589  			}
   590  
   591  			if e, a := x.expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
   592  				t.Fatalf("expect %v operations, got %v", e, a)
   593  			}
   594  		})
   595  	}
   596  }
   597  
   598  func TestMetadataIAMInfo_failure(t *testing.T) {
   599  	cases := map[string]struct {
   600  		NewServer                   func(t *testing.T) *httptest.Server
   601  		expectedData                string
   602  		expectedError               string
   603  		expectedOperationsPerformed []string
   604  	}{
   605  		"Insecure server success case": {
   606  			NewServer: func(t *testing.T) *httptest.Server {
   607  				testType := InsecureTestType
   608  				Ts := &testServer{
   609  					t:      t,
   610  					tokens: nil,
   611  					data:   unsuccessfulIamInfo,
   612  				}
   613  				return newTestServer(t, testType, Ts)
   614  			},
   615  			expectedData:                unsuccessfulIamInfo,
   616  			expectedOperationsPerformed: []string{"GetToken", "GetMetadata"},
   617  		},
   618  		"Secure server success case": {
   619  			NewServer: func(t *testing.T) *httptest.Server {
   620  				testType := SecureTestType
   621  				Ts := &testServer{
   622  					t:      t,
   623  					tokens: []string{"firstToken", "secondToken", "thirdToken"},
   624  					data:   unsuccessfulIamInfo,
   625  				}
   626  				return newTestServer(t, testType, Ts)
   627  			},
   628  			expectedData:                unsuccessfulIamInfo,
   629  			expectedOperationsPerformed: []string{"GetToken", "GetMetadata"},
   630  		},
   631  	}
   632  
   633  	for name, x := range cases {
   634  		t.Run(name, func(t *testing.T) {
   635  
   636  			server := x.NewServer(t)
   637  			defer server.Close()
   638  
   639  			op := &operationListProvider{}
   640  
   641  			c := ec2metadata.New(unit.Session, &aws.Config{
   642  				Endpoint: aws.String(server.URL),
   643  			})
   644  			c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
   645  
   646  			iamInfo, err := c.IAMInfo()
   647  			if err == nil {
   648  				t.Fatalf("expect error")
   649  			}
   650  			if e, a := "", iamInfo.Code; e != a {
   651  				t.Fatalf("expect %v, got %v", e, a)
   652  			}
   653  			if e, a := "", iamInfo.InstanceProfileArn; e != a {
   654  				t.Fatalf("expect %v, got %v", e, a)
   655  			}
   656  			if e, a := "", iamInfo.InstanceProfileID; e != a {
   657  				t.Fatalf("expect %v, got %v", e, a)
   658  			}
   659  			if e, a := x.expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
   660  				t.Fatalf("expect %v operations, got %v", e, a)
   661  			}
   662  		})
   663  	}
   664  }
   665  
   666  func TestMetadataNotAvailable(t *testing.T) {
   667  	c := ec2metadata.New(unit.Session)
   668  	c.Handlers.Send.Clear()
   669  	c.Handlers.Send.PushBack(func(r *request.Request) {
   670  		r.HTTPResponse = &http.Response{
   671  			StatusCode: int(0),
   672  			Status:     http.StatusText(int(0)),
   673  			Body:       ioutil.NopCloser(bytes.NewReader([]byte{})),
   674  		}
   675  		r.Error = awserr.New(request.ErrCodeRequestError, "send request failed", nil)
   676  		r.Retryable = aws.Bool(true) // network errors are retryable
   677  	})
   678  
   679  	if c.Available() {
   680  		t.Fatalf("expect not available")
   681  	}
   682  }
   683  
   684  func TestMetadataErrorResponse(t *testing.T) {
   685  	c := ec2metadata.New(unit.Session)
   686  	c.Handlers.Send.Clear()
   687  	c.Handlers.Send.PushBack(func(r *request.Request) {
   688  		r.HTTPResponse = &http.Response{
   689  			StatusCode: http.StatusBadRequest,
   690  			Status:     http.StatusText(http.StatusBadRequest),
   691  			Body:       ioutil.NopCloser(strings.NewReader("error message text")),
   692  		}
   693  		r.Retryable = aws.Bool(false) // network errors are retryable
   694  	})
   695  
   696  	data, err := c.GetMetadata("uri/path")
   697  	if e, a := "error message text", err.Error(); !strings.Contains(a, e) {
   698  		t.Fatalf("expect %v to be in %v", e, a)
   699  	}
   700  	if len(data) != 0 {
   701  		t.Fatalf("expect empty, got %v", data)
   702  	}
   703  
   704  }
   705  
   706  func TestEC2RoleProviderInstanceIdentity(t *testing.T) {
   707  	cases := map[string]struct {
   708  		NewServer                   func(t *testing.T) *httptest.Server
   709  		expectedData                string
   710  		expectedOperationsPerformed []string
   711  	}{
   712  		"Insecure server success case": {
   713  			NewServer: func(t *testing.T) *httptest.Server {
   714  				testType := InsecureTestType
   715  				Ts := &testServer{
   716  					t:      t,
   717  					tokens: nil,
   718  					data:   instanceIdentityDocument,
   719  				}
   720  				return newTestServer(t, testType, Ts)
   721  			},
   722  			expectedData:                instanceIdentityDocument,
   723  			expectedOperationsPerformed: []string{"GetToken", "GetDynamicData"},
   724  		},
   725  		"Secure server success case": {
   726  			NewServer: func(t *testing.T) *httptest.Server {
   727  				testType := SecureTestType
   728  				Ts := &testServer{
   729  					t:      t,
   730  					tokens: []string{"firstToken", "secondToken", "thirdToken"},
   731  					data:   instanceIdentityDocument,
   732  				}
   733  				return newTestServer(t, testType, Ts)
   734  			},
   735  			expectedData:                instanceIdentityDocument,
   736  			expectedOperationsPerformed: []string{"GetToken", "GetDynamicData"},
   737  		},
   738  	}
   739  
   740  	for name, x := range cases {
   741  		t.Run(name, func(t *testing.T) {
   742  
   743  			server := x.NewServer(t)
   744  			defer server.Close()
   745  
   746  			op := &operationListProvider{}
   747  
   748  			c := ec2metadata.New(unit.Session, &aws.Config{
   749  				Endpoint: aws.String(server.URL),
   750  			})
   751  			c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
   752  			doc, err := c.GetInstanceIdentityDocument()
   753  
   754  			if err != nil {
   755  				t.Fatalf("expected no error, got %v", err)
   756  			}
   757  
   758  			if e, a := doc.AccountID, "123456789012"; e != a {
   759  				t.Fatalf("expect %v, got %v", e, a)
   760  			}
   761  			if e, a := doc.AvailabilityZone, "us-east-1d"; e != a {
   762  				t.Fatalf("expect %v, got %v", e, a)
   763  			}
   764  			if e, a := doc.Region, "us-east-1"; e != a {
   765  				t.Fatalf("expect %v, got %v", e, a)
   766  			}
   767  			if e, a := x.expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
   768  				t.Fatalf("expect %v operations, got %v", e, a)
   769  			}
   770  		})
   771  	}
   772  }
   773  
   774  func TestEC2MetadataRetryFailure(t *testing.T) {
   775  	mux := http.NewServeMux()
   776  
   777  	mux.HandleFunc("/latest/api/token", func(w http.ResponseWriter, r *http.Request) {
   778  		if r.Method == "PUT" && r.Header.Get(ttlHeader) != "" {
   779  			w.Header().Set(ttlHeader, "200")
   780  			http.Error(w, "service unavailable", http.StatusServiceUnavailable)
   781  			return
   782  		}
   783  		http.Error(w, "bad request", http.StatusBadRequest)
   784  	})
   785  
   786  	// meta-data endpoint for this test, just returns the token
   787  	mux.HandleFunc("/latest/meta-data/", func(w http.ResponseWriter, r *http.Request) {
   788  		w.Write([]byte("profile_name"))
   789  	})
   790  
   791  	server := httptest.NewServer(mux)
   792  	defer server.Close()
   793  
   794  	c := ec2metadata.New(unit.Session, &aws.Config{
   795  		Endpoint: aws.String(server.URL),
   796  	})
   797  
   798  	c.Handlers.AfterRetry.PushBack(func(i *request.Request) {
   799  		t.Logf("%v received, retrying operation %v", i.HTTPResponse.StatusCode, i.Operation.Name)
   800  	})
   801  	c.Handlers.Complete.PushBack(func(i *request.Request) {
   802  		t.Logf("%v operation exited with status %v", i.Operation.Name, i.HTTPResponse.StatusCode)
   803  	})
   804  
   805  	resp, err := c.GetMetadata("some/path")
   806  	if err != nil {
   807  		t.Fatalf("Expected none, got error %v", err)
   808  	}
   809  	if resp != "profile_name" {
   810  		t.Fatalf("Expected response to be profile_name, got %v", resp)
   811  	}
   812  
   813  	resp, err = c.GetMetadata("some/path")
   814  	if err != nil {
   815  		t.Fatalf("Expected none, got error %v", err)
   816  	}
   817  	if resp != "profile_name" {
   818  		t.Fatalf("Expected response to be profile_name, got %v", resp)
   819  	}
   820  }
   821  
   822  func TestEC2MetadataRetryOnce(t *testing.T) {
   823  	var secureDataFlow bool
   824  	var retry = true
   825  	mux := http.NewServeMux()
   826  
   827  	mux.HandleFunc("/latest/api/token", func(w http.ResponseWriter, r *http.Request) {
   828  		if r.Method == "PUT" && r.Header.Get(ttlHeader) != "" {
   829  			w.Header().Set(ttlHeader, "200")
   830  			for retry {
   831  				retry = false
   832  				http.Error(w, "service unavailable", http.StatusServiceUnavailable)
   833  				return
   834  			}
   835  			w.Write([]byte("token"))
   836  			secureDataFlow = true
   837  			return
   838  		}
   839  		http.Error(w, "bad request", http.StatusBadRequest)
   840  	})
   841  
   842  	// meta-data endpoint for this test, just returns the token
   843  	mux.HandleFunc("/latest/meta-data/", func(w http.ResponseWriter, r *http.Request) {
   844  		w.Write([]byte(r.Header.Get(tokenHeader)))
   845  	})
   846  
   847  	var tokenRetryCount int
   848  
   849  	server := httptest.NewServer(mux)
   850  	defer server.Close()
   851  	c := ec2metadata.New(unit.Session, &aws.Config{
   852  		Endpoint: aws.String(server.URL),
   853  	})
   854  
   855  	// Handler on client that logs if retried
   856  	c.Handlers.AfterRetry.PushBack(func(i *request.Request) {
   857  		t.Logf("%v received, retrying operation %v", i.HTTPResponse.StatusCode, i.Operation.Name)
   858  		tokenRetryCount++
   859  	})
   860  
   861  	_, err := c.GetMetadata("some/path")
   862  
   863  	if tokenRetryCount != 1 {
   864  		t.Fatalf("Expected number of retries for fetching token to be 1, got %v", tokenRetryCount)
   865  	}
   866  
   867  	if !secureDataFlow {
   868  		t.Fatalf("Expected secure data flow to be %v, got %v", secureDataFlow, !secureDataFlow)
   869  	}
   870  
   871  	if err != nil {
   872  		t.Fatalf("Expected none, got error %v", err)
   873  	}
   874  }
   875  
   876  func TestEC2Metadata_Concurrency(t *testing.T) {
   877  	ts := &testServer{
   878  		t:      t,
   879  		tokens: []string{"firstToken"},
   880  		data:   "IMDSProfileForSDKGo",
   881  	}
   882  
   883  	server := newTestServer(t, SecureTestType, ts)
   884  	defer server.Close()
   885  
   886  	c := ec2metadata.New(unit.Session, &aws.Config{
   887  		Endpoint: aws.String(server.URL),
   888  	})
   889  
   890  	var wg sync.WaitGroup
   891  	wg.Add(10)
   892  	for i := 0; i < 10; i++ {
   893  		go func() {
   894  			defer wg.Done()
   895  			for j := 0; j < 10; j++ {
   896  				resp, err := c.GetMetadata("some/data")
   897  				if err != nil {
   898  					t.Errorf("expect no error, got %v", err)
   899  				}
   900  
   901  				if e, a := "IMDSProfileForSDKGo", resp; e != a {
   902  					t.Errorf("expect %v, got %v", e, a)
   903  				}
   904  			}
   905  		}()
   906  	}
   907  	wg.Wait()
   908  }
   909  
   910  func TestRequestOnMetadata(t *testing.T) {
   911  	ts := &testServer{
   912  		t:      t,
   913  		tokens: []string{"firstToken", "secondToken"},
   914  		data:   "profile_name",
   915  	}
   916  	server := newTestServer(t, SecureTestType, ts)
   917  	defer server.Close()
   918  
   919  	c := ec2metadata.New(unit.Session, &aws.Config{
   920  		Endpoint: aws.String(server.URL),
   921  	})
   922  	req := c.NewRequest(&request.Operation{
   923  		Name:            "Ec2Metadata request",
   924  		HTTPMethod:      "GET",
   925  		HTTPPath:        "/latest/foo",
   926  		Paginator:       nil,
   927  		BeforePresignFn: nil,
   928  	}, nil, nil)
   929  
   930  	op := &operationListProvider{}
   931  	c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
   932  	err := req.Send()
   933  
   934  	if err != nil {
   935  		t.Fatalf("expect no error, got %v", err)
   936  	}
   937  
   938  	if len(op.operationsPerformed) < 1 {
   939  		t.Fatalf("Expected atleast one operation GetToken to be called on EC2Metadata client")
   940  		return
   941  	}
   942  
   943  	if op.operationsPerformed[0] != "GetToken" {
   944  		t.Fatalf("Expected GetToken operation to be called")
   945  	}
   946  
   947  }
   948  
   949  func TestExhaustiveRetryToFetchToken(t *testing.T) {
   950  	ts := &testServer{
   951  		t:      t,
   952  		tokens: []string{"firstToken", "secondToken"},
   953  		data:   "IMDSProfileForSDKGo",
   954  	}
   955  
   956  	server := newTestServer(t, pageNotFoundForTokenTestType, ts)
   957  	defer server.Close()
   958  
   959  	op := &operationListProvider{}
   960  
   961  	c := ec2metadata.New(unit.Session, &aws.Config{
   962  		Endpoint: aws.String(server.URL),
   963  	})
   964  	c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
   965  
   966  	resp, err := c.GetMetadata("/some/path")
   967  	if err != nil {
   968  		t.Fatalf("Expected no error, got %v", err)
   969  	}
   970  	if e, a := "IMDSProfileForSDKGo", resp; e != a {
   971  		t.Fatalf("Expected %v, got %v", e, a)
   972  	}
   973  
   974  	resp, err = c.GetMetadata("/some/path")
   975  	if err != nil {
   976  		t.Fatalf("Expected no error, got %v", err)
   977  	}
   978  	if e, a := "IMDSProfileForSDKGo", resp; e != a {
   979  		t.Fatalf("Expected %v, got %v", e, a)
   980  	}
   981  
   982  	resp, err = c.GetMetadata("/some/path")
   983  	if err != nil {
   984  		t.Fatalf("Expected no error, got %v", err)
   985  	}
   986  	if e, a := "IMDSProfileForSDKGo", resp; e != a {
   987  		t.Fatalf("Expected %v, got %v", e, a)
   988  	}
   989  
   990  	resp, err = c.GetMetadata("/some/path")
   991  	expectedOperationsPerformed := []string{"GetToken", "GetMetadata", "GetMetadata", "GetMetadata", "GetMetadata"}
   992  	if err != nil {
   993  		t.Fatalf("Expected no error, got %v", err)
   994  	}
   995  	if e, a := "IMDSProfileForSDKGo", resp; e != a {
   996  		t.Fatalf("Expected %v, got %v", e, a)
   997  	}
   998  	if e, a := expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
   999  		t.Fatalf("expect %v operations, got %v", e, a)
  1000  	}
  1001  }
  1002  
  1003  func TestExhaustiveRetryWith401(t *testing.T) {
  1004  	ts := &testServer{
  1005  		t:      t,
  1006  		tokens: []string{"firstToken", "secondToken"},
  1007  		data:   "IMDSProfileForSDKGo",
  1008  	}
  1009  
  1010  	server := newTestServer(t, pageNotFoundWith401TestType, ts)
  1011  	defer server.Close()
  1012  
  1013  	op := &operationListProvider{}
  1014  
  1015  	c := ec2metadata.New(unit.Session, &aws.Config{
  1016  		Endpoint: aws.String(server.URL),
  1017  	})
  1018  	c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
  1019  
  1020  	resp, err := c.GetMetadata("/some/path")
  1021  	if err == nil {
  1022  		t.Fatalf("Expected %v error, got none", err)
  1023  	}
  1024  	if e, a := "", resp; e != a {
  1025  		t.Fatalf("Expected %v, got %v", e, a)
  1026  	}
  1027  	resp, err = c.GetMetadata("/some/path")
  1028  	if err == nil {
  1029  		t.Fatalf("Expected %v error, got none", err)
  1030  	}
  1031  	if e, a := "", resp; e != a {
  1032  		t.Fatalf("Expected %v, got %v", e, a)
  1033  	}
  1034  	resp, err = c.GetMetadata("/some/path")
  1035  	if err == nil {
  1036  		t.Fatalf("Expected %v error, got none", err)
  1037  	}
  1038  	if e, a := "", resp; e != a {
  1039  		t.Fatalf("Expected %v, got %v", e, a)
  1040  	}
  1041  	resp, err = c.GetMetadata("/some/path")
  1042  
  1043  	expectedOperationsPerformed := []string{"GetToken", "GetMetadata", "GetToken", "GetMetadata", "GetToken", "GetMetadata", "GetToken", "GetMetadata"}
  1044  
  1045  	if err == nil {
  1046  		t.Fatalf("Expected %v error, got none", err)
  1047  	}
  1048  	if e, a := "", resp; e != a {
  1049  		t.Fatalf("Expected %v, got %v", e, a)
  1050  	}
  1051  	if e, a := expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
  1052  		t.Fatalf("expect %v operations, got %v", e, a)
  1053  	}
  1054  }
  1055  
  1056  func TestRequestTimeOut(t *testing.T) {
  1057  	mux := http.NewServeMux()
  1058  	done := make(chan bool)
  1059  	mux.HandleFunc("/latest/api/token", func(w http.ResponseWriter, r *http.Request) {
  1060  		// wait to read from channel done
  1061  		<-done
  1062  	})
  1063  
  1064  	mux.HandleFunc("/latest/", func(w http.ResponseWriter, r *http.Request) {
  1065  		if len(r.Header.Get(tokenHeader)) != 0 {
  1066  			http.Error(w, "", 400)
  1067  			return
  1068  		}
  1069  		w.Write([]byte("IMDSProfileForSDKGo"))
  1070  	})
  1071  
  1072  	server := httptest.NewServer(mux)
  1073  	defer server.Close()
  1074  	defer close(done)
  1075  
  1076  	op := &operationListProvider{}
  1077  
  1078  	c := ec2metadata.New(unit.Session, &aws.Config{
  1079  		Endpoint: aws.String(server.URL),
  1080  	})
  1081  	// for test, change the timeout to 100 ms
  1082  	c.Config.HTTPClient.Timeout = 100 * time.Millisecond
  1083  
  1084  	c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
  1085  
  1086  	start := time.Now()
  1087  	resp, err := c.GetMetadata("/some/path")
  1088  
  1089  	if e, a := 1*time.Second, time.Since(start); e < a {
  1090  		t.Fatalf("expected duration of test to be less than %v, got %v", e, a)
  1091  	}
  1092  
  1093  	if e, a := "IMDSProfileForSDKGo", resp; e != a {
  1094  		t.Fatalf("Expected %v, got %v", e, a)
  1095  	}
  1096  
  1097  	if err != nil {
  1098  		t.Fatalf("Expected no error, got %v", err)
  1099  	}
  1100  
  1101  	expectedOperationsPerformed := []string{"GetToken", "GetMetadata"}
  1102  	if e, a := expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
  1103  		t.Fatalf("expect %v operations, got %v", e, a)
  1104  	}
  1105  
  1106  	start = time.Now()
  1107  	resp, err = c.GetMetadata("/some/path")
  1108  	if e, a := 1*time.Second, time.Since(start); e < a {
  1109  		t.Fatalf("expected duration of test to be less than %v, got %v", e, a)
  1110  	}
  1111  
  1112  	if e, a := "IMDSProfileForSDKGo", resp; e != a {
  1113  		t.Fatalf("Expected %v, got %v", e, a)
  1114  	}
  1115  
  1116  	if err != nil {
  1117  		t.Fatalf("Expected no error, got %v", err)
  1118  	}
  1119  
  1120  	expectedOperationsPerformed = []string{"GetToken", "GetMetadata", "GetMetadata"}
  1121  	if e, a := expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
  1122  		t.Fatalf("expect %v operations, got %v", e, a)
  1123  	}
  1124  }
  1125  
  1126  func TestTokenExpiredBehavior(t *testing.T) {
  1127  	tokens := []string{"firstToken", "secondToken", "thirdToken"}
  1128  	var activeToken string
  1129  	mux := http.NewServeMux()
  1130  
  1131  	mux.HandleFunc("/latest/api/token", func(w http.ResponseWriter, r *http.Request) {
  1132  		if r.Method == "PUT" && r.Header.Get(ttlHeader) != "" {
  1133  			// set ttl to 0, so TTL is expired.
  1134  			w.Header().Set(ttlHeader, "0")
  1135  			activeToken = tokens[0]
  1136  			if len(tokens) > 1 {
  1137  				tokens = tokens[1:]
  1138  			}
  1139  
  1140  			w.Write([]byte(activeToken))
  1141  			return
  1142  		}
  1143  		http.Error(w, "bad request", http.StatusBadRequest)
  1144  	})
  1145  
  1146  	// meta-data endpoint for this test, just returns the token
  1147  	mux.HandleFunc("/latest/meta-data/", func(w http.ResponseWriter, r *http.Request) {
  1148  		w.Header().Set(ttlHeader, r.Header.Get(ttlHeader))
  1149  		w.Write([]byte(r.Header.Get(tokenHeader)))
  1150  	})
  1151  
  1152  	server := httptest.NewServer(mux)
  1153  	defer server.Close()
  1154  
  1155  	op := &operationListProvider{}
  1156  
  1157  	c := ec2metadata.New(unit.Session, &aws.Config{
  1158  		Endpoint: aws.String(server.URL),
  1159  	})
  1160  	c.Handlers.Complete.PushBack(op.addToOperationPerformedList)
  1161  
  1162  	resp, err := c.GetMetadata("/some/path")
  1163  	if err != nil {
  1164  		t.Fatalf("Expected no error, got %v", err)
  1165  	}
  1166  	if e, a := activeToken, resp; e != a {
  1167  		t.Fatalf("Expected %v, got %v", e, a)
  1168  	}
  1169  
  1170  	// store the token received before
  1171  	var firstToken = activeToken
  1172  
  1173  	resp, err = c.GetMetadata("/some/path")
  1174  	if err != nil {
  1175  		t.Fatalf("Expected no error, got %v", err)
  1176  	}
  1177  	if e, a := activeToken, resp; e != a {
  1178  		t.Fatalf("Expected %v, got %v", e, a)
  1179  	}
  1180  
  1181  	// Since TTL is 0, we should have received a new token
  1182  	if firstToken == activeToken {
  1183  		t.Fatalf("Expected token should have expired, and not the same")
  1184  	}
  1185  
  1186  	expectedOperationsPerformed := []string{"GetToken", "GetMetadata", "GetToken", "GetMetadata"}
  1187  
  1188  	if e, a := expectedOperationsPerformed, op.operationsPerformed; !reflect.DeepEqual(e, a) {
  1189  		t.Fatalf("expect %v operations, got %v", e, a)
  1190  	}
  1191  }