Skip to content

Commit 9c8f131

Browse files
[v2] Update ec2-instance-connect to handle new endpoint states (#9731)
1 parent a8d8f06 commit 9c8f131

File tree

4 files changed

+232
-11
lines changed

4 files changed

+232
-11
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "enhancement",
3+
"category": "ec2-instance-connect",
4+
"description": "Allow ec2-instance-connect ssh and open-tunnel commands to connect to update-complete, update-in-progress, and update-failed EC2 Instance Connect Endpoints. Fixes `#9715 <https://github.com/aws/aws-cli/issues/9715>`__"
5+
}

awscli/customizations/ec2instanceconnect/eicefetcher.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,17 @@ def _get_instance_connect_endpoint_by_id(
5151
self, ec2_client, instance_connect_endpoint_id
5252
):
5353
args = {
54-
"Filters": [{"Name": "state", "Values": ["create-complete"]}],
54+
"Filters": [
55+
{
56+
"Name": "state",
57+
"Values": [
58+
"create-complete",
59+
"update-in-progress",
60+
"update-failed",
61+
"update-complete",
62+
],
63+
}
64+
],
5565
"InstanceConnectEndpointIds": [instance_connect_endpoint_id],
5666
}
5767
describe_eice_response = (
@@ -72,7 +82,15 @@ def _get_instance_connect_endpoint_by_vpc(
7282
## Describe until subnet match and if none match subnet then return the first one based on vpc-id filter
7383
args = {
7484
"Filters": [
75-
{"Name": "state", "Values": ["create-complete"]},
85+
{
86+
"Name": "state",
87+
"Values": [
88+
"create-complete",
89+
"update-in-progress",
90+
"update-failed",
91+
"update-complete",
92+
],
93+
},
7694
{"Name": "vpc-id", "Values": [vpc_id]},
7795
]
7896
}
@@ -90,9 +108,7 @@ def _get_instance_connect_endpoint_by_vpc(
90108
if page_result:
91109
for eice in page_result:
92110
if eice['SubnetId'] == subnet_id:
93-
logger.debug(
94-
f"Using EICE based on subnet: {instance_connect_endpoints[0]}"
95-
)
111+
logger.debug(f"Using EICE based on subnet: {eice}")
96112
return eice
97113

98114
if instance_connect_endpoints:

tests/functional/ec2instanceconnect/test_opentunnel.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,15 @@ def describe_eice_response_empty_fips_dns(dns_name, fips_dns_name):
352352
def request_params_for_describe_eice():
353353
return {
354354
'Filters': [
355-
{'Name': 'state', 'Values': ['create-complete']},
355+
{
356+
'Name': 'state',
357+
'Values': [
358+
'create-complete',
359+
'update-in-progress',
360+
'update-failed',
361+
'update-complete',
362+
],
363+
},
356364
{'Name': 'vpc-id', 'Values': ['vpc-123']},
357365
]
358366
}
@@ -434,6 +442,15 @@ def assert_url(dns_name, url):
434442

435443

436444
class TestOpenTunnel:
445+
@pytest.mark.parametrize(
446+
"endpoint_state",
447+
[
448+
"create-complete",
449+
"update-in-progress",
450+
"update-failed",
451+
"update-complete",
452+
],
453+
)
437454
def test_single_connection_mode(
438455
self,
439456
cli_runner,
@@ -442,10 +459,11 @@ def test_single_connection_mode(
442459
io_patch,
443460
describe_instance_response,
444461
dns_name,
445-
describe_eice_response,
462+
fips_dns_name,
446463
request_params_for_describe_instance,
447464
request_params_for_describe_eice,
448465
datetime_utcnow_patch,
466+
endpoint_state,
449467
):
450468
cli_runner.env["AWS_USE_FIPS_ENDPOINT"] = "false"
451469
cmdline = [
@@ -456,8 +474,27 @@ def test_single_connection_mode(
456474
"--max-tunnel-duration",
457475
"1",
458476
]
477+
478+
# Create endpoint response with the specified state
479+
describe_eice_response_with_state = f"""
480+
<DescribeInstanceConnectEndpointsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
481+
<instanceConnectEndpointSet>
482+
<item>
483+
<dnsName>{dns_name}</dnsName>
484+
<fipsDnsName>{fips_dns_name}</fipsDnsName>
485+
<instanceConnectEndpointId>eice-123</instanceConnectEndpointId>
486+
<state>{endpoint_state}</state>
487+
<subnetId>subnet-123</subnetId>
488+
<vpcId>vpc-123</vpcId>
489+
</item>
490+
</instanceConnectEndpointSet>
491+
</DescribeInstanceConnectEndpointsResponse>
492+
"""
493+
459494
cli_runner.add_response(HTTPResponse(body=describe_instance_response))
460-
cli_runner.add_response(HTTPResponse(body=describe_eice_response))
495+
cli_runner.add_response(
496+
HTTPResponse(body=describe_eice_response_with_state)
497+
)
461498

462499
test_server_input = b"Test Server Output"
463500
mock_crt_websocket.add_output_from_server(test_server_input)
@@ -469,7 +506,7 @@ def test_single_connection_mode(
469506
assert 0 == result.rc
470507
assert pop_stdout_content() == test_server_input
471508
assert_stdout_empty()
472-
# Order of the query params on the url mater because of sigv4
509+
# Order of the query params on the url matter because of sigv4
473510
assert (
474511
"eice-123.ec2-instance-connect-endpoint.us-west-2.amazonaws.com/openTunnel?"
475512
"instanceConnectEndpointId=eice-123&remotePort=22&privateIpAddress=10.0.0.0&"

tests/functional/ec2instanceconnect/test_ssh.py

Lines changed: 165 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,39 @@ def get_describe_eice_response():
176176
"""
177177

178178

179+
def get_describe_eice_response_with_state(state):
180+
return f"""
181+
<DescribeInstanceConnectEndpointsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
182+
<instanceConnectEndpointSet>
183+
<item>
184+
<dnsName>dns.com</dnsName>
185+
<fipsDnsName>fips.dns.com</fipsDnsName>
186+
<instanceConnectEndpointId>eice-123</instanceConnectEndpointId>
187+
<state>{state}</state>
188+
<subnetId>subnet-123</subnetId>
189+
<vpcId>vpc-123</vpcId>
190+
</item>
191+
</instanceConnectEndpointSet>
192+
</DescribeInstanceConnectEndpointsResponse>
193+
"""
194+
195+
196+
def get_describe_eice_response_create_complete():
197+
return get_describe_eice_response_with_state("create-complete")
198+
199+
200+
def get_describe_eice_response_update_in_progress():
201+
return get_describe_eice_response_with_state("update-in-progress")
202+
203+
204+
def get_describe_eice_response_update_complete():
205+
return get_describe_eice_response_with_state("update-complete")
206+
207+
208+
def get_describe_eice_response_update_failed():
209+
return get_describe_eice_response_with_state("update-failed")
210+
211+
179212
@pytest.fixture
180213
def describe_eice_response():
181214
return get_describe_eice_response()
@@ -184,15 +217,33 @@ def describe_eice_response():
184217
def get_request_params_for_describe_eice():
185218
return {
186219
'Filters': [
187-
{'Name': 'state', 'Values': ['create-complete']},
220+
{
221+
'Name': 'state',
222+
'Values': [
223+
'create-complete',
224+
'update-in-progress',
225+
'update-failed',
226+
'update-complete',
227+
],
228+
},
188229
{'Name': 'vpc-id', 'Values': ['vpc-123']},
189230
]
190231
}
191232

192233

193234
def get_request_params_for_describe_eice_with_eice_id():
194235
return {
195-
'Filters': [{'Name': 'state', 'Values': ['create-complete']}],
236+
'Filters': [
237+
{
238+
'Name': 'state',
239+
'Values': [
240+
'create-complete',
241+
'update-in-progress',
242+
'update-failed',
243+
'update-complete',
244+
],
245+
}
246+
],
196247
'InstanceConnectEndpointIds': ['eice-12345'],
197248
}
198249

@@ -568,6 +619,118 @@ class TestSSHCommand:
568619
],
569620
id='Open-Tunnel: use provided ip',
570621
),
622+
pytest.param(
623+
get_describe_private_instance_response(),
624+
get_describe_eice_response_create_complete(),
625+
get_request_params_for_describe_eice(),
626+
[
627+
"ec2-instance-connect",
628+
"ssh",
629+
"--instance-id",
630+
"i-123",
631+
"--private-key-file",
632+
"/tmp/ssh-file",
633+
],
634+
[
635+
'ssh',
636+
'-o',
637+
'ServerAliveInterval=5',
638+
'-p',
639+
'22',
640+
'-i',
641+
'/tmp/ssh-file',
642+
'-o',
643+
'ProxyCommand=aws ec2-instance-connect open-tunnel --instance-id i-123 '
644+
'--private-ip-address 10.0.0.0 --remote-port 22 '
645+
'--instance-connect-endpoint-id eice-123 --instance-connect-endpoint-dns-name dns.com',
646+
'ec2-user@10.0.0.0',
647+
],
648+
id='Open-Tunnel: connect via eice in create-complete',
649+
),
650+
pytest.param(
651+
get_describe_private_instance_response(),
652+
get_describe_eice_response_update_in_progress(),
653+
get_request_params_for_describe_eice(),
654+
[
655+
"ec2-instance-connect",
656+
"ssh",
657+
"--instance-id",
658+
"i-123",
659+
"--private-key-file",
660+
"/tmp/ssh-file",
661+
],
662+
[
663+
'ssh',
664+
'-o',
665+
'ServerAliveInterval=5',
666+
'-p',
667+
'22',
668+
'-i',
669+
'/tmp/ssh-file',
670+
'-o',
671+
'ProxyCommand=aws ec2-instance-connect open-tunnel --instance-id i-123 '
672+
'--private-ip-address 10.0.0.0 --remote-port 22 '
673+
'--instance-connect-endpoint-id eice-123 --instance-connect-endpoint-dns-name dns.com',
674+
'ec2-user@10.0.0.0',
675+
],
676+
id='Open-Tunnel: connect via eice in update-in-progress',
677+
),
678+
pytest.param(
679+
get_describe_private_instance_response(),
680+
get_describe_eice_response_update_complete(),
681+
get_request_params_for_describe_eice(),
682+
[
683+
"ec2-instance-connect",
684+
"ssh",
685+
"--instance-id",
686+
"i-123",
687+
"--private-key-file",
688+
"/tmp/ssh-file",
689+
],
690+
[
691+
'ssh',
692+
'-o',
693+
'ServerAliveInterval=5',
694+
'-p',
695+
'22',
696+
'-i',
697+
'/tmp/ssh-file',
698+
'-o',
699+
'ProxyCommand=aws ec2-instance-connect open-tunnel --instance-id i-123 '
700+
'--private-ip-address 10.0.0.0 --remote-port 22 '
701+
'--instance-connect-endpoint-id eice-123 --instance-connect-endpoint-dns-name dns.com',
702+
'ec2-user@10.0.0.0',
703+
],
704+
id='Open-Tunnel: connect via eice in update-complete',
705+
),
706+
pytest.param(
707+
get_describe_private_instance_response(),
708+
get_describe_eice_response_update_failed(),
709+
get_request_params_for_describe_eice(),
710+
[
711+
"ec2-instance-connect",
712+
"ssh",
713+
"--instance-id",
714+
"i-123",
715+
"--private-key-file",
716+
"/tmp/ssh-file",
717+
],
718+
[
719+
'ssh',
720+
'-o',
721+
'ServerAliveInterval=5',
722+
'-p',
723+
'22',
724+
'-i',
725+
'/tmp/ssh-file',
726+
'-o',
727+
'ProxyCommand=aws ec2-instance-connect open-tunnel --instance-id i-123 '
728+
'--private-ip-address 10.0.0.0 --remote-port 22 '
729+
'--instance-connect-endpoint-id eice-123 --instance-connect-endpoint-dns-name dns.com',
730+
'ec2-user@10.0.0.0',
731+
],
732+
id='Open-Tunnel: connect via eice in update-failed',
733+
),
571734
pytest.param(
572735
get_describe_public_instance_response(),
573736
None,

0 commit comments

Comments
 (0)