Skip to content

Commit

Permalink
Add different Instance Types
Browse files Browse the repository at this point in the history
  • Loading branch information
SoManyHs committed Mar 5, 2019
1 parent 30650a3 commit 48c262f
Show file tree
Hide file tree
Showing 14 changed files with 1,076 additions and 327 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import cdk = require('@aws-cdk/cdk');
import { BaseInstanceProps, InstanceBase } from './instance';
import { NamespaceType } from './namespace';
import { DnsRecordType, IService, RoutingPolicy } from './service';
import { CfnInstance } from './servicediscovery.generated';

export interface AliasTargetInstanceProps extends BaseInstanceProps {
/**
* DNS name of the target
*/
dnsName: string;

/**
* The Cloudmap service this resource is registered to.
*/
service: IService;
}

export class AliasTargetInstance extends InstanceBase {
/**
* The Id of the instance
*/
public readonly instanceId: string;

/**
* The Cloudmap service to which the instance is registered.
*/
public readonly service: IService;

/**
* The Route53 DNS name of the alias target
*/
public readonly dnsName: string;

constructor(scope: cdk.Construct, id: string, props: AliasTargetInstanceProps) {
super(scope, id);

if (props.service.namespace.type === NamespaceType.Http) {
throw new Error('Namespace associated with Service must be a DNS Namespace.');
}

// Should already be enforced when creating service, but validates if service is not instantiated with #createService
const dnsRecordType = props.service.dnsRecordType;
if (dnsRecordType !== DnsRecordType.A
&& dnsRecordType !== DnsRecordType.AAAA
&& dnsRecordType !== DnsRecordType.A_AAAA) {
throw new Error('Service must use `A` or `AAAA` records to register an AliasRecordTarget.');
}

if (props.service.routingPolicy !== RoutingPolicy.Weighted) {
throw new Error('Service must use `WEIGHTED` routing policy.');
}

const resource = new CfnInstance(this, 'Resource', {
instanceAttributes: {
AWS_ALIAS_DNS_NAME: props.dnsName,
...props.customAttributes
},
instanceId: props.instanceId,
serviceId: props.service.serviceId
});

this.service = props.service;
this.instanceId = resource.instanceId;
this.dnsName = props.dnsName;
}
}
65 changes: 65 additions & 0 deletions packages/@aws-cdk/aws-servicediscovery/lib/cname-instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import cdk = require('@aws-cdk/cdk');
import { BaseInstanceProps, InstanceBase } from './instance';
import { NamespaceType } from './namespace';
import { DnsRecordType, IService } from './service';
import { CfnInstance } from './servicediscovery.generated';

export interface CnameInstanceBaseProps extends BaseInstanceProps {
/**
* If the service configuration includes a CNAME record, the domain name that you want Route 53 to return in
* response to DNS queries, for example, example.com. This value is required if the service specified by ServiceId
* includes settings for an CNAME record.
*/
instanceCname: string;
}

export interface CnameInstanceProps extends CnameInstanceBaseProps {
/**
* The Cloudmap service this resource is registered to.
*/
service: IService;
}

export class CnameInstance extends InstanceBase {
/**
* The Id of the instance
*/
public readonly instanceId: string;

/**
* The Cloudmap service to which the instance is registered.
*/
public readonly service: IService;

/**
* The domain name returned by DNS queries for the instance
*/
public readonly instanceCname: string;

constructor(scope: cdk.Construct, id: string, props: CnameInstanceProps) {
super(scope, id);

if (props.service.namespace.type === NamespaceType.Http) {
throw new Error('Namespace associated with Service must be a DNS Namespace.');
}

if (props.service.dnsRecordType === DnsRecordType.Cname) {
if (!props.instanceCname) {
throw new Error('A `instanceCname` must be specified for a service using a `CNAME` record.');
}
}

const resource = new CfnInstance(this, 'Resource', {
instanceId: props.instanceId,
serviceId: props.service.serviceId,
instanceAttributes: {
AWS_INSTANCE_CNAME: props.instanceCname,
...props.customAttributes
}
});

this.service = props.service;
this.instanceId = resource.instanceId;
this.instanceCname = props.instanceCname;
}
}
4 changes: 4 additions & 0 deletions packages/@aws-cdk/aws-servicediscovery/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export * from './instance';
export * from './alias-target-instance';
export * from './cname-instance';
export * from './ip-instance';
export * from './non-ip-instance';
export * from './namespace';
export * from './http-namespace';
export * from './private-dns-namespace';
Expand Down
192 changes: 18 additions & 174 deletions packages/@aws-cdk/aws-servicediscovery/lib/instance.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import cdk = require('@aws-cdk/cdk');
import { NamespaceType } from './namespace';
import { DnsRecordType, IService } from './service';
import { CfnInstance } from './servicediscovery.generated';
import { IService } from './service';

