Skip to content

Commit 716871f

Browse files
authored
feat(batch): grantSubmitJob method (#26729)
Add a new method, `grantSubmitJob`, to the JobDefinition construct. Enables batch users to easily grant `submitJob` permissions to any principal. Closes #25574. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e4e0832 commit 716871f

12 files changed

+2379
-1
lines changed

packages/@aws-cdk/aws-batch-alpha/README.md

+32
Original file line numberDiff line numberDiff line change
@@ -658,3 +658,35 @@ B => 2 vCPU - WAITING
658658
In this situation, Batch will allocate **Job A** to compute resource #1 because it is the most cost efficient resource that matches the vCPU requirement. However, with this `BEST_FIT` strategy, **Job B** will not be allocated to our other available compute resource even though it is strong enough to handle it. Instead, it will wait until the first job is finished processing or wait a similar `m5.xlarge` resource to be provisioned.
659659

660660
The alternative would be to use the `BEST_FIT_PROGRESSIVE` strategy in order for the remaining job to be handled in larger containers regardless of vCPU requirement and costs.
661+
662+
### Permissions
663+
664+
You can grant any Principal the `batch:submitJob` permission on both a job definition and a job queue like this:
665+
666+
```ts
667+
import * as cdk from 'aws-cdk-lib';
668+
import * as iam from 'aws-cdk-lib/aws-iam';
669+
670+
declare const vpc: ec2.IVpc;
671+
672+
const ecsJob = new batch.EcsJobDefinition(this, 'JobDefn', {
673+
container: new batch.EcsEc2ContainerDefinition(this, 'containerDefn', {
674+
image: ecs.ContainerImage.fromRegistry('public.ecr.aws/amazonlinux/amazonlinux:latest'),
675+
memory: cdk.Size.mebibytes(2048),
676+
cpu: 256,
677+
}),
678+
});
679+
680+
const queue = new batch.JobQueue(this, 'JobQueue', {
681+
computeEnvironments: [{
682+
computeEnvironment: new batch.ManagedEc2EcsComputeEnvironment(this, 'managedEc2CE', {
683+
vpc,
684+
}),
685+
order: 1,
686+
}],
687+
priority: 10,
688+
});
689+
690+
const user = new iam.User(this, 'MyUser');
691+
ecsJob.grantSubmitJob(user, queue);
692+
```

packages/@aws-cdk/aws-batch-alpha/lib/ecs-job-definition.ts

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Construct } from 'constructs';
33
import { CfnJobDefinition } from 'aws-cdk-lib/aws-batch';
44
import { EcsEc2ContainerDefinition, IEcsContainerDefinition } from './ecs-container-definition';
55
import { baseJobDefinitionProperties, IJobDefinition, JobDefinitionBase, JobDefinitionProps } from './job-definition-base';
6+
import * as iam from 'aws-cdk-lib/aws-iam';
7+
import { IJobQueue } from './job-queue';
68

