Path: blob/develop/awscli/customizations/gamelift/uploadbuild.py
1567 views
# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.1#2# Licensed under the Apache License, Version 2.0 (the "License"). You3# may not use this file except in compliance with the License. A copy of4# the License is located at5#6# http://aws.amazon.com/apache2.0/7#8# or in the "license" file accompanying this file. This file is9# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF10# ANY KIND, either express or implied. See the License for the specific11# language governing permissions and limitations under the License.12import threading13import contextlib14import os15import tempfile16import sys17import zipfile1819from s3transfer import S3Transfer2021from awscli.customizations.commands import BasicCommand22from awscli.customizations.s3.utils import human_readable_size23from awscli.utils import create_nested_client242526class UploadBuildCommand(BasicCommand):27NAME = 'upload-build'28DESCRIPTION = 'Upload a new build to AWS GameLift.'29ARG_TABLE = [30{'name': 'name', 'required': True,31'help_text': 'The name of the build'},32{'name': 'build-version', 'required': True,33'help_text': 'The version of the build'},34{'name': 'build-root', 'required': True,35'help_text':36'The path to the directory containing the build to upload'},37{'name': 'server-sdk-version', 'required': False,38'help_text':39'The version of the GameLift server SDK used to '40'create the game server'},41{'name': 'operating-system', 'required': False,42'help_text': 'The operating system the build runs on'}43]4445def _run_main(self, args, parsed_globals):46gamelift_client = create_nested_client(47self._session, 'gamelift', region_name=parsed_globals.region,48endpoint_url=parsed_globals.endpoint_url,49verify=parsed_globals.verify_ssl50)51# Validate a build directory52if not validate_directory(args.build_root):53sys.stderr.write(54'Fail to upload %s. '55'The build root directory is empty or does not exist.\n'56% (args.build_root)57)5859return 25560# Create a build based on the operating system given.61create_build_kwargs = {62'Name': args.name,63'Version': args.build_version64}65if args.operating_system:66create_build_kwargs['OperatingSystem'] = args.operating_system67if args.server_sdk_version:68create_build_kwargs['ServerSdkVersion'] = args.server_sdk_version69response = gamelift_client.create_build(**create_build_kwargs)70build_id = response['Build']['BuildId']7172# Retrieve a set of credentials and the s3 bucket and key.73response = gamelift_client.request_upload_credentials(74BuildId=build_id)75upload_credentials = response['UploadCredentials']76bucket = response['StorageLocation']['Bucket']77key = response['StorageLocation']['Key']7879# Create the S3 Client for uploading the build based on the80# credentials returned from creating the build.81access_key = upload_credentials['AccessKeyId']82secret_key = upload_credentials['SecretAccessKey']83session_token = upload_credentials['SessionToken']84s3_client = create_nested_client(85self._session, 's3',86aws_access_key_id=access_key,87aws_secret_access_key=secret_key,88aws_session_token=session_token,89region_name=parsed_globals.region,90verify=parsed_globals.verify_ssl91)9293s3_transfer_mgr = S3Transfer(s3_client)9495try:96fd, temporary_zipfile = tempfile.mkstemp('%s.zip' % build_id)97zip_directory(temporary_zipfile, args.build_root)98s3_transfer_mgr.upload_file(99temporary_zipfile, bucket, key,100callback=ProgressPercentage(101temporary_zipfile,102label='Uploading ' + args.build_root + ':'103)104)105finally:106os.close(fd)107os.remove(temporary_zipfile)108109sys.stdout.write(110'Successfully uploaded %s to AWS GameLift\n'111'Build ID: %s\n' % (args.build_root, build_id))112113return 0114115116def zip_directory(zipfile_name, source_root):117source_root = os.path.abspath(source_root)118with open(zipfile_name, 'wb') as f:119zip_file = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED, True)120with contextlib.closing(zip_file) as zf:121for root, dirs, files in os.walk(source_root):122for filename in files:123full_path = os.path.join(root, filename)124relative_path = os.path.relpath(125full_path, source_root)126zf.write(full_path, relative_path)127128129def validate_directory(source_root):130# For Python26 on Windows, passing an empty string equates to the131# current directory, which is not intended behavior.132if not source_root:133return False134# We walk the root because we want to validate there's at least one file135# that exists recursively from the root directory136for path, dirs, files in os.walk(source_root):137if files:138return True139return False140141142# TODO: Remove this class once available to CLI from s3transfer143# docstring.144class ProgressPercentage(object):145def __init__(self, filename, label=None):146self._filename = filename147self._label = label148if self._label is None:149self._label = self._filename150self._size = float(os.path.getsize(filename))151self._seen_so_far = 0152self._lock = threading.Lock()153154def __call__(self, bytes_amount):155with self._lock:156self._seen_so_far += bytes_amount157if self._size > 0:158percentage = (self._seen_so_far / self._size) * 100159sys.stdout.write(160"\r%s %s / %s (%.2f%%)" % (161self._label, human_readable_size(self._seen_so_far),162human_readable_size(self._size), percentage163)164)165sys.stdout.flush()166167168