|
5 | 5 |
|
6 | 6 | # Based on the ssh connection plugin by Michael DeHaan
|
7 | 7 |
|
| 8 | + |
8 | 9 | DOCUMENTATION = r"""
|
9 | 10 | name: aws_ssm
|
10 | 11 | author:
|
|
284 | 285 | name: nginx
|
285 | 286 | state: present
|
286 | 287 | """
|
287 |
| - |
288 | 288 | import os
|
289 | 289 | import getpass
|
290 | 290 | import json
|
|
295 | 295 | import string
|
296 | 296 | import subprocess
|
297 | 297 | import time
|
| 298 | +from typing import Optional |
298 | 299 |
|
299 | 300 | try:
|
300 | 301 | import boto3
|
@@ -347,7 +348,10 @@ def wrapped(self, *args, **kwargs):
|
347 | 348 | if isinstance(e, AnsibleConnectionFailure):
|
348 | 349 | msg = f"ssm_retry: attempt: {attempt}, cmd ({cmd_summary}), pausing for {pause} seconds"
|
349 | 350 | else:
|
350 |
| - msg = f"ssm_retry: attempt: {attempt}, caught exception({e}) from cmd ({cmd_summary}), pausing for {pause} seconds" |
| 351 | + msg = ( |
| 352 | + f"ssm_retry: attempt: {attempt}, caught exception({e})" |
| 353 | + f"from cmd ({cmd_summary}),pausing for {pause} seconds" |
| 354 | + ) |
351 | 355 |
|
352 | 356 | self._vv(msg)
|
353 | 357 |
|
@@ -390,6 +394,90 @@ class Connection(ConnectionBase):
|
390 | 394 | _timeout = False
|
391 | 395 | MARK_LENGTH = 26
|
392 | 396 |
|
| 397 | + def __init__(self, *args, **kwargs): |
| 398 | + super().__init__(*args, **kwargs) |
| 399 | + |
| 400 | + if not HAS_BOTO3: |
| 401 | + raise AnsibleError(missing_required_lib("boto3")) |
| 402 | + |
| 403 | + self.host = self._play_context.remote_addr |
| 404 | + |
| 405 | + if getattr(self._shell, "SHELL_FAMILY", "") == "powershell": |
| 406 | + self.delegate = None |
| 407 | + self.has_native_async = True |
| 408 | + self.always_pipeline_modules = True |
| 409 | + self.module_implementation_preferences = (".ps1", ".exe", "") |
| 410 | + self.protocol = None |
| 411 | + self.shell_id = None |
| 412 | + self._shell_type = "powershell" |
| 413 | + self.is_windows = True |
| 414 | + |
| 415 | + def __del__(self): |
| 416 | + self.close() |
| 417 | + |
| 418 | + def _connect(self): |
| 419 | + """connect to the host via ssm""" |
| 420 | + |
| 421 | + self._play_context.remote_user = getpass.getuser() |
| 422 | + |
| 423 | + if not self._session_id: |
| 424 | + self.start_session() |
| 425 | + return self |
| 426 | + |
| 427 | + def _init_clients(self) -> None: |
| 428 | + """ |
| 429 | + Initializes required AWS clients (SSM and S3). |
| 430 | + Delegates client initialization to specialized methods. |
| 431 | + """ |
| 432 | + |
| 433 | + self._vvvv("INITIALIZE BOTO3 CLIENTS") |
| 434 | + profile_name = self.get_option("profile") or "" |
| 435 | + region_name = self.get_option("region") |
| 436 | + |
| 437 | + # Initialize SSM client |
| 438 | + self._initialize_ssm_client(region_name, profile_name) |
| 439 | + |
| 440 | + # Initialize S3 client |
| 441 | + self._initialize_s3_client(profile_name) |
| 442 | + |
| 443 | + def _initialize_ssm_client(self, region_name: Optional[str], profile_name: str) -> None: |
| 444 | + """ |
| 445 | + Initializes the SSM client used to manage sessions. |
| 446 | + Args: |
| 447 | + region_name (Optional[str]): AWS region for the SSM client. |
| 448 | + profile_name (str): AWS profile name for authentication. |
| 449 | +
|
| 450 | + Returns: |
| 451 | + None |
| 452 | + """ |
| 453 | + |
| 454 | + self._vvvv("SETUP BOTO3 CLIENTS: SSM") |
| 455 | + self._client = self._get_boto_client( |
| 456 | + "ssm", |
| 457 | + region_name=region_name, |
| 458 | + profile_name=profile_name, |
| 459 | + ) |
| 460 | + |
| 461 | + def _initialize_s3_client(self, profile_name: str) -> None: |
| 462 | + """ |
| 463 | + Initializes the S3 client used for accessing S3 buckets. |
| 464 | +
|
| 465 | + Args: |
| 466 | + profile_name (str): AWS profile name for authentication. |
| 467 | +
|
| 468 | + Returns: |
| 469 | + None |
| 470 | + """ |
| 471 | + |
| 472 | + s3_endpoint_url, s3_region_name = self._get_bucket_endpoint() |
| 473 | + self._vvvv(f"SETUP BOTO3 CLIENTS: S3 {s3_endpoint_url}") |
| 474 | + self._s3_client = self._get_boto_client( |
| 475 | + "s3", |
| 476 | + region_name=s3_region_name, |
| 477 | + endpoint_url=s3_endpoint_url, |
| 478 | + profile_name=profile_name, |
| 479 | + ) |
| 480 | + |
393 | 481 | def _display(self, f, message):
|
394 | 482 | if self.host:
|
395 | 483 | host_args = {"host": self.host}
|
@@ -447,62 +535,6 @@ def _get_bucket_endpoint(self):
|
447 | 535 |
|
448 | 536 | return s3_bucket_client.meta.endpoint_url, s3_bucket_client.meta.region_name
|
449 | 537 |
|
450 |
| - def _init_clients(self): |
451 |
| - self._vvvv("INITIALIZE BOTO3 CLIENTS") |
452 |
| - profile_name = self.get_option("profile") or "" |
453 |
| - region_name = self.get_option("region") |
454 |
| - |
455 |
| - # The SSM Boto client, currently used to initiate and manage the session |
456 |
| - # Note: does not handle the actual SSM session traffic |
457 |
| - self._vvvv("SETUP BOTO3 CLIENTS: SSM") |
458 |
| - ssm_client = self._get_boto_client( |
459 |
| - "ssm", |
460 |
| - region_name=region_name, |
461 |
| - profile_name=profile_name, |
462 |
| - ) |
463 |
| - self._client = ssm_client |
464 |
| - |
465 |
| - s3_endpoint_url, s3_region_name = self._get_bucket_endpoint() |
466 |
| - self._vvvv(f"SETUP BOTO3 CLIENTS: S3 {s3_endpoint_url}") |
467 |
| - s3_bucket_client = self._get_boto_client( |
468 |
| - "s3", |
469 |
| - region_name=s3_region_name, |
470 |
| - endpoint_url=s3_endpoint_url, |
471 |
| - profile_name=profile_name, |
472 |
| - ) |
473 |
| - |
474 |
| - self._s3_client = s3_bucket_client |
475 |
| - |
476 |
| - def __init__(self, *args, **kwargs): |
477 |
| - super().__init__(*args, **kwargs) |
478 |
| - |
479 |
| - if not HAS_BOTO3: |
480 |
| - raise AnsibleError(missing_required_lib("boto3")) |
481 |
| - |
482 |
| - self.host = self._play_context.remote_addr |
483 |
| - |
484 |
| - if getattr(self._shell, "SHELL_FAMILY", "") == "powershell": |
485 |
| - self.delegate = None |
486 |
| - self.has_native_async = True |
487 |
| - self.always_pipeline_modules = True |
488 |
| - self.module_implementation_preferences = (".ps1", ".exe", "") |
489 |
| - self.protocol = None |
490 |
| - self.shell_id = None |
491 |
| - self._shell_type = "powershell" |
492 |
| - self.is_windows = True |
493 |
| - |
494 |
| - def __del__(self): |
495 |
| - self.close() |
496 |
| - |
497 |
| - def _connect(self): |
498 |
| - """connect to the host via ssm""" |
499 |
| - |
500 |
| - self._play_context.remote_user = getpass.getuser() |
501 |
| - |
502 |
| - if not self._session_id: |
503 |
| - self.start_session() |
504 |
| - return self |
505 |
| - |
506 | 538 | def reset(self):
|
507 | 539 | """start a fresh ssm session"""
|
508 | 540 | self._vvvv("reset called on ssm connection")
|
@@ -853,7 +885,8 @@ def _generate_commands(self, bucket_name, s3_path, in_path, out_path):
|
853 | 885 | put_commands = [
|
854 | 886 | (
|
855 | 887 | "Invoke-WebRequest -Method PUT "
|
856 |
| - f"-Headers @{{{put_command_headers}}} " # @{'key' = 'value'; 'key2' = 'value2'} |
| 888 | + # @{'key' = 'value'; 'key2' = 'value2'} |
| 889 | + f"-Headers @{{{put_command_headers}}} " |
857 | 890 | f"-InFile '{in_path}' "
|
858 | 891 | f"-Uri '{put_url}' "
|
859 | 892 | f"-UseBasicParsing"
|
|
0 commit comments