export interface IInstance extends cdk.IConstruct {
/**
* The instance attributes.
*/
readonly instanceAttributes: InstanceAttributes;

/**
* The id of the instance resource
*/
Expand All @@ -21,191 +14,42 @@ export interface IInstance extends cdk.IConstruct {
}

/**
* Properties to define ServiceDiscovery Instance
* Used when the resource that's associated with the service instance is accessible using values other than an IP
* address or a domain name (CNAME), i.e. for non-ip-instances
*/
export interface InstanceProps {
/**
* The instance attributes.
*/
instanceAttributes: InstanceAttributes;

export interface BaseInstanceProps {
/**
* The id of the instance resource
*/
instanceId: string;

/**
* The Cloudmap service this resource is registered to.
* Custom attributes of the instance.
*
* @default none
*/
service: IService;
customAttributes?: object;

}

/**
* Define a Service Discovery Instance
* Properties to define ServiceDiscovery Instance
*/
export class Instance extends cdk.Construct implements IInstance {
/**
* The Id of the instance
*/
public readonly instanceId: string;
export interface InstanceProps extends BaseInstanceProps {
/**
* The Cloudmap service to which the instance is registered.
*/
public readonly service: IService;

/**
* The instance attributes.
* FIXME break out into different instance types
* The Cloudmap service this resource is registered to.
*/
public readonly instanceAttributes: InstanceAttributes;

constructor(scope: cdk.Construct, id: string, props: InstanceProps) {
super(scope, id);

const resource = new CfnInstance(this, 'Resource', {
instanceAttributes: renderInstanceAttributes(props),
instanceId: props.instanceId,
serviceId: props.service.serviceId
});

this.service = props.service;
this.instanceId = resource.instanceId;
}
service: IService;
}

// NOTE: These are the 5 that seem to be supported in cloudformation, but the API docs indicate that you can also
// specify custom attributes. Not sure if CFN would support these? In the generated L1s instance attributes appears to
// just be an object.
export interface InstanceAttributes {
export abstract class InstanceBase extends cdk.Construct implements IInstance {
/**
* If you want AWS Cloud Map to create an Amazon Route 53 alias record that routes traffic to an Elastic Load
* Balancing load balancer, specify the DNS name that is associated with the load balancer.
*
* @default none
*/
aliasDnsName?: string;

/**
* If the service configuration includes a CNAME record, the domain name that you want Route 53 to return in
* response to DNS queries, for example, example.com. This value is required if the service specified by ServiceId
* includes settings for an CNAME record.
*
* @default none
*/
instanceCname?: string;

/**
* The port on the endpoint that you want AWS Cloud Map to perform health checks on. This value is also used for
* the port value in an SRV record if the service that you specify includes an SRV record. You can also specify a
* default port that is applied to all instances in the Service configuration.
*
* @default none
*/
port?: string;

/**
* If the service that you specify contains a template for an A record, the IPv4 address that you want AWS Cloud
* Map to use for the value of the A record.
*
* @default none
*/
ipv4?: string;

/**
* If the service that you specify contains a template for an AAAA record, the IPv6 address that you want AWS Cloud
* Map to use for the value of the AAAA record.
*
* @default none
* The Id of the instance
*/
ipv6?: string;
public abstract readonly instanceId: string;

/**
* Custom attributes of the instance.
*
* @default none
* The Cloudmap service to which the instance is registered.
*/
customAttributes?: object;
}

/**
* Validates instance attributes and returns standard attributes based on the namespace/service type.
*
* @param props instance props
* @throws if the instance attributes are invalid
*/
function renderInstanceAttributes(props: InstanceProps): object {

const customAttributes = props.instanceAttributes.customAttributes || {};

if (props.instanceAttributes.aliasDnsName && props.instanceAttributes.instanceCname) {
throw new Error('Cannot specify both `aliasDnsName` and `instanceCname`.');
}

if (props.service.namespace.type === NamespaceType.Http) {
if (props.instanceAttributes.aliasDnsName || props.instanceAttributes.instanceCname) {
throw new Error('Cannot specify `aliasDnsName` or `instanceCname` for an HTTP namespace.');
}

return {
AWS_INSTANCE_IPV4: props.instanceAttributes.ipv4,
AWS_INSTANCE_IPV6: props.instanceAttributes.ipv6,
AWS_INSTANCE_PORT: props.instanceAttributes.port,
...customAttributes
};
}

if (props.service.dnsRecordType === DnsRecordType.Cname) {
if (!props.instanceAttributes.instanceCname) {
throw new Error('A `instanceCname` must be specified for a service using a `CNAME` record.');
}

return {
AWS_INSTANCE_CNAME: props.instanceAttributes.instanceCname,
...customAttributes
};
}

if (props.service.dnsRecordType === DnsRecordType.Srv) {
if (!props.instanceAttributes.port) {
throw new Error('A `port` must be specified for a service using a `SRV` record.');
}

if (!props.instanceAttributes.ipv4 && !props.instanceAttributes.ipv6) {
throw new Error('At least `ipv4` or `ipv6` must be specified for a service using a `SRV` record.');
}

return {
AWS_INSTANCE_IPV4: props.instanceAttributes.ipv4,
AWS_INSTANCE_IPV6: props.instanceAttributes.ipv6,
AWS_INSTANCE_PORT: props.instanceAttributes.port,
...customAttributes
};
}

if (props.instanceAttributes.aliasDnsName) {
if (props.instanceAttributes.ipv4 || props.instanceAttributes.ipv6 || props.instanceAttributes.port) {
throw new Error('Cannot specify `ipv4`, `ipv6` or `port` when specifying `aliasDnsName`.');
}

return {
AWS_ALIAS_DNS_NAME: props.instanceAttributes.aliasDnsName,
...customAttributes
};
}

if (!props.instanceAttributes.ipv4 && (props.service.dnsRecordType === DnsRecordType.A || props.service.dnsRecordType === DnsRecordType.A_AAAA)) {
throw new Error('An `ipv4` must be specified for a service using a `A` record.');
}

if (!props.instanceAttributes.ipv6 &&
(props.service.dnsRecordType === DnsRecordType.AAAA || props.service.dnsRecordType === DnsRecordType.A_AAAA)) {
throw new Error('An `ipv6` must be specified for a service using a `AAAA` record.');
}

return {
AWS_INSTANCE_IPV4: props.instanceAttributes.ipv4,
AWS_INSTANCE_IPV6: props.instanceAttributes.ipv6,
AWS_INSTANCE_PORT: props.instanceAttributes.port,
...customAttributes
};
public abstract readonly service: IService;
}
Loading

0 comments on commit 48c262f

Please sign in to comment.