Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion awscli/customizations/gamelift/uploadbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@
class UploadBuildCommand(BasicCommand):
NAME = 'upload-build'
DESCRIPTION = 'Upload a new build to AWS GameLift.'
TAGS_SCHEMA = {
"type": "array",
"items": {
"type": "object",
"properties": {
"Key": {
"description": "The tag key.",
"type": "string",
"required": True
},
"Value": {
"description": "The tag value.",
"type": "string",
"required": True
}
}
}
}
ARG_TABLE = [
{'name': 'name', 'required': True,
'help_text': 'The name of the build'},
Expand All @@ -35,7 +53,18 @@ class UploadBuildCommand(BasicCommand):
'help_text':
'The path to the directory containing the build to upload'},
{'name': 'operating-system', 'required': False,
'help_text': 'The operating system the build runs on'}
'help_text': 'The operating system the build runs on'},
{
'name': 'tags',
'synopsis': '--tags <value>',
'required': False,
'nargs': '+',
'schema': TAGS_SCHEMA,
'help_text': (
'Optional. The list of key/value pairs to tag'
'instance.'
)
}
]

def _run_main(self, args, parsed_globals):
Expand All @@ -60,6 +89,18 @@ def _run_main(self, args, parsed_globals):
}
if args.operating_system:
create_build_kwargs['OperatingSystem'] = args.operating_system
if args.tags:
# Validate tags if available
if not validate_tags(args.tags):
sys.stderr.write(
'A maximum of 50 tags may be provided each containing a '
'"Key" property value between 1 and 128 UTF-8 Unicode '
'characters and a "Value" property value between 0 and '
'256 UTF-8 Unicode characters'
)

return 255
create_build_kwargs['Tags'] = args.tags

response = gamelift_client.create_build(**create_build_kwargs)
build_id = response['Build']['BuildId']
Expand Down Expand Up @@ -132,6 +173,17 @@ def validate_directory(source_root):
return True
return False

def validate_tags(tags):
if tags:
if len(tags) > 50:
return False
for tag in tags:
if len(tag['Key']) > 128:
return False
if len(tag['Value']) > 256:
return False
return True


# TODO: Remove this class once available to CLI from s3transfer
# docstring.
Expand Down
220 changes: 220 additions & 0 deletions tests/functional/gamelift/test_upload_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,226 @@ def test_upload_build_with_operating_system_param(self):
stdout)
self.assertIn('Build ID: myid', stdout)

def test_upload_build_with_tags_param(self):
self.files.create_file('tmpfile', 'Some contents')
cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
cmdline += ' --build-root %s' % self.files.rootdir
cmdline += ' --operating-system WINDOWS_2012'
cmdline += ' --tags Key=k1,Value=v1 Key=k2,Value=v2'

self.parsed_responses = [
{'Build': {'BuildId': 'myid'}},
{'StorageLocation': {
'Bucket': 'mybucket',
'Key': 'mykey'},
'UploadCredentials': {
'AccessKeyId': 'myaccesskey',
'SecretAccessKey': 'mysecretkey',
'SessionToken': 'mytoken'}},
{}
]

stdout, stderr, rc = self.run_cmd(cmdline, expected_rc=0)

# First the build is created.
self.assertEqual(len(self.operations_called), 3)
self.assertEqual(self.operations_called[0][0].name, 'CreateBuild')
self.assertEqual(
self.operations_called[0][1],
{'Name': 'mybuild', 'Version': 'myversion',
'OperatingSystem': 'WINDOWS_2012',
'Tags': [{'Key': 'k1', 'Value': 'v1'}, {'Key': 'k2', 'Value': 'v2'}]}
)

# Second the credentials are requested.
self.assertEqual(
self.operations_called[1][0].name, 'RequestUploadCredentials')
self.assertEqual(
self.operations_called[1][1], {'BuildId': 'myid'})

# The build is then uploaded to S3.
self.assertEqual(self.operations_called[2][0].name, 'PutObject')
self.assertEqual(
self.operations_called[2][1],
{'Body': mock.ANY, 'Bucket': 'mybucket', 'Key': 'mykey'}
)

# Check the output of the command.
self.assertIn(
'Successfully uploaded %s to AWS GameLift' % self.files.rootdir,
stdout)
self.assertIn('Build ID: myid', stdout)

def test_upload_build_with_tags_missing_key(self):
self.files.create_file('tmpfile', 'Some contents')
cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
cmdline += ' --build-root %s' % self.files.rootdir
cmdline += ' --operating-system WINDOWS_2012'
cmdline += ' --tags Miss=k1,Value=v1 Key=k2,Value=v2'

self.parsed_responses = [
{'Build': {'BuildId': 'myid'}},
{'StorageLocation': {
'Bucket': 'mybucket',
'Key': 'mykey'},
'UploadCredentials': {
'AccessKeyId': 'myaccesskey',
'SecretAccessKey': 'mysecretkey',
'SessionToken': 'mytoken'}},
{}
]

stdout, stderr, rc = self.run_cmd(cmdline, expected_rc=252)

self.assertIn(
'Missing required parameter in [0]: "Key"\n'
'Unknown parameter in [0]: "Miss", must be one of: Key, Value',
stderr)

