Skip to content

Commit 08b355f

Browse files
committed
connection/aws_ssm - use port forwarding session combined with nc for
file transfer
1 parent 2715efb commit 08b355f

File tree

2 files changed

+372
-4
lines changed

2 files changed

+372
-4
lines changed

plugins/connection/aws_ssm.py

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,29 @@
8686
vars:
8787
- name: ansible_aws_ssm_bucket_endpoint_url
8888
version_added: 5.3.0
89+
host_port_number:
90+
description:
91+
- The Port number of the server on the instance when using Port Forwarding Using AWS System Manager Session Manager
92+
to transfer files from/to local host to/from remote host.
93+
- The port V(80) is used if not provided.
94+
- The C(nc) command should be installed in the remote host to use this option.
95+
- This is not supported for Windows hosts for now.
96+
type: integer
97+
default: 80
98+
vars:
99+
- name: ansible_aws_ssm_host_port_number
100+
version_added: 9.3.0
101+
local_port_number:
102+
description:
103+
- Port number on local machine to forward traffic to when using Port Forwarding Using AWS System Manager Session Manager
104+
to transfer files from/to local host to/from remote host.
105+
- An open port is chosen at run-time if not provided.
106+
- The C(nc) command should be installed in the remote host to use this option.
107+
- This is not supported for Windows hosts for now.
108+
type: integer
109+
vars:
110+
- name: ansible_aws_ssm_local_port_number
111+
version_added: 9.3.0
89112
plugin:
90113
description:
91114
- This defines the location of the session-manager-plugin binary.
@@ -359,6 +382,7 @@
359382
from ansible.utils.display import Display
360383

361384
from ansible_collections.amazon.aws.plugins.module_utils.botocore import HAS_BOTO3
385+
from ansible_collections.community.aws.plugins.plugin_utils.ssm_file_transfer import PortForwardingFileTransferManager
362386

363387
display = Display()
364388

@@ -469,6 +493,7 @@ class Connection(ConnectionBase):
469493
_stdout = None
470494
_session_id = ""
471495
_timeout = False
496+
_filetransfer_mgr = None
472497
MARK_LENGTH = 26
473498

474499
def __init__(self, *args, **kwargs):
@@ -517,8 +542,29 @@ def _init_clients(self) -> None:
517542
# Initialize SSM client
518543
self._initialize_ssm_client(region_name, profile_name)
519544

520-
# Initialize S3 client
521-
self._initialize_s3_client(profile_name)
545+
if self._should_use_port_forwarding_for_file_transfer():
546+
# Initialize S3 client
547+
self._initialize_s3_client(profile_name)
548+
else:
549+
self._initialize_file_transfer_manager()
550+
551+
def _initialize_file_transfer_manager(self) -> None:
552+
ssm_timeout = self.get_option("ssm_timeout")
553+
region_name = self.get_option("region")
554+
profile_name = self.get_option("profile") or ""
555+
host_port = self.get_option("host_port_number")
556+
local_port = self.get_option("local_port_number")
557+
self._filetransfer_mgr = PortForwardingFileTransferManager(
558+
self.host,
559+
ssm_client=self._client,
560+
instance_id=self.instance_id,
561+
executable=self.get_executable(),
562+
ssm_timeout=ssm_timeout,
563+
region_name=region_name,
564+
profile_name=profile_name,
565+
host_port=host_port,
566+
local_port=local_port,
567+
)
522568

523569
def _initialize_ssm_client(self, region_name: Optional[str], profile_name: str) -> None:
524570
"""
@@ -621,6 +667,10 @@ def reset(self):
621667
self.close()
622668
return self.start_session()
623669

670+
def _should_use_port_forwarding_for_file_transfer(self) -> bool:
671+
"""return true if the user has defined a bucket_name to be used for transport"""
672+
return (not self.is_windows and self.get_option("bucket_name") is not None)
673+
624674
@property
625675
def instance_id(self) -> str:
626676
if not self._instance_id:
@@ -1159,15 +1209,21 @@ def put_file(self, in_path, out_path):
11591209
if not os.path.exists(to_bytes(in_path, errors="surrogate_or_strict")):
11601210
raise AnsibleFileNotFound(f"file or module does not exist: {in_path}")
11611211

1162-
return self._file_transport_command(in_path, out_path, "put")
1212+
if self._should_use_port_forwarding_for_file_transfer():
1213+
return self._file_transport_command(in_path, out_path, "put")
1214+
else:
1215+
return self._filetransfer_mgr.put_file(in_path, out_path)
11631216

11641217
def fetch_file(self, in_path, out_path):
11651218
"""fetch a file from remote to local"""
11661219

11671220
super().fetch_file(in_path, out_path)
11681221

11691222
self._vvv(f"FETCH {in_path} TO {out_path}")
1170-
return self._file_transport_command(in_path, out_path, "get")
1223+
if self._should_use_port_forwarding_for_file_transfer():
1224+
return self._file_transport_command(in_path, out_path, "get")
1225+
else:
1226+
return self._filetransfer_mgr.fetch_file(in_path, out_path)
11711227

11721228
def close(self):
11731229
"""terminate the connection"""

0 commit comments

Comments
 (0)