Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/awscli/customizations/ecs/executecommand.py
1567 views
1
# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
import logging
14
import json
15
import errno
16
17
from subprocess import check_call
18
from awscli.compat import ignore_user_entered_signals
19
from awscli.clidriver import ServiceOperation, CLIOperationCaller
20
21
logger = logging.getLogger(__name__)
22
23
ERROR_MESSAGE = (
24
'SessionManagerPlugin is not found. ',
25
'Please refer to SessionManager Documentation here: ',
26
'http://docs.aws.amazon.com/console/systems-manager/',
27
'session-manager-plugin-not-found'
28
)
29
30
TASK_NOT_FOUND = (
31
'The task provided in the request was '
32
'not found.'
33
)
34
35
36
class ECSExecuteCommand(ServiceOperation):
37
38
def create_help_command(self):
39
help_command = super(ECSExecuteCommand, self).create_help_command()
40
# change the output shape because the command provides no output.
41
self._operation_model.output_shape = None
42
return help_command
43
44
45
def get_container_runtime_id(client, container_name, task_id, cluster_name):
46
describe_tasks_params = {
47
"cluster": cluster_name,
48
"tasks": [task_id]
49
}
50
describe_tasks_response = client.describe_tasks(**describe_tasks_params)
51
# need to fail here if task has failed in the intermediate time
52
tasks = describe_tasks_response['tasks']
53
if not tasks:
54
raise ValueError(TASK_NOT_FOUND)
55
response = describe_tasks_response['tasks'][0]['containers']
56
for container in response:
57
if container_name == container['name']:
58
return container['runtimeId']
59
60
61
def build_ssm_request_paramaters(response, client):
62
cluster_name = response['clusterArn'].split('/')[-1]
63
task_id = response['taskArn'].split('/')[-1]
64
container_name = response['containerName']
65
# in order to get container run-time id
66
# we need to make a call to describe-tasks
67
container_runtime_id = \
68
get_container_runtime_id(client, container_name,
69
task_id, cluster_name)
70
target = "ecs:{}_{}_{}".format(cluster_name, task_id,
71
container_runtime_id)
72
ssm_request_params = {"Target": target}
73
return ssm_request_params
74
75
76
class ExecuteCommandCaller(CLIOperationCaller):
77
def invoke(self, service_name, operation_name, parameters, parsed_globals):
78
try:
79
# making an execute-command call to connect to an
80
# active session on a container would require
81
# session-manager-plugin to be installed on the client machine.
82
# Hence, making this empty session-manager-plugin call
83
# before calling execute-command to ensure that
84
# session-manager-plugin is installed
85
# before execute-command-command is made
86
check_call(["session-manager-plugin"])
87
client = self._session.create_client(
88
service_name, region_name=parsed_globals.region,
89
endpoint_url=parsed_globals.endpoint_url,
90
verify=parsed_globals.verify_ssl)
91
response = client.execute_command(**parameters)
92
region_name = client.meta.region_name
93
profile_name = self._session.profile \
94
if self._session.profile is not None else ''
95
endpoint_url = client.meta.endpoint_url
96
ssm_request_params = build_ssm_request_paramaters(response, client)
97
# ignore_user_entered_signals ignores these signals
98
# because if signals which kills the process are not
99
# captured would kill the foreground process but not the
100
# background one. Capturing these would prevents process
101
# from getting killed and these signals are input to plugin
102
# and handling in there
103
with ignore_user_entered_signals():
104
# call executable with necessary input
105
check_call(["session-manager-plugin",
106
json.dumps(response['session']),
107
region_name,
108
"StartSession",
109
profile_name,
110
json.dumps(ssm_request_params),
111
endpoint_url])
112
return 0
113
except OSError as ex:
114
if ex.errno == errno.ENOENT:
115
logger.debug('SessionManagerPlugin is not present',
116
exc_info=True)
117
raise ValueError(''.join(ERROR_MESSAGE))
118
119