From c89443dacd2f1e4e5d82070efc5e48765812740e Mon Sep 17 00:00:00 2001 From: Ahmed Kamel Date: Wed, 17 Feb 2021 15:23:24 +0000 Subject: [PATCH] feat(glue): Connection construct (#12444) Closes #12442 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-glue/README.md | 18 + packages/@aws-cdk/aws-glue/lib/connection.ts | 216 +++++++ packages/@aws-cdk/aws-glue/lib/index.ts | 1 + packages/@aws-cdk/aws-glue/package.json | 2 + .../@aws-cdk/aws-glue/test/connection.test.ts | 159 +++++ .../test/integ.connection.expected.json | 559 ++++++++++++++++++ .../aws-glue/test/integ.connection.ts | 20 + 7 files changed, 975 insertions(+) create mode 100644 packages/@aws-cdk/aws-glue/lib/connection.ts create mode 100644 packages/@aws-cdk/aws-glue/test/connection.test.ts create mode 100644 packages/@aws-cdk/aws-glue/test/integ.connection.expected.json create mode 100644 packages/@aws-cdk/aws-glue/test/integ.connection.ts diff --git a/packages/@aws-cdk/aws-glue/README.md b/packages/@aws-cdk/aws-glue/README.md index 5f841bda367ce..20e08d7c14e31 100644 --- a/packages/@aws-cdk/aws-glue/README.md +++ b/packages/@aws-cdk/aws-glue/README.md @@ -23,6 +23,24 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. +## Connection + +A `Connection` allows Glue jobs, crawlers and development endpoints to access certain types of data stores. For example, to create a network connection to connect to a data source within a VPC: + +```ts +new glue.Connection(stack, 'MyConnection', { + connectionType: glue.ConnectionTypes.NETWORK, + // The security groups granting AWS Glue inbound access to the data source within the VPC + securityGroups: [securityGroup], + // The VPC subnet which contains the data source + subnet, +}); +``` + +If you need to use a connection type that doesn't exist as a static member on `ConnectionType`, you can instantiate a `ConnectionType` object, e.g: `new glue.ConnectionType('NEW_TYPE')`. + +See [Adding a Connection to Your Data Store](https://docs.aws.amazon.com/glue/latest/dg/populate-add-connection.html) and [Connection Structure](https://docs.aws.amazon.com/glue/latest/dg/aws-glue-api-catalog-connections.html#aws-glue-api-catalog-connections-Connection) documentation for more information on the supported data stores and their configurations. + ## Database A `Database` is a logical grouping of `Tables` in the Glue Catalog. diff --git a/packages/@aws-cdk/aws-glue/lib/connection.ts b/packages/@aws-cdk/aws-glue/lib/connection.ts new file mode 100644 index 0000000000000..56cd115e4c6f9 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/lib/connection.ts @@ -0,0 +1,216 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as constructs from 'constructs'; +import { CfnConnection } from './glue.generated'; + +/** + * The type of the glue connection + * + * If you need to use a connection type that doesn't exist as a static member, you + * can instantiate a `ConnectionType` object, e.g: `new ConnectionType('NEW_TYPE')`. + */ +export class ConnectionType { + + /** + * Designates a connection to a database through Java Database Connectivity (JDBC). + */ + public static readonly JDBC = new ConnectionType('JDBC'); + + /** + * Designates a connection to an Apache Kafka streaming platform. + */ + public static readonly KAFKA = new ConnectionType('KAFKA'); + + /** + * Designates a connection to a MongoDB document database. + */ + public static readonly MONGODB = new ConnectionType('MONGODB'); + + /** + * Designates a network connection to a data source within an Amazon Virtual Private Cloud environment (Amazon VPC). + */ + public static readonly NETWORK = new ConnectionType('NETWORK'); + + /** + * The name of this ConnectionType, as expected by Connection resource. + */ + public readonly name: string; + + constructor(name: string) { + this.name = name; + } + + /** + * The connection type name as expected by Connection resource. + */ + public toString(): string { + return this.name; + } +} + +/** + * Interface representing a created or an imported {@link Connection} + */ +export interface IConnection extends cdk.IResource { + /** + * The name of the connection + * @attribute + */ + readonly connectionName: string; + + /** + * The ARN of the connection + * @attribute + */ + readonly connectionArn: string; +} + +/** + * Base Connection Options + */ +export interface ConnectionOptions { + /** + * The name of the connection + * @default cloudformation generated name + */ + readonly connectionName?: string; + + /** + * The description of the connection. + * @default no description + */ + readonly description?: string; + + /** + * Key-Value pairs that define parameters for the connection. + * @default empty properties + * @see https://docs.aws.amazon.com/glue/latest/dg/aws-glue-programming-etl-connect.html + */ + readonly properties?: { [key: string]: string }; + + /** + * A list of criteria that can be used in selecting this connection. + * This is useful for filtering the results of https://awscli.amazonaws.com/v2/documentation/api/latest/reference/glue/get-connections.html + * @default no match criteria + */ + readonly matchCriteria?: string[]; + + /** + * The list of security groups needed to successfully make this connection e.g. to successfully connect to VPC. + * @default no security group + */ + readonly securityGroups?: ec2.ISecurityGroup[]; + + /** + * The VPC subnet to connect to resources within a VPC. See more at https://docs.aws.amazon.com/glue/latest/dg/start-connecting.html. + * @default no subnet + */ + readonly subnet?: ec2.ISubnet; +} + +/** + * Construction properties for {@link Connection} + */ +export interface ConnectionProps extends ConnectionOptions { + /** + * The type of the connection + */ + readonly type: ConnectionType; +} + +/** + * An AWS Glue connection to a data source. + */ +export class Connection extends cdk.Resource implements IConnection { + + /** + * Creates a Connection construct that represents an external connection. + * + * @param scope The scope creating construct (usually `this`). + * @param id The construct's id. + * @param connectionArn arn of external connection. + */ + public static fromConnectionArn(scope: constructs.Construct, id: string, connectionArn: string): IConnection { + class Import extends cdk.Resource implements IConnection { + public readonly connectionName = cdk.Arn.extractResourceName(connectionArn, 'connection'); + public readonly connectionArn = connectionArn; + } + + return new Import(scope, id); + } + + /** + * Creates a Connection construct that represents an external connection. + * + * @param scope The scope creating construct (usually `this`). + * @param id The construct's id. + * @param connectionName name of external connection. + */ + public static fromConnectionName(scope: constructs.Construct, id: string, connectionName: string): IConnection { + class Import extends cdk.Resource implements IConnection { + public readonly connectionName = connectionName; + public readonly connectionArn = Connection.buildConnectionArn(scope, connectionName); + } + + return new Import(scope, id); + } + + private static buildConnectionArn(scope: constructs.Construct, connectionName: string) : string { + return cdk.Stack.of(scope).formatArn({ + service: 'glue', + resource: 'connection', + resourceName: connectionName, + }); + } + + /** + * The ARN of the connection + */ + public readonly connectionArn: string; + + /** + * The name of the connection + */ + public readonly connectionName: string; + + private readonly properties: {[key: string]: string}; + + constructor(scope: constructs.Construct, id: string, props: ConnectionProps) { + super(scope, id, { + physicalName: props.connectionName, + }); + + this.properties = props.properties || {}; + + const physicalConnectionRequirements = props.subnet || props.securityGroups ? { + availabilityZone: props.subnet ? props.subnet.availabilityZone : undefined, + subnetId: props.subnet ? props.subnet.subnetId : undefined, + securityGroupIdList: props.securityGroups ? props.securityGroups.map(sg => sg.securityGroupId) : undefined, + } : undefined; + + const connectionResource = new CfnConnection(this, 'Resource', { + catalogId: cdk.Stack.of(this).account, + connectionInput: { + connectionProperties: cdk.Lazy.any({ produce: () => Object.keys(this.properties).length > 0 ? this.properties : undefined }), + connectionType: props.type.name, + description: props.description, + matchCriteria: props.matchCriteria, + name: props.connectionName, + physicalConnectionRequirements, + }, + }); + + const resourceName = this.getResourceNameAttribute(connectionResource.ref); + this.connectionArn = Connection.buildConnectionArn(this, resourceName); + this.connectionName = resourceName; + } + + /** + * Add additional connection parameters + * @param key parameter key + * @param value parameter value + */ + public addProperty(key: string, value: string): void { + this.properties[key] = value; + } +} diff --git a/packages/@aws-cdk/aws-glue/lib/index.ts b/packages/@aws-cdk/aws-glue/lib/index.ts index b219daf0996d2..a3dfa85b3be71 100644 --- a/packages/@aws-cdk/aws-glue/lib/index.ts +++ b/packages/@aws-cdk/aws-glue/lib/index.ts @@ -1,6 +1,7 @@ // AWS::Glue CloudFormation Resources: export * from './glue.generated'; +export * from './connection'; export * from './data-format'; export * from './database'; export * from './schema'; diff --git a/packages/@aws-cdk/aws-glue/package.json b/packages/@aws-cdk/aws-glue/package.json index ca6ed1bb731a5..22243f7922478 100644 --- a/packages/@aws-cdk/aws-glue/package.json +++ b/packages/@aws-cdk/aws-glue/package.json @@ -80,6 +80,7 @@ "pkglint": "0.0.0" }, "dependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", @@ -88,6 +89,7 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", diff --git a/packages/@aws-cdk/aws-glue/test/connection.test.ts b/packages/@aws-cdk/aws-glue/test/connection.test.ts new file mode 100644 index 0000000000000..5846bf161fa69 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/connection.test.ts @@ -0,0 +1,159 @@ +import * as cdkassert from '@aws-cdk/assert'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import '@aws-cdk/assert/jest'; +import * as glue from '../lib'; + +test('a connection with connection properties', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.JDBC, + properties: { + JDBC_CONNECTION_URL: 'jdbc:server://server:443/connection', + USERNAME: 'username', + PASSWORD: 'password', + }, + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionProperties: { + JDBC_CONNECTION_URL: 'jdbc:server://server:443/connection', + USERNAME: 'username', + PASSWORD: 'password', + }, + ConnectionType: 'JDBC', + }, + })); +}); + +test('a connection with a subnet and security group', () => { + const stack = new cdk.Stack(); + const subnet = ec2.Subnet.fromSubnetAttributes(stack, 'subnet', { + subnetId: 'subnetId', + availabilityZone: 'azId', + }); + const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(stack, 'securityGroup', 'sgId'); + new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.NETWORK, + securityGroups: [securityGroup], + subnet, + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + PhysicalConnectionRequirements: { + AvailabilityZone: 'azId', + SubnetId: 'subnetId', + SecurityGroupIdList: ['sgId'], + }, + }, + })); +}); + +test('a connection with a name and description', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + connectionName: 'name', + description: 'description', + type: glue.ConnectionType.NETWORK, + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + Name: 'name', + Description: 'description', + }, + })); +}); + +test('a connection with a custom type', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + connectionName: 'name', + description: 'description', + type: new glue.ConnectionType('CUSTOM_TYPE'), + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'CUSTOM_TYPE', + Name: 'name', + Description: 'description', + }, + })); +}); + +test('a connection with match criteria', () => { + const stack = new cdk.Stack(); + new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.NETWORK, + matchCriteria: ['c1', 'c2'], + }); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + MatchCriteria: ['c1', 'c2'], + }, + })); +}); + +test('addProperty', () => { + const stack = new cdk.Stack(); + const connection = new glue.Connection(stack, 'Connection', { + type: glue.ConnectionType.NETWORK, + }); + connection.addProperty('SomeKey', 'SomeValue'); + + cdkassert.expect(stack).to(cdkassert.haveResource('AWS::Glue::Connection', { + CatalogId: { + Ref: 'AWS::AccountId', + }, + ConnectionInput: { + ConnectionType: 'NETWORK', + ConnectionProperties: { + SomeKey: 'SomeValue', + }, + }, + })); +}); + +test('fromConnectionName', () => { + const connectionName = 'name'; + const stack = new cdk.Stack(); + const connection = glue.Connection.fromConnectionName(stack, 'ImportedConnection', connectionName); + + expect(connection.connectionName).toEqual(connectionName); + expect(connection.connectionArn).toEqual(stack.formatArn({ + service: 'glue', + resource: 'connection', + resourceName: connectionName, + })); +}); + +test('fromConnectionArn', () => { + const connectionArn = 'arn:aws:glue:region:account-id:connection/name'; + const stack = new cdk.Stack(); + const connection = glue.Connection.fromConnectionArn(stack, 'ImportedConnection', connectionArn); + + expect(connection.connectionName).toEqual('name'); + expect(connection.connectionArn).toEqual(connectionArn); +}); diff --git a/packages/@aws-cdk/aws-glue/test/integ.connection.expected.json b/packages/@aws-cdk/aws-glue/test/integ.connection.expected.json new file mode 100644 index 0000000000000..3422ce4ff408b --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/integ.connection.expected.json @@ -0,0 +1,559 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc" + } + ] + } + }, + "VpcPublicSubnet1Subnet5C2D37C4": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.0.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTable6C95E38E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1RouteTableAssociation97140677": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + } + } + }, + "VpcPublicSubnet1DefaultRoute3DA9E72A": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet1RouteTable6C95E38E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet1EIPD7E02669": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet1NATGateway4D7517AA": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet1EIPD7E02669", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet1Subnet5C2D37C4" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet1" + } + ] + } + }, + "VpcPublicSubnet2Subnet691E08A3": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.32.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTable94F7E489": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2RouteTableAssociationDD5762D8": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + } + } + }, + "VpcPublicSubnet2DefaultRoute97F91067": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet2RouteTable94F7E489" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet2EIP3C605A87": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet2NATGateway9182C01D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet2EIP3C605A87", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet2Subnet691E08A3" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet2" + } + ] + } + }, + "VpcPublicSubnet3SubnetBE12F0B6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.64.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTable93458DBB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3RouteTableAssociation1F1EDF02": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + } + } + }, + "VpcPublicSubnet3DefaultRoute4697774F": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPublicSubnet3RouteTable93458DBB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VpcIGWD7BA715C" + } + }, + "DependsOn": [ + "VpcVPCGWBF912B6E" + ] + }, + "VpcPublicSubnet3EIP3A666A23": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPublicSubnet3NATGateway7640CD1D": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VpcPublicSubnet3EIP3A666A23", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VpcPublicSubnet3SubnetBE12F0B6" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PublicSubnet3" + } + ] + } + }, + "VpcPrivateSubnet1Subnet536B997A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.96.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1a", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableB2C5B500": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet1" + } + ] + } + }, + "VpcPrivateSubnet1RouteTableAssociation70C59FA6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + }, + "VpcPrivateSubnet1DefaultRouteBE02A9ED": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet1RouteTableB2C5B500" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet1NATGateway4D7517AA" + } + } + }, + "VpcPrivateSubnet2Subnet3788AAA1": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.128.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1b", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableA678073B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet2" + } + ] + } + }, + "VpcPrivateSubnet2RouteTableAssociationA89CAD56": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet2Subnet3788AAA1" + } + } + }, + "VpcPrivateSubnet2DefaultRoute060D2087": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet2RouteTableA678073B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet2NATGateway9182C01D" + } + } + }, + "VpcPrivateSubnet3SubnetF258B56E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "CidrBlock": "10.0.160.0/19", + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": "test-region-1c", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableD98824C7": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc/PrivateSubnet3" + } + ] + } + }, + "VpcPrivateSubnet3RouteTableAssociation16BDDC43": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "SubnetId": { + "Ref": "VpcPrivateSubnet3SubnetF258B56E" + } + } + }, + "VpcPrivateSubnet3DefaultRoute94B74F0D": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "VpcPrivateSubnet3RouteTableD98824C7" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VpcPublicSubnet3NATGateway7640CD1D" + } + } + }, + "VpcIGWD7BA715C": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-glue-connection/Vpc" + } + ] + } + }, + "VpcVPCGWBF912B6E": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "InternetGatewayId": { + "Ref": "VpcIGWD7BA715C" + } + } + }, + "SecurityGroupDD263621": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "aws-glue-connection/SecurityGroup", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "NetworkConnection2B07B7E5": { + "Type": "AWS::Glue::Connection", + "Properties": { + "CatalogId": { + "Ref": "AWS::AccountId" + }, + "ConnectionInput": { + "ConnectionType": "NETWORK", + "PhysicalConnectionRequirements": { + "AvailabilityZone": "test-region-1a", + "SecurityGroupIdList": [ + { + "Fn::GetAtt": [ + "SecurityGroupDD263621", + "GroupId" + ] + } + ], + "SubnetId": { + "Ref": "VpcPrivateSubnet1Subnet536B997A" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-glue/test/integ.connection.ts b/packages/@aws-cdk/aws-glue/test/integ.connection.ts new file mode 100644 index 0000000000000..3d586f97c85c0 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/test/integ.connection.ts @@ -0,0 +1,20 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as glue from '../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-glue-connection'); + +const vpc = new ec2.Vpc(stack, 'Vpc'); + +const sg = new ec2.SecurityGroup(stack, 'SecurityGroup', { + vpc, +}); + +// Network connection +new glue.Connection(stack, 'NetworkConnection', { + type: glue.ConnectionType.NETWORK, + subnet: vpc.privateSubnets[0], + securityGroups: [sg], +});