| Server IP : 3.96.16.70 / Your IP : 216.73.216.15 Web Server : Apache System : Linux ip-172-31-26-103.ca-central-1.compute.internal 6.1.163-186.299.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Feb 24 16:35:42 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.18 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /lib/python3.9/site-packages/awscli/customizations/ |
Upload File : |
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import errno
import json
import logging
import os
import re
from subprocess import check_call, check_output
from awscli.clidriver import CLIOperationCaller, ServiceOperation
from awscli.compat import ignore_user_entered_signals
logger = logging.getLogger(__name__)
ERROR_MESSAGE = (
'SessionManagerPlugin is not found. ',
'Please refer to SessionManager Documentation here: ',
'http://docs.aws.amazon.com/console/systems-manager/',
'session-manager-plugin-not-found',
)
def register_ssm_session(event_handlers):
event_handlers.register(
'building-command-table.ssm', add_custom_start_session
)
def add_custom_start_session(session, command_table, **kwargs):
command_table['start-session'] = StartSessionCommand(
name='start-session',
parent_name='ssm',
session=session,
operation_model=session.get_service_model('ssm').operation_model(
'StartSession'
),
operation_caller=StartSessionCaller(session),
)
class VersionRequirement:
WHITESPACE_REGEX = re.compile(r"\s+")
SSM_SESSION_PLUGIN_VERSION_REGEX = re.compile(r"^\d+(\.\d+){0,3}$")
def __init__(self, min_version):
self.min_version = min_version
def meets_requirement(self, version):
ssm_plugin_version = self._sanitize_plugin_version(version)
if self._is_valid_version(ssm_plugin_version):
norm_version, norm_min_version = self._normalize(
ssm_plugin_version, self.min_version
)
return norm_version > norm_min_version
else:
return False
def _sanitize_plugin_version(self, plugin_version):
return re.sub(self.WHITESPACE_REGEX, "", plugin_version)
def _is_valid_version(self, plugin_version):
return bool(
self.SSM_SESSION_PLUGIN_VERSION_REGEX.match(plugin_version)
)
def _normalize(self, v1, v2):
v1_parts = [int(v) for v in v1.split(".")]
v2_parts = [int(v) for v in v2.split(".")]
while len(v1_parts) != len(v2_parts):
if len(v1_parts) - len(v2_parts) > 0:
v2_parts.append(0)
else:
v1_parts.append(0)
return v1_parts, v2_parts
class StartSessionCommand(ServiceOperation):
def create_help_command(self):
help_command = super(StartSessionCommand, self).create_help_command()
# Change the output shape because the command provides no output.
self._operation_model.output_shape = None
return help_command
class StartSessionCaller(CLIOperationCaller):
LAST_PLUGIN_VERSION_WITHOUT_ENV_VAR = "1.2.497.0"
DEFAULT_SSM_ENV_NAME = "AWS_SSM_START_SESSION_RESPONSE"
def invoke(self, service_name, operation_name, parameters, parsed_globals):
client = self._session.create_client(
service_name,
region_name=parsed_globals.region,
endpoint_url=parsed_globals.endpoint_url,
verify=parsed_globals.verify_ssl,
)
response = client.start_session(**parameters)
session_id = response['SessionId']
region_name = client.meta.region_name
# Profile_name is used to passed on to session manager plugin
# to fetch same profile credentials to make an api call in the plugin.
# If --profile flag is configured, pass it to Session Manager plugin.
# If not, set empty string.
profile_name = (
parsed_globals.profile
if parsed_globals.profile is not None
else ''
)
endpoint_url = client.meta.endpoint_url
ssm_env_name = self.DEFAULT_SSM_ENV_NAME
try:
session_parameters = {
"SessionId": response["SessionId"],
"TokenValue": response["TokenValue"],
"StreamUrl": response["StreamUrl"],
}
start_session_response = json.dumps(session_parameters)
plugin_version = check_output(
["session-manager-plugin", "--version"], text=True
)
env = os.environ.copy()
# Check if this plugin supports passing the start session response
# as an environment variable name. If it does, it will set the
# value to the response from the start_session operation to the env
# variable defined in DEFAULT_SSM_ENV_NAME. If the session plugin
# version is invalid or older than the version defined in
# LAST_PLUGIN_VERSION_WITHOUT_ENV_VAR, it will fall back to
# passing the start_session response directly.
version_requirement = VersionRequirement(
min_version=self.LAST_PLUGIN_VERSION_WITHOUT_ENV_VAR
)
if version_requirement.meets_requirement(plugin_version):
env[ssm_env_name] = start_session_response
start_session_response = ssm_env_name
# ignore_user_entered_signals ignores these signals
# because if signals which kills the process are not
# captured would kill the foreground process but not the
# background one. Capturing these would prevents process
# from getting killed and these signals are input to plugin
# and handling in there
with ignore_user_entered_signals():
# call executable with necessary input
check_call(
[
"session-manager-plugin",
start_session_response,
region_name,
"StartSession",
profile_name,
json.dumps(parameters),
endpoint_url,
],
env=env,
)
return 0
except OSError as ex:
if ex.errno == errno.ENOENT:
logger.debug(
'SessionManagerPlugin is not present', exc_info=True
)
# start-session api call returns response and starts the
# session on ssm-agent and response is forwarded to
# session-manager-plugin. If plugin is not present, terminate
# is called so that service and ssm-agent terminates the
# session to avoid zombie session active on ssm-agent for
# default self terminate time
client.terminate_session(SessionId=session_id)
raise ValueError(''.join(ERROR_MESSAGE))