Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/awscli/customizations/gamelift/uploadbuild.py
1567 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 threading
14
import contextlib
15
import os
16
import tempfile
17
import sys
18
import zipfile
19
20
from s3transfer import S3Transfer
21
22
from awscli.customizations.commands import BasicCommand
23
from awscli.customizations.s3.utils import human_readable_size
24
from awscli.utils import create_nested_client
25
26
27
class UploadBuildCommand(BasicCommand):
28
NAME = 'upload-build'
29
DESCRIPTION = 'Upload a new build to AWS GameLift.'
30
ARG_TABLE = [
31
{'name': 'name', 'required': True,
32
'help_text': 'The name of the build'},
33
{'name': 'build-version', 'required': True,
34
'help_text': 'The version of the build'},
35
{'name': 'build-root', 'required': True,
36
'help_text':
37
'The path to the directory containing the build to upload'},
38
{'name': 'server-sdk-version', 'required': False,
39
'help_text':
40
'The version of the GameLift server SDK used to '
41
'create the game server'},
42
{'name': 'operating-system', 'required': False,
43
'help_text': 'The operating system the build runs on'}
44
]
45
46
def _run_main(self, args, parsed_globals):
47
gamelift_client = create_nested_client(
48
self._session, 'gamelift', region_name=parsed_globals.region,
49
endpoint_url=parsed_globals.endpoint_url,
50
verify=parsed_globals.verify_ssl
51
)
52
# Validate a build directory
53
if not validate_directory(args.build_root):
54
sys.stderr.write(
55
'Fail to upload %s. '
56
'The build root directory is empty or does not exist.\n'
57
% (args.build_root)
58
)
59
60
return 255
61
# Create a build based on the operating system given.
62
create_build_kwargs = {
63
'Name': args.name,
64
'Version': args.build_version
65
}
66
if args.operating_system:
67
create_build_kwargs['OperatingSystem'] = args.operating_system
68
if args.server_sdk_version:
69
create_build_kwargs['ServerSdkVersion'] = args.server_sdk_version
70
response = gamelift_client.create_build(**create_build_kwargs)
71
build_id = response['Build']['BuildId']
72
73
# Retrieve a set of credentials and the s3 bucket and key.
74
response = gamelift_client.request_upload_credentials(
75
BuildId=build_id)
76
upload_credentials = response['UploadCredentials']
77
bucket = response['StorageLocation']['Bucket']
78
key = response['StorageLocation']['Key']
79
80
# Create the S3 Client for uploading the build based on the
81
# credentials returned from creating the build.
82
access_key = upload_credentials['AccessKeyId']
83
secret_key = upload_credentials['SecretAccessKey']
84
session_token = upload_credentials['SessionToken']
85
s3_client = create_nested_client(
86
self._session, 's3',
87
aws_access_key_id=access_key,
88
aws_secret_access_key=secret_key,
89
aws_session_token=session_token,
90
region_name=parsed_globals.region,
91
verify=parsed_globals.verify_ssl
92
)
93
94
s3_transfer_mgr = S3Transfer(s3_client)
95
96
try:
97
fd, temporary_zipfile = tempfile.mkstemp('%s.zip' % build_id)
98
zip_directory(temporary_zipfile, args.build_root)
99
s3_transfer_mgr.upload_file(
100
temporary_zipfile, bucket, key,
101
callback=ProgressPercentage(
102
temporary_zipfile,
103
label='Uploading ' + args.build_root + ':'
104
)
105
)
106
finally:
107
os.close(fd)
108
os.remove(temporary_zipfile)
109
110
sys.stdout.write(
111
'Successfully uploaded %s to AWS GameLift\n'
112
'Build ID: %s\n' % (args.build_root, build_id))
113
114
return 0
115
116
117
def zip_directory(zipfile_name, source_root):
118
source_root = os.path.abspath(source_root)
119
with open(zipfile_name, 'wb') as f:
120
zip_file = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED, True)
121
with contextlib.closing(zip_file) as zf:
122
for root, dirs, files in os.walk(source_root):
123
for filename in files:
124
full_path = os.path.join(root, filename)
125
relative_path = os.path.relpath(
126
full_path, source_root)
127
zf.write(full_path, relative_path)
128
129
130
def validate_directory(source_root):
131
# For Python26 on Windows, passing an empty string equates to the
132
# current directory, which is not intended behavior.
133
if not source_root:
134
return False
135
# We walk the root because we want to validate there's at least one file
136
# that exists recursively from the root directory
137
for path, dirs, files in os.walk(source_root):
138
if files:
139
return True
140
return False
141
142
143
# TODO: Remove this class once available to CLI from s3transfer
144
# docstring.
145
class ProgressPercentage(object):
146
def __init__(self, filename, label=None):
147
self._filename = filename
148
self._label = label
149
if self._label is None:
150
self._label = self._filename
151
self._size = float(os.path.getsize(filename))
152
self._seen_so_far = 0
153
self._lock = threading.Lock()
154
155
def __call__(self, bytes_amount):
156
with self._lock:
157
self._seen_so_far += bytes_amount
158
if self._size > 0:
159
percentage = (self._seen_so_far / self._size) * 100
160
sys.stdout.write(
161
"\r%s %s / %s (%.2f%%)" % (
162
self._label, human_readable_size(self._seen_so_far),
163
human_readable_size(self._size), percentage
164
)
165
)
166
sys.stdout.flush()
167
168