Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/awscli/paramfile.py
2624 views
1
# Copyright 2012-2013 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 sys
14
15
import copy
16
import logging
17
import os
18
19
from botocore.awsrequest import AWSRequest
20
from botocore.exceptions import ProfileNotFound
21
from botocore.httpsession import URLLib3Session
22
23
from awscli import argprocess
24
from awscli.compat import compat_open
25
from awscli.utils import resolve_v2_debug_mode
26
27
logger = logging.getLogger(__name__)
28
29
# These are special cased arguments that do _not_ get the
30
# special param file processing. This is typically because it
31
# refers to an actual URI of some sort and we don't want to actually
32
# download the content (i.e TemplateURL in cloudformation).
33
PARAMFILE_DISABLED = set(
34
[
35
'api-gateway.put-integration.uri',
36
'api-gateway.create-integration.integration-uri',
37
'api-gateway.update-integration.integration-uri',
38
'api-gateway.create-api.target',
39
'api-gateway.update-api.target',
40
'appstream.create-stack.redirect-url',
41
'appstream.create-stack.feedback-url',
42
'appstream.update-stack.redirect-url',
43
'appstream.update-stack.feedback-url',
44
'cloudformation.create-stack.template-url',
45
'cloudformation.update-stack.template-url',
46
'cloudformation.create-stack-set.template-url',
47
'cloudformation.update-stack-set.template-url',
48
'cloudformation.create-change-set.template-url',
49
'cloudformation.validate-template.template-url',
50
'cloudformation.estimate-template-cost.template-url',
51
'cloudformation.get-template-summary.template-url',
52
'cloudformation.create-stack.stack-policy-url',
53
'cloudformation.update-stack.stack-policy-url',
54
'cloudformation.set-stack-policy.stack-policy-url',
55
# aws cloudformation package --template-file
56
'custom.package.template-file',
57
# aws cloudformation deploy --template-file
58
'custom.deploy.template-file',
59
'cloudformation.update-stack.stack-policy-during-update-url',
60
'cloudformation.register-type.schema-handler-package',
61
# We will want to change the event name to ``s3`` as opposed to
62
# custom in the near future along with ``s3`` to ``s3api``.
63
'custom.cp.website-redirect',
64
'custom.mv.website-redirect',
65
'custom.sync.website-redirect',
66
'guardduty.create-ip-set.location',
67
'guardduty.update-ip-set.location',
68
'guardduty.create-threat-intel-set.location',
69
'guardduty.update-threat-intel-set.location',
70
'comprehend.detect-dominant-language.text',
71
'comprehend.batch-detect-dominant-language.text-list',
72
'comprehend.detect-entities.text',
73
'comprehend.batch-detect-entities.text-list',
74
'comprehend.detect-key-phrases.text',
75
'comprehend.batch-detect-key-phrases.text-list',
76
'comprehend.detect-sentiment.text',
77
'comprehend.batch-detect-sentiment.text-list',
78
'emr.create-studio.idp-auth-url',
79
'iam.create-open-id-connect-provider.url',
80
'machine-learning.predict.predict-endpoint',
81
'mediatailor.put-playback-configuration.ad-decision-server-url',
82
'mediatailor.put-playback-configuration.slate-ad-url',
83
'mediatailor.put-playback-configuration.video-content-source-url',
84
'rds.copy-db-cluster-snapshot.pre-signed-url',
85
'rds.create-db-cluster.pre-signed-url',
86
'rds.copy-db-snapshot.pre-signed-url',
87
'rds.create-db-instance-read-replica.pre-signed-url',
88
'sagemaker.create-notebook-instance.default-code-repository',
89
'sagemaker.create-notebook-instance.additional-code-repositories',
90
'sagemaker.update-notebook-instance.default-code-repository',
91
'sagemaker.update-notebook-instance.additional-code-repositories',
92
'serverlessapplicationrepository.create-application.home-page-url',
93
'serverlessapplicationrepository.create-application.license-url',
94
'serverlessapplicationrepository.create-application.readme-url',
95
'serverlessapplicationrepository.create-application.source-code-url',
96
'serverlessapplicationrepository.create-application.template-url',
97
'serverlessapplicationrepository.create-application-version.source-code-url',
98
'serverlessapplicationrepository.create-application-version.template-url',
99
'serverlessapplicationrepository.update-application.home-page-url',
100
'serverlessapplicationrepository.update-application.readme-url',
101
'service-catalog.create-product.support-url',
102
'service-catalog.update-product.support-url',
103
'ses.create-custom-verification-email-template.failure-redirection-url',
104
'ses.create-custom-verification-email-template.success-redirection-url',
105
'ses.put-account-details.website-url',
106
'ses.update-custom-verification-email-template.failure-redirection-url',
107
'ses.update-custom-verification-email-template.success-redirection-url',
108
'sqs.add-permission.queue-url',
109
'sqs.change-message-visibility.queue-url',
110
'sqs.change-message-visibility-batch.queue-url',
111
'sqs.delete-message.queue-url',
112
'sqs.delete-message-batch.queue-url',
113
'sqs.delete-queue.queue-url',
114
'sqs.get-queue-attributes.queue-url',
115
'sqs.list-dead-letter-source-queues.queue-url',
116
'sqs.receive-message.queue-url',
117
'sqs.remove-permission.queue-url',
118
'sqs.send-message.queue-url',
119
'sqs.send-message-batch.queue-url',
120
'sqs.set-queue-attributes.queue-url',
121
'sqs.purge-queue.queue-url',
122
'sqs.list-queue-tags.queue-url',
123
'sqs.tag-queue.queue-url',
124
'sqs.untag-queue.queue-url',
125
's3.copy-object.website-redirect-location',
126
's3.create-multipart-upload.website-redirect-location',
127
's3.put-object.website-redirect-location',
128
# Double check that this has been renamed!
129
'sns.subscribe.notification-endpoint',
130
'iot.create-job.document-source',
131
'translate.translate-text.text',
132
'workdocs.create-notification-subscription.notification-endpoint',
133
]
134
)
135
136
137
class ResourceLoadingError(Exception):
138
pass
139
140
141
def register_uri_param_handler(session, **kwargs):
142
prefix_map = copy.deepcopy(LOCAL_PREFIX_MAP)
143
try:
144
fetch_url = (
145
session.get_scoped_config().get('cli_follow_urlparam', 'true')
146
== 'true'
147
)
148
except ProfileNotFound:
149
# If a --profile is provided that does not exist, loading
150
# a value from get_scoped_config will crash the CLI.
151
# This function can be called as the first handler for
152
# the session-initialized event, which happens before a
153
# profile can be created, even if the command would have
154
# successfully created a profile. Instead of crashing here
155
# on a ProfileNotFound the CLI should just use 'none'.
156
fetch_url = True
157
158
if fetch_url:
159
prefix_map.update(REMOTE_PREFIX_MAP)
160
161
handler = URIArgumentHandler(prefix_map)
162
session.register('load-cli-arg', handler)
163
164
165
class URIArgumentHandler:
166
def __init__(self, prefixes=None):
167
if prefixes is None:
168
prefixes = copy.deepcopy(LOCAL_PREFIX_MAP)
169
prefixes.update(REMOTE_PREFIX_MAP)
170
self._prefixes = prefixes
171
172
def __call__(self, event_name, param, value, parsed_globals=None, **kwargs):
173
"""Handler that supports param values from URIs."""
174
cli_argument = param
175
qualified_param_name = '.'.join(event_name.split('.')[1:])
176
if qualified_param_name in PARAMFILE_DISABLED or getattr(
177
cli_argument, 'no_paramfile', None
178
):
179
return
180
else:
181
return self._check_for_uri_param(cli_argument, value, parsed_globals)
182
183
def _check_for_uri_param(self, param, value, parsed_globals):
184
if isinstance(value, list) and len(value) == 1:
185
value = value[0]
186
try:
187
param_file = get_paramfile(value, self._prefixes)
188
if param_file is not None and resolve_v2_debug_mode(parsed_globals):
189
print(
190
'\nAWS CLI v2 UPGRADE WARNING: For input parameters that '
191
'have a prefix of `http://` or `https://`, AWS CLI v2 '
192
'will not automatically request the content of the URL '
193
'for the parameter, and the `cli_follow_urlparam` option '
194
'has been removed. For guidance on how to adapt this '
195
'command to AWS CLI v2 usage, see '
196
'https://docs.aws.amazon.com/cli/latest/userguide/'
197
'cliv2-migration-changes.html'
198
'#cliv2-migration-paramfile.\n',
199
file=sys.stderr,
200
)
201
return param_file
202
except ResourceLoadingError as e:
203
raise argprocess.ParamError(param.cli_name, str(e))
204
205
206
def get_paramfile(path, cases):
207
"""Load parameter based on a resource URI.
208
209
It is possible to pass parameters to operations by referring
210
to files or URI's. If such a reference is detected, this
211
function attempts to retrieve the data from the file or URI
212
and returns it. If there are any errors or if the ``path``
213
does not appear to refer to a file or URI, a ``None`` is
214
returned.
215
216
:type path: str
217
:param path: The resource URI, e.g. file://foo.txt. This value
218
may also be a non resource URI, in which case ``None`` is returned.
219
220
:type cases: dict
221
:param cases: A dictionary of URI prefixes to function mappings
222
that a parameter is checked against.
223
224
:return: The loaded value associated with the resource URI.
225
If the provided ``path`` is not a resource URI, then a
226
value of ``None`` is returned.
227
228
"""
229
data = None
230
if isinstance(path, str):
231
for prefix, function_spec in cases.items():
232
if path.startswith(prefix):
233
function, kwargs = function_spec
234
data = function(prefix, path, **kwargs)
235
return data
236
237
238
def get_file(prefix, path, mode):
239
file_path = os.path.expandvars(os.path.expanduser(path[len(prefix) :]))
240
try:
241
with compat_open(file_path, mode) as f:
242
return f.read()
243
except UnicodeDecodeError:
244
raise ResourceLoadingError(
245
'Unable to load paramfile (%s), text contents could '
246
'not be decoded. If this is a binary file, please use the '
247
'fileb:// prefix instead of the file:// prefix.' % file_path
248
)
249
except OSError as e:
250
raise ResourceLoadingError(
251
f'Unable to load paramfile {path}: {e}'
252
)
253
254
255
def get_uri(prefix, uri):
256
try:
257
session = URLLib3Session()
258
r = session.send(AWSRequest('GET', uri).prepare())
259
if r.status_code == 200:
260
return r.text
261
else:
262
raise ResourceLoadingError(
263
f"received non 200 status code of {r.status_code}"
264
)
265
except Exception as e:
266
raise ResourceLoadingError('Unable to retrieve %s: %s' % (uri, e))
267
268
269
LOCAL_PREFIX_MAP = {
270
'file://': (get_file, {'mode': 'r'}),
271
'fileb://': (get_file, {'mode': 'rb'}),
272
}
273
274
275
REMOTE_PREFIX_MAP = {
276
'http://': (get_uri, {}),
277
'https://': (get_uri, {}),
278
}
279
280