Skip to content

Commit 53d61bb

Browse files
authored
feat(apigateway): L2 construct for Sagemaker Integration (#25459)
Sagemaker integration for ApiGateway. Pulled the IEndpoint from the alpha module. Stabilizes `sagemaker.IEndpoint` from `aws-sagemaker-alpha` so that it can be used in the integration. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent b5bd39e commit 53d61bb

File tree

10 files changed

+169
-35
lines changed

10 files changed

+169
-35
lines changed

packages/@aws-cdk/aws-sagemaker-alpha/lib/endpoint.ts

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
44
import * as ec2 from 'aws-cdk-lib/aws-ec2';
55
import * as iam from 'aws-cdk-lib/aws-iam';
66
import * as cdk from 'aws-cdk-lib/core';
7+
import * as sagemaker from 'aws-cdk-lib/aws-sagemaker';
78
import { Construct } from 'constructs';
89
import { EndpointConfig, IEndpointConfig, InstanceProductionVariant } from './endpoint-config';
910
import { InstanceType } from './instance-type';
@@ -20,30 +21,12 @@ const BURSTABLE_INSTANCE_TYPE_PREFIXES = Object.entries(ec2.InstanceClass)
2021
.filter(([name, _]) => name.startsWith('T'))
2122
.map(([_, prefix]) => `ml.${prefix}.`);
2223

24+
// IEndpoint is stabilized so that it can be used in aws-apigateway SagemakerIntegration
25+
// Exposing it again here so that there is no breakage to aws-sagemaker-alpha
2326
/**
24-
* The interface for a SageMaker Endpoint resource.
27+
* The Interface for a SageMaker Endpoint resource.
2528
*/
26-
export interface IEndpoint extends cdk.IResource {
27-
/**
28-
* The ARN of the endpoint.
29-
*
30-
* @attribute
31-
*/
32-
readonly endpointArn: string;
33-
34-
/**
35-
* The name of the endpoint.
36-
*
37-
* @attribute
38-
*/
39-
readonly endpointName: string;
40-
41-
/**
42-
* Permits an IAM principal to invoke this endpoint
43-
* @param grantee The principal to grant access to
44-
*/
45-
grantInvoke(grantee: iam.IGrantable): iam.Grant;
46-
}
29+
export interface IEndpoint extends sagemaker.IEndpoint {}
4730

4831
/**
4932
* Represents the features common to all production variant types (e.g., instance, serverless) that

packages/aws-cdk-lib/aws-apigateway/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,10 @@ method is called. API Gateway supports the following integrations:
257257

258258
- `MockIntegration` - can be used to test APIs. This is the default
259259
integration if one is not specified.
260-
- `LambdaIntegration` - can be used to invoke an AWS Lambda function.
261260
- `AwsIntegration` - can be used to invoke arbitrary AWS service APIs.
262261
- `HttpIntegration` - can be used to invoke HTTP endpoints.
262+
- `LambdaIntegration` - can be used to invoke an AWS Lambda function.
263+
- `SagemakerIntegration` - can be used to invoke Sagemaker Endpoints.
263264

264265
The following example shows how to integrate the `GET /book/{book_id}` method to
265266
an AWS Lambda function:

packages/aws-cdk-lib/aws-apigateway/lib/integrations/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export * from './lambda';
33
export * from './http';
44
export * from './mock';
55
export * from './stepfunctions';
6+
export * from './sagemaker';
67
export * from './request-context';
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { AwsIntegration } from './aws';
2+
import * as iam from '../../../aws-iam';
3+
import { IEndpoint } from '../../../aws-sagemaker';
4+
import { IntegrationConfig, IntegrationOptions } from '../integration';
5+
import { Method } from '../method';
6+
7+
/**
8+
* Options for SageMakerIntegration
9+
*/
10+
export interface SagemakerIntegrationOptions extends IntegrationOptions {
11+
}
12+
13+
/**
14+
* Integrates an AWS Sagemaker Endpoint to an API Gateway method
15+
*
16+
* @example
17+
*
18+
* declare const resource: apigateway.Resource;
19+
* declare const endpoint: sagemaker.IEndpoint;
20+
* resource.addMethod('POST', new apigateway.SagemakerIntegration(endpoint));
21+
*
22+
*/
23+
export class SagemakerIntegration extends AwsIntegration {
24+
private readonly endpoint: IEndpoint;
25+
26+
constructor(endpoint: IEndpoint, options: SagemakerIntegrationOptions = {}) {
27+
super({
28+
service: 'runtime.sagemaker',
29+
path: `endpoints/${endpoint.endpointName}/invocations`,
30+
options: {
31+
credentialsRole: options.credentialsRole,
32+
integrationResponses: [
33+
{ statusCode: '200' },
34+
],
35+
...options,
36+
},
37+
});
38+
39+
this.endpoint = endpoint;
40+
}
41+
42+
public bind(method: Method): IntegrationConfig {
43+
const bindResult = super.bind(method);
44+
45+
const credentialsRole = bindResult.options?.credentialsRole ?? new iam.Role(method, 'SagemakerRole', {
46+
assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'),
47+
description: 'Generated by CDK::ApiGateway::SagemakerIntegration',
48+
});
49+
50+
this.endpoint.grantInvoke(credentialsRole);
51+
52+
method.addMethodResponse({
53+
statusCode: '200',
54+
});
55+
56+
return {
57+
...bindResult,
58+
options: {
59+
...bindResult.options,
60+
credentialsRole,
61+
},
62+
};
63+
}
64+
}

packages/aws-cdk-lib/aws-apigateway/lib/integrations/stepfunctions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { Token } from '../../../core';
88
import { IntegrationConfig, IntegrationOptions, PassthroughBehavior } from '../integration';
99
import { Method } from '../method';
1010
import { Model } from '../model';
11+
1112
/**
1213
* Options when configuring Step Functions synchronous integration with Rest API
1314
*/
1415
export interface StepFunctionsExecutionIntegrationOptions extends IntegrationOptions {
15-
1616
/**
1717
* Which details of the incoming request must be passed onto the underlying state machine,
1818
* such as, account id, user identity, request id, etc. The execution input will include a new key `requestContext`:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Template } from '../../../assertions';
2+
import * as iam from '../../../aws-iam';
3+
import * as sagemaker from '../../../aws-sagemaker';
4+
import * as cdk from '../../../core';
5+
import * as apigateway from '../../lib';
6+
7+
describe('SageMaker Integration', () => {
8+
test('minimal setup', () => {
9+
// GIVEN
10+
const stack = new cdk.Stack();
11+
const api = new apigateway.RestApi(stack, 'my-api');
12+
const endpoint = new FakeEndpoint(stack, 'FakeEndpoint');
13+
14+
// WHEN
15+
const integration = new apigateway.SagemakerIntegration(endpoint);
16+
api.root.addMethod('POST', integration);
17+
18+
// THEN
19+
Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', {
20+
Integration: {
21+
IntegrationHttpMethod: 'POST',
22+
Type: 'AWS',
23+
Uri: {
24+
'Fn::Join': [
25+
'',
26+
[
27+
'arn:',
28+
{
29+
Ref: 'AWS::Partition',
30+
},
31+
':apigateway:',
32+
{
33+
Ref: 'AWS::Region',
34+
},
35+
':runtime.sagemaker:path/endpoints/endpointName/invocations',
36+
],
37+
],
38+
},
39+
},
40+
});
41+
});
42+
});
43+
44+
class FakeEndpoint extends cdk.Resource implements sagemaker.IEndpoint {
45+
public readonly endpointArn = 'endpointArn';
46+
47+
public readonly endpointName = 'endpointName';
48+
49+
public grantInvoke(grantee: iam.IGrantable) {
50+
return iam.Grant.addToPrincipal({
51+
grantee,
52+
actions: ['sagemaker:InvokeEndpoint'],
53+
resourceArns: [this.endpointArn],
54+
});
55+
}
56+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as iam from '../../aws-iam';
2+
import { IResource } from '../../core';
3+
4+
/**
5+
* The interface for a SageMaker Endpoint resource.
6+
*/
7+
export interface IEndpoint extends IResource {
8+
/**
9+
* The ARN of the endpoint.
10+
*
11+
* @attribute
12+
*/
13+
readonly endpointArn: string;
14+
15+
/**
16+
* The name of the endpoint.
17+
*
18+
* @attribute
19+
*/
20+
readonly endpointName: string;
21+
22+
/**
23+
* Permits an IAM principal to invoke this endpoint
24+
* @param grantee The principal to grant access to
25+
*/
26+
grantInvoke(grantee: iam.IGrantable): iam.Grant;
27+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export * from './sagemaker.generated';
1+
export * from './sagemaker.generated';
2+
export * from './endpoint';

packages/aws-cdk-lib/rosetta/aws_apigateway/default.ts-fixture

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// Fixture with packages imported, but nothing else
22
import { Construct } from 'constructs';
33
import { Duration, Stack } from 'aws-cdk-lib';
4-
import apigateway = require('aws-cdk-lib/aws-apigateway');
5-
import cognito = require('aws-cdk-lib/aws-cognito');
6-
import lambda = require('aws-cdk-lib/aws-lambda');
7-
import iam = require('aws-cdk-lib/aws-iam');
8-
import s3 = require('aws-cdk-lib/aws-s3');
9-
import ec2 = require('aws-cdk-lib/aws-ec2');
10-
import logs = require('aws-cdk-lib/aws-logs');
11-
import stepfunctions = require('aws-cdk-lib/aws-stepfunctions');
4+
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
5+
import * as cognito from 'aws-cdk-lib/aws-cognito';
6+
import * as lambda from 'aws-cdk-lib/aws-lambda';
7+
import * as iam from 'aws-cdk-lib/aws-iam';
8+
import * as s3 from 'aws-cdk-lib/aws-s3';
9+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
10+
import * as logs from 'aws-cdk-lib/aws-logs';
11+
import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions';
12+
import * as sagemaker from 'aws-cdk-lib/aws-sagemaker';
1213

1314
class Fixture extends Stack {
1415
constructor(scope: Construct, id: string) {

packages/aws-cdk-lib/rosetta/aws_apigateway/stepfunctions.ts-fixture

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Construct } from 'constructs';
22
import { Stack } from 'aws-cdk-lib';
3-
import apigateway = require('aws-cdk-lib/aws-apigateway');
4-
import stepfunctions = require('aws-cdk-lib/aws-stepfunctions');
3+
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
4+
import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions';
55

66
class Fixture extends Stack {
77
constructor(scope: Construct, id: string) {

0 commit comments

Comments
 (0)