|
| 1 | +import * as iam from '@aws-cdk/aws-iam'; |
| 2 | +import * as s3 from '@aws-cdk/aws-s3'; |
| 3 | +import * as s3_assets from '@aws-cdk/aws-s3-assets'; |
| 4 | +import * as cdk from '@aws-cdk/core'; |
| 5 | +import { Construct } from 'constructs'; |
| 6 | +import { Content } from './content'; |
| 7 | +import { CfnBuild } from './gamelift.generated'; |
| 8 | + |
| 9 | +/** |
| 10 | + * Represents a GameLift server build. |
| 11 | + */ |
| 12 | +export interface IBuild extends cdk.IResource, iam.IGrantable { |
| 13 | + |
| 14 | + /** |
| 15 | + * The Identifier of the build. |
| 16 | + * |
| 17 | + * @attribute |
| 18 | + */ |
| 19 | + readonly buildId: string; |
| 20 | +} |
| 21 | + |
| 22 | +/** |
| 23 | + * Base class for new and imported GameLift server build. |
| 24 | + */ |
| 25 | +export abstract class BuildBase extends cdk.Resource implements IBuild { |
| 26 | + /** |
| 27 | + * The Identifier of the build. |
| 28 | + */ |
| 29 | + public abstract readonly buildId: string; |
| 30 | + |
| 31 | + public abstract readonly grantPrincipal: iam.IPrincipal; |
| 32 | +} |
| 33 | + |
| 34 | +/** |
| 35 | + * The operating system that the game server binaries are built to run on. |
| 36 | + */ |
| 37 | +export enum OperatingSystem { |
| 38 | + AMAZON_LINUX = 'AMAZON_LINUX', |
| 39 | + AMAZON_LINUX_2 = 'AMAZON_LINUX_2', |
| 40 | + WINDOWS_2012 = 'WINDOWS_2012' |
| 41 | +} |
| 42 | + |
| 43 | + |
| 44 | +/** |
| 45 | + * Represents a Build content defined outside of this stack. |
| 46 | + */ |
| 47 | +export interface BuildAttributes { |
| 48 | + /** |
| 49 | + * The identifier of the build |
| 50 | + */ |
| 51 | + readonly buildId: string; |
| 52 | + /** |
| 53 | + * The IAM role assumed by GameLift to access server build in S3. |
| 54 | + * @default - undefined |
| 55 | + */ |
| 56 | + readonly role?: iam.IRole; |
| 57 | +} |
| 58 | + |
| 59 | +/** |
| 60 | + * Properties for a new build |
| 61 | + */ |
| 62 | +export interface BuildProps { |
| 63 | + /** |
| 64 | + * Name of this build |
| 65 | + * |
| 66 | + * @default No name |
| 67 | + */ |
| 68 | + readonly buildName?: string; |
| 69 | + |
| 70 | + /** |
| 71 | + * Version of this build |
| 72 | + * |
| 73 | + * @default No version |
| 74 | + */ |
| 75 | + readonly buildVersion?: string; |
| 76 | + |
| 77 | + /** |
| 78 | + * The operating system that the game server binaries are built to run on. |
| 79 | + * |
| 80 | + * @default No version |
| 81 | + */ |
| 82 | + readonly operatingSystem?: OperatingSystem; |
| 83 | + |
| 84 | + /** |
| 85 | + * The game build file storage |
| 86 | + */ |
| 87 | + readonly content: Content; |
| 88 | + |
| 89 | + /** |
| 90 | + * The IAM role assumed by GameLift to access server build in S3. |
| 91 | + * If providing a custom role, it needs to trust the GameLift service principal (gamelift.amazonaws.com) and be granted sufficient permissions |
| 92 | + * to have Read access to a specific key content into a specific S3 bucket. |
| 93 | + * Below an example of required permission: |
| 94 | + * { |
| 95 | + * "Version": "2012-10-17", |
| 96 | + * "Statement": [{ |
| 97 | + * "Effect": "Allow", |
| 98 | + * "Action": [ |
| 99 | + * "s3:GetObject", |
| 100 | + * "s3:GetObjectVersion" |
| 101 | + * ], |
| 102 | + * "Resource": "arn:aws:s3:::bucket-name/object-name" |
| 103 | + * }] |
| 104 | + *} |
| 105 | + * |
| 106 | + * @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 |
| 107 | + * |
| 108 | + * @default - a role will be created with default permissions. |
| 109 | + */ |
| 110 | + readonly role?: iam.IRole; |
| 111 | +} |
| 112 | + |
| 113 | +/** |
| 114 | + * A GameLift build, that is installed and runs on instances in an Amazon GameLift fleet. It consists of |
| 115 | + * a zip file with all of the components of the game server build. |
| 116 | + * |
| 117 | + * @see https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-build-cli-uploading.html |
| 118 | + * |
| 119 | + * @resource AWS::GameLift::Build |
| 120 | + */ |
| 121 | +export class Build extends BuildBase { |
| 122 | + |
| 123 | + /** |
| 124 | + * Create a new Build from s3 content |
| 125 | + */ |
| 126 | + static fromBucket(scope: Construct, id: string, bucket: s3.IBucket, key: string, objectVersion?: string) { |
| 127 | + return new Build(scope, id, { |
| 128 | + content: Content.fromBucket(bucket, key, objectVersion), |
| 129 | + }); |
| 130 | + } |
| 131 | + |
| 132 | + /** |
| 133 | + * Create a new Build from asset content |
| 134 | + */ |
| 135 | + static fromAsset(scope: Construct, id: string, path: string, options?: s3_assets.AssetOptions) { |
| 136 | + return new Build(scope, id, { |
| 137 | + content: Content.fromAsset(path, options), |
| 138 | + }); |
| 139 | + } |
| 140 | + |
| 141 | + /** |
| 142 | + * Import a build into CDK using its identifier |
| 143 | + */ |
| 144 | + static fromBuildId(scope: Construct, id: string, buildId: string): IBuild { |
| 145 | + return this.fromBuildAttributes(scope, id, { buildId }); |
| 146 | + } |
| 147 | + |
| 148 | + /** |
| 149 | + * Import an existing build from its attributes. |
| 150 | + */ |
| 151 | + static fromBuildAttributes(scope: Construct, id: string, attrs: BuildAttributes): IBuild { |
| 152 | + class Import extends BuildBase { |
| 153 | + public readonly buildId = attrs.buildId; |
| 154 | + public readonly grantPrincipal = attrs.role ?? new iam.UnknownPrincipal({ resource: this }); |
| 155 | + } |
| 156 | + |
| 157 | + return new Import(scope, id); |
| 158 | + } |
| 159 | + |
| 160 | + /** |
| 161 | + * The Identifier of the build. |
| 162 | + */ |
| 163 | + public readonly buildId: string; |
| 164 | + |
| 165 | + /** |
| 166 | + * The IAM role GameLift assumes to acccess server build content. |
| 167 | + */ |
| 168 | + public readonly role: iam.IRole; |
| 169 | + |
| 170 | + /** |
| 171 | + * The principal this GameLift Build is using. |
| 172 | + */ |
| 173 | + public readonly grantPrincipal: iam.IPrincipal; |
| 174 | + |
| 175 | + constructor(scope: Construct, id: string, props: BuildProps) { |
| 176 | + super(scope, id, { |
| 177 | + physicalName: props.buildName, |
| 178 | + }); |
| 179 | + |
| 180 | + if (props.buildName && !cdk.Token.isUnresolved(props.buildName)) { |
| 181 | + if (props.buildName.length > 1024) { |
| 182 | + throw new Error(`Build name can not be longer than 1024 characters but has ${props.buildName.length} characters.`); |
| 183 | + } |
| 184 | + } |
| 185 | + this.role = props.role ?? new iam.Role(this, 'ServiceRole', { |
| 186 | + assumedBy: new iam.ServicePrincipal('gamelift.amazonaws.com'), |
| 187 | + }); |
| 188 | + this.grantPrincipal = this.role; |
| 189 | + const content = props.content.bind(this, this.role); |
| 190 | + |
| 191 | + const resource = new CfnBuild(this, 'Resource', { |
| 192 | + name: props.buildName, |
| 193 | + version: props.buildVersion, |
| 194 | + operatingSystem: props.operatingSystem, |
| 195 | + storageLocation: { |
| 196 | + bucket: content.s3Location && content.s3Location.bucketName, |
| 197 | + key: content.s3Location && content.s3Location.objectKey, |
| 198 | + objectVersion: content.s3Location && content.s3Location.objectVersion, |
| 199 | + roleArn: this.role.roleArn, |
| 200 | + }, |
| 201 | + }); |
| 202 | + |
| 203 | + this.buildId = resource.ref; |
| 204 | + } |
| 205 | + |
| 206 | + |
| 207 | +} |
0 commit comments