Skip to content

Commit

Permalink
Merge pull request #98 from mbonig/feat/wakeywakey
Browse files Browse the repository at this point in the history
Feat/wakeywakey
  • Loading branch information
mbonig committed Mar 23, 2021
2 parents 84af0ac + 2fd8985 commit 20f5fa5
Show file tree
Hide file tree
Showing 16 changed files with 419 additions and 18 deletions.
3 changes: 0 additions & 3 deletions .projenrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ const project = new AwsCdkConstructLibrary({
authorName: 'Matthew Bonig',
cdkVersion: '1.89.0',
repository: 'https://github.com/mbonig/nightynight',
bin: {
nightynight: 'lib/nightynight.js',
},
defaultReleaseBranch: 'master',
deps: dependencies,
peerDeps: dependencies,
Expand Down
96 changes: 92 additions & 4 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Name|Description
[NightyNightForAsg](#matthewbonig-nightynight-nightynightforasg)|A construct that will build a Lambda and a CloudWatch Rule (cron schedule) that will set the given ASG's desired capacity.
[NightyNightForEc2](#matthewbonig-nightynight-nightynightforec2)|A construct that will build a Lambda and a CloudWatch Rule (cron schedule) that will stop the given ec2 instance at the specified time.
[NightyNightForRds](#matthewbonig-nightynight-nightynightforrds)|A construct that will build a Lambda and a CloudWatch Rule (cron schedule) that will stop the given rds instance at the specified time.
[WakeyWakeyForEc2](#matthewbonig-nightynight-wakeywakeyforec2)|A construct that will build a Lambda and a CloudWatch Rule (cron schedule) that will start the given ec2 instance at the specified time.
[WakeyWakeyForRds](#matthewbonig-nightynight-wakeywakeyforrds)|A construct that will build a Lambda and a CloudWatch Rule (cron schedule) that will start the given rds instance at the specified time.


**Structs**
Expand All @@ -18,6 +20,8 @@ Name|Description
[NightyNightForEc2Props](#matthewbonig-nightynight-nightynightforec2props)|Props for the NightNight construct.
[NightyNightForRdsProps](#matthewbonig-nightynight-nightynightforrdsprops)|Props for the NightNight construct.
[NightyNightProps](#matthewbonig-nightynight-nightynightprops)|*No description*
[WakeyWakeyForEc2Props](#matthewbonig-nightynight-wakeywakeyforec2props)|*No description*
[WakeyWakeyForRdsProps](#matthewbonig-nightynight-wakeywakeyforrdsprops)|Props for the WakeyWakeyForRds construct.



Expand Down Expand Up @@ -67,9 +71,9 @@ new NightyNightForAsg(scope: Construct, id: string, props: NightyNightForAsgProp
* **scope** (<code>[Construct](#aws-cdk-core-construct)</code>) *No description*
* **id** (<code>string</code>) *No description*
* **props** (<code>[NightyNightForAsgProps](#matthewbonig-nightynight-nightynightforasgprops)</code>) *No description*
* **autoScalingGroup** (<code>[IAutoScalingGroup](#aws-cdk-aws-autoscaling-iautoscalinggroup)</code>) the instanceId of the EC2 instance you'd like stopped.
* **autoScalingGroup** (<code>[IAutoScalingGroup](#aws-cdk-aws-autoscaling-iautoscalinggroup)</code>) the AutoScalingGroup you'd like to change the instance count on.
* **desiredCapacity** (<code>number</code>) Desired capacity.
* **schedule** (<code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code>) An option CronOptions to specify the time of day to stop the instance. __*Default*__: { day: '*', hour: '4', minute: '0' }
* **schedule** (<code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code>) An option CronOptions to specify the time of day to scale. __*Default*__: { day: '*', hour: '4', minute: '0' }



Expand Down Expand Up @@ -130,6 +134,62 @@ new NightyNightForRds(scope: Construct, id: string, props: NightyNightForRdsProp



## class WakeyWakeyForEc2 <a id="matthewbonig-nightynight-wakeywakeyforec2"></a>

A construct that will build a Lambda and a CloudWatch Rule (cron schedule) that will start the given ec2 instance at the specified time.

Typically used when you've got ec2 instances that you only need during business hours
and want to reduce the costs of. Use in conjunction with the Nightynight construct at

__Implements__: [IConstruct](#constructs-iconstruct), [IConstruct](#aws-cdk-core-iconstruct), [IConstruct](#constructs-iconstruct), [IDependable](#aws-cdk-core-idependable)
__Extends__: [Construct](#aws-cdk-core-construct)

### Initializer




```ts
new WakeyWakeyForEc2(scope: Construct, id: string, props: WakeyWakeyForEc2Props)
```

* **scope** (<code>[Construct](#aws-cdk-core-construct)</code>) *No description*
* **id** (<code>string</code>) *No description*
* **props** (<code>[WakeyWakeyForEc2Props](#matthewbonig-nightynight-wakeywakeyforec2props)</code>) *No description*
* **instanceId** (<code>string</code>) the instanceId of the EC2 instance you'd like started.
* **schedule** (<code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code>) An option CronOptions to specify the time of day to start the instance. __*Default*__: { day: '*', hour: '12', minute: '0' }




## class WakeyWakeyForRds <a id="matthewbonig-nightynight-wakeywakeyforrds"></a>

A construct that will build a Lambda and a CloudWatch Rule (cron schedule) that will start the given rds instance at the specified time.

Typically used when you've got rds instances that you only need during business hours
and want to reduce the costs of.

__Implements__: [IConstruct](#constructs-iconstruct), [IConstruct](#aws-cdk-core-iconstruct), [IConstruct](#constructs-iconstruct), [IDependable](#aws-cdk-core-idependable)
__Extends__: [Construct](#aws-cdk-core-construct)

### Initializer




```ts
new WakeyWakeyForRds(scope: Construct, id: string, props: WakeyWakeyForRdsProps)
```

* **scope** (<code>[Construct](#aws-cdk-core-construct)</code>) *No description*
* **id** (<code>string</code>) *No description*
* **props** (<code>[WakeyWakeyForRdsProps](#matthewbonig-nightynight-wakeywakeyforrdsprops)</code>) *No description*
* **dbInstanceIdentifier** (<code>string</code>) the DBInstanceIdentifier of the RDS instance you'd like started.
* **schedule** (<code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code>) An option CronOptions to specify the time of day to start the instance. __*Default*__: { day: '*', hour: '4', minute: '0' }




## struct NightyNightForAsgProps <a id="matthewbonig-nightynight-nightynightforasgprops"></a>


Expand All @@ -139,9 +199,9 @@ Props for the NightNight construct.

Name | Type | Description
-----|------|-------------
**autoScalingGroup** | <code>[IAutoScalingGroup](#aws-cdk-aws-autoscaling-iautoscalinggroup)</code> | the instanceId of the EC2 instance you'd like stopped.
**autoScalingGroup** | <code>[IAutoScalingGroup](#aws-cdk-aws-autoscaling-iautoscalinggroup)</code> | the AutoScalingGroup you'd like to change the instance count on.
**desiredCapacity** | <code>number</code> | Desired capacity.
**schedule**? | <code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code> | An option CronOptions to specify the time of day to stop the instance.<br/>__*Default*__: { day: '*', hour: '4', minute: '0' }
**schedule**? | <code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code> | An option CronOptions to specify the time of day to scale.<br/>__*Default*__: { day: '*', hour: '4', minute: '0' }



Expand Down Expand Up @@ -187,3 +247,31 @@ Name | Type | Description



## struct WakeyWakeyForEc2Props <a id="matthewbonig-nightynight-wakeywakeyforec2props"></a>






Name | Type | Description
-----|------|-------------
**instanceId** | <code>string</code> | the instanceId of the EC2 instance you'd like started.
**schedule**? | <code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code> | An option CronOptions to specify the time of day to start the instance.<br/>__*Default*__: { day: '*', hour: '12', minute: '0' }



## struct WakeyWakeyForRdsProps <a id="matthewbonig-nightynight-wakeywakeyforrdsprops"></a>


Props for the WakeyWakeyForRds construct.



Name | Type | Description
-----|------|-------------
**dbInstanceIdentifier** | <code>string</code> | the DBInstanceIdentifier of the RDS instance you'd like started.
**schedule**? | <code>[CronOptions](#aws-cdk-aws-events-cronoptions)</code> | An option CronOptions to specify the time of day to start the instance.<br/>__*Default*__: { day: '*', hour: '4', minute: '0' }



17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# NightyNight!
# NightyNight and WakeyWakey!

Do you have a EC2 instance or an RDS instance that you only need during certain hours of the day? Do you want to reduce it's cost? How about just stopping it every night?

Expand All @@ -10,6 +10,16 @@ There are currently two variations of the construct:
* [NightyNightForRds](./API.md#matthewbonig-nightynight-nightynightforrds) - stops an RDS instance at a given time.
* [NightyNightForAsg](./API.md#matthewbonig-nightynight-nightynightforasg) - sets the desired capacity for an ASG at a given time.

# WakeyWakey

The WakeyWakey construct (from [this](https://github.com/mbonig/wakeywakey) repository) has been integrated into this library. You don't need to install
a separate dependency anymore.

* [WakeyWakeyForEc2](./API.md#matthewbonig-nightynight-wakeywakeyforec2) - start an EC2 instance at a given time.
* [WakeyWakeyForRds](./API.md#matthewbonig-nightynight-wakeywakeyforrds) - start an RDS instance at a given time.

There isn't a specific construct for starting ASGs, since you can just set the count to whatever you want.

# This is a pre-release!

This is a quick first-draft. All the options that will likely need to be added to accommodate a large
Expand All @@ -26,7 +36,7 @@ open an [Issue](https://github.com/mbonig/nightynight/issues) or a [PR](https://
# Example:

```typescript
import {NightyNightForEc2} from "./ec2";
import {NightyNightForEc2, WakeyWakeyForEc2} from "./ec2";

export class NightyNightStack extends Stack {

Expand All @@ -35,12 +45,13 @@ export class NightyNightStack extends Stack {

// The code that defines your stack goes here
new NightyNightForEc2(this, 'nighty-night', {instanceId: 'i-123123123123'});
new WakeyWakeyForEc2(this, 'wakey-wakey', {instanceId: 'i-123123123123'})
}
}

```

This will stop the instance with id `i-123123123123` at (the default) 4am GMT.
This will stop the instance with id `i-123123123123` at (the default) 4am UTC. It will then start the instance at 12am UTC.

# API Doc

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
29 changes: 29 additions & 0 deletions src/WakeyWakeyForEc2.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const AWS = require('aws-sdk'); // eslint-disable-line
const ec2 = new AWS.EC2();

const instanceId = process.env.INSTANCE_ID;
export const handler = async (event: any) => {
console.log({ event });
console.log({ instanceId });

console.log('Getting instance details');

let params = {
InstanceIds: [
instanceId,
],
};
const {
Reservations: [{ Instances: [instanceDetails] }],
} = await ec2.describeInstances(params).promise();
console.log({ instanceDetails });
if (!instanceDetails) {
throw new Error('Couldn\'t find instance details. Weird... if the instance was terminated, this app should be removed.');
}
if (instanceDetails.State.Name === 'stopped') {
console.log('starting the instance');
await ec2.startInstances(params).promise();
let now = new Date().toISOString();
console.log(`Started instance ${instanceId} at ${now}`);
}
};
27 changes: 27 additions & 0 deletions src/WakeyWakeyForRds.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const AWS = require('aws-sdk'); // eslint-disable-line
const rds = new AWS.RDS();

const dbInstanceIdentifier = process.env.DB_INSTANCE_IDENTIFIER;
export const handler = async (event: any) => {
console.log({ event });
console.log({ dbInstanceIdentifier });
console.log('Getting instance details');
let params = {
DBInstanceIdentifier: dbInstanceIdentifier,
};
const {
DBInstances: [instanceDetails],
} = await rds.describeDBInstances(params).promise();
console.log({ instanceDetails });
if (!instanceDetails) {
throw new Error("Couldn't find instance details. Weird... if the instance was terminated, this app should be too");
}
if (instanceDetails.DBInstanceStatus === 'stopped') {
console.log('starting the instance');
await rds.startDBInstance({ DBInstanceIdentifier: dbInstanceIdentifier }).promise();
let now = new Date().toISOString();
console.log(`Started instance ${dbInstanceIdentifier} at ${now}`);
} else {
console.warn(`Not starting instance because the status is: ${instanceDetails.DBInstanceStatus}`);
}
};
6 changes: 3 additions & 3 deletions src/asg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import * as statement from 'cdk-iam-floyd';
*/
export interface NightyNightForAsgProps {
/**
* An option CronOptions to specify the time of day to stop the instance.
* An option CronOptions to specify the time of day to scale.
*
* @default {
day: '*',
Expand All @@ -23,7 +23,7 @@ export interface NightyNightForAsgProps {
readonly schedule?: CronOptions;

/**
* the instanceId of the EC2 instance you'd like stopped.
* the AutoScalingGroup you'd like to change the instance count on.
*/
readonly autoScalingGroup: IAutoScalingGroup;

Expand All @@ -44,7 +44,7 @@ export class NightyNightForAsg extends Construct {
constructor(scope: Construct, id: string, props: NightyNightForAsgProps) {
super(scope, id);
const lambda = new NodejsFunction(this, 'handler', {
entry: join(__dirname, 'asg.handler.ts'),
entry: join(__dirname, 'NightyNightForAsg.handler.ts'),
runtime: Runtime.NODEJS_12_X,
environment: {
AUTO_SCALING_GROUP_NAME: props.autoScalingGroup.autoScalingGroupName,
Expand Down
62 changes: 61 additions & 1 deletion src/ec2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class NightyNightForEc2 extends Construct {
constructor(scope: Construct, id: string, props: NightyNightForEc2Props) {
super(scope, id);
const lambda = new NodejsFunction(this, 'handler', {
entry: join(__dirname, 'ec2.handler.ts'),
entry: join(__dirname, 'NightyNightForEc2.handler.ts'),
runtime: Runtime.NODEJS_12_X,
environment: {
INSTANCE_ID: props.instanceId,
Expand Down Expand Up @@ -82,3 +82,63 @@ export class NightyNight extends NightyNightForEc2 {
super(scope, id, props);
}
}


export interface WakeyWakeyForEc2Props {
/**
* An option CronOptions to specify the time of day to start the instance.
*
* @default {
day: '*',
hour: '12',
minute: '0'
}
*/
readonly schedule?: CronOptions;
/**
* the instanceId of the EC2 instance you'd like started.
*/
readonly instanceId: string;
}


/**
* A construct that will build a Lambda and a CloudWatch Rule (cron schedule)
* that will start the given ec2 instance at the specified time.
*
* Typically used when you've got ec2 instances that you only need during business hours
* and want to reduce the costs of. Use in conjunction with the Nightynight construct at
* @matthewbonig/nightynight
*/
export class WakeyWakeyForEc2 extends Construct {
constructor(scope: Construct, id: string, props: WakeyWakeyForEc2Props) {
super(scope, id);
const lambda = new NodejsFunction(this, 'handler', {
entry: join(__dirname, 'WakeyWakeyForEc2.handler.ts'),
environment: {
INSTANCE_ID: props.instanceId,
},
runtime: Runtime.NODEJS_12_X,
});

lambda.addToRolePolicy(new statement.Ec2().allow().toDescribeInstances());
lambda.addToRolePolicy(new statement.Ec2().allow().toStartInstances().on(Arn.format({
resourceName: props.instanceId,
resource: 'instance',
service: 'ec2',
}, Stack.of(this))));

let schedule = props.schedule || {
day: '*',
hour: '12',
minute: '0',
};
const rule = new Rule(this, 'rule', {
schedule: Schedule.cron(schedule),
});

rule.addTarget(new LambdaFunction(lambda, {
event: RuleTargetInput.fromObject({}),
}));
}
}
Loading

0 comments on commit 20f5fa5

Please sign in to comment.