79
/**
810
* A JobDefinition that uses ECS orchestration
@@ -102,6 +104,17 @@ export class EcsJobDefinition extends JobDefinitionBase implements IEcsJobDefini
102104
this.jobDefinitionName = EcsJobDefinition.getJobDefinitionName(scope, this.jobDefinitionArn);
103105
}
104106

107+
/**
108+
* Grants the `batch:submitJob` permission to the identity on both this job definition and the `queue`
109+
*/
110+
public grantSubmitJob(identity: iam.IGrantable, queue: IJobQueue) {
111+
iam.Grant.addToPrincipal({
112+
actions: ['batch:SubmitJob'],
113+
grantee: identity,
114+
resourceArns: [this.jobDefinitionArn, queue.jobQueueArn],
115+
});
116+
}
117+
105118
private renderPlatformCapabilities() {
106119
if (this.container instanceof EcsEc2ContainerDefinition) {
107120
return [Compatibility.EC2];

packages/@aws-cdk/aws-batch-alpha/test/ecs-job-definition.test.ts

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Template } from 'aws-cdk-lib/assertions';
22
import * as ecs from 'aws-cdk-lib/aws-ecs';
33
import { DefaultTokenResolver, Size, StringConcat, Stack, Tokenization } from 'aws-cdk-lib';
4-
import { Compatibility, EcsEc2ContainerDefinition, EcsFargateContainerDefinition, EcsJobDefinition } from '../lib';
4+
import * as iam from 'aws-cdk-lib/aws-iam';
5+
import { Compatibility, EcsEc2ContainerDefinition, EcsFargateContainerDefinition, EcsJobDefinition, JobQueue, ManagedEc2EcsComputeEnvironment } from '../lib';
6+
import { Vpc } from 'aws-cdk-lib/aws-ec2';
57

68
test('EcsJobDefinition respects propagateTags', () => {
79
// GIVEN
@@ -127,3 +129,44 @@ test('JobDefinitionName is parsed from arn in imported job', () => {
127129
// THEN
128130
expect(importedJob.jobDefinitionName).toEqual('job-def-name');
129131
});
132+
133+
test('grantSubmitJob() grants the job role the correct actions', () => {
134+
// GIVEN
135+
const stack = new Stack();
136+
const ecsJob = new EcsJobDefinition(stack, 'ECSJob', {
137+
container: new EcsFargateContainerDefinition(stack, 'EcsContainer', {
138+
cpu: 256,
139+
memory: Size.mebibytes(2048),
140+
image: ecs.ContainerImage.fromRegistry('foorepo/fooimage'),
141+
}),
142+
});
143+
const queue = new JobQueue(stack, 'queue');
144+
145+
queue.addComputeEnvironment(
146+
new ManagedEc2EcsComputeEnvironment(stack, 'env', {
147+
vpc: new Vpc(stack, 'VPC'),
148+
}),
149+
1,
150+
);
151+
152+
const user = new iam.User(stack, 'MyUser');
153+
154+
// WHEN
155+
ecsJob.grantSubmitJob(user, queue);
156+
157+
// THEN
158+
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', {
159+
PolicyDocument: {
160+
Statement: [{
161+
Action: 'batch:SubmitJob',
162+
Effect: 'Allow',
163+
Resource: [
164+
{ Ref: 'ECSJobFFFEA569' },
165+
{ 'Fn::GetAtt': ['queue276F7297', 'JobQueueArn'] },
166+
],
167+
}],
168+
Version: '2012-10-17',
169+
},
170+
PolicyName: 'MyUserDefaultPolicy7B897426',
171+
});
172+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"version": "33.0.0",
3+
"files": {
4+
"21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": {
5+
"source": {
6+
"path": "BatchEcsJobDefinitionTestDefaultTestDeployAssertE5BAAC9B.template.json",
7+
"packaging": "file"
8+
},
9+
"destinations": {
10+
"current_account-current_region": {
11+
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12+
"objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json",
13+
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
14+
}
15+
}
16+
}
17+
},
18+
"dockerImages": {}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"Parameters": {
3+
"BootstrapVersion": {
4+
"Type": "AWS::SSM::Parameter::Value<String>",
5+
"Default": "/cdk-bootstrap/hnb659fds/version",
6+
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
7+
}
8+
},
9+
"Rules": {
10+
"CheckBootstrapVersion": {
11+
"Assertions": [
12+
{
13+
"Assert": {
14+
"Fn::Not": [
15+
{
16+
"Fn::Contains": [
17+
[
18+
"1",
19+
"2",
20+
"3",
21+
"4",
22+
"5"
23+
],
24+
{
25+
"Ref": "BootstrapVersion"
26+
}
27+
]
28+
}
29+
]
30+
},
31+
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
32+
}
33+
]
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":"33.0.0"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "33.0.0",
3+
"testCases": {
4+
"BatchEcsJobDefinitionTest/DefaultTest": {
5+
"stacks": [
6+
"stack"
7+
],
8+
"assertionStack": "BatchEcsJobDefinitionTest/DefaultTest/DeployAssert",
9+
"assertionStackName": "BatchEcsJobDefinitionTestDefaultTestDeployAssertE5BAAC9B"
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)