From ca35900011b2e5ace5aebd9fa11e25015a983520 Mon Sep 17 00:00:00 2001 From: Steve Houel Date: Fri, 30 Sep 2022 18:08:15 +0200 Subject: [PATCH 1/7] feat(gamelift): Adding Build L2 construct --- packages/@aws-cdk/aws-gamelift/README.md | 86 ++++-- packages/@aws-cdk/aws-gamelift/lib/build.ts | 191 ++++++++++++ packages/@aws-cdk/aws-gamelift/lib/content.ts | 109 +++++++ packages/@aws-cdk/aws-gamelift/lib/index.ts | 3 + packages/@aws-cdk/aws-gamelift/package.json | 35 ++- .../aws-gamelift/rosetta/default.ts-fixture | 16 + .../index.js | 1 + .../aws-gamelift-build.assets.json | 32 ++ .../aws-gamelift-build.template.json | 141 +++++++++ .../test/build.integ.snapshot/cdk.out | 1 + .../test/build.integ.snapshot/integ.json | 14 + .../test/build.integ.snapshot/manifest.json | 72 +++++ .../test/build.integ.snapshot/tree.json | 202 +++++++++++++ .../@aws-cdk/aws-gamelift/test/build.test.ts | 220 ++++++++++++++ .../aws-gamelift/test/content.test.ts | 280 ++++++++++++++++++ .../aws-gamelift/test/gamelift.test.ts | 6 - .../@aws-cdk/aws-gamelift/test/integ.build.ts | 13 + .../aws-gamelift/test/my-game-build.zip | Bin 0 -> 419 bytes 18 files changed, 1392 insertions(+), 30 deletions(-) create mode 100644 packages/@aws-cdk/aws-gamelift/lib/build.ts create mode 100644 packages/@aws-cdk/aws-gamelift/lib/content.ts create mode 100644 packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/index.js create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-gamelift/test/build.test.ts create mode 100644 packages/@aws-cdk/aws-gamelift/test/content.test.ts delete mode 100644 packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts create mode 100644 packages/@aws-cdk/aws-gamelift/test/integ.build.ts create mode 100644 packages/@aws-cdk/aws-gamelift/test/my-game-build.zip diff --git a/packages/@aws-cdk/aws-gamelift/README.md b/packages/@aws-cdk/aws-gamelift/README.md index 5cc87f2e9eafc..fe80f21acd5d2 100644 --- a/packages/@aws-cdk/aws-gamelift/README.md +++ b/packages/@aws-cdk/aws-gamelift/README.md @@ -9,31 +9,71 @@ > > [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib +![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) + +> The APIs of higher level constructs in this module are experimental and under active development. +> They are subject to non-backward compatible changes or removal in any future version. These are +> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be +> announced in the release notes. This means that while you may use them, you may need to update +> your source code when upgrading to a newer version of this package. + --- -This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. - -```ts nofixture -import * as gamelift from '@aws-cdk/aws-gamelift'; +[Amazon GameLift](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-intro.html) is a service used +to deploy, operate, and scale dedicated, low-cost servers in the cloud for session-based multiplayer games. Built +on AWS global computing infrastructure, GameLift helps deliver high-performance, high-reliability game servers +while dynamically scaling your resource usage to meet worldwide player demand. + +GameLift is composed of three main components: + +* GameLift FlexMatch which is a customizable matchmaking service for +multiplayer games. With FlexMatch, you can +build a custom set of rules that defines what a multiplayer match looks like +for your game, and determines how to +evaluate and select compatible players for each match. You can also customize +key aspects of the matchmaking +process to fit your game, including fine-tuning the matching algorithm. + +* GameLift hosting for custom or realtime servers which helps you deploy, +operate, and scale dedicated game servers. It regulates the resources needed to +host games, finds available game servers to host new game sessions, and puts +players into games. + +* GameLift FleetIQ to optimize the use of low-cost Amazon Elastic Compute Cloud +(Amazon EC2) Spot Instances for cloud-based game hosting. With GameLift +FleetIQ, you can work directly with your hosting resources in Amazon EC2 and +Amazon EC2 Auto Scaling while taking advantage of GameLift optimizations to +deliver inexpensive, resilient game hosting for your players + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. It allows you to define components for your matchmaking +configuration or game server fleet management system. + +## GameLift Hosting + +### Defining a GameLift Fleet + +GameLift helps you deploy, operate, and scale dedicated game servers for +session-based multiplayer games. It helps you regulate the resources needed to +host your games, finds available game servers to host new game sessions, and +puts players into games. + +### Creating a custom server build + +Your uploaded game servers are hosted on GameLift virtual computing resources, +called instances. You set up your hosting resources by creating a fleet of +instances and deploying them to run your game servers. You can design a fleet +to fit your game's needs. + +```ts +import * as gamelift from 'aws-cdk-lib/aws-gamelift'; + +// Build can be declared using either declarative version in the constructor +const build = new gamelift.Build(this, 'Build', { + content: new gamelift.Content.fromAsset(path.join(__dirname, "sample-asset-directory")) +}); + +// Either using dedicated factory static method +const build = gamelift.Build.fromBuildAsset(path.join(__dirname, 'CustomerGameServer/'); ``` - - - -There are no official hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. Here are some suggestions on how to proceed: - -- Search [Construct Hub for GameLift construct libraries](https://constructs.dev/search?q=gamelift) -- Use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, in the same way you would use [the CloudFormation AWS::GameLift resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GameLift.html) directly. - - - - -There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. -However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. - -For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::GameLift](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_GameLift.html). - -(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and submit an RFC if you are interested in contributing to this construct library.) - - diff --git a/packages/@aws-cdk/aws-gamelift/lib/build.ts b/packages/@aws-cdk/aws-gamelift/lib/build.ts new file mode 100644 index 0000000000000..783c43fd3cdf4 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/lib/build.ts @@ -0,0 +1,191 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as s3_assets from '@aws-cdk/aws-s3-assets'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; +import { Content } from './content'; +import { CfnBuild } from './gamelift.generated'; + +/** + * Represents a GameLift server build. + */ +export interface IBuild extends cdk.IResource, iam.IGrantable { + + /** + * The Identifier of the build. + * + * @attribute + */ + readonly buildId: string; +} + +/** + * Base class for new and imported GameLift server build. + */ +export abstract class BuildBase extends cdk.Resource implements IBuild { + /** + * The Identifier of the build. + */ + public abstract readonly buildId: string; + + public abstract readonly grantPrincipal: iam.IPrincipal; +} + +/** + * The operating system that the game server binaries are built to run on. + */ +export enum OperatingSystem { + AMAZON_LINUX = 'AMAZON_LINUX', + AMAZON_LINUX_2 = 'AMAZON_LINUX_2', + WINDOWS_2012 = 'WINDOWS_2012' +} + + +/** + * Represents a Build content defined outside of this stack. + */ +export interface BuildAttributes { + /** + * The identifier of the build + */ + readonly buildId: string; + /** + * The IAM role assumed by GameLift to access server build in S3. + * @default - undefined + */ + readonly role?: iam.IRole; +} + +/** + * Properties for a new build + */ +export interface BuildProps { + /** + * Name of this build + * + * @default No name + */ + readonly buildName?: string; + + /** + * Version of this build + * + * @default No version + */ + readonly buildVersion?: string; + + /** + * The operating system that the game server binaries are built to run on. + * + * @default No version + */ + readonly operatingSystem?: OperatingSystem; + + /** + * The game build file storage + */ + readonly content: Content; + + /** + * The IAM role assumed by GameLift to access server build in S3. + * If providing a custom role, it needs to trust the GameLift service principal (gamelift.amazonaws.com) and be granted sufficient permissions. + * + * @see https://docs.aws.amazon.com/gamelift/latest/developerguide/security_iam_id-based-policy-examples.html#security_iam_id-based-policy-examples-access-storage-loc + * + * @default - a role will be created with default permissions. + */ + readonly role?: iam.IRole; +} + +/** + * Create a GameLift server build + * + * @resource AWS::GameLift::Build + */ +export class Build extends BuildBase { + + /** + * Create a new Build from s3 content + */ + static fromBucket(scope: Construct, id: string, bucket: s3.IBucket, key: string, objectVersion?: string) { + return new Build(scope, id, { + content: Content.fromBucket(bucket, key, objectVersion), + }); + } + + /** + * Create a new Build from asset content + */ + static fromAsset(scope: Construct, id: string, path: string, options?: s3_assets.AssetOptions) { + return new Build(scope, id, { + content: Content.fromAsset(path, options), + }); + } + + /** + * Import a build into CDK using its identifier + */ + static fromBuildId(scope: Construct, id: string, buildId: string): IBuild { + return this.fromBuildAttributes(scope, id, { buildId }); + } + + /** + * Import an existing build from its attributes. + */ + static fromBuildAttributes(scope: Construct, id: string, attrs: BuildAttributes): IBuild { + class Import extends BuildBase { + public readonly buildId = attrs.buildId; + public readonly grantPrincipal = attrs.role ?? new iam.UnknownPrincipal({ resource: this }); + } + + return new Import(scope, id); + } + + /** + * The Identifier of the build. + */ + public readonly buildId: string; + + /** + * The IAM role GameLift assumes to acccess server build content. + */ + public readonly role: iam.IRole; + + /** + * The principal this GameLift Build is using. + */ + public readonly grantPrincipal: iam.IPrincipal; + + constructor(scope: Construct, id: string, props: BuildProps) { + super(scope, id, { + physicalName: props.buildName, + }); + + if (props.buildName) { + if (props.buildName.length > 1024) { + throw new Error(`Build name can not be longer than 1024 characters but has ${props.buildName.length} characters.`); + } + } + this.role = props.role ?? new iam.Role(this, 'ServiceRole', { + assumedBy: new iam.ServicePrincipal('gamelift.amazonaws.com'), + }); + this.grantPrincipal = this.role; + const content = props.content.bind(this, this.role); + + const resource = new CfnBuild(this, 'Resource', { + name: props.buildName, + version: props.buildVersion, + operatingSystem: props.operatingSystem, + storageLocation: { + bucket: content.s3Location && content.s3Location.bucketName, + key: content.s3Location && content.s3Location.objectKey, + objectVersion: content.s3Location && content.s3Location.objectVersion, + roleArn: this.role.roleArn, + }, + }); + + this.buildId = resource.ref; + } + + +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/lib/content.ts b/packages/@aws-cdk/aws-gamelift/lib/content.ts new file mode 100644 index 0000000000000..e68f3eeebebfb --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/lib/content.ts @@ -0,0 +1,109 @@ +import * as iam from '@aws-cdk/aws-iam'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as s3_assets from '@aws-cdk/aws-s3-assets'; +import * as cdk from '@aws-cdk/core'; +import { Construct } from 'constructs'; + +/** + * Represents a server content. + */ +export abstract class Content { + /** + * Game content as an S3 object. + * @param bucket The S3 bucket + * @param key The object key + * @param objectVersion Optional S3 ob ject version + */ + public static fromBucket(bucket: s3.IBucket, key: string, objectVersion?: string): S3Content { + return new S3Content(bucket, key, objectVersion); + } + + + /** + * Loads the game content from a local disk path. + * + * @param path Either a directory with the game content bundle or a .zip file + */ + public static fromAsset(path: string, options?: s3_assets.AssetOptions): AssetContent { + return new AssetContent(path, options); + } + + /** + * Called when the Build is initialized to allow this object to bind + */ + public abstract bind(scope: Construct, grantable: iam.IGrantable): ContentConfig; + +} + +/** + * Result of binding `Content` into a `Build`. + */ +export interface ContentConfig { + /** + * The location of the content in S3. + */ + readonly s3Location: s3.Location; +} + +/** + * Game content from an S3 archive. + */ +export class S3Content extends Content { + + constructor(private readonly bucket: s3.IBucket, private key: string, private objectVersion?: string) { + super(); + if (!bucket.bucketName) { + throw new Error('bucketName is undefined for the provided bucket'); + } + } + + public bind(_scope: Construct, grantable: iam.IGrantable): ContentConfig { + this.bucket.grantRead(grantable, this.key); + return { + s3Location: { + bucketName: this.bucket.bucketName, + objectKey: this.key, + objectVersion: this.objectVersion, + }, + }; + } +} + +/** + * Game content from a local directory. + */ +export class AssetContent extends Content { + private asset?: s3_assets.Asset; + + /** + * @param path The path to the asset file or directory. + */ + constructor(public readonly path: string, private readonly options: s3_assets.AssetOptions = { }) { + super(); + } + + public bind(scope: Construct, grantable: iam.IGrantable): ContentConfig { + // If the same AssetContent is used multiple times, retain only the first instantiation. + if (!this.asset) { + this.asset = new s3_assets.Asset(scope, 'Content', { + path: this.path, + ...this.options, + }); + } else if (cdk.Stack.of(this.asset) !== cdk.Stack.of(scope)) { + throw new Error(`Asset is already associated with another stack '${cdk.Stack.of(this.asset).stackName}'. ` + + 'Create a new Content instance for every stack.'); + } + this.asset.grantRead(grantable); + + if (!this.asset.isZipArchive) { + throw new Error(`Asset must be a .zip file or a directory (${this.path})`); + } + + return { + s3Location: { + bucketName: this.asset.s3BucketName, + objectKey: this.asset.s3ObjectKey, + }, + }; + } +} diff --git a/packages/@aws-cdk/aws-gamelift/lib/index.ts b/packages/@aws-cdk/aws-gamelift/lib/index.ts index 843bf2236645e..cf989967b922d 100644 --- a/packages/@aws-cdk/aws-gamelift/lib/index.ts +++ b/packages/@aws-cdk/aws-gamelift/lib/index.ts @@ -1,2 +1,5 @@ +export * from './content'; +export * from './build'; + // AWS::GameLift CloudFormation Resources: export * from './gamelift.generated'; diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index 19f96730ef99e..d466a978537c1 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -81,25 +81,58 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/integ-tests": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", + "@aws-cdk/integ-runner": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", + "@aws-cdk/cfnspec": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^27.5.2" }, "dependencies": { "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/region-info": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^10.0.0" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", + "@aws-cdk/aws-events": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", + "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", + "@aws-cdk/aws-s3": "0.0.0", + "@aws-cdk/aws-s3-assets": "0.0.0", + "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/core": "0.0.0", + "@aws-cdk/region-info": "0.0.0", + "@aws-cdk/cx-api": "0.0.0", "constructs": "^10.0.0" }, "engines": { "node": ">= 14.15.0" }, + "awslint": { + "exclude": [ + "docs-public-apis:@aws-cdk/aws-gamelift.OperatingSystem.AMAZON_LINUX", + "docs-public-apis:@aws-cdk/aws-gamelift.OperatingSystem.AMAZON_LINUX_2", + "docs-public-apis:@aws-cdk/aws-gamelift.OperatingSystem.WINDOWS_2012" + ] + }, "stability": "experimental", - "maturity": "cfn-only", + "maturity": "experimental", "awscdkio": { "announce": false }, diff --git a/packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture b/packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture new file mode 100644 index 0000000000000..4a4c332becb50 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/rosetta/default.ts-fixture @@ -0,0 +1,16 @@ +// Fixture with packages imported, but nothing else +import { Construct } from 'constructs'; +import { Duration, Size, Stack } from '@aws-cdk/core'; +import * as gamelift from '@aws-cdk/aws-gamelift'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as kms from '@aws-cdk/aws-kms'; +import * as iam from '@aws-cdk/aws-iam'; +import * as path from 'path'; + +class Fixture extends Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + + /// here + } +} diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/index.js b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/index.js new file mode 100644 index 0000000000000..73c02658c48d9 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/index.js @@ -0,0 +1 @@ +console.log('Hello World'); \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json new file mode 100644 index 0000000000000..e083fe082a1ea --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json @@ -0,0 +1,32 @@ +{ + "version": "20.0.0", + "files": { + "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7": { + "source": { + "path": "asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "9c561e93c7a2947a15dba683670660e922cf493e17b2a6f8ca03cf221442c222": { + "source": { + "path": "aws-gamelift-build.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "9c561e93c7a2947a15dba683670660e922cf493e17b2a6f8ca03cf221442c222.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json new file mode 100644 index 0000000000000..0b9884f4cb0ec --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json @@ -0,0 +1,141 @@ +{ + "Resources": { + "BuildServiceRole1F57E904": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "gamelift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "BuildServiceRoleDefaultPolicyCB7101C6": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" + } + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "BuildServiceRoleDefaultPolicyCB7101C6", + "Roles": [ + { + "Ref": "BuildServiceRole1F57E904" + } + ] + } + }, + "Build45A36621": { + "Type": "AWS::GameLift::Build", + "Properties": { + "StorageLocation": { + "Bucket": { + "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" + }, + "Key": { + "Fn::Join": [ + "", + [ + { + "Fn::Select": [ + 0, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC" + } + ] + } + ] + }, + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "||", + { + "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC" + } + ] + } + ] + } + ] + ] + }, + "RoleArn": { + "Fn::GetAtt": [ + "BuildServiceRole1F57E904", + "Arn" + ] + } + } + } + } + }, + "Parameters": { + "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645": { + "Type": "String", + "Description": "S3 bucket for asset \"6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7\"" + }, + "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC": { + "Type": "String", + "Description": "S3 key for asset version \"6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7\"" + }, + "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7ArtifactHashFA16AACF": { + "Type": "String", + "Description": "Artifact hash for asset \"6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7\"" + } + } + } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..588d7b269d34f --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"20.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json new file mode 100644 index 0000000000000..624315dd9870e --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "version": "20.0.0", + "testCases": { + "@aws-cdk/aws-gamelift/test/integ.build": { + "stacks": [ + "aws-gamelift-build" + ], + "diffAssets": false, + "stackUpdateWorkflow": true + } + }, + "synthContext": {}, + "enableLookups": false +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..c56a6eec3e0ef --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json @@ -0,0 +1,72 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-gamelift-build": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-gamelift-build.template.json", + "validateOnSynth": false + }, + "metadata": { + "/aws-gamelift-build": [ + { + "type": "aws:cdk:asset", + "data": { + "path": "asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7", + "id": "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7", + "packaging": "zip", + "sourceHash": "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7", + "s3BucketParameter": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645", + "s3KeyParameter": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC", + "artifactHashParameter": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7ArtifactHashFA16AACF" + } + } + ], + "/aws-gamelift-build/Build/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BuildServiceRole1F57E904" + } + ], + "/aws-gamelift-build/Build/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BuildServiceRoleDefaultPolicyCB7101C6" + } + ], + "/aws-gamelift-build/Build/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Build45A36621" + } + ], + "/aws-gamelift-build/AssetParameters/6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/S3Bucket": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" + } + ], + "/aws-gamelift-build/AssetParameters/6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/S3VersionKey": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC" + } + ], + "/aws-gamelift-build/AssetParameters/6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/ArtifactHash": [ + { + "type": "aws:cdk:logicalId", + "data": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7ArtifactHashFA16AACF" + } + ] + }, + "displayName": "aws-gamelift-build" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/tree.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/tree.json new file mode 100644 index 0000000000000..96d14a552e490 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/tree.json @@ -0,0 +1,202 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.33" + } + }, + "build-test-assets": { + "id": "build-test-assets", + "path": "build-test-assets", + "children": { + "Build": { + "id": "Build", + "path": "build-test-assets/Build", + "children": { + "Service Role": { + "id": "Service Role", + "path": "build-test-assets/Build/Service Role", + "children": { + "Resource": { + "id": "Resource", + "path": "build-test-assets/Build/Service Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "gamelift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "build-test-assets/Build/Service Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "build-test-assets/Build/Service Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetObject*", + "s3:GetBucket*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + } + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "BuildServiceRoleDefaultPolicy90803718", + "roles": [ + { + "Ref": "BuildServiceRole4643E19E" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Content": { + "id": "Content", + "path": "build-test-assets/Build/Content", + "children": { + "Stage": { + "id": "Stage", + "path": "build-test-assets/Build/Content/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "build-test-assets/Build/Content/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "build-test-assets/Build/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::GameLift::Build", + "aws:cdk:cloudformation:props": { + "storageLocation": { + "bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "key": "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7.zip", + "roleArn": { + "Fn::GetAtt": [ + "BuildServiceRole4643E19E", + "Arn" + ] + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.CfnBuild", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-gamelift.Build", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.test.ts b/packages/@aws-cdk/aws-gamelift/test/build.test.ts new file mode 100644 index 0000000000000..33f71b171049c --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/build.test.ts @@ -0,0 +1,220 @@ +import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as gamelift from '../lib'; + +describe('build', () => { + const buildId = 'test-identifier'; + const buildName = 'test-build'; + let stack: cdk.Stack; + + beforeEach(() => { + const app = new cdk.App({ context: { [cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: false } }); + stack = new cdk.Stack(app); + }); + + describe('.fromBuildId()', () => { + test('with required fields', () => { + const build = gamelift.Build.fromBuildId(stack, 'ImportedBuild', buildId); + + expect(build.buildId).toEqual(buildId); + expect(build.grantPrincipal).toEqual(new iam.UnknownPrincipal({ resource: build })); + }); + }); + + describe('.fromBuildAttributes()', () => { + test('with required attrs only', () => { + const build = gamelift.Build.fromBuildAttributes(stack, 'ImportedBuild', { buildId }); + + expect(build.buildId).toEqual(buildId); + expect(build.grantPrincipal).toEqual(new iam.UnknownPrincipal({ resource: build })); + }); + + test('with all attrs', () => { + const role = iam.Role.fromRoleArn(stack, 'Role', 'arn:aws:iam::123456789012:role/TestRole'); + const build = gamelift.Build.fromBuildAttributes(stack, 'ImportedBuild', { buildId, role }); + + expect(buildId).toEqual(buildId); + expect(build.grantPrincipal).toEqual(role); + }); + }); + + describe('new', () => { + const localAsset = path.join(__dirname, 'my-game-build'); + const contentBucketName = 'bucketname'; + const contentBucketAccessStatement = { + Action: [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + ], + Effect: 'Allow', + Resource: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + `:s3:::${contentBucketName}`, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + `:s3:::${contentBucketName}/content`, + ], + ], + }, + ], + }; + let contentBucket: s3.IBucket; + let content: gamelift.Content; + let build: gamelift.Build; + let defaultProps: gamelift.BuildProps; + + beforeEach(() => { + contentBucket = s3.Bucket.fromBucketName(stack, 'ContentBucket', contentBucketName); + content = gamelift.Content.fromBucket(contentBucket, 'content'); + defaultProps = { + content, + }; + }); + + describe('.fromAsset()', () => { + test('should create a new build from asset', () => { + build = gamelift.Build.fromAsset(stack, 'ImportedBuild', localAsset); + + expect(stack.node.metadata.find(m => m.type === 'aws:cdk:asset')).toBeDefined(); + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation: { + Bucket: { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket72AA8348', + }, + }, + }); + + }); + }); + + describe('.fromBucket()', () => { + test('should create a new build from bucket', () => { + build = gamelift.Build.fromBucket(stack, 'ImportedBuild', contentBucket, 'content'); + + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation: { + Bucket: 'bucketname', + Key: 'content', + }, + }); + + }); + }); + + describe('with necessary props only', () => { + beforeEach(() => { + build = new gamelift.Build(stack, 'Build', defaultProps); + }); + + test('should create a role and use it with the build', () => { + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { + Service: 'gamelift.amazonaws.com', + }, + }, + ], + Version: '2012-10-17', + }, + }); + + // Role policy should grant reading from the assets bucket + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + contentBucketAccessStatement, + ], + }, + Roles: [ + { + Ref: 'BuildServiceRole1F57E904', + }, + ], + }); + + // check the build using the role + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation: { + Bucket: 'bucketname', + Key: 'content', + RoleArn: { + 'Fn::GetAtt': [ + 'BuildServiceRole1F57E904', + 'Arn', + ], + }, + }, + }); + }); + + test('should return correct buildId from CloudFormation', () => { + expect(stack.resolve(build.buildId)).toEqual({ Ref: 'Build45A36621' }); + }); + + test('with a custom role should use it and set it in CloudFormation', () => { + const role = iam.Role.fromRoleArn(stack, 'Role', 'arn:aws:iam::123456789012:role/TestRole'); + build = new gamelift.Build(stack, 'BuildWithRole', { + ...defaultProps, + role, + }); + + expect(build.grantPrincipal).toEqual(role); + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation: { + RoleArn: role.roleArn, + }, + }); + }); + + test('with a custom buildName should set it in CloudFormation', () => { + build = new gamelift.Build(stack, 'BuildWithName', { + ...defaultProps, + buildName: buildName, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + Name: buildName, + }); + }); + + test('with an incorrect buildName (>1024)', () => { + let incorrectBuildName = ''; + for (let i = 0; i < 1025; i++) { + incorrectBuildName += 'A'; + } + + expect(() => new gamelift.Build(stack, 'BuildWithWrongName', { + content, + buildName: incorrectBuildName, + })).toThrow(/Build name can not be longer than 1024 characters but has 1025 characters./); + }); + }); + }); +}); + + diff --git a/packages/@aws-cdk/aws-gamelift/test/content.test.ts b/packages/@aws-cdk/aws-gamelift/test/content.test.ts new file mode 100644 index 0000000000000..0c1f6e0617121 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/content.test.ts @@ -0,0 +1,280 @@ +import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as cxapi from '@aws-cdk/cx-api'; +import * as gamelift from '../lib'; + +describe('Code', () => { + let stack: cdk.Stack; + let content: gamelift.Content; + + beforeEach(() => { + const app = new cdk.App({ context: { [cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: false } }); + stack = new cdk.Stack(app, 'Stack'); + }); + + describe('.fromBucket()', () => { + const key = 'content'; + let bucket: s3.IBucket; + + test('with valid bucket name and key and bound by build sets the right path and grants the build permissions to read from it', () => { + bucket = s3.Bucket.fromBucketName(stack, 'Bucket', 'bucketname'); + content = gamelift.Content.fromBucket(bucket, key); + new gamelift.Build(stack, 'Build1', { + content: content, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation: { + Bucket: 'bucketname', + Key: 'content', + }, + }); + + // Role policy should grant reading from the assets bucket + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + ], + Effect: 'Allow', + Resource: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::bucketname', + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::bucketname/content', + ], + ], + }, + ], + }, + ], + }, + Roles: [ + { + Ref: 'Build1ServiceRole24FABCB7', + }, + ], + }); + }); + }); + + describe('.fromAsset()', () => { + const directoryPath = path.join(__dirname, 'my-game-build'); + + beforeEach(() => { + content = gamelift.Content.fromAsset(directoryPath); + }); + + test("with valid and existing file path and bound to job sets job's script location and permissions stack metadata", () => { + new gamelift.Build(stack, 'Build1', { + content: content, + }); + + expect(stack.node.metadata.find(m => m.type === 'aws:cdk:asset')).toBeDefined(); + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation: { + Bucket: { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket72AA8348', + }, + Key: { + 'Fn::Join': [ + '', + [ + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey720D3160', + }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey720D3160', + }, + ], + }, + ], + }, + ], + ], + }, + RoleArn: { + 'Fn::GetAtt': [ + 'Build1ServiceRole24FABCB7', + 'Arn', + ], + }, + }, + }); + // Role policy should grant reading from the assets bucket + Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: [ + 's3:GetObject*', + 's3:GetBucket*', + 's3:List*', + ], + Effect: 'Allow', + Resource: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', + { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket72AA8348', + }, + ], + ], + }, + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':s3:::', + { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket72AA8348', + }, + '/*', + ], + ], + }, + ], + }, + ], + }, + Roles: [ + { + Ref: 'Build1ServiceRole24FABCB7', + }, + ], + }); + }); + + test('with an unsupported file path throws', () => { + // GIVEN + const fileAsset = gamelift.Content.fromAsset(path.join(__dirname, 'my-game-build', 'index.js')); + + // THEN + expect(() => new gamelift.Build(stack, 'Build1', { content: fileAsset })) + .toThrow(/Asset must be a \.zip file or a directory/); + }); + + test('used in more than 1 build in the same stack should be reused', () => { + new gamelift.Build(stack, 'Build1', { + content: content, + }); + new gamelift.Build(stack, 'Build2', { + content: content, + }); + const StorageLocation = { + Bucket: { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket72AA8348', + }, + Key: { + 'Fn::Join': [ + '', + [ + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey720D3160', + }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { + Ref: 'AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey720D3160', + }, + ], + }, + ], + }, + ], + ], + }, + RoleArn: { + 'Fn::GetAtt': [ + 'Build1ServiceRole24FABCB7', + 'Arn', + ], + }, + }; + + expect(stack.node.metadata.find(m => m.type === 'aws:cdk:asset')).toBeDefined(); + // Job1 and Job2 use reuse the asset + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation, + }); + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + StorageLocation, + }); + }); + + test('throws if trying to rebind in another stack', () => { + new gamelift.Build(stack, 'Build1', { + content, + }); + const differentStack = new cdk.Stack(); + + expect(() => new gamelift.Build(differentStack, 'Build2', { + content, + })).toThrow(/Asset is already associated with another stack/); + }); + }); +}); diff --git a/packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts b/packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts deleted file mode 100644 index 465c7bdea0693..0000000000000 --- a/packages/@aws-cdk/aws-gamelift/test/gamelift.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@aws-cdk/assertions'; -import {} from '../lib'; - -test('No tests are specified for this package', () => { - expect(true).toBe(true); -}); diff --git a/packages/@aws-cdk/aws-gamelift/test/integ.build.ts b/packages/@aws-cdk/aws-gamelift/test/integ.build.ts new file mode 100644 index 0000000000000..d216cbccd9212 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/integ.build.ts @@ -0,0 +1,13 @@ +import * as path from 'path'; +import * as cdk from '@aws-cdk/core'; +import * as gamelift from '../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-gamelift-build'); + +new gamelift.Build(stack, 'Build', { + content: gamelift.Content.fromAsset(path.join(__dirname, 'my-game-build')), +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-gamelift/test/my-game-build.zip b/packages/@aws-cdk/aws-gamelift/test/my-game-build.zip new file mode 100644 index 0000000000000000000000000000000000000000..4a13be08c2721f5ebc49f7a00b844dd5ec909d5e GIT binary patch literal 419 zcmWIWW@Zs#0D+~wwxM7Kl;C4fV92f1O;5~C)lDkR%t_G?4dG>AZ{KU0+yTTOy0n6u zfsy40BLf52i~z7%91I)`E0N5S2AU^^VOC~dN@|5(Rx#MjexO+sffz)indyD*y!N^C zo>xzw^uHeP-Q(=Zli?ia^-p;QUf;sT5a7+u@kLl-yDZQOkTn6`j7%cTxV;1Q8N*vg q5Q|jLLCl7E57}Oj_h4X2qYsAJ#CkTso0Sb@4igX_0Mchc90mXZ_+Z)q literal 0 HcmV?d00001 From b9fc99de015d6187e0799134b1f28020f3f513c7 Mon Sep 17 00:00:00 2001 From: Steve Houel Date: Fri, 30 Sep 2022 19:24:35 +0200 Subject: [PATCH 2/7] Adding missing file ignored by gitignore --- packages/@aws-cdk/aws-gamelift/.gitignore | 3 +++ packages/@aws-cdk/aws-gamelift/test/my-game-build/index.js | 1 + 2 files changed, 4 insertions(+) create mode 100644 packages/@aws-cdk/aws-gamelift/test/my-game-build/index.js diff --git a/packages/@aws-cdk/aws-gamelift/.gitignore b/packages/@aws-cdk/aws-gamelift/.gitignore index 6d05bba61dfa7..ff82c8959aad2 100644 --- a/packages/@aws-cdk/aws-gamelift/.gitignore +++ b/packages/@aws-cdk/aws-gamelift/.gitignore @@ -21,3 +21,6 @@ junit.xml !**/*.integ.snapshot/**/asset.*/*.d.ts !**/*.integ.snapshot/**/asset.*/** + +#include game build js file +!test/my-game-build/*.js diff --git a/packages/@aws-cdk/aws-gamelift/test/my-game-build/index.js b/packages/@aws-cdk/aws-gamelift/test/my-game-build/index.js new file mode 100644 index 0000000000000..73c02658c48d9 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/test/my-game-build/index.js @@ -0,0 +1 @@ +console.log('Hello World'); \ No newline at end of file From e2cb700aaac21e2c37a3be5fcf9ea28538d698d4 Mon Sep 17 00:00:00 2001 From: Steve Houel Date: Mon, 3 Oct 2022 12:18:27 +0200 Subject: [PATCH 3/7] Improve code documentation for Build and Content ressource Improve README documentation on game Build ressource. --- packages/@aws-cdk/aws-gamelift/README.md | 27 +++++++++++++++---- packages/@aws-cdk/aws-gamelift/lib/build.ts | 23 +++++++++++++--- packages/@aws-cdk/aws-gamelift/lib/content.ts | 3 ++- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk/aws-gamelift/README.md b/packages/@aws-cdk/aws-gamelift/README.md index fe80f21acd5d2..f8ffbff67a5c8 100644 --- a/packages/@aws-cdk/aws-gamelift/README.md +++ b/packages/@aws-cdk/aws-gamelift/README.md @@ -59,12 +59,29 @@ session-based multiplayer games. It helps you regulate the resources needed to host your games, finds available game servers to host new game sessions, and puts players into games. -### Creating a custom server build +### Uploading builds and scripts to GameLift -Your uploaded game servers are hosted on GameLift virtual computing resources, -called instances. You set up your hosting resources by creating a fleet of -instances and deploying them to run your game servers. You can design a fleet -to fit your game's needs. +Before deploying your GameLift-enabled multiplayer game servers for hosting with the GameLift service, you need to upload +your game server files. This section provide guidance on preparing and uploading custom game server build +files or Realtime Servers server script files. When you upload files, you create a GameLift build or script resource, which +you then deploy on fleets of hosting resources. + +### Upload a custom server build to GameLift + +Before uploading your configured game server to GameLift for hosting, package the game build files into a build directory. +This directory must include all components required to run your game servers and host game sessions, including the following: + +* Game server binaries – The binary files required to run the game server. A build can include binaries for multiple game +servers built to run on the same platform. For a list of supported platforms, see Download Amazon GameLift SDKs. + +* Dependencies – Any dependent files that your game server executables require to run. Examples include assets, configuration +files, and dependent libraries. + +* Install script – A script file to handle tasks that are required to fully install your game build on GameLift hosting +servers. Place this file at the root of the build directory. GameLift runs the install script as part of fleet creation. + +You can set up any application in your build, including your install script, to access your resources securely on other AWS +services. ```ts import * as gamelift from 'aws-cdk-lib/aws-gamelift'; diff --git a/packages/@aws-cdk/aws-gamelift/lib/build.ts b/packages/@aws-cdk/aws-gamelift/lib/build.ts index 783c43fd3cdf4..f017ff0b8221d 100644 --- a/packages/@aws-cdk/aws-gamelift/lib/build.ts +++ b/packages/@aws-cdk/aws-gamelift/lib/build.ts @@ -88,7 +88,20 @@ export interface BuildProps { /** * The IAM role assumed by GameLift to access server build in S3. - * If providing a custom role, it needs to trust the GameLift service principal (gamelift.amazonaws.com) and be granted sufficient permissions. + * If providing a custom role, it needs to trust the GameLift service principal (gamelift.amazonaws.com) and be granted sufficient permissions + * to have Read access to a specific key content into a specific S3 bucket. + * Below an example of required permission: + * { + * "Version": "2012-10-17", + * "Statement": [{ + * "Effect": "Allow", + * "Action": [ + * "s3:GetObject", + * "s3:GetObjectVersion" + * ], + * "Resource": "arn:aws:s3:::bucket-name/object-name" + * }] + *} * * @see https://docs.aws.amazon.com/gamelift/latest/developerguide/security_iam_id-based-policy-examples.html#security_iam_id-based-policy-examples-access-storage-loc * @@ -98,7 +111,11 @@ export interface BuildProps { } /** - * Create a GameLift server build + * Create a GameLift build ressource + * The AWS::GameLift::Build resource creates a game server build that is installed and run on instances in an Amazon GameLift fleet. + * This resource points to an Amazon S3 location that contains a zip file with all of the components of the game server build. + * + * @see https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-build-cli-uploading.html * * @resource AWS::GameLift::Build */ @@ -161,7 +178,7 @@ export class Build extends BuildBase { physicalName: props.buildName, }); - if (props.buildName) { + if (props.buildName && !cdk.Token.isUnresolved(props.buildName)) { if (props.buildName.length > 1024) { throw new Error(`Build name can not be longer than 1024 characters but has ${props.buildName.length} characters.`); } diff --git a/packages/@aws-cdk/aws-gamelift/lib/content.ts b/packages/@aws-cdk/aws-gamelift/lib/content.ts index e68f3eeebebfb..3c510757b3880 100644 --- a/packages/@aws-cdk/aws-gamelift/lib/content.ts +++ b/packages/@aws-cdk/aws-gamelift/lib/content.ts @@ -5,7 +5,8 @@ import * as cdk from '@aws-cdk/core'; import { Construct } from 'constructs'; /** - * Represents a server content. + * Before deploying your GameLift-enabled multiplayer game servers for hosting with the GameLift service, you need to upload your game server files. + * The class helps you on preparing and uploading custom game server build files or Realtime Servers server script files. */ export abstract class Content { /** From efd89d0720ec24d529a05b81823a39c4fdacc5eb Mon Sep 17 00:00:00 2001 From: Steve Houel Date: Mon, 3 Oct 2022 14:05:46 +0200 Subject: [PATCH 4/7] Upgrading integ tests to fit refactoring --- packages/@aws-cdk/aws-gamelift/package.json | 13 ++- .../aws-gamelift-build.assets.json | 2 +- .../aws-gamelift-build.template.json | 86 ++++++++----------- .../test/build.integ.snapshot/cdk.out | 2 +- .../test/build.integ.snapshot/integ.json | 4 +- .../test/build.integ.snapshot/manifest.json | 60 ++++++------- .../@aws-cdk/aws-gamelift/test/build.test.ts | 16 ++++ 7 files changed, 88 insertions(+), 95 deletions(-) diff --git a/packages/@aws-cdk/aws-gamelift/package.json b/packages/@aws-cdk/aws-gamelift/package.json index d466a978537c1..6f133644d1d2b 100644 --- a/packages/@aws-cdk/aws-gamelift/package.json +++ b/packages/@aws-cdk/aws-gamelift/package.json @@ -81,14 +81,13 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assertions": "0.0.0", - "@aws-cdk/aws-s3": "0.0.0", - "@aws-cdk/integ-tests": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/integ-runner": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", - "@aws-cdk/cfnspec": "0.0.0", "@aws-cdk/pkglint": "0.0.0", - "@types/jest": "^27.5.2" + "@aws-cdk/cx-api": "0.0.0", + "@types/jest": "^27.5.2", + "jest": "^27.5.1" }, "dependencies": { "@aws-cdk/core": "0.0.0", @@ -102,12 +101,12 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "constructs": "^10.0.0" }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/aws-cloudwatch": "0.0.0", + "@aws-cdk/core": "0.0.0", + "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-events": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", @@ -116,9 +115,7 @@ "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", - "@aws-cdk/core": "0.0.0", "@aws-cdk/region-info": "0.0.0", - "@aws-cdk/cx-api": "0.0.0", "constructs": "^10.0.0" }, "engines": { diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json index e083fe082a1ea..d27cd073bc49a 100644 --- a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.assets.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "21.0.0", "files": { "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7": { "source": { diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json index 0b9884f4cb0ec..394b49a1b66ff 100644 --- a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/aws-gamelift-build.template.json @@ -40,7 +40,7 @@ }, ":s3:::", { - "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, "/*" ] @@ -56,7 +56,7 @@ }, ":s3:::", { - "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" } ] ] @@ -79,41 +79,9 @@ "Properties": { "StorageLocation": { "Bucket": { - "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" - }, - "Key": { - "Fn::Join": [ - "", - [ - { - "Fn::Select": [ - 0, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC" - } - ] - } - ] - }, - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "||", - { - "Ref": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC" - } - ] - } - ] - } - ] - ] + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, + "Key": "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7.zip", "RoleArn": { "Fn::GetAtt": [ "BuildServiceRole1F57E904", @@ -125,17 +93,37 @@ } }, "Parameters": { - "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645": { - "Type": "String", - "Description": "S3 bucket for asset \"6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7\"" - }, - "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC": { - "Type": "String", - "Description": "S3 key for asset version \"6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7\"" - }, - "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7ArtifactHashFA16AACF": { - "Type": "String", - "Description": "Artifact hash for asset \"6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7\"" - } - } + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out index 588d7b269d34f..8ecc185e9dbee 100644 --- a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/cdk.out @@ -1 +1 @@ -{"version":"20.0.0"} \ No newline at end of file +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json index 624315dd9870e..f646149706bea 100644 --- a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/integ.json @@ -1,7 +1,7 @@ { - "version": "20.0.0", + "version": "21.0.0", "testCases": { - "@aws-cdk/aws-gamelift/test/integ.build": { + "integ.build": { "stacks": [ "aws-gamelift-build" ], diff --git a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json index c56a6eec3e0ef..43fe5eb776640 100644 --- a/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-gamelift/test/build.integ.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "21.0.0", "artifacts": { "Tree": { "type": "cdk:tree", @@ -7,28 +7,38 @@ "file": "tree.json" } }, + "aws-gamelift-build.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-gamelift-build.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, "aws-gamelift-build": { "type": "aws:cloudformation:stack", "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-gamelift-build.template.json", - "validateOnSynth": false + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9c561e93c7a2947a15dba683670660e922cf493e17b2a6f8ca03cf221442c222.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-gamelift-build.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } }, + "dependencies": [ + "aws-gamelift-build.assets" + ], "metadata": { - "/aws-gamelift-build": [ - { - "type": "aws:cdk:asset", - "data": { - "path": "asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7", - "id": "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7", - "packaging": "zip", - "sourceHash": "6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7", - "s3BucketParameter": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645", - "s3KeyParameter": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC", - "artifactHashParameter": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7ArtifactHashFA16AACF" - } - } - ], "/aws-gamelift-build/Build/ServiceRole/Resource": [ { "type": "aws:cdk:logicalId", @@ -46,24 +56,6 @@ "type": "aws:cdk:logicalId", "data": "Build45A36621" } - ], - "/aws-gamelift-build/AssetParameters/6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/S3Bucket": [ - { - "type": "aws:cdk:logicalId", - "data": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3Bucket1354C645" - } - ], - "/aws-gamelift-build/AssetParameters/6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/S3VersionKey": [ - { - "type": "aws:cdk:logicalId", - "data": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7S3VersionKey5D873FAC" - } - ], - "/aws-gamelift-build/AssetParameters/6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/ArtifactHash": [ - { - "type": "aws:cdk:logicalId", - "data": "AssetParameters6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7ArtifactHashFA16AACF" - } ] }, "displayName": "aws-gamelift-build" diff --git a/packages/@aws-cdk/aws-gamelift/test/build.test.ts b/packages/@aws-cdk/aws-gamelift/test/build.test.ts index 33f71b171049c..7bf763ea2ebfc 100644 --- a/packages/@aws-cdk/aws-gamelift/test/build.test.ts +++ b/packages/@aws-cdk/aws-gamelift/test/build.test.ts @@ -5,6 +5,7 @@ import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import * as gamelift from '../lib'; +import { OperatingSystem } from '../lib'; describe('build', () => { const buildId = 'test-identifier'; @@ -202,6 +203,21 @@ describe('build', () => { }); }); + test('with all optional attributes should set it in CloudFormation', () => { + build = new gamelift.Build(stack, 'BuildWithName', { + ...defaultProps, + buildName: buildName, + operatingSystem: OperatingSystem.AMAZON_LINUX_2, + buildVersion: '1.0', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::GameLift::Build', { + Name: buildName, + OperatingSystem: OperatingSystem.AMAZON_LINUX_2, + Version: '1.0', + }); + }); + test('with an incorrect buildName (>1024)', () => { let incorrectBuildName = ''; for (let i = 0; i < 1025; i++) { From 39699ac7d78bfaac2979cc83755c5f0e34df170f Mon Sep 17 00:00:00 2001 From: Steve Houel Date: Mon, 3 Oct 2022 16:06:44 +0200 Subject: [PATCH 5/7] Fixing rosetta issues --- packages/@aws-cdk/aws-gamelift/README.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/aws-gamelift/README.md b/packages/@aws-cdk/aws-gamelift/README.md index f8ffbff67a5c8..11f466a891fb8 100644 --- a/packages/@aws-cdk/aws-gamelift/README.md +++ b/packages/@aws-cdk/aws-gamelift/README.md @@ -84,13 +84,8 @@ You can set up any application in your build, including your install script, to services. ```ts -import * as gamelift from 'aws-cdk-lib/aws-gamelift'; - -// Build can be declared using either declarative version in the constructor -const build = new gamelift.Build(this, 'Build', { - content: new gamelift.Content.fromAsset(path.join(__dirname, "sample-asset-directory")) +declare const bucket: s3.Bucket; +new gamelift.Build(this, 'Build', { + content: gamelift.Content.fromBucket(bucket, "sample-asset-key") }); - -// Either using dedicated factory static method -const build = gamelift.Build.fromBuildAsset(path.join(__dirname, 'CustomerGameServer/'); ``` From 53d426351aae9a79659589974abe3e52d38174b7 Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 4 Oct 2022 09:06:02 +0100 Subject: [PATCH 6/7] Update build.ts --- packages/@aws-cdk/aws-gamelift/lib/build.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-gamelift/lib/build.ts b/packages/@aws-cdk/aws-gamelift/lib/build.ts index f017ff0b8221d..12c066880473c 100644 --- a/packages/@aws-cdk/aws-gamelift/lib/build.ts +++ b/packages/@aws-cdk/aws-gamelift/lib/build.ts @@ -111,9 +111,8 @@ export interface BuildProps { } /** - * Create a GameLift build ressource - * The AWS::GameLift::Build resource creates a game server build that is installed and run on instances in an Amazon GameLift fleet. - * This resource points to an Amazon S3 location that contains a zip file with all of the components of the game server build. + * A GameLift build, that is installed and runs on instances in an Amazon GameLift fleet. It consists of + * a zip file with all of the components of the game server build. * * @see https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-build-cli-uploading.html * @@ -205,4 +204,4 @@ export class Build extends BuildBase { } -} \ No newline at end of file +} From fe4be274ed008f653e0d6f48d65e45db7d47c6ad Mon Sep 17 00:00:00 2001 From: Otavio Macedo Date: Tue, 4 Oct 2022 09:09:35 +0100 Subject: [PATCH 7/7] Update README.md --- packages/@aws-cdk/aws-gamelift/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-gamelift/README.md b/packages/@aws-cdk/aws-gamelift/README.md index 11f466a891fb8..3d84f4b418ebb 100644 --- a/packages/@aws-cdk/aws-gamelift/README.md +++ b/packages/@aws-cdk/aws-gamelift/README.md @@ -62,7 +62,7 @@ puts players into games. ### Uploading builds and scripts to GameLift Before deploying your GameLift-enabled multiplayer game servers for hosting with the GameLift service, you need to upload -your game server files. This section provide guidance on preparing and uploading custom game server build +your game server files. This section provides guidance on preparing and uploading custom game server build files or Realtime Servers server script files. When you upload files, you create a GameLift build or script resource, which you then deploy on fleets of hosting resources. @@ -72,7 +72,7 @@ Before uploading your configured game server to GameLift for hosting, package th This directory must include all components required to run your game servers and host game sessions, including the following: * Game server binaries – The binary files required to run the game server. A build can include binaries for multiple game -servers built to run on the same platform. For a list of supported platforms, see Download Amazon GameLift SDKs. +servers built to run on the same platform. For a list of supported platforms, see [Download Amazon GameLift SDKs](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-supported.html). * Dependencies – Any dependent files that your game server executables require to run. Examples include assets, configuration files, and dependent libraries.