Skip to content

Commit

Permalink
feat(gamelift): add Build L2 constructs for GameLift (#22313)
Browse files Browse the repository at this point in the history
Following [aws-cdk-rfcs](aws/aws-cdk-rfcs#436) I have written the first `Build` L2 resource which create a GameLift Build element based on a S3 location.

----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
stevehouel committed Oct 4, 2022
1 parent 63d3c54 commit 983d26e
Show file tree
Hide file tree
Showing 20 changed files with 1,419 additions and 31 deletions.
3 changes: 3 additions & 0 deletions packages/@aws-cdk/aws-gamelift/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ junit.xml
!**/*.integ.snapshot/**/asset.*/*.d.ts

!**/*.integ.snapshot/**/asset.*/**

#include game build js file
!test/my-game-build/*.js
98 changes: 75 additions & 23 deletions packages/@aws-cdk/aws-gamelift/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,83 @@
>
> [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.
---

<!--END STABILITY BANNER-->

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.

### 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 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.

### 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](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.

* 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
declare const bucket: s3.Bucket;
new gamelift.Build(this, 'Build', {
content: gamelift.Content.fromBucket(bucket, "sample-asset-key")
});
```

<!--BEGIN CFNONLY DISCLAIMER-->

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.


<!--BEGIN CFNONLY DISCLAIMER-->

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.)

<!--END CFNONLY DISCLAIMER-->
207 changes: 207 additions & 0 deletions packages/@aws-cdk/aws-gamelift/lib/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
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
* 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
*
* @default - a role will be created with default permissions.
*/
readonly role?: iam.IRole;
}

/**
* 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
*
* @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 && !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.`);
}
}
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;
}


}
Loading

0 comments on commit 983d26e

Please sign in to comment.