diff --git a/packages/aws-rfdk/lib/core/test/asset-constants.ts b/packages/aws-rfdk/lib/core/test/asset-constants.ts index 0648f620b..0b529463b 100644 --- a/packages/aws-rfdk/lib/core/test/asset-constants.ts +++ b/packages/aws-rfdk/lib/core/test/asset-constants.ts @@ -29,228 +29,3 @@ export const INSTALL_MONGODB_3_6_SCRIPT_LINUX = { export const MONGODB_INSTANCE_3_6_SCRIPT = { Bucket: stringLike('AssetParameters*S3Bucket352E624B'), }; - -export function linuxDownloadRunScriptBoilerplate(script: { Bucket: string, Key: string }) { - return [ - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - '\')\naws s3 cp \'s3://', - {Ref: script.Bucket}, - '/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - '\' \'/tmp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - '\'\n' + - 'set -e\n' + - 'chmod +x \'/tmp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - { - Ref: script.Key, - }, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - '\'\n\'/tmp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - ]; -} - -export function windowsDownloadRunScriptBoilerplate(script: { Bucket: string, Key: string }) { - return [ - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - '\' ) -ea 0\nRead-S3Object -BucketName \'', - {Ref: script.Bucket}, - '\' -key \'', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - '\' -file \'C:/temp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - '\' -ErrorAction Stop\n&\'C:/temp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - { - Ref: script.Key, - }, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: script.Key}, - ], - }, - ], - }, - ]; -} diff --git a/packages/aws-rfdk/lib/deadline/lib/worker-configuration.ts b/packages/aws-rfdk/lib/deadline/lib/worker-configuration.ts index 0e48a4fe6..0c82a0a46 100644 --- a/packages/aws-rfdk/lib/deadline/lib/worker-configuration.ts +++ b/packages/aws-rfdk/lib/deadline/lib/worker-configuration.ts @@ -8,6 +8,7 @@ import * as path from 'path'; import { OperatingSystemType, } from '@aws-cdk/aws-ec2'; +import { Asset } from '@aws-cdk/aws-s3-assets'; import { Construct, Duration, @@ -116,6 +117,16 @@ export interface WorkerSettings { * @default - Worker is not assigned to any region */ readonly region?: string; + + /** + * The port to configure the worker to listen on for remote commands such as + * requests for its log stream. If more than one worker is present on a single + * host, connsecutive ports will be opened, starting with the supplied port, + * up to the maximum number of workers defined by the WorkerInstanceFleet. + * + * @default 56032 + */ + readonly listenerPort?: number; } /** @@ -178,6 +189,16 @@ export interface WorkerInstanceConfigurationProps { * environments. */ export class WorkerInstanceConfiguration extends Construct { + /** + * The default port to use for a worker to listen on for remote commands. + */ + private static readonly DEFAULT_LISTENER_PORT = 56032; + + /** + * @inheritdoc + */ + public readonly listenerPort: number; + constructor(scope: Construct, id: string, props: WorkerInstanceConfigurationProps) { super(scope, id); props.userDataProvider?.preCloudWatchAgent(props.worker); @@ -185,9 +206,12 @@ export class WorkerInstanceConfiguration extends Construct { this.configureCloudWatchLogStream(props.worker, id, props.cloudwatchLogSettings); } props.userDataProvider?.preRenderQueueConfiguration(props.worker); - props.renderQueue?.configureClientInstance({ host: props.worker}); + props.renderQueue?.configureClientInstance({ host: props.worker }); props.userDataProvider?.preWorkerConfiguration(props.worker); + + this.listenerPort = props.workerSettings?.listenerPort ?? WorkerInstanceConfiguration.DEFAULT_LISTENER_PORT; this.configureWorkerSettings(props.worker, id, props.workerSettings); + props.userDataProvider?.postWorkerLaunch(props.worker); } @@ -257,6 +281,14 @@ export class WorkerInstanceConfiguration extends Construct { 'scripts/', ), }); + const configureWorkerPortAsset = new Asset(this, `${id}WorkerListenerScript`, { + path: path.join(__dirname, '..', 'scripts', 'python', 'worker-listening-port.py'), + }); + + const configWorkerPortLocalPath = worker.userData.addS3DownloadCommand({ + bucket: configureWorkerPortAsset.bucket, + bucketKey: configureWorkerPortAsset.s3ObjectKey, + }); // Converting to lower case, as groups and pools are all stored in lower case in deadline. const groups = settings?.groups?.map(val => val.toLowerCase()).join(',') ?? ''; @@ -269,6 +301,8 @@ export class WorkerInstanceConfiguration extends Construct { `'${pools}'`, `'${settings?.region ?? ''}'`, `'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}'`, + this.listenerPort.toString(), + configWorkerPortLocalPath, ], }); } diff --git a/packages/aws-rfdk/lib/deadline/lib/worker-fleet.ts b/packages/aws-rfdk/lib/deadline/lib/worker-fleet.ts index 26383c828..310aef644 100644 --- a/packages/aws-rfdk/lib/deadline/lib/worker-fleet.ts +++ b/packages/aws-rfdk/lib/deadline/lib/worker-fleet.ts @@ -20,6 +20,7 @@ import { InstanceType, ISecurityGroup, IVpc, + Port, SubnetSelection, SubnetType, } from '@aws-cdk/aws-ec2'; @@ -64,6 +65,35 @@ import { * Interface for Deadline Worker Fleet. */ export interface IWorkerFleet extends IResource, IConnectable, IGrantable { + /** + * Allow access to the worker's remote command listener port (configured as a part of the + * WorkerConfiguration) for an IConnectable that is either in this stack, or in a stack that + * depends on this stack. If this stack depends on the other stack, use allowListenerPortTo(). + * + * Common uses are: + * + * Adding a SecurityGroup: + * `workerFleet.allowListenerPortFrom(securityGroup)` + * + * Adding a CIDR: + * `workerFleet.allowListenerPortFrom(Peer.ipv4('10.0.0.0/24').connections)` + */ + allowListenerPortFrom(other: IConnectable): void; + + /** + * Allow access to the worker's remote command listener port (configured as a part of the + * WorkerConfiguration) for an IConnectable that is either in this stack, or in a stack that this + * stack depends on. If the other stack depends on this stack, use allowListenerPortFrom(). + * + * Common uses are: + * + * Adding a SecurityGroup: + * `workerFleet.allowListenerPortTo(securityGroup)` + * + * Adding a CIDR: + * `workerFleet.allowListenerPortTo(Peer.ipv4('10.0.0.0/24').connections)` + */ + allowListenerPortTo(other: IConnectable): void; } /** @@ -87,8 +117,6 @@ export interface WorkerInstanceFleetProps extends WorkerSettings { * * The role must be assumable by the service principal `ec2.amazonaws.com`: * - * @example - * * const role = new iam.Role(this, 'MyRole', { * assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com') * }); @@ -262,6 +290,16 @@ abstract class WorkerInstanceFleetBase extends Construct implements IWorkerFleet * like TargetGroups, Listener etc. */ public abstract readonly targetScope: Construct; + + /** + * @inheritdoc + */ + public abstract allowListenerPortFrom(other: IConnectable): void; + + /** + * @inheritdoc + */ + public abstract allowListenerPortTo(other: IConnectable): void; } /** @@ -295,7 +333,6 @@ abstract class WorkerInstanceFleetBase extends Construct implements IWorkerFleet * https://docs.aws.amazon.com/rfdk/latest/guide/patching-software.html for more information. */ export class WorkerInstanceFleet extends WorkerInstanceFleetBase { - /** * The min limit for spot price. */ @@ -311,13 +348,20 @@ export class WorkerInstanceFleet extends WorkerInstanceFleetBase { * Resource Tracker does deep ping every 5 minutes. These checks should be more frequent so * that any EC2 level issues are identified ASAP. Hence setting it to 1 minute. */ - private static DEFAULT_HEALTH_CHECK_INTERVAL = Duration.minutes(1); + private static readonly DEFAULT_HEALTH_CHECK_INTERVAL = Duration.minutes(1); /** * Default prefix for a LogGroup if one isn't provided in the props. */ private static readonly DEFAULT_LOG_GROUP_PREFIX: string = '/renderfarm/'; + /** + * This is the current maximum for number of workers that can be started on a single host. Currently the + * only thing using this limit is the configuration of the listener ports. More than 8 workers can be started, + * but only the first 8 will have their ports opened in the workers' security group. + */ + private static readonly MAX_WORKERS_PER_HOST = 8; + /** * Setting the default signal timeout to 15 min. This is the max time, a single instance is expected * to take for launch and execute the user-data for deadline worker configuration. As we are setting @@ -350,6 +394,11 @@ export class WorkerInstanceFleet extends WorkerInstanceFleetBase { */ public readonly env: ResourceEnvironment; + /** + * The port workers listen on to share their logs. + */ + public readonly listeningPorts: Port; + /** * This field implements the base capacity metric of the fleet against * which, the healthy percent will be calculated. @@ -448,7 +497,7 @@ export class WorkerInstanceFleet extends WorkerInstanceFleetBase { // script restarting the launcher. this.configureHealthMonitor(props); - new WorkerInstanceConfiguration(this, id, { + const workerConfig = new WorkerInstanceConfiguration(this, id, { worker: this.fleet, cloudwatchLogSettings: { logGroupPrefix: WorkerInstanceFleet.DEFAULT_LOG_GROUP_PREFIX, @@ -458,6 +507,10 @@ export class WorkerInstanceFleet extends WorkerInstanceFleetBase { workerSettings: props, userDataProvider: props.userDataProvider, }); + this.listeningPorts = Port.tcpRange( + workerConfig.listenerPort, + workerConfig.listenerPort + WorkerInstanceFleet.MAX_WORKERS_PER_HOST, + ); // Updating the user data with successful cfn-signal commands. this.fleet.userData.addSignalOnExitCommand(this.fleet); @@ -475,6 +528,20 @@ export class WorkerInstanceFleet extends WorkerInstanceFleetBase { this.fleet.addSecurityGroup(securityGroup); } + /** + * @inheritdoc + */ + public allowListenerPortFrom(other: IConnectable): void { + this.connections.allowFrom(other.connections, this.listeningPorts, 'Worker remote command listening port'); + } + + /** + * @inheritdoc + */ + public allowListenerPortTo(other: IConnectable): void { + other.connections.allowTo(this.connections, this.listeningPorts, 'Worker remote command listening port'); + } + private validateProps(props: WorkerInstanceFleetProps) { this.validateSpotPrice(props.spotPrice); this.validateArrayGroupsPoolsSyntax(props.groups, /^(?!none$)[a-zA-Z0-9-_]+$/i, 'groups'); diff --git a/packages/aws-rfdk/lib/deadline/scripts/bash/configureWorker.sh b/packages/aws-rfdk/lib/deadline/scripts/bash/configureWorker.sh index 77812888b..173abc410 100644 --- a/packages/aws-rfdk/lib/deadline/scripts/bash/configureWorker.sh +++ b/packages/aws-rfdk/lib/deadline/scripts/bash/configureWorker.sh @@ -9,6 +9,8 @@ # $2: comma separated pools # $3: region # $4: minimum supported deadline version +# $5: worker listening port +# $6: worker listening port configuration script # exit when any command fails set -xeuo pipefail @@ -17,6 +19,8 @@ WORKER_GROUPS=(${1//,/ }) WORKER_POOLS=(${2//,/ }) WORKER_REGION="$3" MINIMUM_SUPPORTED_DEADLINE_VERSION=$4 +WORKER_LISTENING_PORT=$5 +WORKER_LISTENING_PORT_CONFIG_SCRIPT=$6 # Cloud-init does not load system environment variables. Cherry-pick the # environment variable installed by the Deadline Client installer. @@ -113,6 +117,13 @@ if [ ${#WORKER_POOLS[@]} -gt 0 ]; then "$DEADLINE_COMMAND" -SetPoolsForSlave $(IFS=, ; echo "${WORKER_NAMES[*]}") $(IFS=, ; echo "${WORKER_POOLS[*]}") fi +# Setting listening port for the workers on this node (we cannot have multiple workers listening on the same port) +port_offset=0 +for worker_name in "${WORKER_NAMES[@]}"; do + "$DEADLINE_COMMAND" -ExecuteScriptNoGui "$WORKER_LISTENING_PORT_CONFIG_SCRIPT" -n $worker_name -p $(($WORKER_LISTENING_PORT+$port_offset)) + port_offset=$((port_offset+1)) +done + # Restart service, if it exists, else restart application if service --status-all | grep -q 'Deadline 10 Launcher'; then service deadline10launcher stop diff --git a/packages/aws-rfdk/lib/deadline/scripts/powershell/configureWorker.ps1 b/packages/aws-rfdk/lib/deadline/scripts/powershell/configureWorker.ps1 index f3731c3a5..ea58beb0c 100644 --- a/packages/aws-rfdk/lib/deadline/scripts/powershell/configureWorker.ps1 +++ b/packages/aws-rfdk/lib/deadline/scripts/powershell/configureWorker.ps1 @@ -9,7 +9,11 @@ param ( [Parameter(Mandatory=$True)] $workerRegion, [Parameter(Mandatory=$True)] - $minimumSupportedDeadlineVersion + $minimumSupportedDeadlineVersion, + [Parameter(Mandatory=$True)] + $workerListeningPort, + [Parameter(Mandatory=$True)] + $workerListeningPortConfigScript ) Set-PSDebug -Trace 1 @@ -101,6 +105,19 @@ if($WORKER_POOLS) { & $DEADLINE_COMMAND -SetPoolsForSlave $WORKER_NAMES_CSV $workerPools | Out-Default } +# Setting listening port for the workers on this node (we cannot have multiple workers listening on the same port) +[int]$portOffset=0 +if ($WORKER_NAMES) { + foreach ($workerName in $WORKER_NAMES) { + $currentPort=([int]$workerListeningPort + $portOffset) + + & $DEADLINE_COMMAND -ExecuteScriptNoGui "$workerListeningPortConfigScript" -n $workerName -p $currentPort | Out-Default + & netsh advfirewall firewall add rule name="Worker Log Listening" dir=in action=allow protocol=TCP localport=$currentPort | Out-Default + + $portOffset++ + } +} + $serviceName="deadline10launcherservice" If (Get-Service $serviceName -ErrorAction SilentlyContinue) { Stop-Service $serviceName diff --git a/packages/aws-rfdk/lib/deadline/scripts/python/client-rq-connection.py b/packages/aws-rfdk/lib/deadline/scripts/python/client-rq-connection.py index 12e8e7d49..c40a5939a 100644 --- a/packages/aws-rfdk/lib/deadline/scripts/python/client-rq-connection.py +++ b/packages/aws-rfdk/lib/deadline/scripts/python/client-rq-connection.py @@ -131,6 +131,9 @@ def configure_deadline( config ): :param config: The parsed configuration object """ + # Ensure that the client is configured to connect to a Remote RCS. + call_deadline_command(['SetIniFileSetting', 'ConnectionType', 'Remote']) + repo_args = ['ChangeRepository','Proxy',config.render_queue.address] if config.render_queue.scheme == 'http': print( "Configuring Deadline to connect to the Render Queue (%s) using HTTP Traffic" % config.render_queue.address ) diff --git a/packages/aws-rfdk/lib/deadline/scripts/python/worker-listening-port.py b/packages/aws-rfdk/lib/deadline/scripts/python/worker-listening-port.py new file mode 100644 index 000000000..d18297645 --- /dev/null +++ b/packages/aws-rfdk/lib/deadline/scripts/python/worker-listening-port.py @@ -0,0 +1,41 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import Deadline + +worker_name = None +listening_port = None + +def __main__(*args): + parser = argparse.ArgumentParser(description="Configures the listening port for a deadline worker") + parser.add_argument( + '-n', + dest="worker_name", + required=True, + type=str, + help="The worker's name" + ) + parser.add_argument( + '-p', + dest="listening_port", + required=True, + type=int, + help="The port to configure for listening on" + ) + args = parser.parse_args(args) + + try: + worker_settings = Deadline.Scripting.RepositoryUtils.GetSlaveSettings(args.worker_name, True) + except: + raise Exception("Failed to get settings for worker: {}".format(args.worker_name)) + + worker_settings.SlaveListeningPort = args.listening_port + worker_settings.SlaveOverrideListeningPort = True + + try: + Deadline.Scripting.RepositoryUtils.SaveSlaveSettings(worker_settings) + except: + raise Exception("Failing to save settings for {}".format(args.worker_name)) + + print("Successfully set {} to listen on port {}".format(args.worker_name, args.listening_port)) diff --git a/packages/aws-rfdk/lib/deadline/test/asset-constants.ts b/packages/aws-rfdk/lib/deadline/test/asset-constants.ts index f89b118df..ba32637aa 100644 --- a/packages/aws-rfdk/lib/deadline/test/asset-constants.ts +++ b/packages/aws-rfdk/lib/deadline/test/asset-constants.ts @@ -9,21 +9,28 @@ import { stringLike } from '@aws-cdk/assert'; import { CWA_ASSET_LINUX, CWA_ASSET_WINDOWS, - linuxDownloadRunScriptBoilerplate, - windowsDownloadRunScriptBoilerplate, } from '../../core/test/asset-constants'; -export { CWA_ASSET_LINUX, CWA_ASSET_WINDOWS, linuxDownloadRunScriptBoilerplate, windowsDownloadRunScriptBoilerplate }; + +export { + CWA_ASSET_LINUX, + CWA_ASSET_WINDOWS, +}; // configureWorker.sh export const CONFIG_WORKER_ASSET_LINUX = { - Bucket: 'AssetParameterse90d5322c2b7457e7dbbacdfc3a350aa501f6a63b939475977f2464abb268b73S3Bucket1840D7FB', - Key: 'AssetParameterse90d5322c2b7457e7dbbacdfc3a350aa501f6a63b939475977f2464abb268b73S3VersionKey7BA1309D', + Bucket: 'AssetParameters21c2af3bc1d4fd78061765b059dcc8e32568828e5cf479b08115489651491c8fS3BucketF10C60A7', + Key: 'AssetParameters21c2af3bc1d4fd78061765b059dcc8e32568828e5cf479b08115489651491c8fS3VersionKey7FDCC89A', }; // configureWorker.ps1 export const CONFIG_WORKER_ASSET_WINDOWS = { - Bucket: 'AssetParametersb1df82abec8605ca7a4666803d27eafda3bd66a9db0e5366d61cdf3d184af8b2S3BucketD9C14531', - Key: 'AssetParametersb1df82abec8605ca7a4666803d27eafda3bd66a9db0e5366d61cdf3d184af8b2S3VersionKey40FA52FC', + Bucket: 'AssetParametersa10d67420c8758e35d8dae5fa406c7acb92b1bd40924167d5564aa0037b4a980S3Bucket953E30DC', + Key: 'AssetParametersa10d67420c8758e35d8dae5fa406c7acb92b1bd40924167d5564aa0037b4a980S3VersionKeyAFB97BD6', +}; + +export const CONFIG_WORKER_PORT_ASSET_WINDOWS = { + Bucket: 'AssetParameters0b4fe3ffb7177773bb2781f92b37d9b01b3bd37ee60ea1715c0ad407f141005dS3BucketE7B32C3E', + Key: 'AssetParameters0b4fe3ffb7177773bb2781f92b37d9b01b3bd37ee60ea1715c0ad407f141005dS3VersionKey843794E3', }; // installDeadlineRepository.sh @@ -44,6 +51,665 @@ export const REPO_DC_ASSET = { }; export const RQ_CONNECTION_ASSET = { - Bucket: 'AssetParameters89a29e05a2a88ec4d4a02e847e3c3c9461d0154b326492f4cad655d4ca0bda98S3BucketC22E185C', - Key: 'AssetParameters89a29e05a2a88ec4d4a02e847e3c3c9461d0154b326492f4cad655d4ca0bda98S3VersionKey0833D670', + Bucket: 'AssetParameters74fd6cba5cebe5a13738b535ab6b010a0fe1154689bad4df3ef49ed7bddc1075S3Bucket0337801D', + Key: 'AssetParameters74fd6cba5cebe5a13738b535ab6b010a0fe1154689bad4df3ef49ed7bddc1075S3VersionKey144181B5', }; + +export function linuxConfigureWorkerScriptBoilerplate(scriptParams: string) { + return [ + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + "')\naws s3 cp 's3://", + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Bucket}, + '/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + "' '/tmp/", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + "'\nmkdir -p $(dirname '/tmp/", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\')\naws s3 cp \'s3://', + {Ref: CONFIG_WORKER_ASSET_LINUX.Bucket}, + '/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\' \'/tmp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\'\n' + + 'set -e\n' + + 'chmod +x \'/tmp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\'\n\'/tmp/', + { + 'Fn::Select': [ + 0, + + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + ], + }, + ], + }, + scriptParams, + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + ]; +} + +export function linuxCloudWatchScriptBoilerplate() { + return [ + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\')\naws s3 cp \'s3://', + {Ref: CWA_ASSET_LINUX.Bucket}, + '/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\' \'/tmp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\'\n' + + 'set -e\n' + + 'chmod +x \'/tmp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + '\'\n\'/tmp/', + { + 'Fn::Select': [ + 0, + + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_LINUX.Key}, + ], + }, + ], + }, + ]; +} + +export function windowsConfigureWorkerScriptBoilerplate(scriptParams: string) { + return [ + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + '\' ) -ea 0\nRead-S3Object -BucketName \'', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Bucket}, + '\' -key \'', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + '\' -file \'C:/temp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + "' -ErrorAction Stop\nmkdir (Split-Path -Path 'C:/temp/", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + "' ) -ea 0\nRead-S3Object -BucketName '", + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Bucket}, + "' -key '", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + "' -file 'C:/temp/", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + '\' -ErrorAction Stop\n&\'C:/temp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + scriptParams, + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { + Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, + }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { + Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, + }, + ], + }, + ], + }, + '\nif (!$?) { Write-Error \'Failed to execute the file \"C:/temp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CONFIG_WORKER_PORT_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + ]; +} + +export function windowsCloudWatchScriptBoilerplate() { + return [ + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + '\' ) -ea 0\nRead-S3Object -BucketName \'', + {Ref: CWA_ASSET_WINDOWS.Bucket}, + '\' -key \'', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + '\' -file \'C:/temp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + '\' -ErrorAction Stop\n&\'C:/temp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + {Ref: CWA_ASSET_WINDOWS.Key}, + ], + }, + ], + }, + ]; +} diff --git a/packages/aws-rfdk/lib/deadline/test/worker-configuration.test.ts b/packages/aws-rfdk/lib/deadline/test/worker-configuration.test.ts index bb0e05003..6cd972d65 100644 --- a/packages/aws-rfdk/lib/deadline/test/worker-configuration.test.ts +++ b/packages/aws-rfdk/lib/deadline/test/worker-configuration.test.ts @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* eslint-disable dot-notation */ + import { expect as expectCDK, haveResource, @@ -41,12 +43,11 @@ import { WorkerInstanceConfiguration, } from '../lib'; import { - CONFIG_WORKER_ASSET_LINUX, - CONFIG_WORKER_ASSET_WINDOWS, - CWA_ASSET_LINUX, CWA_ASSET_WINDOWS, - linuxDownloadRunScriptBoilerplate, - windowsDownloadRunScriptBoilerplate, + linuxCloudWatchScriptBoilerplate, + linuxConfigureWorkerScriptBoilerplate, + windowsCloudWatchScriptBoilerplate, + windowsConfigureWorkerScriptBoilerplate, } from './asset-constants'; describe('Test WorkerInstanceConfiguration for Linux', () => { @@ -71,14 +72,38 @@ describe('Test WorkerInstanceConfiguration for Linux', () => { }); const userData = stack.resolve(instance.userData.render()); - // THEN + // // THEN + expect(userData).toStrictEqual({ + 'Fn::Join': [ + '', + [ + '#!/bin/bash\nmkdir -p $(dirname \'/tmp/', + ...linuxConfigureWorkerScriptBoilerplate( + `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} /tmp/`), + ], + ], + }); + }); + + test('custom listener port', () => { + const otherListenerPort = 55555; + + // WHEN + new WorkerInstanceConfiguration(stack, 'Config', { + worker: instance, + workerSettings: { + listenerPort: otherListenerPort, + }, + }); + const userData = stack.resolve(instance.userData.render()); + + // // THEN expect(userData).toStrictEqual({ 'Fn::Join': [ '', [ '#!/bin/bash\nmkdir -p $(dirname \'/tmp/', - ...linuxDownloadRunScriptBoilerplate(CONFIG_WORKER_ASSET_LINUX), - `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\'`, + ...linuxConfigureWorkerScriptBoilerplate(`\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${otherListenerPort} /tmp/`), ], ], }); @@ -96,14 +121,14 @@ describe('Test WorkerInstanceConfiguration for Linux', () => { }); const userData = stack.resolve(instance.userData.render()); - // THEN + // // THEN expect(userData).toStrictEqual({ 'Fn::Join': [ '', [ '#!/bin/bash\nmkdir -p $(dirname \'/tmp/', - ...linuxDownloadRunScriptBoilerplate(CONFIG_WORKER_ASSET_LINUX), - `\' \'g1,g2\' \'p1,p2\' \'r1\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\'`, + ...linuxConfigureWorkerScriptBoilerplate( + `\' \'g1,g2\' \'p1,p2\' \'r1\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} /tmp/`), ], ], }); @@ -132,12 +157,12 @@ describe('Test WorkerInstanceConfiguration for Linux', () => { '', [ '#!/bin/bash\nmkdir -p $(dirname \'/tmp/', - ...linuxDownloadRunScriptBoilerplate(CWA_ASSET_LINUX), + ...linuxCloudWatchScriptBoilerplate(), '\' ', ssmParamName, '\nmkdir -p $(dirname \'/tmp/', - ...linuxDownloadRunScriptBoilerplate(CONFIG_WORKER_ASSET_LINUX), - `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\'`, + ...linuxConfigureWorkerScriptBoilerplate( + `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} /tmp/`), ], ], }); @@ -189,33 +214,8 @@ describe('Test WorkerInstanceConfiguration for Windows', () => { '', [ 'mkdir (Split-Path -Path \'C:/temp/', - ...windowsDownloadRunScriptBoilerplate(CONFIG_WORKER_ASSET_WINDOWS), - `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\'` + - '\nif (!$?) { Write-Error \'Failed to execute the file \"C:/temp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - { - Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, - }, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, - ], - }, - ], - }, + ...windowsConfigureWorkerScriptBoilerplate( + `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} C:/temp/`), '\"\' -ErrorAction Stop }', ], ], @@ -240,33 +240,33 @@ describe('Test WorkerInstanceConfiguration for Windows', () => { '', [ 'mkdir (Split-Path -Path \'C:/temp/', - ...windowsDownloadRunScriptBoilerplate(CONFIG_WORKER_ASSET_WINDOWS), - `\' \'g1,g2\' \'p1,p2\' \'r1\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\'` + - '\nif (!$?) { Write-Error \'Failed to execute the file \"C:/temp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - { - Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, - }, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, - ], - }, - ], - }, + ...windowsConfigureWorkerScriptBoilerplate( + `\' \'g1,g2\' \'p1,p2\' \'r1\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} C:/temp/`), + '\"\' -ErrorAction Stop }', + ], + ], + }); + }); + + test('custom listner port', () => { + const otherListenerPort = 55555; + // WHEN + new WorkerInstanceConfiguration(stack, 'Config', { + worker: instance, + workerSettings: { + listenerPort: otherListenerPort, + }, + }); + const userData = stack.resolve(instance.userData.render()); + + // THEN + expect(userData).toStrictEqual({ + 'Fn::Join': [ + '', + [ + 'mkdir (Split-Path -Path \'C:/temp/', + ...windowsConfigureWorkerScriptBoilerplate( + `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${otherListenerPort} C:/temp/`), '\"\' -ErrorAction Stop }', ], ], @@ -296,7 +296,7 @@ describe('Test WorkerInstanceConfiguration for Windows', () => { '', [ 'mkdir (Split-Path -Path \'C:/temp/', - ...windowsDownloadRunScriptBoilerplate(CWA_ASSET_WINDOWS), + ...windowsCloudWatchScriptBoilerplate(), '\' ', ssmParamName, '\nif (!$?) { Write-Error \'Failed to execute the file \"C:/temp/', @@ -326,33 +326,8 @@ describe('Test WorkerInstanceConfiguration for Windows', () => { }, '\"\' -ErrorAction Stop }' + '\nmkdir (Split-Path -Path \'C:/temp/', - ...windowsDownloadRunScriptBoilerplate(CONFIG_WORKER_ASSET_WINDOWS), - `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\'` + - '\nif (!$?) { Write-Error \'Failed to execute the file \"C:/temp/', - { - 'Fn::Select': [ - 0, - { - 'Fn::Split': [ - '||', - { - Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, - }, - ], - }, - ], - }, - { - 'Fn::Select': [ - 1, - { - 'Fn::Split': [ - '||', - {Ref: CONFIG_WORKER_ASSET_WINDOWS.Key}, - ], - }, - ], - }, + ...windowsConfigureWorkerScriptBoilerplate( + `\' \'\' \'\' \'\' \'${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION.toString()}\' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} C:/temp/`), '\"\' -ErrorAction Stop }', ], ], diff --git a/packages/aws-rfdk/lib/deadline/test/worker-fleet.test.ts b/packages/aws-rfdk/lib/deadline/test/worker-fleet.test.ts index 522471b43..c583091c9 100644 --- a/packages/aws-rfdk/lib/deadline/test/worker-fleet.test.ts +++ b/packages/aws-rfdk/lib/deadline/test/worker-fleet.test.ts @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* eslint-disable dot-notation */ + import { ABSENT, expect as expectCDK, @@ -19,6 +21,7 @@ import { InstanceSize, InstanceType, IVpc, + Peer, SecurityGroup, SubnetType, Vpc, @@ -51,10 +54,12 @@ import { Repository, Version, VersionQuery, + WorkerInstanceConfiguration, WorkerInstanceFleet, } from '../lib'; import { CONFIG_WORKER_ASSET_LINUX, + CONFIG_WORKER_ASSET_WINDOWS, CWA_ASSET_LINUX, RQ_CONNECTION_ASSET, } from './asset-constants'; @@ -180,6 +185,158 @@ test('WorkerFleet uses given security group', () => { })); }); +describe('allowing log listener port', () => { + test('from CIDR', () => { + // WHEN + const fleet = new WorkerInstanceFleet(stack, 'workerFleet', { + vpc, + workerMachineImage: new GenericWindowsImage({ + 'us-east-1': 'ami-any', + }), + renderQueue, + }); + + fleet.allowListenerPortFrom(Peer.ipv4('127.0.0.1/24').connections); + + // THEN + expectCDK(stack).to(haveResourceLike('AWS::EC2::SecurityGroup', { + SecurityGroupEgress: [{ CidrIp: '0.0.0.0/0' }], + SecurityGroupIngress: [ + { + CidrIp: '127.0.0.1/24', + Description: 'Worker remote command listening port', + FromPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'], + IpProtocol: 'tcp', + ToPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'] + WorkerInstanceFleet['MAX_WORKERS_PER_HOST'], + }, + ], + })); + }); + + test('to CIDR', () => { + // WHEN + const fleet = new WorkerInstanceFleet(stack, 'workerFleet', { + vpc, + workerMachineImage: new GenericWindowsImage({ + 'us-east-1': 'ami-any', + }), + renderQueue, + }); + + fleet.allowListenerPortTo(Peer.ipv4('127.0.0.1/24').connections); + + // THEN + expectCDK(stack).to(haveResourceLike('AWS::EC2::SecurityGroup', { + SecurityGroupEgress: [{ CidrIp: '0.0.0.0/0' }], + SecurityGroupIngress: [ + { + CidrIp: '127.0.0.1/24', + Description: 'Worker remote command listening port', + FromPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'], + IpProtocol: 'tcp', + ToPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'] + WorkerInstanceFleet['MAX_WORKERS_PER_HOST'], + }, + ], + })); + }); + + test('from SecurityGroup', () => { + // WHEN + const fleet = new WorkerInstanceFleet(stack, 'workerFleet', { + vpc, + workerMachineImage: new GenericWindowsImage({ + 'us-east-1': 'ami-any', + }), + renderQueue, + }); + const securityGroup = SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789'); + + fleet.allowListenerPortFrom(securityGroup); + + // THEN + expectCDK(stack).to(haveResourceLike('AWS::EC2::SecurityGroupIngress', { + FromPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'], + IpProtocol: 'tcp', + SourceSecurityGroupId: 'sg-123456789', + ToPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'] + WorkerInstanceFleet['MAX_WORKERS_PER_HOST'], + })); + }); + + test('to SecurityGroup', () => { + // WHEN + const fleet = new WorkerInstanceFleet(stack, 'workerFleet', { + vpc, + workerMachineImage: new GenericWindowsImage({ + 'us-east-1': 'ami-any', + }), + renderQueue, + }); + const securityGroup = SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789'); + + fleet.allowListenerPortTo(securityGroup); + + // THEN + expectCDK(stack).to(haveResourceLike('AWS::EC2::SecurityGroupIngress', { + FromPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'], + IpProtocol: 'tcp', + SourceSecurityGroupId: 'sg-123456789', + ToPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'] + WorkerInstanceFleet['MAX_WORKERS_PER_HOST'], + })); + }); + + test('from other stack', () => { + const otherStack = new Stack(app, 'otherStack', { + env: { region: 'us-east-1' }, + }); + + // WHEN + const fleet = new WorkerInstanceFleet(stack, 'workerFleet', { + vpc, + workerMachineImage: new GenericWindowsImage({ + 'us-east-1': 'ami-any', + }), + renderQueue, + }); + const securityGroup = SecurityGroup.fromSecurityGroupId(otherStack, 'SG', 'sg-123456789'); + + fleet.allowListenerPortFrom(securityGroup); + + // THEN + expectCDK(stack).to(haveResourceLike('AWS::EC2::SecurityGroupIngress', { + FromPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'], + IpProtocol: 'tcp', + SourceSecurityGroupId: 'sg-123456789', + ToPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'] + WorkerInstanceFleet['MAX_WORKERS_PER_HOST'], + })); + }); + + test('to other stack', () => { + const otherStack = new Stack(app, 'otherStack', { + env: { region: 'us-east-1' }, + }); + + // WHEN + const fleet = new WorkerInstanceFleet(stack, 'workerFleet', { + vpc, + workerMachineImage: new GenericWindowsImage({ + 'us-east-1': 'ami-any', + }), + renderQueue, + }); + const securityGroup = SecurityGroup.fromSecurityGroupId(otherStack, 'SG', 'sg-123456789'); + + fleet.allowListenerPortTo(securityGroup); + + // THEN + expectCDK(otherStack).to(haveResourceLike('AWS::EC2::SecurityGroupIngress', { + FromPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'], + IpProtocol: 'tcp', + SourceSecurityGroupId: 'sg-123456789', + ToPort: WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT'] + WorkerInstanceFleet['MAX_WORKERS_PER_HOST'], + })); + }); +}); + test('default worker fleet is created correctly with linux image', () => { // WHEN new WorkerInstanceFleet(stack, 'workerFleet', { @@ -320,7 +477,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -331,13 +488,13 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], }, - '\')\naws s3 cp \'s3://', - {Ref: CWA_ASSET_LINUX.Bucket}, + "\')\naws s3 cp 's3://", + { Ref: CWA_ASSET_LINUX.Bucket }, '/', { 'Fn::Select': [ @@ -345,7 +502,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -356,19 +513,19 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], }, - '\' \'/tmp/', + "' '/tmp/", { 'Fn::Select': [ 0, { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -379,7 +536,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -393,9 +550,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - { - Ref: CWA_ASSET_LINUX.Key, - }, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -406,7 +561,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -418,7 +573,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -429,7 +584,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CWA_ASSET_LINUX.Key}, + { Ref: CWA_ASSET_LINUX.Key }, ], }, ], @@ -443,7 +598,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -454,13 +609,13 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], }, '\')\naws s3 cp \'s3://', - {Ref: RQ_CONNECTION_ASSET.Bucket}, + { Ref: RQ_CONNECTION_ASSET.Bucket }, '/', { 'Fn::Select': [ @@ -468,7 +623,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -479,7 +634,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -491,7 +646,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -502,7 +657,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -518,7 +673,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -529,7 +684,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -549,7 +704,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -560,7 +715,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: RQ_CONNECTION_ASSET.Key}, + { Ref: RQ_CONNECTION_ASSET.Key }, ], }, ], @@ -576,7 +731,32 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + '\')\naws s3 cp \'s3://', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Bucket }, + '/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, ], }, ], @@ -587,13 +767,59 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + '\' \'/tmp/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + "'\nmkdir -p $(dirname '/tmp/", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, ], }, ], }, "')\naws s3 cp 's3://", - {Ref: CONFIG_WORKER_ASSET_LINUX.Bucket}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Bucket }, '/', { 'Fn::Select': [ @@ -601,7 +827,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, ], }, ], @@ -612,7 +838,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, ], }, ], @@ -624,7 +850,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, ], }, ], @@ -635,7 +861,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, ], }, ], @@ -647,7 +873,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, ], }, ], @@ -658,7 +884,7 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, ], }, ], @@ -670,7 +896,30 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_LINUX.Key }, + ], + }, + ], + }, + `' '' '' '' '${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION}' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} /tmp/`, + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, ], }, ], @@ -681,12 +930,11 @@ test('default worker fleet is created correctly custom subnet values', () => { { 'Fn::Split': [ '||', - {Ref: CONFIG_WORKER_ASSET_LINUX.Key}, + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, ], }, ], }, - `' '' '' '' '${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION}'`, ], ], }); @@ -740,7 +988,7 @@ test('default worker fleet is created correctly with groups, pools and region', }, ], }, - "')\naws s3 cp 's3://", + '\')\naws s3 cp \'s3://', {Ref: CWA_ASSET_LINUX.Bucket}, '/', { @@ -970,6 +1218,83 @@ test('default worker fleet is created correctly with groups, pools and region', ' service deadline10launcher restart\n' + 'fi\n' + "mkdir -p $(dirname '/tmp/", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { + Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, + }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { + Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, + }, + ], + }, + ], + }, + "')\naws s3 cp 's3://", + { + Ref: CONFIG_WORKER_ASSET_WINDOWS.Bucket, + }, + '/', + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + "' '/tmp/", + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { Ref: CONFIG_WORKER_ASSET_WINDOWS.Key }, + ], + }, + ], + }, + "'\nmkdir -p $(dirname '/tmp/", { 'Fn::Select': [ 0, @@ -1086,7 +1411,33 @@ test('default worker fleet is created correctly with groups, pools and region', }, ], }, - `' 'a,b' 'c,d' 'E' '${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION}'`, + `' 'a,b' 'c,d' 'E' '${Version.MINIMUM_SUPPORTED_DEADLINE_VERSION}' ${WorkerInstanceConfiguration['DEFAULT_LISTENER_PORT']} /tmp/`, + { + 'Fn::Select': [ + 0, + { + 'Fn::Split': [ + '||', + { + Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, + }, + ], + }, + ], + }, + { + 'Fn::Select': [ + 1, + { + 'Fn::Split': [ + '||', + { + Ref: CONFIG_WORKER_ASSET_WINDOWS.Key, + }, + ], + }, + ], + }, ]], }); });