def test_upload_build_with_tags_missing_value(self):
self.files.create_file('tmpfile', 'Some contents')
cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
cmdline += ' --build-root %s' % self.files.rootdir
cmdline += ' --operating-system WINDOWS_2012'
cmdline += ' --tags Key=k1,Miss=v1 Key=k2,Value=v2'

self.parsed_responses = [
{'Build': {'BuildId': 'myid'}},
{'StorageLocation': {
'Bucket': 'mybucket',
'Key': 'mykey'},
'UploadCredentials': {
'AccessKeyId': 'myaccesskey',
'SecretAccessKey': 'mysecretkey',
'SessionToken': 'mytoken'}},
{}
]

stdout, stderr, rc = self.run_cmd(cmdline, expected_rc=252)

self.assertIn(
'Missing required parameter in [0]: "Value"\n'
'Unknown parameter in [0]: "Miss", must be one of: Key, Value',
stderr)

def test_upload_build_with_tags_empty_key(self):
self.files.create_file('tmpfile', 'Some contents')
cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
cmdline += ' --build-root %s' % self.files.rootdir
cmdline += ' --operating-system WINDOWS_2012'
cmdline += ' --tags Key=,Value=v1 Key=k2,Value=v2'

self.parsed_responses = [
{'Build': {'BuildId': 'myid'}},
{'StorageLocation': {
'Bucket': 'mybucket',
'Key': 'mykey'},
'UploadCredentials': {
'AccessKeyId': 'myaccesskey',
'SecretAccessKey': 'mysecretkey',
'SessionToken': 'mytoken'}},
{}
]

stdout, stderr, rc = self.run_cmd(cmdline, expected_rc=252)

self.assertIn(
'Invalid length for parameter Tags[0].Key, value: 0, valid min '
'length: 1', stderr)

def test_upload_build_with_tags_long_key(self):
self.files.create_file('tmpfile', 'Some contents')
cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
cmdline += ' --build-root %s' % self.files.rootdir
cmdline += ' --operating-system WINDOWS_2012'
cmdline += ' --tags Key=' + ('k' * 129) + ',Value=v1 Key=k2,Value=v2'

self.parsed_responses = [
{'Build': {'BuildId': 'myid'}},
{'StorageLocation': {
'Bucket': 'mybucket',
'Key': 'mykey'},
'UploadCredentials': {
'AccessKeyId': 'myaccesskey',
'SecretAccessKey': 'mysecretkey',
'SessionToken': 'mytoken'}},
{}
]

stdout, stderr, rc = self.run_cmd(cmdline, expected_rc=255)

self.assertIn(
'A maximum of 50 tags may be provided each containing a "Key" '
'property value between 1 and 128 UTF-8 Unicode characters and a '
'"Value" property value between 0 and 256 UTF-8 Unicode '
'characters', stderr)

def test_upload_build_with_tags_long_value(self):
self.files.create_file('tmpfile', 'Some contents')
cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
cmdline += ' --build-root %s' % self.files.rootdir
cmdline += ' --operating-system WINDOWS_2012'
cmdline += ' --tags Key=k1,Value=' + ('v' * 257) + ' Key=k2,Value=v2'

self.parsed_responses = [
{'Build': {'BuildId': 'myid'}},
{'StorageLocation': {
'Bucket': 'mybucket',
'Key': 'mykey'},
'UploadCredentials': {
'AccessKeyId': 'myaccesskey',
'SecretAccessKey': 'mysecretkey',
'SessionToken': 'mytoken'}},
{}
]

stdout, stderr, rc = self.run_cmd(cmdline, expected_rc=255)

self.assertIn(
'A maximum of 50 tags may be provided each containing a "Key" '
'property value between 1 and 128 UTF-8 Unicode characters and a '
'"Value" property value between 0 and 256 UTF-8 Unicode '
'characters', stderr)

def test_upload_build_with_too_many_tags(self):
self.files.create_file('tmpfile', 'Some contents')

tags = [
'Key=k' + str(x) + ',Value=v' + str(x) for x in range(51)
]

cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
cmdline += ' --build-root %s' % self.files.rootdir
cmdline += ' --operating-system WINDOWS_2012'
cmdline += ' --tags %s' % ' '.join(tags)

self.parsed_responses = [
{'Build': {'BuildId': 'myid'}},
{'StorageLocation': {
'Bucket': 'mybucket',
'Key': 'mykey'},
'UploadCredentials': {
'AccessKeyId': 'myaccesskey',
'SecretAccessKey': 'mysecretkey',
'SessionToken': 'mytoken'}},
{}
]

stdout, stderr, rc = self.run_cmd(cmdline, expected_rc=255)

self.assertIn(
'A maximum of 50 tags may be provided each containing a "Key" '
'property value between 1 and 128 UTF-8 Unicode characters and a '
'"Value" property value between 0 and 256 UTF-8 Unicode '
'characters', stderr)

def test_upload_build_with_empty_directory(self):
cmdline = self.prefix
cmdline += ' --name mybuild --build-version myversion'
Expand Down
Loading