Skip to content

Commit

Permalink
fix(deadline): User Data execution on Worker Nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
Eugene Kozlov committed Nov 19, 2020
1 parent 9387f60 commit 2e4a186
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@
IVpc,
Port
)
from aws_cdk.aws_s3_assets import (
Asset
)

from aws_rfdk import (
HealthMonitor,
)
from aws_rfdk.deadline import (
InstanceUserDataProvider,
IRenderQueue,
WorkerInstanceFleet,
)

import os

@dataclass
class ComputeTierProps(StackProps):
Expand All @@ -43,6 +48,22 @@ class ComputeTierProps(StackProps):
# The bastion host to allow connection to Worker nodes.
bastion: Optional[BastionHostLinux] = None

class UserDataProvider(InstanceUserDataProvider):
def pre_cloud_watch_agent(self, host) -> None:
host.user_data.add_commands("echo preCloudWatchAgent")
def pre_deadline_configuration(self, host) -> None:
host.user_data.add_commands("echo preDeadlineConfiguration")
def post_worker_launch(self, host) -> None:
host.user_data.add_commands("echo postWorkerLaunch")
test_script=Asset(host.node.scope, "SampleAsset",
path=os.path.join(os.getcwd(), "..", "scripts", "configure_worker.sh")
)
test_script.grant_read(host)
local_path = host.user_data.add_s3_download_command(
bucket=test_script.bucket,
bucket_key=test_script.s3_object_key
)
host.user_data.add_execute_file_command(file_path=local_path)

