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 4 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
86 changes: 63 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,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.

---

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

### Creating a custom server build

Your uploaded game servers are hosted on GameLift virtual computing resources,
Copy link
Contributor

Choose a reason for hiding this comment

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

This section is about server builds, but there is no mention of anything called "build" in this paragraph.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

documentation has been updated

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/');
```

<!--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-->
191 changes: 191 additions & 0 deletions packages/@aws-cdk/aws-gamelift/lib/build.ts
Original file line number Diff line number Diff line change
@@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

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

Please explain to the user which permissions are sufficient.

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 have improved documentation and added a required policy sample

*
* @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) {
stevehouel marked this conversation as resolved.
Show resolved Hide resolved
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