Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gamelift): add Build L2 constructs for GameLift #22313

Merged
merged 14 commits into from
Oct 4, 2022
Merged
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
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'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm: you don't need to pass any policies?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am granting read access to for an S3 bucket + dedicated content key on binding phase for a content (see content.ts on bind methods) but otherwise no specific needs here or any specific policy

});
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