├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app.py ├── architecture.png ├── assets ├── component.yml ├── create-dependency-archive.ps1 ├── start-agent.ps1 └── start-coordinator.ps1 ├── cdk.json ├── cloudformation ├── swarm-deployment.yaml └── swarm-infra.yaml ├── requirements.txt └── swarm_cdk ├── __init__.py ├── swarm_cdk_deployment.py └── swarm_cdk_infra.py /.gitignore: -------------------------------------------------------------------------------- 1 | # VSCode extension 2 | 3 | # Store launch config in repo but not settings 4 | .vscode/settings.json 5 | /.favorites.json 6 | 7 | # TypeScript incremental build states 8 | *.tsbuildinfo 9 | 10 | # Local state files & OS specifics 11 | .DS_Store 12 | node_modules/ 13 | lerna-debug.log 14 | dist/ 15 | pack/ 16 | .BUILD_COMPLETED 17 | .local-npm/ 18 | .tools/ 19 | coverage/ 20 | .nyc_output 21 | .nycrc 22 | .LAST_BUILD 23 | *.sw[a-z] 24 | *~ 25 | .idea 26 | junit.xml 27 | 28 | # We don't want tsconfig at the root 29 | /tsconfig.json 30 | 31 | # CDK Context & Staging files 32 | cdk.context.json 33 | .cdk.staging/ 34 | cdk.out/ 35 | *.tabl.json 36 | 37 | # Python local env 38 | .env/ 39 | .venv/ 40 | *__pycache__/ 41 | 42 | # Yarn error log 43 | yarn-error.log 44 | 45 | # VSCode history plugin 46 | .vscode/.history/ 47 | 48 | # Cloud9 49 | .c9 50 | 51 | /.versionrc.json -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amazon EC2 cluster for Unreal Swarm 2 | 3 | - [Description](#description) 4 | - [Contents](#contents) 5 | - [Architecture Diagram](#architecture-diagram) 6 | - [Prerequirements](#prerequirements) 7 | - [Deployment Steps](#deployment-steps) 8 | * [Initiate CDK](#initiate-cdk) 9 | * [Infra Deployment](#infra-deployment) 10 | * [Optional: Create EC2 Instance for Unreal Engine 4 -workstation](#Optional-Create-EC2-Instance-for-Unreal-Engine-4--workstation) 11 | * [Collecting dependencies](#Collecting-dependencies) 12 | * [Swarm Cluster Deployment](#swarm-cluster-deployment) 13 | * [Baking custom Windows AMI for UE4 Swarm](#Baking-custom-Windows-AMI-for-UE4-Swarm) 14 | * [Deploying UE4 Swarm Coordinator](#Deploying-UE4-Swarm-Coordinator) 15 | * [Deploying UE4 Swarm Agent Auto Scaling Group](#Deploying-UE4-Swarm-Agent-Auto-Scaling-Group) 16 | - [Sending build task to UE4 Swarm on AWS](#Sending-build-task-to-UE4-Swarm-on-AWS) 17 | - [Cleaning Up Resources](#cleaning-up-resources) 18 | - [Extra Tips](#extra-tips) 19 | - [License](#license) 20 | 21 | 22 | # Description 23 | 24 | This example allows you to run Unreal Swarm cluster on AWS. The CDK or Cloudformation templates create a new VPC for the Swarm EC2 instances to run in and it also uses EC2 Image Builder to automatically create a custom AMI as the base for your cluster. It also creates a S3 bucket where you will upload the Unreal Engine 4 dependencies packaged into a ZIP archive. This S3 bucket is also used as destination for EC2 Image Builder logs. 25 | 26 | To be able to use the Swarm cluster you will need to be connected to the VPCs private subnets. You can achieve this by manually installing your own EC2 Instance where you install Unreal Engine. If you already have an existing workstation then you can connect to the cluster via Site to Site VPN or Client VPN. The Cluster needs to run inside private ip address range as you can't specify what IP addresses are used by the Swarm Agent process. 27 | 28 | **Note**: _“The sample code; software libraries; command line tools; proofs of concept; templates; or other related technology (including any of the foregoing that are provided by our personnel) is provided to you, as AWS Content under the AWS Customer Agreement, or the relevant written agreement between you and AWS (whichever applies). You should not use this AWS Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the AWS Content, such as sample code, as appropriate for production grade use based on your specific quality control practices and standards. Deploying AWS Content may incur AWS charges for creating or using AWS chargeable resources, such as running Amazon EC2 instances or using Amazon S3 storage.”_ 29 | 30 | # Contents 31 | 32 | This project repo contains: 33 | * **PowerShell Scripts** that are used to collect dependencies from your local Unreal Engine 4 installation, customizing a Windows instance and launching the Swarm Agent with correct settings. 34 | * **Infrastructure deployment automation** that deploys required infrastructure resources using AWS CDK or AWS CloudFormation. 35 | 36 | # Architecture Diagram 37 | 38 | ![Architecture](architecture.png "Architecture") 39 | 40 | # Prerequirements 41 | 42 | To be able to build and use this example you will need a Unreal Engine 4 installation on Windows. This could be your existing setup, or you can deploy a new Windows EC2 Instance into the VPC deployed in this example and install the Unreal Engine 4 onto that machine. 43 | 44 | Before launching this sample, you must log in to the AWS Management Console with IAM permissions for the resources and actions the templates deploy. The AdministratorAccess managed policy within IAM provides sufficient permissions, although your organization may choose to [use a custom policy with more restrictions](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). Please view the [AWS managed policies documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions.html) for more info. 45 | 46 | **Please do not use your root user for this deployment.** 47 | 48 | # Deployment Steps 49 | 50 | On a high level the deployment is split into 3 parts: 51 | 1. First step is to create a VPC, and a S3 bucket. 52 | 1. Second step is to connect your existing workstation to the VPC or creating a new virtual workstation into the VPC you created. 53 | 1. During this step you will also run a Powershell script to create an archive of all the Swarm dependencies we need to create the cluster. 54 | 1. Last step uses EC2 Image Builder to create a custom AMI from the dependencies archive you created and deploys a Swarm cluster for you. 55 | 56 | The entire deployment process should take around 1 hour depending on your familiarity with CDK and CloudFormation template. 57 | 58 | ## Initiate CDK 59 | 60 | > This step is optional if you decide to use the CloudFormation templates in the `cloudformation` -directory. 61 | 62 | This project uses standard Python CDK project to deploy the Swarm cluster. If you don't have CDK installed then please follow these instructions at [AWS Cloud Development Kit](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_install) -documentation. 63 | 64 | When you have CDK and Python installed you can use following steps to initiate this project: 65 | 66 | To initialize this project we will need to create a virtualenv that stores dependencies under the `.venv` directory. To create the virtualenv the following commands assumes that there is a `python3` (or `python` for Windows) executable in your path with access to the `venv` package. 67 | 68 | Manually create a virtualenv on MacOS and Linux: 69 | 70 | ``` 71 | $ python3 -m venv .env 72 | ``` 73 | 74 | After the init process is completed, and the virtualenv is created, you can use the following 75 | step to activate your virtualenv. 76 | 77 | ``` 78 | $ source .env/bin/activate 79 | ``` 80 | 81 | If you are a Windows platform you can manually create a virtualenv with following command: 82 | 83 | ``` 84 | % python -m venv .venv 85 | ``` 86 | 87 | Then you can activate the virtualenv like this: 88 | 89 | ``` 90 | % .env\Scripts\activate.bat 91 | ``` 92 | 93 | Also, if you are on Windows platform, please edit `cdk.json` -file to point to your Python runtime. 94 | 95 | Once the virtualenv is activated, you can install the required dependencies. 96 | 97 | ``` 98 | $ pip install -r requirements.txt 99 | ``` 100 | ## Infra Deployment 101 | 102 | **Please note that you are responsible for the cost of the AWS services used while running this 103 | sample reference deployment. For full details, see the pricing pages for each AWS 104 | service you will be using for this deployment.** 105 | 106 | For the list of services used and their pricing documentation: 107 | 1. [CloudFormation pricing](https://aws.amazon.com/cloudformation/pricing/) 108 | 1. [S3 bucket pricing](https://aws.amazon.com/s3/pricing/) 109 | 1. [VPC Pricing](https://aws.amazon.com/vpc/pricing/) 110 | 1. [Site-to-Site AND Client VPN Pricing](https://aws.amazon.com/vpn/pricing/) 111 | 1. [EC2 Pricing](https://aws.amazon.com/ec2/pricing/). In this deployment, we use: 112 | 1. m5.large for UE4 Swarm Server 113 | 1. t3.large for UE4 Swarm Controller 114 | 1. t3.xlarge for UE4 Swarm Agent 115 | 1. Autoscaling is enabled, therefore be mindful of the number of Swarm Agent instances your workload is generating. 116 | 117 | The example needs a VPC with two Public subnets and two Private subnets plus Nat Gateway. We also need a S3 bucket for the dependency archive and EC2 Image Builder logs. 118 | 119 | You can deploy these with CDK or by using CloudFormation template. By default, we will create the VPC with CIDR `10.0.0.0/16` and allow traffic to the Swarm Cluster from CIDR Prefix `10.0.0.0/8`. These values can be changed by editing the `cdk.json`-file and giving new values for `vpc_cidr` and `trusted_cidr`. 120 | 121 | To deploy the Infrastructure you can run following command: 122 | ``` 123 | $ cdk deploy swarm-infra 124 | ``` 125 | 126 | Alternatively you can use the `cloudformation/swarm-infra.yaml` -template to create a CloudFormation stack called `swarm-infra` using the AWS Console and AWS CLI. If you want to customize the VPC CIDR you will need to edit the CloudFormation template or use the CDK to synthesize new one with the CDK context variable (see the [Tips](#extra-tips) section). 127 | 128 | CLI example: 129 | ```` 130 | $ aws cloudformation create-stack --stack-name swarm-infra --template-body file://cloudformation/swarm-infra.yaml 131 | ```` 132 | 133 | Once the creation of resources is ready, you can move to next step. 134 | 135 | ## Connecting your Unreal Engine 4 -workstation to the new VPC 136 | 137 | To be able to use the Swarm Agent cluster, you will need to have an existing Unreal Engine 4 -workstation that is able to connect to this VPC. Or you can follow the optional step below to create a new EC2 Instance to host your Unreal Engine 4 -workstation. 138 | This workstation needs to be able to communicate to all the private IP addresses of the Swarm cluster nodes on TCP port 8008 and 8009. The workstation also need to be able to send ICMP Ping (Request and response) to the Swarm cluster nodes. 139 | 140 | You can use following commands on Windows Workstation Powershell to open the necessary ports: 141 | ```` 142 | New-NetFirewallRule -DisplayName 'Allow UE4 Swarm TCP' -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8008-8009 -RemoteAddress 143 | New-NetFirewallRule -DisplayName 'Allow UE4 Swarm UDP' -Direction Inbound -Action Allow -Protocol UDP -LocalPort 8008-8009 -RemoteAddress 144 | New-NetFirewallRule -DisplayName 'Allow ICMP' -Direction Inbound -Action Allow -Protocol ICMPv4 -RemoteAddress 145 | ```` 146 | 147 | Methods of connection existing workstation to this UE4 Swarm cluster: 148 | * If you just need to connect one work station you can use [AWS Client VPN](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/what-is.html) -service 149 | * If you are going to share the cluster with other or work from an office you should use [AWS Site-to-Site VPN](https://docs.aws.amazon.com/vpn/latest/s2svpn/VPC_VPN.html) -service 150 | * If you already have existing AWS infrastructure you can also consider using Amazon Virtual Private Cloud's [VPC Peering](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html) -feature or [AWS Transit Gateway](https://docs.aws.amazon.com/vpc/latest/tgw/what-is-transit-gateway.html) -service to allow you to communicate from your workstation to the Swarm Cluster. 151 | 152 | 153 | ## Optional: Create EC2 Instance for Unreal Engine 4 -workstation 154 | 155 | If you don't already have an Unreal Engine 4 workstation that you can connect to the VPC via VPN (Site to Site or Client VPN) then you can now launch a new Windows EC2 Instance into the VPCs Public subnets. You can for example launch [NVIDIA's AMI](https://aws.amazon.com/marketplace/search/results/?page=1&filters=instance_types&instance_types=g4dn.xlarge&searchTerms=NVIDIA%20Gaming) with all the drivers or follow for this [guide from Parsec](https://blog.parsec.app/rtx-cloud-gaming-with-the-new-aws-g4-instances-11d1c60c2d09/) on how to create a G4dn based graphical workstation on AWS. **Note:** If you have a new AWS account you need to request EC2 limit increase, please see our [EC2 Request a limit increase](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-on-demand-instances.html#vcpu-limits-request-increase) -documentation for more information. 156 | 157 | ## Collecting dependencies 158 | 159 | Any Windows instance that acts as a Swarm Coordinator or as a Swarm Agent will need a set of prerequisites installed. 160 | We can collect these prerequisites from your existing Unreal Engine 4 installation with the provided `assets/create-depdendency-archive.ps1` -script in this repo. 161 | * This PowerShell script will copy all the components that are needed to customize a fresh Window installation 162 | * The script assumes that your Unreal Engine is installed to `C:\Program Files\Epic Games\UE_4.25`-directory, but you can customize the script to match your location 163 | * Script will create a compressed archive called `ue4-swarm-archive.zip` under your `My Documents` -directory 164 | * You can find more details about these prerequisites at: 165 | * [Unreal Engines 4's Hardware and Software requirements page](https://docs.unrealengine.com/en-US/GettingStarted/RecommendedSpecifications/index.html) 166 | * [Setting up Swarm Coordinator and Swarm Agents instructions page](https://docs.unrealengine.com/en-US/Engine/Rendering/LightingAndShadows/Lightmass/UnrealSwarmOverview/index.html) 167 | 168 | After you have created the `ue4-swarm-archive.zip` -archive you need to upload it into the root -directory of the newly created S3 bucket. It will be downloaded from that location and used during the EC2 Image Builder -process. The name of the bucket is available as an output called `BucketName` from the `swarm-infra` -stack. 169 | 170 | With AWS CLI you can use following command: 171 | ``` 172 | $ aws s3 cp ue4-swarm-archive.zip s3:/// 173 | ``` 174 | 175 | ## Swarm Cluster Deployment 176 | 177 | To deploy the Swarm Cluster you can run following command: 178 | ``` 179 | $ cdk deploy swarm-deployment 180 | ``` 181 | 182 | Alternatively you can use the `cloudformation/swarm-deployment.yaml` -template to create a CloudFormation stack called `swarm-deployment` using the AWS Console and AWS CLI. 183 | 184 | CLI example: 185 | ```` 186 | $ aws cloudformation create-stack --stack-name swarm-deployment --capabilities CAPABILITY_NAMED_IAM --template-body file://cloudformation/swarm-deployment.yaml 187 | ```` 188 | 189 | This step will take **30 minutes** on average as it's baking the Window AMI for Swarm. The steps to install all dependencies does take some time to complete. While the deployment is running you can read below for details on what's happening during stack creation. 190 | 191 | ### Baking custom Windows AMI for UE4 Swarm 192 | The `swarm-deployment` -stack will first configure EC2 Image Builder to use latest "Microsoft Windows Server 2019 Base" image as the base image. It also creates a EC2 Image Builder component defining the build steps. These steps will download the Zip -archive from S3, install .Net runtime, run the `UE4PrereqSetup_x64.exe` -installer and then open Windows Firewall for the Swarm ports. You can view the `assets/component.yaml` -file for details. 193 | 194 | Once the EC2 Image Builder completes, it will create a private AMI under your account. This AMI contains all the required Unreal Engine 4 Swarm build dependencies and can be used to quickly launch the Swarm Coordinator and Swarm Agents. 195 | 196 | ### Deploying UE4 Swarm Coordinator 197 | The Swarm Coordinator will be launched as a single EC2 Instance. The launch will use `User Data` to configure the Windows to start SwarmCoordinator.exe on bootup. You can view the contents of the `User Data` in `assets/start-coordinator.ps1` - Powershell script. 198 | 199 | ### Deploying UE4 Swarm Agent Auto Scaling Group 200 | The Swarm Agents are going to be launched as Auto Scaling Group. Enabling us to quickly scale the number of nodes up and down. As the Swarm Agents need to be already online and registered when you submit a UE4 build, we can't use any metrics to scale the cluster on demand. 201 | Instead, you can use for example Schedule, or some script to scale the cluster before submit a job. With a schedule you could for example configure the cluster to scale up to certain number of nodes in the morning and then after office hours scale the cluster back to zero. 202 | 203 | The Swarm Agent will also use `User Data` to configure the Windows to start SwarmAgent.exe on boot-up and injects a Swarm configuration file into the Instance. This configuration file will set number of threads to equal amount of CPU Core and also will set the Coordinator IP address. You can view the contents of the `User Data` in `assets/start-agent.ps1` - Powershell script. 204 | 205 | # Sending build task to UE4 Swarm on AWS 206 | 207 | Now that the Swarm Cluster CloudFormation stack has completed deployment you should see two EC2 Instances running on your new VPC. Also the CDK/CloudFormation stack should have an output for the private IP address of the Swarm Coordinator that you can now use. 208 | 209 | On your Unreal Engine 4 -workstation you have to configure the local Swarm Agent. You can launch it from `C:\Program Files\Epic Games\UE_4.25\Engine\Binaries\DotNET` -directory. After this you will need fo configure following settings: 210 | * `AgentGroupName`: `ue4-swarm-aws` 211 | * `AllowedRemoteAgentGroup`: `ue4-swarm-aws` 212 | * `AllowedRemoteAgentNames`: `*` 213 | * `CoordinatorREmoteHost`: `` 214 | 215 | # Cleaning Up Resources 216 | 217 | To clean up this example you need to delete the two CloudFormation stacks. Start by deleting the `swarm-deployment` -stack and once it's completely removed you can delete the `swarm-infra` -stack. 218 | 219 | With CDK you can delete the stacks with: 220 | Example commands: 221 | ```` 222 | $ cdk destroy "*" 223 | ```` 224 | 225 | After running these commands, you will have two resources that you need to delete manually. First the S3 bucket will need to be deleted manually and second the AMI that was created needs to be deleted. 226 | 227 | Example commands: 228 | ```` 229 | $ aws s3 rb s3:// --force 230 | $ 231 | $ aws ec2 deregister-image --image-id 232 | ```` 233 | 234 | # Extra Tips 235 | ## How to view Swarm agent logs 236 | 237 | You can use the Session Manager to open Powershell session to the Coordinator or Swarm instances. Only Swarm Agent writes logs (Coordinator doesn't have any logs) that are located under: `C:\ue4-swarm\SwarmCache\Logs` 238 | 239 | ## How to access Swarm Instances Remote Desktop 240 | 241 | As we are not defining the Administrator password nor defining an SSH key for the EC2 instances we have to reset the password manually. The instances do have System Manager enabled, so we can use Session Manager to launch a Powershell inside the Instance and use following snippet to reset the password: 242 | 243 | ``` 244 | $Password = Read-Host -AsSecureString 245 | Get-LocalUser -Name "Administrator" | Set-LocalUser -Password $Password 246 | ``` 247 | ## Updating CloudFormation templates after code changes 248 | 249 | If you make changes to the CDK code and want to generate new CloudFormation templates you will need to use following commands to keep the stack references in sync: 250 | 251 | ``` 252 | cdk synth swarm-infra -e > cloudformation/swarm-infra.yaml 253 | cdk synth swarm-deployment -e > cloudformation/swarm-deployment.yaml 254 | ``` 255 | 256 | ## Troubleshooting 257 | 258 | If there is trouble when provisioning the infrastructure via the CloudFormation template or running the CDK commands, [please create an issue here](https://github.com/aws-samples/ec2-cluster-for-unreal-swarms/issues). 259 | 260 | # Security 261 | 262 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 263 | 264 | # License 265 | 266 | This library is licensed under the MIT-0 License. See the LICENSE file. 267 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | ## SPDX-License-Identifier: MIT-0 5 | 6 | from aws_cdk import core 7 | import os 8 | 9 | from swarm_cdk.swarm_cdk_deployment import SwarmDeployment 10 | from swarm_cdk.swarm_cdk_infra import SwarmInfra 11 | 12 | app = core.App() 13 | infra = SwarmInfra(app, "swarm-infra", env={'region': os.environ['CDK_DEFAULT_REGION']}) 14 | deployment = SwarmDeployment(app, "swarm-deployment", bucket=infra.bucket, vpc=infra.vpc, env={'region': os.environ['CDK_DEFAULT_REGION']}) 15 | 16 | app.synth() 17 | -------------------------------------------------------------------------------- /architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ec2-cluster-for-unreal-swarms/3d7a02c7fbf33b50ed287b88476b468aebac3766/architecture.png -------------------------------------------------------------------------------- /assets/component.yml: -------------------------------------------------------------------------------- 1 | name: InstallUE4Swarm 2 | description: This component installs UE4 Swarm from S3 archive and also installs all prerequirements for a build. 3 | schemaVersion: 1.0 4 | 5 | phases: 6 | - name: build 7 | steps: 8 | - name: CreateTempFolder 9 | action: CreateFolder 10 | inputs: 11 | - path: C:\ue4-swarm-temp 12 | - name: DownloadDependencies 13 | action: S3Download 14 | maxAttempts: 3 15 | inputs: 16 | - source: s3://S3-BUCKET-NAME/ue4-swarm-archive.zip 17 | destination: C:\ue4-swarm-temp\ue4-swarm-archive.zip 18 | - name: CreateSwarmFolder 19 | action: CreateFolder 20 | inputs: 21 | - path: C:\ue4-swarm 22 | - name: UncompressSwarmFiles 23 | action: ExecutePowerShell 24 | inputs: 25 | commands: 26 | - Expand-Archive -LiteralPath C:\ue4-swarm-temp\ue4-swarm-archive.zip -DestinationPath C:\ue4-swarm 27 | - name: DeleteTempFolder 28 | action: DeleteFolder 29 | inputs: 30 | - path: C:\ue4-swarm-temp 31 | force: true 32 | - name: InstallDotNet 33 | action: ExecutePowerShell 34 | inputs: 35 | commands: 36 | - Install-WindowsFeature Net-Framework-Core 37 | - name: InstallPreReqs 38 | action: ExecutePowerShell 39 | inputs: 40 | commands: 41 | - Start-Process -Wait -FilePath "C:\ue4-swarm\UE4PrereqSetup_x64.exe" -ArgumentList "/install /quiet" 42 | - name: OpenFirewall 43 | action: ExecutePowerShell 44 | inputs: 45 | commands: 46 | - New-NetFirewallRule -DisplayName 'Allow UE4 Swarm TCP' -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8008-8009 47 | - New-NetFirewallRule -DisplayName 'Allow UE4 Swarm UDP' -Direction Inbound -Action Allow -Protocol UDP -LocalPort 8008-8009 48 | - New-NetFirewallRule -DisplayName 'Allow ICMP' -Direction Inbound -Action Allow -Protocol ICMPv4 -------------------------------------------------------------------------------- /assets/create-dependency-archive.ps1: -------------------------------------------------------------------------------- 1 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | ## SPDX-License-Identifier: MIT-0 3 | 4 | # This PowerShell script creates a Zip archive with all required 5 | # files for creating UE4 Swarm node and Controller 6 | 7 | # Your Unreal Engine 4 root folder 8 | # Change this according to your location and version 9 | $ue4root = 'C:\Program Files\Epic Games\UE_4.25' 10 | 11 | # Where we are going to store the archive into your Documents folder 12 | $ue4SwarmArchive = "ue4-swarm-archive" 13 | $archivePath = [Environment]::GetFolderPath('MyDocuments')+"\"+$ue4SwarmArchive 14 | 15 | # Path to Swarm related files 16 | $ue4swarmpath = $ue4root + "\Engine\Binaries\DotNET" 17 | $swarmPaths = @() 18 | $swarmfiles = "AgentInterface.dll", "SwarmAgent.exe", "SwarmAgent.exe.config" 19 | $swarmfiles += "SwarmCommonUtils.dll", "SwarmCoordinator.exe" 20 | $swarmfiles += "SwarmCoordinator.exe.config","SwarmCoordinatorInterface.dll" 21 | $swarmfiles += "SwarmInterface.dll","UnrealControls.dll" 22 | $swarmfiles | Foreach-Object { $swarmPaths += $ue4swarmpath + '\' + $_ } 23 | 24 | # Path to UE4PrereqSetup 25 | $ue4prereq = $ue4root + "\Engine\Extras\Redist\en-us\UE4PrereqSetup_x64.exe" 26 | $compressPaths = @() 27 | $compressPaths = $swarmPaths + $ue4prereq 28 | Compress-Archive -LiteralPath $compressPaths -DestinationPath $archivePath -Force -------------------------------------------------------------------------------- /assets/start-agent.ps1: -------------------------------------------------------------------------------- 1 | 2 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | ## SPDX-License-Identifier: MIT-0 4 | 5 | # Define Coordinator IP, Cloudformation replaces this when task is been created 6 | $coordinator_ip = "COORDINATOR_IP" 7 | 8 | # Template of the Swarm Agent Developper Options file 9 | $developeroptions = ' 10 | 11 | true 12 | LOCALCORES 13 | BelowNormal 14 | REMOTECORES 15 | Idle 16 | false 17 | 15 18 | ' 19 | 20 | # Calculate number of cores 21 | $cores = (Get-WmiObject -Class Win32_Processor | Select-Object -Property NumberOfLogicalProcessors).NumberOfLogicalProcessors 22 | 23 | # Set the core values for the Swarm Agent 24 | $developeroptions = $developeroptions.replace("REMOTECORES", $cores) 25 | $developeroptions = $developeroptions.replace("LOCALCORES", $cores-1) 26 | 27 | # Save the configureation file 28 | $developeroptions | Out-File -FilePath "C:\ue4-swarm\SwarmAgent.DeveloperOptions.xml" 29 | 30 | # Template of the Swarm Options file 31 | $agentoptions = ' 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | * 63 | ue4-swarm-aws 64 | ue4-swarm-aws 65 | COORDINATORHOST 66 | C:\ue4-swarm/SwarmCache 67 | 5 68 | false 69 | true 70 | 15 71 | 72 | 0 73 | 0 74 | 75 | 76 | 768 77 | 768 78 | 79 | 2 80 | 4 81 | ' 82 | 83 | # Replace the Coordinator IP in the template 84 | $agentoptions = $agentoptions.replace("COORDINATORHOST", $coordinator_ip) 85 | 86 | # Save the configuration file 87 | $agentoptions | Out-File -FilePath "C:\ue4-swarm\SwarmAgent.Options.xml" 88 | 89 | # Define the Swarm agent as Scheduled Task that starts at instance boot 90 | $action = New-ScheduledTaskAction -Execute "C:\ue4-swarm\SwarmAgent.exe" 91 | $trigger = New-ScheduledTaskTrigger -AtStartup 92 | $principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest 93 | Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "SwarmAgent" -Description "UE4 Swarm Agent" 94 | 95 | # Restart the instance to trigger the Swarm Agent Scheduled Task 96 | Restart-Computer 97 | -------------------------------------------------------------------------------- /assets/start-coordinator.ps1: -------------------------------------------------------------------------------- 1 | 2 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | ## SPDX-License-Identifier: MIT-0 4 | 5 | # Define the Swarm Coordinator to start as a Scheduled task at startup 6 | $action = New-ScheduledTaskAction -Execute "C:\ue4-swarm\SwarmCoordinator.exe" 7 | $trigger = New-ScheduledTaskTrigger -AtStartup 8 | $principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest 9 | Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "SwarmCoordinator" -Description "UE4 Swarm Coordinator" 10 | 11 | # Restart the instance to trigger the Schedule task. 12 | Restart-Computer 13 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "python3 app.py", 3 | "context": { 4 | "@aws-cdk/core:enableStackNameDuplicates": "true", 5 | "aws-cdk:enableDiffNoFail": "true", 6 | "@aws-cdk/core:stackRelativeExports": "true", 7 | "vpc_cidr": "10.0.0.0/16", 8 | "trusted_cidr": "10.0.0.0/8", 9 | "agent_instancy_type": "t3.xlarge", 10 | "coordinator_instancy_type": "t3.large" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cloudformation/swarm-deployment.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | SwarmInstanceRole6BCAB0C0: 3 | Type: AWS::IAM::Role 4 | Properties: 5 | AssumeRolePolicyDocument: 6 | Statement: 7 | - Action: sts:AssumeRole 8 | Effect: Allow 9 | Principal: 10 | Service: ec2.amazonaws.com 11 | Version: "2012-10-17" 12 | ManagedPolicyArns: 13 | - Fn::Join: 14 | - "" 15 | - - "arn:" 16 | - Ref: AWS::Partition 17 | - :iam::aws:policy/service-role/AmazonEC2RoleforSSM 18 | - Fn::Join: 19 | - "" 20 | - - "arn:" 21 | - Ref: AWS::Partition 22 | - :iam::aws:policy/EC2InstanceProfileForImageBuilder 23 | Policies: 24 | - PolicyDocument: 25 | Statement: 26 | - Action: s3:GetObject 27 | Effect: Allow 28 | Resource: 29 | Fn::Join: 30 | - "" 31 | - - Fn::ImportValue: swarm-infra:ExportsOutputFnGetAttue4swarmbucketFCE52A18Arn2B326C3E 32 | - /* 33 | Version: "2012-10-17" 34 | PolicyName: "0" 35 | Metadata: 36 | aws:cdk:path: swarm-deployment/SwarmInstanceRole/Resource 37 | InstanceProfile: 38 | Type: AWS::IAM::InstanceProfile 39 | Properties: 40 | Roles: 41 | - Ref: SwarmInstanceRole6BCAB0C0 42 | InstanceProfileName: ue4-swarm-instance-profile 43 | Path: /executionServiceEC2Role/ 44 | Metadata: 45 | aws:cdk:path: swarm-deployment/InstanceProfile 46 | SecurityGroupDD263621: 47 | Type: AWS::EC2::SecurityGroup 48 | Properties: 49 | GroupDescription: Security Group for UE4 Swarm 50 | GroupName: Allow UE4 Swarm communication 51 | SecurityGroupEgress: 52 | - CidrIp: 0.0.0.0/0 53 | Description: Allow all outbound traffic by default 54 | IpProtocol: "-1" 55 | SecurityGroupIngress: 56 | - CidrIp: 10.0.0.0/8 57 | Description: Allow Trusted IP Swarm TCP 58 | FromPort: 8008 59 | IpProtocol: tcp 60 | ToPort: 8009 61 | - CidrIp: 10.0.0.0/8 62 | Description: Allow Trusted IP Swarm ICMP Ping 63 | FromPort: 8 64 | IpProtocol: icmp 65 | ToPort: -1 66 | - CidrIp: 10.0.0.0/8 67 | Description: Allow Trusted IP RDP TCP 68 | FromPort: 3389 69 | IpProtocol: tcp 70 | ToPort: 3389 71 | VpcId: 72 | Fn::ImportValue: swarm-infra:ExportsOutputRefSwarmVPCBD3E33869159DD07 73 | Metadata: 74 | aws:cdk:path: swarm-deployment/SecurityGroup/Resource 75 | SecurityGroupfromswarmdeploymentSecurityGroup5FE8F0348008800950569849: 76 | Type: AWS::EC2::SecurityGroupIngress 77 | Properties: 78 | IpProtocol: tcp 79 | Description: Allow SG Swarm TCP 80 | FromPort: 8008 81 | GroupId: 82 | Fn::GetAtt: 83 | - SecurityGroupDD263621 84 | - GroupId 85 | SourceSecurityGroupId: 86 | Fn::GetAtt: 87 | - SecurityGroupDD263621 88 | - GroupId 89 | ToPort: 8009 90 | Metadata: 91 | aws:cdk:path: swarm-deployment/SecurityGroup/from swarmdeploymentSecurityGroup5FE8F034:8008-8009 92 | SecurityGroupfromswarmdeploymentSecurityGroup5FE8F034ICMPType869D8BFE1: 93 | Type: AWS::EC2::SecurityGroupIngress 94 | Properties: 95 | IpProtocol: icmp 96 | Description: Allow SG Swarm ICMP Ping 97 | FromPort: 8 98 | GroupId: 99 | Fn::GetAtt: 100 | - SecurityGroupDD263621 101 | - GroupId 102 | SourceSecurityGroupId: 103 | Fn::GetAtt: 104 | - SecurityGroupDD263621 105 | - GroupId 106 | ToPort: -1 107 | Metadata: 108 | aws:cdk:path: swarm-deployment/SecurityGroup/from swarmdeploymentSecurityGroup5FE8F034:ICMP Type 8 109 | SwarmComponent: 110 | Type: AWS::ImageBuilder::Component 111 | Properties: 112 | Name: Install-Swarm-Dependencies 113 | Platform: Windows 114 | Version: 1.0.0 115 | Data: 116 | Fn::Join: 117 | - "" 118 | - - >- 119 | name: InstallUE4Swarm 120 | 121 | description: This component installs UE4 Swarm from S3 archive and also installs all prerequirements for a build. 122 | 123 | schemaVersion: 1.0 124 | 125 | 126 | phases: 127 | - name: build 128 | steps: 129 | - name: CreateTempFolder 130 | action: CreateFolder 131 | inputs: 132 | - path: C:\ue4-swarm-temp 133 | - name: DownloadDependencies 134 | action: S3Download 135 | maxAttempts: 3 136 | inputs: 137 | - source: s3:// 138 | - Fn::ImportValue: swarm-infra:ExportsOutputRefue4swarmbucketFCE52A18974D2A52 139 | - >- 140 | /ue4-swarm-archive.zip 141 | destination: C:\ue4-swarm-temp\ue4-swarm-archive.zip 142 | - name: CreateSwarmFolder 143 | action: CreateFolder 144 | inputs: 145 | - path: C:\ue4-swarm 146 | - name: UncompressSwarmFiles 147 | action: ExecutePowerShell 148 | inputs: 149 | commands: 150 | - Expand-Archive -LiteralPath C:\ue4-swarm-temp\ue4-swarm-archive.zip -DestinationPath C:\ue4-swarm 151 | - name: DeleteTempFolder 152 | action: DeleteFolder 153 | inputs: 154 | - path: C:\ue4-swarm-temp 155 | force: true 156 | - name: InstallDotNet 157 | action: ExecutePowerShell 158 | inputs: 159 | commands: 160 | - Install-WindowsFeature Net-Framework-Core 161 | - name: InstallPreReqs 162 | action: ExecutePowerShell 163 | inputs: 164 | commands: 165 | - Start-Process -Wait -FilePath "C:\ue4-swarm\UE4PrereqSetup_x64.exe" -ArgumentList "/install /quiet" 166 | - name: OpenFirewall 167 | action: ExecutePowerShell 168 | inputs: 169 | commands: 170 | - New-NetFirewallRule -DisplayName 'Allow UE4 Swarm TCP' -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8008-8009 171 | - New-NetFirewallRule -DisplayName 'Allow UE4 Swarm UDP' -Direction Inbound -Action Allow -Protocol UDP -LocalPort 8008-8009 172 | - New-NetFirewallRule -DisplayName 'Allow ICMP' -Direction Inbound -Action Allow -Protocol ICMPv4 173 | Metadata: 174 | aws:cdk:path: swarm-deployment/SwarmComponent 175 | SwarmInfraConfig: 176 | Type: AWS::ImageBuilder::InfrastructureConfiguration 177 | Properties: 178 | InstanceProfileName: ue4-swarm-instance-profile 179 | Name: UE4-Swarm-WindowsServer-2019-Infra-Config 180 | InstanceTypes: 181 | - m5.large 182 | SecurityGroupIds: 183 | - Fn::GetAtt: 184 | - SecurityGroupDD263621 185 | - GroupId 186 | SubnetId: 187 | Fn::ImportValue: swarm-infra:ExportsOutputRefSwarmVPCSwarmPrivateSubnet1Subnet80CE24A1CA52A385 188 | DependsOn: 189 | - InstanceProfile 190 | Metadata: 191 | aws:cdk:path: swarm-deployment/SwarmInfraConfig 192 | ImageRecipe: 193 | Type: AWS::ImageBuilder::ImageRecipe 194 | Properties: 195 | Components: 196 | - ComponentArn: 197 | Fn::GetAtt: 198 | - SwarmComponent 199 | - Arn 200 | Name: UE4-Swarm-Image 201 | ParentImage: 202 | Ref: SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishFullBaseC96584B6F00A464EAD1953AFF4B05118Parameter 203 | Version: 1.0.0 204 | Metadata: 205 | aws:cdk:path: swarm-deployment/ImageRecipe 206 | SwarmImage: 207 | Type: AWS::ImageBuilder::Image 208 | Properties: 209 | ImageRecipeArn: 210 | Fn::GetAtt: 211 | - ImageRecipe 212 | - Arn 213 | InfrastructureConfigurationArn: 214 | Fn::GetAtt: 215 | - SwarmInfraConfig 216 | - Arn 217 | Metadata: 218 | aws:cdk:path: swarm-deployment/SwarmImage 219 | ue4swarmcoordinatorInstanceProfile1A74E600: 220 | Type: AWS::IAM::InstanceProfile 221 | Properties: 222 | Roles: 223 | - Ref: SwarmInstanceRole6BCAB0C0 224 | Metadata: 225 | aws:cdk:path: swarm-deployment/ue4-swarm-coordinator/InstanceProfile 226 | ue4swarmcoordinator743D2823: 227 | Type: AWS::EC2::Instance 228 | Properties: 229 | AvailabilityZone: 230 | Fn::Select: 231 | - 0 232 | - Fn::GetAZs: "" 233 | IamInstanceProfile: 234 | Ref: ue4swarmcoordinatorInstanceProfile1A74E600 235 | ImageId: 236 | Fn::GetAtt: 237 | - SwarmImage 238 | - ImageId 239 | InstanceType: t3.large 240 | SecurityGroupIds: 241 | - Fn::GetAtt: 242 | - SecurityGroupDD263621 243 | - GroupId 244 | SubnetId: 245 | Fn::ImportValue: swarm-infra:ExportsOutputRefSwarmVPCSwarmPrivateSubnet1Subnet80CE24A1CA52A385 246 | Tags: 247 | - Key: Name 248 | Value: swarm-deployment/ue4-swarm-coordinator 249 | UserData: 250 | Fn::Base64: >- 251 | 252 | 253 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 254 | 255 | ## SPDX-License-Identifier: MIT-0 256 | 257 | 258 | # Define the Swarm Coordinator to start as a Scheduled task at startup 259 | 260 | $action = New-ScheduledTaskAction -Execute "C:\ue4-swarm\SwarmCoordinator.exe" 261 | 262 | $trigger = New-ScheduledTaskTrigger -AtStartup 263 | 264 | $principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest 265 | 266 | Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "SwarmCoordinator" -Description "UE4 Swarm Coordinator" 267 | 268 | 269 | # Restart the instance to trigger the Schedule task. 270 | 271 | Restart-Computer 272 | 273 | 274 | DependsOn: 275 | - SwarmInstanceRole6BCAB0C0 276 | Metadata: 277 | aws:cdk:path: swarm-deployment/ue4-swarm-coordinator/Resource 278 | ue4swarmagentInstanceProfileE2056578: 279 | Type: AWS::IAM::InstanceProfile 280 | Properties: 281 | Roles: 282 | - Ref: SwarmInstanceRole6BCAB0C0 283 | Metadata: 284 | aws:cdk:path: swarm-deployment/ue4-swarm-agent/InstanceProfile 285 | ue4swarmagentLaunchConfigC9C7E35F: 286 | Type: AWS::AutoScaling::LaunchConfiguration 287 | Properties: 288 | ImageId: 289 | Fn::GetAtt: 290 | - SwarmImage 291 | - ImageId 292 | InstanceType: t3.xlarge 293 | BlockDeviceMappings: 294 | - DeviceName: /dev/sda1 295 | Ebs: 296 | DeleteOnTermination: true 297 | VolumeSize: 100 298 | IamInstanceProfile: 299 | Ref: ue4swarmagentInstanceProfileE2056578 300 | SecurityGroups: 301 | - Fn::GetAtt: 302 | - SecurityGroupDD263621 303 | - GroupId 304 | UserData: 305 | Fn::Base64: 306 | Fn::Join: 307 | - "" 308 | - - >- 309 | 310 | 311 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 312 | 313 | ## SPDX-License-Identifier: MIT-0 314 | 315 | 316 | # Define Coordinator IP, Cloudformation replaces this when task is been created 317 | 318 | $coordinator_ip = " 319 | - Fn::GetAtt: 320 | - ue4swarmcoordinator743D2823 321 | - PrivateIp 322 | - >- 323 | " 324 | 325 | 326 | # Template of the Swarm Agent Developper Options file 327 | 328 | $developeroptions = ' 329 | 330 | 331 | true 332 | LOCALCORES 333 | BelowNormal 334 | REMOTECORES 335 | Idle 336 | false 337 | 15 338 | ' 339 | 340 | 341 | # Calculate number of cores 342 | 343 | $cores = (Get-WmiObject -Class Win32_Processor | Select-Object -Property NumberOfLogicalProcessors).NumberOfLogicalProcessors 344 | 345 | 346 | # Set the core values for the Swarm Agent 347 | 348 | $developeroptions = $developeroptions.replace("REMOTECORES", $cores) 349 | 350 | $developeroptions = $developeroptions.replace("LOCALCORES", $cores-1) 351 | 352 | 353 | # Save the configureation file 354 | 355 | $developeroptions | Out-File -FilePath "C:\ue4-swarm\SwarmAgent.DeveloperOptions.xml" 356 | 357 | 358 | # Template of the Swarm Options file 359 | 360 | $agentoptions = ' 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | * 393 | ue4-swarm-aws 394 | ue4-swarm-aws 395 | COORDINATORHOST 396 | C:\ue4-swarm/SwarmCache 397 | 5 398 | false 399 | true 400 | 15 401 | 402 | 0 403 | 0 404 | 405 | 406 | 768 407 | 768 408 | 409 | 2 410 | 4 411 | ' 412 | 413 | 414 | # Replace the Coordinator IP in the template 415 | 416 | $agentoptions = $agentoptions.replace("COORDINATORHOST", $coordinator_ip) 417 | 418 | 419 | # Save the configuration file 420 | 421 | $agentoptions | Out-File -FilePath "C:\ue4-swarm\SwarmAgent.Options.xml" 422 | 423 | 424 | # Define the Swarm agent as Scheduled Task that starts at instance boot 425 | 426 | $action = New-ScheduledTaskAction -Execute "C:\ue4-swarm\SwarmAgent.exe" 427 | 428 | $trigger = New-ScheduledTaskTrigger -AtStartup 429 | 430 | $principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest 431 | 432 | Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "SwarmAgent" -Description "UE4 Swarm Agent" 433 | 434 | 435 | # Restart the instance to trigger the Swarm Agent Scheduled Task 436 | 437 | Restart-Computer 438 | 439 | 440 | DependsOn: 441 | - SwarmInstanceRole6BCAB0C0 442 | Metadata: 443 | aws:cdk:path: swarm-deployment/ue4-swarm-agent/LaunchConfig 444 | ue4swarmagentASG86631DEA: 445 | Type: AWS::AutoScaling::AutoScalingGroup 446 | Properties: 447 | MaxSize: "1" 448 | MinSize: "1" 449 | DesiredCapacity: "1" 450 | LaunchConfigurationName: 451 | Ref: ue4swarmagentLaunchConfigC9C7E35F 452 | Tags: 453 | - Key: Name 454 | PropagateAtLaunch: true 455 | Value: swarm-deployment/ue4-swarm-agent 456 | VPCZoneIdentifier: 457 | - Fn::ImportValue: swarm-infra:ExportsOutputRefSwarmVPCSwarmPrivateSubnet1Subnet80CE24A1CA52A385 458 | - Fn::ImportValue: swarm-infra:ExportsOutputRefSwarmVPCSwarmPrivateSubnet2Subnet090387FF4A3C79E6 459 | UpdatePolicy: 460 | AutoScalingScheduledAction: 461 | IgnoreUnmodifiedGroupSizeProperties: true 462 | Metadata: 463 | aws:cdk:path: swarm-deployment/ue4-swarm-agent/ASG 464 | CDKMetadata: 465 | Type: AWS::CDK::Metadata 466 | Properties: 467 | Modules: aws-cdk=1.89.0,@aws-cdk/assets=1.91.0,@aws-cdk/aws-applicationautoscaling=1.91.0,@aws-cdk/aws-autoscaling=1.91.0,@aws-cdk/aws-autoscaling-common=1.91.0,@aws-cdk/aws-certificatemanager=1.91.0,@aws-cdk/aws-cloudformation=1.91.0,@aws-cdk/aws-cloudwatch=1.91.0,@aws-cdk/aws-codeguruprofiler=1.91.0,@aws-cdk/aws-ec2=1.91.0,@aws-cdk/aws-ecr=1.91.0,@aws-cdk/aws-ecr-assets=1.91.0,@aws-cdk/aws-efs=1.91.0,@aws-cdk/aws-elasticloadbalancing=1.91.0,@aws-cdk/aws-elasticloadbalancingv2=1.91.0,@aws-cdk/aws-events=1.91.0,@aws-cdk/aws-iam=1.91.0,@aws-cdk/aws-imagebuilder=1.91.0,@aws-cdk/aws-kms=1.91.0,@aws-cdk/aws-lambda=1.91.0,@aws-cdk/aws-logs=1.91.0,@aws-cdk/aws-route53=1.91.0,@aws-cdk/aws-s3=1.91.0,@aws-cdk/aws-s3-assets=1.91.0,@aws-cdk/aws-sns=1.91.0,@aws-cdk/aws-sqs=1.91.0,@aws-cdk/aws-ssm=1.91.0,@aws-cdk/cloud-assembly-schema=1.91.0,@aws-cdk/core=1.91.0,@aws-cdk/custom-resources=1.91.0,@aws-cdk/cx-api=1.91.0,@aws-cdk/region-info=1.91.0,jsii-runtime=Python/3.9.1 468 | Metadata: 469 | aws:cdk:path: swarm-deployment/CDKMetadata/Default 470 | Parameters: 471 | SsmParameterValueawsserviceamiwindowslatestWindowsServer2019EnglishFullBaseC96584B6F00A464EAD1953AFF4B05118Parameter: 472 | Type: AWS::SSM::Parameter::Value 473 | Default: /aws/service/ami-windows-latest/Windows_Server-2019-English-Full-Base 474 | Outputs: 475 | ImageID: 476 | Description: Swarm AMI ID 477 | Value: 478 | Fn::GetAtt: 479 | - SwarmImage 480 | - ImageId 481 | CoordinatorPrivateIP: 482 | Description: Coordinator Instance Private IP 483 | Value: 484 | Fn::GetAtt: 485 | - ue4swarmcoordinator743D2823 486 | - PrivateIp 487 | 488 | -------------------------------------------------------------------------------- /cloudformation/swarm-infra.yaml: -------------------------------------------------------------------------------- 1 | Resources: 2 | ue4swarmbucketFCE52A18: 3 | Type: AWS::S3::Bucket 4 | UpdateReplacePolicy: Retain 5 | DeletionPolicy: Retain 6 | Metadata: 7 | aws:cdk:path: swarm-infra/ue4-swarm-bucket/Resource 8 | SwarmVPCBD3E3386: 9 | Type: AWS::EC2::VPC 10 | Properties: 11 | CidrBlock: 10.0.0.0/16 12 | EnableDnsHostnames: true 13 | EnableDnsSupport: true 14 | InstanceTenancy: default 15 | Tags: 16 | - Key: Name 17 | Value: swarm-infra/Swarm-VPC 18 | Metadata: 19 | aws:cdk:path: swarm-infra/Swarm-VPC/Resource 20 | SwarmVPCSwarmPublicSubnet1Subnet68AF46CE: 21 | Type: AWS::EC2::Subnet 22 | Properties: 23 | CidrBlock: 10.0.0.0/18 24 | VpcId: 25 | Ref: SwarmVPCBD3E3386 26 | AvailabilityZone: 27 | Fn::Select: 28 | - 0 29 | - Fn::GetAZs: "" 30 | MapPublicIpOnLaunch: true 31 | Tags: 32 | - Key: aws-cdk:subnet-name 33 | Value: Swarm-Public 34 | - Key: aws-cdk:subnet-type 35 | Value: Public 36 | - Key: Name 37 | Value: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1 38 | Metadata: 39 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1/Subnet 40 | SwarmVPCSwarmPublicSubnet1RouteTableB9D2A52E: 41 | Type: AWS::EC2::RouteTable 42 | Properties: 43 | VpcId: 44 | Ref: SwarmVPCBD3E3386 45 | Tags: 46 | - Key: Name 47 | Value: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1 48 | Metadata: 49 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1/RouteTable 50 | SwarmVPCSwarmPublicSubnet1RouteTableAssociation7A27F9BD: 51 | Type: AWS::EC2::SubnetRouteTableAssociation 52 | Properties: 53 | RouteTableId: 54 | Ref: SwarmVPCSwarmPublicSubnet1RouteTableB9D2A52E 55 | SubnetId: 56 | Ref: SwarmVPCSwarmPublicSubnet1Subnet68AF46CE 57 | Metadata: 58 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1/RouteTableAssociation 59 | SwarmVPCSwarmPublicSubnet1DefaultRoute6D98198A: 60 | Type: AWS::EC2::Route 61 | Properties: 62 | RouteTableId: 63 | Ref: SwarmVPCSwarmPublicSubnet1RouteTableB9D2A52E 64 | DestinationCidrBlock: 0.0.0.0/0 65 | GatewayId: 66 | Ref: SwarmVPCIGW4D16EC27 67 | DependsOn: 68 | - SwarmVPCVPCGW9D5EF4D0 69 | Metadata: 70 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1/DefaultRoute 71 | SwarmVPCSwarmPublicSubnet1EIPA2B8752B: 72 | Type: AWS::EC2::EIP 73 | Properties: 74 | Domain: vpc 75 | Tags: 76 | - Key: Name 77 | Value: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1 78 | Metadata: 79 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1/EIP 80 | SwarmVPCSwarmPublicSubnet1NATGatewayC7F4C94B: 81 | Type: AWS::EC2::NatGateway 82 | Properties: 83 | AllocationId: 84 | Fn::GetAtt: 85 | - SwarmVPCSwarmPublicSubnet1EIPA2B8752B 86 | - AllocationId 87 | SubnetId: 88 | Ref: SwarmVPCSwarmPublicSubnet1Subnet68AF46CE 89 | Tags: 90 | - Key: Name 91 | Value: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1 92 | Metadata: 93 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet1/NATGateway 94 | SwarmVPCSwarmPublicSubnet2Subnet2939B1DC: 95 | Type: AWS::EC2::Subnet 96 | Properties: 97 | CidrBlock: 10.0.64.0/18 98 | VpcId: 99 | Ref: SwarmVPCBD3E3386 100 | AvailabilityZone: 101 | Fn::Select: 102 | - 1 103 | - Fn::GetAZs: "" 104 | MapPublicIpOnLaunch: true 105 | Tags: 106 | - Key: aws-cdk:subnet-name 107 | Value: Swarm-Public 108 | - Key: aws-cdk:subnet-type 109 | Value: Public 110 | - Key: Name 111 | Value: swarm-infra/Swarm-VPC/Swarm-PublicSubnet2 112 | Metadata: 113 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet2/Subnet 114 | SwarmVPCSwarmPublicSubnet2RouteTableAA2D1291: 115 | Type: AWS::EC2::RouteTable 116 | Properties: 117 | VpcId: 118 | Ref: SwarmVPCBD3E3386 119 | Tags: 120 | - Key: Name 121 | Value: swarm-infra/Swarm-VPC/Swarm-PublicSubnet2 122 | Metadata: 123 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet2/RouteTable 124 | SwarmVPCSwarmPublicSubnet2RouteTableAssociation263F1174: 125 | Type: AWS::EC2::SubnetRouteTableAssociation 126 | Properties: 127 | RouteTableId: 128 | Ref: SwarmVPCSwarmPublicSubnet2RouteTableAA2D1291 129 | SubnetId: 130 | Ref: SwarmVPCSwarmPublicSubnet2Subnet2939B1DC 131 | Metadata: 132 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet2/RouteTableAssociation 133 | SwarmVPCSwarmPublicSubnet2DefaultRouteC73F3024: 134 | Type: AWS::EC2::Route 135 | Properties: 136 | RouteTableId: 137 | Ref: SwarmVPCSwarmPublicSubnet2RouteTableAA2D1291 138 | DestinationCidrBlock: 0.0.0.0/0 139 | GatewayId: 140 | Ref: SwarmVPCIGW4D16EC27 141 | DependsOn: 142 | - SwarmVPCVPCGW9D5EF4D0 143 | Metadata: 144 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PublicSubnet2/DefaultRoute 145 | SwarmVPCSwarmPrivateSubnet1Subnet80CE24A1: 146 | Type: AWS::EC2::Subnet 147 | Properties: 148 | CidrBlock: 10.0.128.0/18 149 | VpcId: 150 | Ref: SwarmVPCBD3E3386 151 | AvailabilityZone: 152 | Fn::Select: 153 | - 0 154 | - Fn::GetAZs: "" 155 | MapPublicIpOnLaunch: false 156 | Tags: 157 | - Key: aws-cdk:subnet-name 158 | Value: Swarm-Private 159 | - Key: aws-cdk:subnet-type 160 | Value: Private 161 | - Key: Name 162 | Value: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet1 163 | Metadata: 164 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet1/Subnet 165 | SwarmVPCSwarmPrivateSubnet1RouteTable61575E59: 166 | Type: AWS::EC2::RouteTable 167 | Properties: 168 | VpcId: 169 | Ref: SwarmVPCBD3E3386 170 | Tags: 171 | - Key: Name 172 | Value: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet1 173 | Metadata: 174 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet1/RouteTable 175 | SwarmVPCSwarmPrivateSubnet1RouteTableAssociation03849ECB: 176 | Type: AWS::EC2::SubnetRouteTableAssociation 177 | Properties: 178 | RouteTableId: 179 | Ref: SwarmVPCSwarmPrivateSubnet1RouteTable61575E59 180 | SubnetId: 181 | Ref: SwarmVPCSwarmPrivateSubnet1Subnet80CE24A1 182 | Metadata: 183 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet1/RouteTableAssociation 184 | SwarmVPCSwarmPrivateSubnet1DefaultRouteAB9BFF7A: 185 | Type: AWS::EC2::Route 186 | Properties: 187 | RouteTableId: 188 | Ref: SwarmVPCSwarmPrivateSubnet1RouteTable61575E59 189 | DestinationCidrBlock: 0.0.0.0/0 190 | NatGatewayId: 191 | Ref: SwarmVPCSwarmPublicSubnet1NATGatewayC7F4C94B 192 | Metadata: 193 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet1/DefaultRoute 194 | SwarmVPCSwarmPrivateSubnet2Subnet090387FF: 195 | Type: AWS::EC2::Subnet 196 | Properties: 197 | CidrBlock: 10.0.192.0/18 198 | VpcId: 199 | Ref: SwarmVPCBD3E3386 200 | AvailabilityZone: 201 | Fn::Select: 202 | - 1 203 | - Fn::GetAZs: "" 204 | MapPublicIpOnLaunch: false 205 | Tags: 206 | - Key: aws-cdk:subnet-name 207 | Value: Swarm-Private 208 | - Key: aws-cdk:subnet-type 209 | Value: Private 210 | - Key: Name 211 | Value: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet2 212 | Metadata: 213 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet2/Subnet 214 | SwarmVPCSwarmPrivateSubnet2RouteTable41E63F76: 215 | Type: AWS::EC2::RouteTable 216 | Properties: 217 | VpcId: 218 | Ref: SwarmVPCBD3E3386 219 | Tags: 220 | - Key: Name 221 | Value: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet2 222 | Metadata: 223 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet2/RouteTable 224 | SwarmVPCSwarmPrivateSubnet2RouteTableAssociation305321F9: 225 | Type: AWS::EC2::SubnetRouteTableAssociation 226 | Properties: 227 | RouteTableId: 228 | Ref: SwarmVPCSwarmPrivateSubnet2RouteTable41E63F76 229 | SubnetId: 230 | Ref: SwarmVPCSwarmPrivateSubnet2Subnet090387FF 231 | Metadata: 232 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet2/RouteTableAssociation 233 | SwarmVPCSwarmPrivateSubnet2DefaultRouteB0DD1E30: 234 | Type: AWS::EC2::Route 235 | Properties: 236 | RouteTableId: 237 | Ref: SwarmVPCSwarmPrivateSubnet2RouteTable41E63F76 238 | DestinationCidrBlock: 0.0.0.0/0 239 | NatGatewayId: 240 | Ref: SwarmVPCSwarmPublicSubnet1NATGatewayC7F4C94B 241 | Metadata: 242 | aws:cdk:path: swarm-infra/Swarm-VPC/Swarm-PrivateSubnet2/DefaultRoute 243 | SwarmVPCIGW4D16EC27: 244 | Type: AWS::EC2::InternetGateway 245 | Properties: 246 | Tags: 247 | - Key: Name 248 | Value: swarm-infra/Swarm-VPC 249 | Metadata: 250 | aws:cdk:path: swarm-infra/Swarm-VPC/IGW 251 | SwarmVPCVPCGW9D5EF4D0: 252 | Type: AWS::EC2::VPCGatewayAttachment 253 | Properties: 254 | VpcId: 255 | Ref: SwarmVPCBD3E3386 256 | InternetGatewayId: 257 | Ref: SwarmVPCIGW4D16EC27 258 | Metadata: 259 | aws:cdk:path: swarm-infra/Swarm-VPC/VPCGW 260 | CDKMetadata: 261 | Type: AWS::CDK::Metadata 262 | Properties: 263 | Modules: aws-cdk=1.89.0,@aws-cdk/assets=1.91.0,@aws-cdk/aws-applicationautoscaling=1.91.0,@aws-cdk/aws-autoscaling=1.91.0,@aws-cdk/aws-autoscaling-common=1.91.0,@aws-cdk/aws-certificatemanager=1.91.0,@aws-cdk/aws-cloudformation=1.91.0,@aws-cdk/aws-cloudwatch=1.91.0,@aws-cdk/aws-codeguruprofiler=1.91.0,@aws-cdk/aws-ec2=1.91.0,@aws-cdk/aws-ecr=1.91.0,@aws-cdk/aws-ecr-assets=1.91.0,@aws-cdk/aws-efs=1.91.0,@aws-cdk/aws-elasticloadbalancing=1.91.0,@aws-cdk/aws-elasticloadbalancingv2=1.91.0,@aws-cdk/aws-events=1.91.0,@aws-cdk/aws-iam=1.91.0,@aws-cdk/aws-imagebuilder=1.91.0,@aws-cdk/aws-kms=1.91.0,@aws-cdk/aws-lambda=1.91.0,@aws-cdk/aws-logs=1.91.0,@aws-cdk/aws-route53=1.91.0,@aws-cdk/aws-s3=1.91.0,@aws-cdk/aws-s3-assets=1.91.0,@aws-cdk/aws-sns=1.91.0,@aws-cdk/aws-sqs=1.91.0,@aws-cdk/aws-ssm=1.91.0,@aws-cdk/cloud-assembly-schema=1.91.0,@aws-cdk/core=1.91.0,@aws-cdk/custom-resources=1.91.0,@aws-cdk/cx-api=1.91.0,@aws-cdk/region-info=1.91.0,jsii-runtime=Python/3.9.1 264 | Metadata: 265 | aws:cdk:path: swarm-infra/CDKMetadata/Default 266 | Outputs: 267 | BucketName: 268 | Description: Swarm Bucket Name 269 | Value: 270 | Ref: ue4swarmbucketFCE52A18 271 | ExportsOutputFnGetAttue4swarmbucketFCE52A18Arn2B326C3E: 272 | Value: 273 | Fn::GetAtt: 274 | - ue4swarmbucketFCE52A18 275 | - Arn 276 | Export: 277 | Name: swarm-infra:ExportsOutputFnGetAttue4swarmbucketFCE52A18Arn2B326C3E 278 | ExportsOutputRefSwarmVPCBD3E33869159DD07: 279 | Value: 280 | Ref: SwarmVPCBD3E3386 281 | Export: 282 | Name: swarm-infra:ExportsOutputRefSwarmVPCBD3E33869159DD07 283 | ExportsOutputRefue4swarmbucketFCE52A18974D2A52: 284 | Value: 285 | Ref: ue4swarmbucketFCE52A18 286 | Export: 287 | Name: swarm-infra:ExportsOutputRefue4swarmbucketFCE52A18974D2A52 288 | ExportsOutputRefSwarmVPCSwarmPrivateSubnet1Subnet80CE24A1CA52A385: 289 | Value: 290 | Ref: SwarmVPCSwarmPrivateSubnet1Subnet80CE24A1 291 | Export: 292 | Name: swarm-infra:ExportsOutputRefSwarmVPCSwarmPrivateSubnet1Subnet80CE24A1CA52A385 293 | ExportsOutputRefSwarmVPCSwarmPrivateSubnet2Subnet090387FF4A3C79E6: 294 | Value: 295 | Ref: SwarmVPCSwarmPrivateSubnet2Subnet090387FF 296 | Export: 297 | Name: swarm-infra:ExportsOutputRefSwarmVPCSwarmPrivateSubnet2Subnet090387FF4A3C79E6 298 | 299 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aws-cdk.core 2 | aws-cdk.aws_s3 3 | aws-cdk.aws_ec2 4 | aws-cdk.aws_iam 5 | aws-cdk.aws_imagebuilder 6 | aws-cdk.aws_autoscaling 7 | -------------------------------------------------------------------------------- /swarm_cdk/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ec2-cluster-for-unreal-swarms/3d7a02c7fbf33b50ed287b88476b468aebac3766/swarm_cdk/__init__.py -------------------------------------------------------------------------------- /swarm_cdk/swarm_cdk_deployment.py: -------------------------------------------------------------------------------- 1 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | ## SPDX-License-Identifier: MIT-0 3 | 4 | from aws_cdk import ( 5 | aws_ec2 as ec2, 6 | aws_iam as iam, 7 | aws_s3 as s3, 8 | aws_imagebuilder as imagebuilder, 9 | aws_autoscaling as autoscaling, 10 | core 11 | ) 12 | 13 | class SwarmDeployment(core.Stack): 14 | 15 | def __init__(self, scope: core.Construct, id: str, bucket, vpc, **kwargs) -> None: 16 | super().__init__(scope, id, **kwargs) 17 | 18 | publicsubnets = vpc.select_subnets(subnet_type=ec2.SubnetType.PUBLIC) 19 | privatesubnets = vpc.select_subnets(subnet_type=ec2.SubnetType.PRIVATE) 20 | 21 | # Custom policy to allow writes to S3 bucket for 22 | 23 | writelogspolicy = iam.PolicyStatement( 24 | effect=iam.Effect.ALLOW, 25 | actions=["s3:GetObject",], 26 | resources=[bucket.bucket_arn+ "/*"] 27 | ) 28 | 29 | writelogsdocument = iam.PolicyDocument() 30 | writelogsdocument.add_statements(writelogspolicy) 31 | 32 | # Instance Role and SSM Managed Policy 33 | role = iam.Role(self, "SwarmInstanceRole", assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"), inline_policies=[writelogsdocument]) 34 | 35 | role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AmazonSSMManagedInstanceCore")) 36 | role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("EC2InstanceProfileForImageBuilder")) 37 | 38 | # Create instance profile that EC2 Image builder can use 39 | # This can be also later used running Swarm instances 40 | instanceprofile = iam.CfnInstanceProfile(self, "InstanceProfile", 41 | instance_profile_name="ue4-swarm-instance-profile", 42 | path="/executionServiceEC2Role/", 43 | roles=[role.role_name] 44 | ) 45 | 46 | # Security Group for the Swarm instances that allows communication 47 | securitygroup = ec2.SecurityGroup(self, "SecurityGroup", 48 | vpc=vpc, 49 | description="Security Group for UE4 Swarm", 50 | security_group_name="Allow UE4 Swarm communication", 51 | allow_all_outbound=True 52 | ) 53 | 54 | 55 | # Allow Swarm Agents and Coordinator to talk to each other in same Security Group 56 | securitygroup.add_ingress_rule(securitygroup, ec2.Port.tcp_range(8008,8009), 'Allow SG Swarm TCP') 57 | securitygroup.add_ingress_rule(securitygroup, ec2.Port.icmp_ping(), 'Allow SG Swarm ICMP Ping') 58 | 59 | # Parameter for the trusted network 60 | trusted_cidr = self.node.try_get_context("trusted_cidr") 61 | 62 | # Define default trusted CIDR 63 | if trusted_cidr is None: 64 | trusted_cidr = "10.0.0.0/8" 65 | 66 | # Allow RDP, Swarm and ICMP ping from trusted CIDR prefix 67 | securitygroup.add_ingress_rule(ec2.Peer.ipv4(trusted_cidr), ec2.Port.tcp_range(8008,8009), 'Allow Trusted IP Swarm TCP') 68 | securitygroup.add_ingress_rule(ec2.Peer.ipv4(trusted_cidr), ec2.Port.icmp_ping(), 'Allow Trusted IP Swarm ICMP Ping') 69 | securitygroup.add_ingress_rule(ec2.Peer.ipv4(trusted_cidr), ec2.Port.tcp(3389), 'Allow Trusted IP RDP TCP') 70 | 71 | # Read the EC2 Image builder component instructions from a file 72 | # These instructions are PowerShell commands to download dependencies ZIP. 73 | # It will then uncompress it, run nessesary installations for the components. 74 | 75 | component_file_path = "assets/component.yml" 76 | image_builder_instance_type = ["m5.large"] 77 | 78 | with open(component_file_path, 'r') as componentfile: 79 | componentdata = componentfile.read() 80 | 81 | componentdata = componentdata.replace("S3-BUCKET-NAME", bucket.bucket_name) 82 | 83 | # Define the component for EC2 Image Builder 84 | swarmcomponent = imagebuilder.CfnComponent(self, 85 | "SwarmComponent", 86 | name="Install-Swarm-Dependencies", 87 | platform="Windows", 88 | version="1.0.0", 89 | data=componentdata 90 | ) 91 | 92 | # Define the new VPC and Instanceprofile to be used for Image Building 93 | infraconfig = imagebuilder.CfnInfrastructureConfiguration(self, 94 | "SwarmInfraConfig", 95 | name="UE4-Swarm-WindowsServer-2019-Infra-Config", 96 | instance_profile_name=instanceprofile.instance_profile_name, 97 | # logging=imagebuilder.CfnInfrastructureConfiguration.S3LogsProperty(s3_bucket_name=bucket.bucket_name), 98 | subnet_id=privatesubnets.subnets[0].subnet_id, 99 | security_group_ids=[securitygroup.security_group_id], 100 | instance_types=image_builder_instance_type 101 | ) 102 | 103 | # Ensure that instance profile has completed creation before applying the aboce config 104 | infraconfig.add_depends_on(instanceprofile) 105 | 106 | # Lookup latest Windows Server 2019 107 | basewindows = ec2.MachineImage.latest_windows(ec2.WindowsVersion.WINDOWS_SERVER_2019_ENGLISH_FULL_BASE); 108 | 109 | # Define Image build recipe combinen the Windows image and our Component 110 | recipe = imagebuilder.CfnImageRecipe(self, 111 | "ImageRecipe", 112 | name="UE4-Swarm-Image", 113 | parent_image=basewindows.get_image(self).image_id, 114 | version="1.0.0", 115 | components=[{"componentArn":swarmcomponent.attr_arn}] 116 | ) 117 | 118 | # Start the build of new AMI based on the Recipe and Infra config 119 | swarmimage = imagebuilder.CfnImage(self, 120 | "SwarmImage", 121 | image_recipe_arn=recipe.attr_arn, 122 | infrastructure_configuration_arn=infraconfig.attr_arn 123 | ) 124 | 125 | # Lookup the AMI ID for the resulting image 126 | swarmami = ec2.GenericWindowsImage({self.region: swarmimage.attr_image_id}) 127 | 128 | # Read the Script to start Swarm Coordinator 129 | # Will be used in the instance user data 130 | with open('assets/start-coordinator.ps1', 'r') as coordfile: 131 | coorduserdata = coordfile.read() 132 | 133 | # Parameter for the instance type 134 | coordinator_instancy_type = self.node.try_get_context("coordinator_instancy_type") 135 | 136 | # Define default instance type 137 | if coordinator_instancy_type is None: 138 | coordinator_instancy_type = "t3.large" 139 | 140 | # Launch the Swarm Coordinator instance 141 | coordinator = ec2.Instance(self, "ue4-swarm-coordinator", 142 | instance_type=ec2.InstanceType(coordinator_instancy_type), 143 | machine_image=swarmami, 144 | vpc = vpc, 145 | vpc_subnets = ec2.SubnetSelection(subnet_type=ec2.SubnetType('PRIVATE')), 146 | role = role, 147 | security_group=securitygroup, 148 | user_data=ec2.UserData.custom(coorduserdata) 149 | ) 150 | 151 | with open('assets/start-agent.ps1', 'r') as agentfile: 152 | agentuserdata = agentfile.read() 153 | 154 | agentuserdata = agentuserdata.replace("COORDINATOR_IP", coordinator.instance_private_ip) 155 | 156 | # Define C: -drives size for the Swarm Agents 157 | root_device = autoscaling.BlockDevice( 158 | device_name='/dev/sda1', 159 | volume=autoscaling.BlockDeviceVolume.ebs( 160 | volume_size=100, 161 | delete_on_termination=True 162 | ), 163 | ) 164 | 165 | # Parameter for the instance type 166 | agent_instancy_type = self.node.try_get_context("agent_instancy_type") 167 | 168 | # Define default instance type 169 | if agent_instancy_type is None: 170 | agent_instancy_type = "t3.xlarge" 171 | 172 | # Create Autoscaling group for Swarm Agents 173 | # It won't automaticaly scale on load but instead it will automatically 174 | # Scale down at evening and bring the cluster up again in the morning 175 | swarmasg = autoscaling.AutoScalingGroup(self, "ue4-swarm-agent", 176 | instance_type=ec2.InstanceType(agent_instancy_type), 177 | machine_image=swarmami, 178 | role=role, 179 | vpc=vpc, 180 | vpc_subnets = ec2.SubnetSelection(subnet_type=ec2.SubnetType('PRIVATE')), 181 | security_group=securitygroup, 182 | block_devices=[root_device], 183 | user_data=ec2.UserData.custom(agentuserdata), 184 | desired_capacity=1, 185 | max_capacity=1, 186 | min_capacity=1) 187 | 188 | 189 | # Output the AMI ID and Coordinator IP 190 | output = core.CfnOutput(self, "ImageID", 191 | value=swarmimage.attr_image_id, 192 | description="Swarm AMI ID") 193 | 194 | output = core.CfnOutput(self, "CoordinatorPrivateIP", 195 | value=coordinator.instance_private_ip, 196 | description="Coordinator Instance Private IP") 197 | 198 | -------------------------------------------------------------------------------- /swarm_cdk/swarm_cdk_infra.py: -------------------------------------------------------------------------------- 1 | ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | ## SPDX-License-Identifier: MIT-0 3 | 4 | from aws_cdk import ( 5 | aws_ec2 as ec2, 6 | aws_s3 as s3, 7 | core 8 | ) 9 | 10 | 11 | class SwarmInfra(core.Stack): 12 | 13 | bucket = s3.IBucket 14 | vpc = ec2.IVpc 15 | 16 | def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: 17 | super().__init__(scope, id, **kwargs) 18 | 19 | # Create S3 Bucket for the Swarm Dependencies 20 | self.bucket = s3.Bucket(self, "ue4-swarm-bucket") 21 | 22 | # Retrieve CIDR from CDK Context for the VPC CIDR 23 | vpc_cidr = self.node.try_get_context("vpc_cidr") 24 | 25 | # Create new VPC with one subnet for the test EC2 instance 26 | self.vpc = ec2.Vpc(self, "Swarm-VPC", 27 | cidr=vpc_cidr, 28 | nat_gateways=1, 29 | subnet_configuration=[ec2.SubnetConfiguration(name="Swarm-Public",subnet_type=ec2.SubnetType.PUBLIC), 30 | ec2.SubnetConfiguration(name="Swarm-Private",subnet_type=ec2.SubnetType.PRIVATE)] 31 | ) 32 | 33 | # Output the S3 Bucket name for the Swarm ZIP file 34 | output = core.CfnOutput(self, "BucketName", 35 | value=self.bucket.bucket_name, 36 | description="Swarm Bucket Name") --------------------------------------------------------------------------------