Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/awscli/customizations/awslambda.py
1566 views
1
# Copyright 2015 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 zipfile
14
import copy
15
from contextlib import closing
16
17
from awscli.arguments import CustomArgument, CLIArgument
18
from awscli.compat import BytesIO
19
20
21
ERROR_MSG = (
22
"--zip-file must be a zip file with the fileb:// prefix.\n"
23
"Example usage: --zip-file fileb://path/to/file.zip")
24
25
ZIP_DOCSTRING = (
26
'<p>The path to the zip file of the {param_type} you are uploading. '
27
'Specify --zip-file or --{param_type}, but not both. '
28
'Example: fileb://{param_type}.zip</p>'
29
)
30
31
32
def register_lambda_create_function(cli):
33
cli.register('building-argument-table.lambda.create-function',
34
ZipFileArgumentHoister('Code').hoist)
35
cli.register('building-argument-table.lambda.publish-layer-version',
36
ZipFileArgumentHoister('Content').hoist)
37
cli.register('building-argument-table.lambda.update-function-code',
38
_modify_zipfile_docstring)
39
cli.register('process-cli-arg.lambda.update-function-code',
40
validate_is_zip_file)
41
42
43
def validate_is_zip_file(cli_argument, value, **kwargs):
44
if cli_argument.name == 'zip-file':
45
_should_contain_zip_content(value)
46
47
48
class ZipFileArgumentHoister(object):
49
"""Hoists a ZipFile argument up to the top level.
50
51
Injects a top-level ZipFileArgument into the argument table which maps
52
a --zip-file parameter to the underlying ``serialized_name`` ZipFile
53
shape. Replaces the old ZipFile argument with an instance of
54
ReplacedZipFileArgument to prevent its usage and recommend the new
55
top-level injected parameter.
56
"""
57
def __init__(self, serialized_name):
58
self._serialized_name = serialized_name
59
self._name = serialized_name.lower()
60
61
def hoist(self, session, argument_table, **kwargs):
62
help_text = ZIP_DOCSTRING.format(param_type=self._name)
63
argument_table['zip-file'] = ZipFileArgument(
64
'zip-file', help_text=help_text, cli_type_name='blob',
65
serialized_name=self._serialized_name
66
)
67
argument = argument_table[self._name]
68
model = copy.deepcopy(argument.argument_model)
69
del model.members['ZipFile']
70
argument_table[self._name] = ReplacedZipFileArgument(
71
name=self._name,
72
argument_model=model,
73
operation_model=argument._operation_model,
74
is_required=False,
75
event_emitter=session.get_component('event_emitter'),
76
serialized_name=self._serialized_name,
77
)
78
79
80
def _modify_zipfile_docstring(session, argument_table, **kwargs):
81
if 'zip-file' in argument_table:
82
argument_table['zip-file'].documentation = ZIP_DOCSTRING
83
84
85
def _should_contain_zip_content(value):
86
if not isinstance(value, bytes):
87
# If it's not bytes it's basically impossible for
88
# this to be valid zip content, but we'll at least
89
# still try to load the contents as a zip file
90
# to be absolutely sure.
91
value = value.encode('utf-8')
92
fileobj = BytesIO(value)
93
try:
94
with closing(zipfile.ZipFile(fileobj)) as f:
95
f.infolist()
96
except zipfile.BadZipFile:
97
raise ValueError(ERROR_MSG)
98
99
100
class ZipFileArgument(CustomArgument):
101
"""A new ZipFile argument to be injected at the top level.
102
103
This class injects a ZipFile argument under the specified serialized_name
104
parameter. This can be used to take a top level parameter like --zip-file
105
and inject it into a nested different parameter like Code so
106
--zip-file foo.zip winds up being serialized as
107
{ 'Code': { 'ZipFile': <contents of foo.zip> } }.
108
"""
109
def __init__(self, *args, **kwargs):
110
self._param_to_replace = kwargs.pop('serialized_name')
111
super(ZipFileArgument, self).__init__(*args, **kwargs)
112
113
def add_to_params(self, parameters, value):
114
if value is None:
115
return
116
_should_contain_zip_content(value)
117
zip_file_param = {'ZipFile': value}
118
if parameters.get(self._param_to_replace):
119
parameters[self._param_to_replace].update(zip_file_param)
120
else:
121
parameters[self._param_to_replace] = zip_file_param
122
123
124
class ReplacedZipFileArgument(CLIArgument):
125
"""A replacement arugment for nested ZipFile argument.
126
127
This prevents the use of a non-working nested argument that expects binary.
128
Instead an instance of ZipFileArgument should be injected at the top level
129
and used instead. That way fileb:// can be used to load the binary
130
contents. And the argument class can inject those bytes into the correct
131
serialization name.
132
"""
133
def __init__(self, *args, **kwargs):
134
super(ReplacedZipFileArgument, self).__init__(*args, **kwargs)
135
self._cli_name = '--%s' % kwargs['name']
136
self._param_to_replace = kwargs['serialized_name']
137
138
def add_to_params(self, parameters, value):
139
if value is None:
140
return
141
unpacked = self._unpack_argument(value)
142
if 'ZipFile' in unpacked:
143
raise ValueError(
144
"ZipFile cannot be provided "
145
"as part of the %s argument. "
146
"Please use the '--zip-file' "
147
"option instead to specify a zip file." % self._cli_name)
148
if parameters.get(self._param_to_replace):
149
parameters[self._param_to_replace].update(unpacked)
150
else:
151
parameters[self._param_to_replace] = unpacked
152
153