github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/cloud/ec2util/ec2util_test.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache-2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package ec2util_test
     6  
     7  import (
     8  	"reflect"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/aws/aws-sdk-go/aws"
    14  	"github.com/aws/aws-sdk-go/service/ec2"
    15  	"github.com/Schaudge/grailbase/cloud/ec2util"
    16  )
    17  
    18  func TestGetInstance(t *testing.T) {
    19  	cases := []struct {
    20  		output *ec2.DescribeInstancesOutput
    21  
    22  		arn       string
    23  		errPrefix string
    24  	}{
    25  		{&ec2.DescribeInstancesOutput{}, "", "unexpected number of Reservations"},
    26  		{&ec2.DescribeInstancesOutput{
    27  			Reservations: []*ec2.Reservation{
    28  				&ec2.Reservation{},
    29  			},
    30  		}, "", "unexpected number of Instances"},
    31  		{&ec2.DescribeInstancesOutput{
    32  			Reservations: []*ec2.Reservation{
    33  				&ec2.Reservation{},
    34  				&ec2.Reservation{},
    35  			},
    36  		}, "", "unexpected number of Reservations"},
    37  		{&ec2.DescribeInstancesOutput{
    38  			Reservations: []*ec2.Reservation{
    39  				&ec2.Reservation{
    40  					Instances: []*ec2.Instance{
    41  						&ec2.Instance{},
    42  						&ec2.Instance{},
    43  					},
    44  				},
    45  			},
    46  		}, "", "unexpected number of Instances"},
    47  		{&ec2.DescribeInstancesOutput{
    48  			Reservations: []*ec2.Reservation{
    49  				&ec2.Reservation{
    50  					Instances: []*ec2.Instance{
    51  						&ec2.Instance{},
    52  					},
    53  				},
    54  			},
    55  		}, "", "non-nil IamInstanceProfile"},
    56  	}
    57  
    58  	for _, c := range cases {
    59  		_, err := ec2util.GetInstance(c.output)
    60  		if err != nil && (c.errPrefix == "" || !strings.HasPrefix(err.Error(), c.errPrefix)) {
    61  			t.Errorf("GetInstance: got %q, want %q", err, c.errPrefix)
    62  		}
    63  	}
    64  }
    65  
    66  func TestGetARN(t *testing.T) {
    67  	cases := []struct {
    68  		output *ec2.Instance
    69  
    70  		arn       string
    71  		errPrefix string
    72  	}{
    73  		{
    74  			&ec2.Instance{
    75  				IamInstanceProfile: &ec2.IamInstanceProfile{},
    76  			}, "", "non-nil Arn"},
    77  		{newInstancesOutput("", "", ""), "", "non-empty Arn"},
    78  		{newInstancesOutput("", "dummy", ""), "dummy", ""},
    79  	}
    80  
    81  	for _, c := range cases {
    82  		arn, err := ec2util.GetIamInstanceProfileARN(c.output)
    83  		if err != nil && (c.errPrefix == "" || !strings.HasPrefix(err.Error(), c.errPrefix)) {
    84  			t.Errorf("GetIamInstanceProfileARN: got %q, want %q", err, c.errPrefix)
    85  		}
    86  		if arn != c.arn {
    87  			t.Errorf("GetIamInstanceProfileARN: got %q, want %q", arn, c.arn)
    88  		}
    89  	}
    90  }
    91  
    92  func TestGetInstanceId(t *testing.T) {
    93  	cases := []struct {
    94  		output *ec2.Instance
    95  
    96  		instanceId string
    97  		errPrefix  string
    98  	}{
    99  		{nil, "", "non-nil"},
   100  		{newInstancesOutput("i-1234", "", ""),
   101  			"i-1234", ""},
   102  	}
   103  
   104  	for _, c := range cases {
   105  		instanceId, err := ec2util.GetInstanceId(c.output)
   106  		if err != nil && (c.errPrefix == "" || !strings.HasPrefix(err.Error(), c.errPrefix)) {
   107  			t.Errorf("GetInstanceId: got %q, want %q", err, c.errPrefix)
   108  		}
   109  		if instanceId != c.instanceId {
   110  			t.Errorf("GetInstanceId: got %q, want %q", instanceId, c.instanceId)
   111  		}
   112  	}
   113  }
   114  
   115  func TestGetPublicIPAddress(t *testing.T) {
   116  	cases := []struct {
   117  		output *ec2.Instance
   118  
   119  		publicIp  string
   120  		errPrefix string
   121  	}{
   122  		{nil, "", "non-nil"},
   123  		{newInstancesOutput("", "", "192.168.1.1"),
   124  			"192.168.1.1", ""},
   125  	}
   126  
   127  	for _, c := range cases {
   128  		publicIp, err := ec2util.GetPublicIPAddress(c.output)
   129  		if err != nil && (c.errPrefix == "" || !strings.HasPrefix(err.Error(), c.errPrefix)) {
   130  			t.Errorf("GetPublicIPAddress: got %q, want %q", err, c.errPrefix)
   131  		}
   132  		if publicIp != c.publicIp {
   133  			t.Errorf("GetPublicIPAddress: got %q, want %q", publicIp, c.publicIp)
   134  		}
   135  	}
   136  }
   137  
   138  // TODO(aeiser) Implement test checking for tags
   139  func TestGetTags(t *testing.T) {
   140  	cases := []struct {
   141  		output *ec2.Instance
   142  
   143  		tags      string
   144  		errPrefix string
   145  	}{
   146  		{nil, "", "non-nil"},
   147  		{&ec2.Instance{
   148  			IamInstanceProfile: &ec2.IamInstanceProfile{},
   149  		}, "", "non-nil Arn"},
   150  	}
   151  
   152  	for _, c := range cases {
   153  		_, err := ec2util.GetTags(c.output)
   154  		if err != nil && (c.errPrefix == "" || !strings.HasPrefix(err.Error(), c.errPrefix)) {
   155  			t.Errorf("GetTags: got %q, want %q", err, c.errPrefix)
   156  		}
   157  		//		if tags != c.tags {
   158  		//			t.Errorf("GetTags: got %q, want %q", tags, c.tags)
   159  		//		}
   160  	}
   161  }
   162  
   163  func TestValidateInstance(t *testing.T) {
   164  	cases := []struct {
   165  		describeInstances *ec2.DescribeInstancesOutput
   166  		doc               ec2util.IdentityDocument
   167  		remoteAddr        string
   168  
   169  		role      string
   170  		errPrefix string
   171  	}{
   172  		{newDescribeInstancesOutput("dummy", "x.x.x.x"), ec2util.IdentityDocument{}, "34.215.119.108:1111", "", "mismatch"},
   173  		{newDescribeInstancesOutput("dummy", "34.215.119.108"), ec2util.IdentityDocument{}, "34.215.119.108:", "", "unexpected ARN"},
   174  		{
   175  			newDescribeInstancesOutput("arn:aws:iam::123456789012:instance-profile/dummyRole", "34.215.119.108"),
   176  			ec2util.IdentityDocument{AccountID: "xx"},
   177  			"34.215.119.108:",
   178  			"",
   179  			"mismatch between account ID",
   180  		},
   181  		{
   182  			newDescribeInstancesOutput("arn:aws:iam::123456789012:instance-profile/dummyRole", "34.215.119.108"),
   183  			ec2util.IdentityDocument{AccountID: "123456789012"},
   184  			"34.215.119.108:",
   185  			"dummyRole",
   186  			"",
   187  		},
   188  		//Instance that does not have a public IP
   189  		{
   190  			newDescribeInstancesOutput("arn:aws:iam::987654321012:instance-profile/dummyRole", ""),
   191  			ec2util.IdentityDocument{AccountID: "987654321012"},
   192  			"52.215.119.108:",
   193  			"dummyRole",
   194  			"",
   195  		},
   196  	}
   197  
   198  	for _, c := range cases {
   199  		role, err := ec2util.ValidateInstance(c.describeInstances, c.doc, c.remoteAddr)
   200  		if err != nil && (c.errPrefix == "" || !strings.HasPrefix(err.Error(), c.errPrefix)) {
   201  			t.Errorf("ValidateInstance: got %q, want %q", err, c.errPrefix)
   202  		}
   203  		if role != c.role {
   204  			t.Errorf("GetIamInstanceProfileARN: got %q, want %q", role, c.role)
   205  		}
   206  	}
   207  }
   208  
   209  func TestParseIdentityDocument(t *testing.T) {
   210  	pkcs7 := `MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCAJIAEggGuewog
   211  ICJwcml2YXRlSXAiIDogIjE3Mi4zMS40MS43MyIsCiAgImRldnBheVByb2R1Y3RDb2RlcyIgOiBu
   212  dWxsLAogICJhdmFpbGFiaWxpdHlab25lIiA6ICJ1cy13ZXN0LTJhIiwKICAiYWNjb3VudElkIiA6
   213  ICIwMTA1ODE4MjM4MDgiLAogICJ2ZXJzaW9uIiA6ICIyMDEwLTA4LTMxIiwKICAiaW5zdGFuY2VJ
   214  ZCIgOiAiaS0wMjY5YTc4YzgxNzA4MDg4YSIsCiAgImJpbGxpbmdQcm9kdWN0cyIgOiBudWxsLAog
   215  ICJpbnN0YW5jZVR5cGUiIDogInQyLm5hbm8iLAogICJwZW5kaW5nVGltZSIgOiAiMjAxNi0wOS0w
   216  OVQyMjoyNDo0MFoiLAogICJpbWFnZUlkIiA6ICJhbWktMDZhZjdmNjYiLAogICJhcmNoaXRlY3R1
   217  cmUiIDogIng4Nl82NCIsCiAgImtlcm5lbElkIiA6IG51bGwsCiAgInJhbWRpc2tJZCIgOiBudWxs
   218  LAogICJyZWdpb24iIDogInVzLXdlc3QtMiIKfQAAAAAAADGCARcwggETAgEBMGkwXDELMAkGA1UE
   219  BhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAeBgNV
   220  BAoTF0FtYXpvbiBXZWIgU2VydmljZXMgTExDAgkAlrpI2eVeGmcwCQYFKw4DAhoFAKBdMBgGCSqG
   221  SIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE2MDkwOTIyMjQ0NFowIwYJKoZI
   222  hvcNAQkEMRYEFMdcnDOfpT6XUhoRWNCDVMUpEpmvMAkGByqGSM44BAMELjAsAhR6HQzcZybHbbZ5
   223  JIrbrql6Il0jMwIUaeuNd15Shx/G9mpfXL1XIADV+IgAAAAAAAA=`
   224  	want := ec2util.IdentityDocument{
   225  		InstanceID:  "i-0269a78c81708088a",
   226  		AccountID:   "010581823808",
   227  		Region:      "us-west-2",
   228  		PendingTime: time.Date(2016, 9, 9, 22, 24, 40, 0, time.UTC),
   229  	}
   230  
   231  	cases := []struct {
   232  		pkcs7 string
   233  
   234  		want      ec2util.IdentityDocument
   235  		errPrefix string
   236  	}{
   237  		{
   238  			pkcs7,
   239  			ec2util.IdentityDocument{
   240  				InstanceID:  "i-0269a78c81708088a",
   241  				AccountID:   "010581823808",
   242  				Region:      "us-west-2",
   243  				PendingTime: time.Date(2016, 9, 9, 22, 24, 40, 0, time.UTC),
   244  			},
   245  			""},
   246  		{pkcs7[1:], ec2util.IdentityDocument{}, "failed to decode"},
   247  		{`MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCAJIAEggHPewog
   248  ICJhdmFpbGFiaWxpdHlab25lIiA6ICJ1cy13ZXN0LTJhIiwKICAiZGV2cGF5UHJvZHVjdENvZGVz
   249  IiA6IG51bGwsCiAgIm1hcmtldHBsYWNlUHJvZHVjdENvZGVzIiA6IG51bGwsCiAgInZlcnNpb24i
   250  IDogIjIwMTctMDktMzAiLAogICJwZW5kaW5nVGltZSIgOiAiMjAxNy0xMi0wNVQwMjoxMDo0Mloi
   251  LAogICJpbnN0YW5jZUlkIiA6ICJpLTA2YWY5YmIyYTNhMjg2MWNkIiwKICAiYmlsbGluZ1Byb2R1
   252  Y3RzIiA6IG51bGwsCiAgImluc3RhbmNlVHlwZSIgOiAidDIubmFubyIsCiAgInByaXZhdGVJcCIg
   253  OiAiMTAuMC43LjE2IiwKICAiaW1hZ2VJZCIgOiAiYW1pLTFmNjNiYTY3IiwKICAiYWNjb3VudElk
   254  IiA6ICI2MTk4NjcxMTA4MTAiLAogICJhcmNoaXRlY3R1cmUiIDogIng4Nl82NCIsCiAgImtlcm5l
   255  bElkIiA6IG51bGwsCiAgInJhbWRpc2tJZCIgOiBudWxsLAogICJyZWdpb24iIDogInVzLXdlc3Qt
   256  MiIKfQAAAAAAADGCARgwggEUAgEBMGkwXDELMAkGA1UEBhMCVVMxGTAXBgNVBAgTEFdhc2hpbmd0
   257  b24gU3RhdGUxEDAOBgNVBAcTB1NlYXR0bGUxIDAeBgNVBAoTF0FtYXpvbiBXZWIgU2VydmljZXMg
   258  TExDAgkAlrpI2eVeGmcwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJ
   259  KoZIhvcNAQkFMQ8XDTE3MTIwNTAyMTA0N1owIwYJKoZIhvcNAQkEMRYEFM7lf3kDblbNv0FTTlbH
   260  cxXtq51HMAkGByqGSM44BAMELzAtAhUAhh/F7KIV+NmGGuJ3B2GEAAA50NkCFD/VElA2Qe11PS6d
   261  N9KbKK34hcCtAAAAAAAA`,
   262  			ec2util.IdentityDocument{
   263  				InstanceID:  "i-06af9bb2a3a2861cd",
   264  				AccountID:   "619867110810",
   265  				Region:      "us-west-2",
   266  				PendingTime: time.Date(2017, 12, 5, 2, 10, 42, 0, time.UTC),
   267  			},
   268  			"",
   269  		},
   270  	}
   271  
   272  	for i, c := range cases {
   273  		doc, _, err := ec2util.ParseAndVerifyIdentityDocument(pkcs7)
   274  		if err != nil && (c.errPrefix == "" || !strings.HasPrefix(err.Error(), c.errPrefix)) {
   275  			t.Errorf("ParseIdentityDocument %d: got %q, want %q", i, err, c.errPrefix)
   276  			continue
   277  		}
   278  		if !reflect.DeepEqual(want, *doc) {
   279  			t.Fatalf("ParseIdentityDocument: got %+v, want %+v", *doc, want)
   280  		}
   281  	}
   282  }
   283  
   284  func newDescribeInstancesOutput(arn string, publicIP string) *ec2.DescribeInstancesOutput {
   285  	return &ec2.DescribeInstancesOutput{
   286  		Reservations: []*ec2.Reservation{
   287  			&ec2.Reservation{
   288  				Instances: []*ec2.Instance{
   289  					newInstancesOutput("", arn, publicIP),
   290  				},
   291  			},
   292  		},
   293  	}
   294  }
   295  
   296  func newInstancesOutput(instanceId string, arn string, publicIP string) *ec2.Instance {
   297  	return &ec2.Instance{
   298  		InstanceId: &instanceId,
   299  		IamInstanceProfile: &ec2.IamInstanceProfile{
   300  			Arn: aws.String(arn),
   301  		},
   302  		PublicIpAddress: aws.String(publicIP),
   303  	}
   304  }