-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(gamelift): add Script L2 Construct for GameLift (#22343)
Following [aws-cdk-rfcs](aws/aws-cdk-rfcs#436) I have written the first Script L2 resource which create a GameLift Script resource 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
1 parent
b342566
commit da181ba
Showing
16 changed files
with
978 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
export * from './content'; | ||
export * from './build'; | ||
export * from './script'; | ||
|
||
// AWS::GameLift CloudFormation Resources: | ||
export * from './gamelift.generated'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
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 { CfnScript } from './gamelift.generated'; | ||
|
||
/** | ||
* Your configuration and custom game logic for use with Realtime Servers. | ||
* Realtime Servers are provided by GameLift to use instead of a custom-built game server. | ||
* You configure Realtime Servers for your game clients by creating a script using JavaScript, | ||
* and add custom game logic as appropriate to host game sessions for your players. | ||
* You upload the Realtime script to the GameLift service in the Regions where you plan to set up fleets. | ||
* | ||
* @see https://docs.aws.amazon.com/gamelift/latest/developerguide/realtime-script-uploading.html | ||
*/ | ||
export interface IScript extends cdk.IResource, iam.IGrantable { | ||
|
||
/** | ||
* The Identifier of the realtime server script. | ||
* | ||
* @attribute | ||
*/ | ||
readonly scriptId: string; | ||
|
||
/** | ||
* The ARN of the realtime server script. | ||
* | ||
* @attribute | ||
*/ | ||
readonly scriptArn: string; | ||
} | ||
|
||
/** | ||
* Base class for new and imported GameLift realtime server script. | ||
*/ | ||
export abstract class ScriptBase extends cdk.Resource implements IScript { | ||
/** | ||
* The Identifier of the realtime server script. | ||
*/ | ||
public abstract readonly scriptId: string; | ||
public abstract readonly scriptArn: string; | ||
|
||
public abstract readonly grantPrincipal: iam.IPrincipal; | ||
} | ||
|
||
/** | ||
* Represents a Script content defined outside of this stack. | ||
*/ | ||
export interface ScriptAttributes { | ||
/** | ||
* The ARN of the realtime server script | ||
*/ | ||
readonly scriptArn: string; | ||
/** | ||
* The IAM role assumed by GameLift to access server script in S3. | ||
* @default - undefined | ||
*/ | ||
readonly role?: iam.IRole; | ||
} | ||
|
||
/** | ||
* Properties for a new realtime server script | ||
*/ | ||
export interface ScriptProps { | ||
/** | ||
* Name of this realtime server script | ||
* | ||
* @default No name | ||
*/ | ||
readonly scriptName?: string; | ||
|
||
/** | ||
* Version of this realtime server script | ||
* | ||
* @default No version | ||
*/ | ||
readonly scriptVersion?: string; | ||
|
||
/** | ||
* The game content | ||
*/ | ||
readonly content: Content; | ||
|
||
/** | ||
* The IAM role assumed by GameLift to access server script 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 script, 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 realtime game server script. | ||
* | ||
* @see https://docs.aws.amazon.com/gamelift/latest/developerguide/realtime-script-uploading.html | ||
* | ||
* @resource AWS::GameLift::Script | ||
*/ | ||
export class Script extends ScriptBase { | ||
|
||
/** | ||
* Create a new realtime server script from s3 content | ||
*/ | ||
static fromBucket(scope: Construct, id: string, bucket: s3.IBucket, key: string, objectVersion?: string) { | ||
return new Script(scope, id, { | ||
content: Content.fromBucket(bucket, key, objectVersion), | ||
}); | ||
} | ||
|
||
/** | ||
* Create a new realtime server script from asset content | ||
*/ | ||
static fromAsset(scope: Construct, id: string, path: string, options?: s3_assets.AssetOptions) { | ||
return new Script(scope, id, { | ||
content: Content.fromAsset(path, options), | ||
}); | ||
} | ||
|
||
/** | ||
* Import a script into CDK using its ARN | ||
*/ | ||
static fromScriptArn(scope: Construct, id: string, scriptArn: string): IScript { | ||
return this.fromScriptAttributes(scope, id, { scriptArn }); | ||
} | ||
|
||
/** | ||
* Import an existing realtime server script from its attributes. | ||
*/ | ||
static fromScriptAttributes(scope: Construct, id: string, attrs: ScriptAttributes): IScript { | ||
const scriptArn = attrs.scriptArn; | ||
const scriptId = extractIdFromArn(attrs.scriptArn); | ||
const role = attrs.role; | ||
|
||
class Import extends ScriptBase { | ||
public readonly scriptArn = scriptArn; | ||
public readonly scriptId = scriptId; | ||
public readonly grantPrincipal:iam.IPrincipal; | ||
public readonly role = role | ||
|
||
constructor(s: Construct, i: string) { | ||
super(s, i, { | ||
environmentFromArn: scriptArn, | ||
}); | ||
|
||
this.grantPrincipal = this.role || new iam.UnknownPrincipal({ resource: this }); | ||
} | ||
} | ||
|
||
return new Import(scope, id); | ||
} | ||
|
||
/** | ||
* The Identifier of the realtime server script. | ||
*/ | ||
public readonly scriptId: string; | ||
|
||
/** | ||
* The ARN of the realtime server script. | ||
*/ | ||
public readonly scriptArn: string; | ||
|
||
/** | ||
* The IAM role GameLift assumes to acccess server script content. | ||
*/ | ||
public readonly role: iam.IRole; | ||
|
||
/** | ||
* The principal this GameLift script is using. | ||
*/ | ||
public readonly grantPrincipal: iam.IPrincipal; | ||
|
||
constructor(scope: Construct, id: string, props: ScriptProps) { | ||
super(scope, id, { | ||
physicalName: props.scriptName, | ||
}); | ||
|
||
if (props.scriptName && !cdk.Token.isUnresolved(props.scriptName)) { | ||
if (props.scriptName.length > 1024) { | ||
throw new Error(`Script name can not be longer than 1024 characters but has ${props.scriptName.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 CfnScript(this, 'Resource', { | ||
name: props.scriptName, | ||
version: props.scriptVersion, | ||
storageLocation: { | ||
bucket: content.s3Location && content.s3Location.bucketName, | ||
key: content.s3Location && content.s3Location.objectKey, | ||
objectVersion: content.s3Location && content.s3Location.objectVersion, | ||
roleArn: this.role.roleArn, | ||
}, | ||
}); | ||
|
||
this.scriptId = this.getResourceNameAttribute(resource.ref); | ||
this.scriptArn = this.getResourceArnAttribute(resource.attrArn, { | ||
service: 'gamelift', | ||
resource: `script/${this.physicalName}`, | ||
arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME, | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Given an opaque (token) ARN, returns a CloudFormation expression that extracts the script | ||
* identifier from the ARN. | ||
* | ||
* Script ARNs look like this: | ||
* | ||
* arn:aws:gamelift:region:account-id:script/script-identifier | ||
* | ||
* ..which means that in order to extract the `script-identifier` component from the ARN, we can | ||
* split the ARN using ":" and select the component in index 5 then split using "/" and select the component in index 1. | ||
* | ||
* @returns the script identifier from his ARN | ||
*/ | ||
function extractIdFromArn(arn: string) { | ||
const splitValue = cdk.Fn.select(5, cdk.Fn.split(':', arn)); | ||
return cdk.Fn.select(1, cdk.Fn.split('/', splitValue)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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-script'); | ||
|
||
new gamelift.Script(stack, 'Script', { | ||
content: gamelift.Content.fromAsset(path.join(__dirname, 'my-game-script')), | ||
}); | ||
|
||
app.synth(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
console.log('Hello World'); |
1 change: 1 addition & 0 deletions
1
....snapshot/asset.6019bfc8ab05a24b0ae9b5d8f4585cbfc7d1c30a23286d0b25ce7066a368a5d7/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
console.log('Hello World'); |
32 changes: 32 additions & 0 deletions
32
packages/@aws-cdk/aws-gamelift/test/script.integ.snapshot/aws-gamelift-script.assets.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"version": "21.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-script.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": {} | ||
} |
Oops, something went wrong.