github.com/grailbio/base@v0.0.11/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/grailbio/base/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 }