class ComputeTier(Stack):
"""
Expand Down Expand Up @@ -78,6 +99,7 @@ def __init__(self, scope: Construct, stack_id: str, *, props: ComputeTierProps,
worker_machine_image=props.worker_machine_image,
health_monitor=self.health_monitor,
key_name=props.key_pair_name,
user_data_provider=UserDataProvider()
)

if props.bastion:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mkdir test_dir
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
} from '@aws-cdk/aws-ec2';
import * as cdk from '@aws-cdk/core';
import {
IHost,
InstanceUserDataProvider,
IRenderQueue,
IWorkerFleet,
WorkerInstanceFleet,
Expand All @@ -19,6 +21,8 @@ import {
HealthMonitor,
IHealthMonitor,
} from 'aws-rfdk';
import { Asset } from '@aws-cdk/aws-s3-assets';
import * as path from 'path'

/**
* Properties for {@link ComputeTier}.
Expand Down Expand Up @@ -50,6 +54,33 @@ export interface ComputeTierProps extends cdk.StackProps {
readonly bastion?: BastionHostLinux;
}

class UserDataProvider extends InstanceUserDataProvider {
preCloudWatchAgent(host: IHost): void {
host.userData.addCommands('echo preCloudWatchAgent');
}
preDeadlineConfiguration(host: IHost): void {
host.userData.addCommands('echo preDeadlineConfiguration');
}
postWorkerLaunch(host: IHost): void {
host.userData.addCommands('echo postWorkerLaunch');
if (host.node.scope != undefined) {
const testScript = new Asset(
host.node.scope as cdk.Construct,
'SampleAsset',
{path: path.join(__dirname, '..', 'configure_worker.sh')},
);
testScript.grantRead(host);
const localPath = host.userData.addS3DownloadCommand({
bucket: testScript.bucket,
bucketKey: testScript.s3ObjectKey,
});
host.userData.addExecuteFileCommand({
filePath: localPath,
})
}
}
}

/**
* The computer tier consists of raw compute power. For a Deadline render farm,
* this will be the fleet of Worker nodes that render Deadline jobs.
Expand Down Expand Up @@ -88,6 +119,7 @@ export class ComputeTier extends cdk.Stack {
workerMachineImage: props.workerMachineImage,
healthMonitor: this.healthMonitor,
keyName: props.keyPairName,
userDataProvider: new UserDataProvider(),
});

if (props.bastion) {
Expand Down
29 changes: 28 additions & 1 deletion packages/aws-rfdk/lib/deadline/lib/worker-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,26 @@ import {
Version,
} from './version';

/**
* Provider for adding user data scripts
*/
export interface IInstanceUserDataProvider {
// Method that is invoked before configuration Cloud Watch Agent.
preCloudWatchAgent(host: IHost): void;
// Method that is invoked before Deadline worker and renderqueue configuration .
preDeadlineConfiguration(host: IHost): void;
// Method that is invoked after all configuration is done and worker started.
postWorkerLaunch(host: IHost): void;
}

export class InstanceUserDataProvider implements IInstanceUserDataProvider{
preCloudWatchAgent(_host: IHost): void {
}
preDeadlineConfiguration(_host: IHost): void {
}
postWorkerLaunch(_host: IHost): void {
}
}
/**
* Configuration settings for Deadline Workers
*/
Expand Down Expand Up @@ -86,6 +106,11 @@ export interface WorkerInstanceConfigurationProps {
* @default The Worker is assigned the default settings as outlined in the WorkerSettings interface.
*/
readonly workerSettings?: WorkerSettings;

/**
* The provider for User data scripts that will be invoke during worker configuration.
*/
readonly userDataProvider?: IInstanceUserDataProvider;
}

/**
Expand All @@ -105,12 +130,14 @@ export interface WorkerInstanceConfigurationProps {
export class WorkerInstanceConfiguration extends Construct {
constructor(scope: Construct, id: string, props: WorkerInstanceConfigurationProps) {
super(scope, id);

props.userDataProvider?.preCloudWatchAgent(props.worker);
if (props.cloudwatchLogSettings) {
this.configureCloudWatchLogStream(props.worker, id, props.cloudwatchLogSettings);
}
props.userDataProvider?.preDeadlineConfiguration(props.worker);
props.renderQueue?.configureClientInstance({ host: props.worker});
this.configureWorkerSettings(props.worker, id, props.workerSettings);
props.userDataProvider?.postWorkerLaunch(props.worker);
}

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/aws-rfdk/lib/deadline/lib/worker-fleet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
} from './render-queue';
import { Version } from './version';
import {
IInstanceUserDataProvider,
WorkerInstanceConfiguration,
WorkerSettings,
} from './worker-configuration';
Expand Down Expand Up @@ -189,6 +190,11 @@ export interface WorkerInstanceFleetProps extends WorkerSettings {
* @default The default devices of the provided ami will be used.
*/
readonly blockDevices?: BlockDevice[];

/**
* The provider for User data scripts that will be invoke during worker configuration.
*/
readonly userDataProvider?: IInstanceUserDataProvider;
}

/**
Expand Down Expand Up @@ -449,6 +455,7 @@ export class WorkerInstanceFleet extends WorkerInstanceFleetBase {
},
renderQueue: props.renderQueue,
workerSettings: props,
userDataProvider: props.userDataProvider,
});

// Updating the user data with successful cfn-signal commands.
Expand Down
5 changes: 0 additions & 5 deletions packages/aws-rfdk/lib/deadline/test/asset-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,3 @@ export const RQ_CONNECTION_ASSET = {
Bucket: 'AssetParameters89a29e05a2a88ec4d4a02e847e3c3c9461d0154b326492f4cad655d4ca0bda98S3BucketC22E185C',
Key: 'AssetParameters89a29e05a2a88ec4d4a02e847e3c3c9461d0154b326492f4cad655d4ca0bda98S3VersionKey0833D670',
};

export const VERSION_QUERY_ASSET = {
Bucket: stringLike('AssetParameters*S3Bucket6ABF873D'),
Key: stringLike('AssetParameters*S3VersionKey5A5FE29C'),
};
40 changes: 0 additions & 40 deletions packages/aws-rfdk/lib/deadline/test/version-query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import {
VersionQuery,
} from '../lib';

import { VERSION_QUERY_ASSET } from './asset-constants';

test('VersionQuery constructor full version', () => {
const app = new App();
const stack = new Stack(app, 'Stack');
Expand Down Expand Up @@ -57,44 +55,6 @@ test('VersionQuery constructor full version', () => {
],
}));
expectCDK(stack).to(haveResourceLike('AWS::Lambda::Function', {
Code: {
S3Bucket: {
Ref: VERSION_QUERY_ASSET.Bucket,
},
S3Key: {
'Fn::Join': [
'',
[
{
'Fn::Select': [
0,
{
'Fn::Split': [
'||',
{
Ref: VERSION_QUERY_ASSET.Key,
},
],
},
],
},
{
'Fn::Select': [
1,
{
'Fn::Split': [
'||',
{
Ref: VERSION_QUERY_ASSET.Key,
},
],
},
],
},
],
],
},
},
Handler: 'version-provider.handler',
Role: {
'Fn::GetAtt': [
Expand Down
38 changes: 38 additions & 0 deletions packages/aws-rfdk/lib/deadline/test/worker-fleet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import {
escapeTokenRegex,
} from '../../core/test/token-regex-helpers';
import {
IHost,
InstanceUserDataProvider,
IRenderQueue,
RenderQueue,
Repository,
Expand Down Expand Up @@ -92,12 +94,18 @@ beforeEach(() => {

test('default worker fleet is created correctly', () => {
// WHEN
class userDataProvider extends InstanceUserDataProvider{
preCloudWatchAgent(host: IHost) {
host.userData.addCommands('mkdir test_dir');
}
}
const fleet = new WorkerInstanceFleet(wfstack, 'workerFleet', {
vpc,
workerMachineImage: new GenericWindowsImage({
'us-east-1': 'ami-any',
}),
renderQueue,
userDataProvider: new userDataProvider(),
});

// THEN
Expand Down Expand Up @@ -1461,6 +1469,36 @@ describe('HealthMonitor Tests', () => {
TargetType: 'instance',
}));
});

test('UserData is added', () => {
// WHEN
class UserDataProvider extends InstanceUserDataProvider {
preCloudWatchAgent(host: IHost): void {
host.userData.addCommands('echo preCloudWatchAgent');
}
preDeadlineConfiguration(host: IHost): void {
host.userData.addCommands('echo preDeadlineConfiguration');
}
postWorkerLaunch(host: IHost): void {
host.userData.addCommands('echo postWorkerLaunch');
}
}
const fleet = new WorkerInstanceFleet(wfstack, 'workerFleet', {
vpc,
workerMachineImage: new GenericWindowsImage({
'us-east-1': 'ami-any',
}),
renderQueue,
healthMonitor,
userDataProvider: new UserDataProvider(),
});
const userData = fleet.fleet.userData.render();

// THEN
expect(userData).toContain('echo preCloudWatchAgent');
expect(userData).toContain('echo preDeadlineConfiguration');
expect(userData).toContain('echo postWorkerLaunch');
});
});

describe('tagging', () => {
Expand Down

0 comments on commit 2e4a186

Please sign in to comment.