├── package.json ├── config.json ├── .gitattributes ├── LICENSE.md ├── sns.js ├── emr.js ├── ec2 ├── ebs.js ├── elb.js ├── eip.js ├── as.js └── ec2.js ├── cloudwatch.js ├── redshift └── redshift.js ├── rds └── rds.js ├── cleanup.js ├── README.md └── .gitignore /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"aws-cleanup", 3 | "version":"0.2.0", 4 | "author":{ 5 | "name":"Himanshu Sachdeva" 6 | }, 7 | "homepage":"https://github.com/hsachdevah/aws-cleanup", 8 | "dependencies": { 9 | "aws-sdk": ">=1.8.0", 10 | "prompt":"*" 11 | } 12 | } -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "regions":{ 3 | "us-east-1":"true", 4 | "us-west-1":"true", 5 | "us-west-2":"true", 6 | "eu-west-1":"true", 7 | "sa-east-1":"true", 8 | "ap-southeast-1":"true", 9 | "ap-southeast-2":"true", 10 | "ap-northeast-1":"true" 11 | }, 12 | "services":{ 13 | "ec2":true, 14 | "eip":true, 15 | "elb":true, 16 | "ebs":true, 17 | "rds":true, 18 | "as":true, 19 | "redshift":true, 20 | "sns":false, 21 | "cloudwatch":false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) {{{2014}}} {{{Himanshu Sachdeva}}} 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sns.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var sns = new AWS.SNS({region:region}); 3 | var listTopics = sns.listTopics(); 4 | 5 | listTopics.on('success',function(resp){ 6 | if (resp.data.Topics.length>0) { 7 | for(var t in resp.data.Topics){ 8 | var topicARN = resp.data.Topics[t].TopicArn; 9 | deleteTopic(AWS,region,topicARN); 10 | } 11 | }; 12 | }); 13 | 14 | listTopics.on('error',function(resp){ 15 | if(resp['code']=='UnauthorizedOperation') 16 | console.log('ERROR: Access denied to list SNS topics in',region); 17 | else{ 18 | console.log('Error occured while listing SNS topics: '); 19 | console.log(resp); 20 | } 21 | }); 22 | 23 | listTopics.send(); 24 | }; 25 | module.exports.clean = clean; 26 | 27 | var deleteTopic = function(AWS,region,topicARN){ 28 | var params = { 29 | TopicArn: topicARN 30 | }; 31 | 32 | var sns = new AWS.SNS({region:region}); 33 | var deleteTopic = sns.deleteTopic(params); 34 | 35 | deleteTopic.on('error',function(resp){ 36 | console.log('Error occured while deleting SNS topic: '); 37 | console.log(resp); 38 | }); 39 | deleteTopic.on('success',function(resp){ 40 | console.log('Successfully deleted SNS Topic',topicARN); 41 | // console.log(resp); 42 | }); 43 | deleteTopic.send(); 44 | } 45 | -------------------------------------------------------------------------------- /emr.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var sns = new AWS.EMR({region:region}); 3 | var listClusters = sns.listClusters(); 4 | 5 | listClusters.on('success',function(resp){ 6 | console.log('EMR:',resp.data) 7 | // if (resp.data.Topics.length>0) { 8 | // for(var t in resp.data.Topics){ 9 | // var topicARN = resp.data.Topics[t].TopicArn; 10 | // deleteTopic(AWS,region,topicARN); 11 | // } 12 | // }; 13 | }); 14 | 15 | listClusters.on('error',function(resp){ 16 | if(resp['code']=='UnauthorizedOperation') 17 | console.log('ERROR: Access denied to list SNS topics in',region); 18 | else{ 19 | console.log('Error occured while listing SNS topics: '); 20 | console.log(resp); 21 | } 22 | }); 23 | 24 | listClusters.send(); 25 | }; 26 | module.exports.clean = clean; 27 | 28 | var deleteTopic = function(AWS,region,topicARN){ 29 | var params = { 30 | TopicArn: topicARN 31 | }; 32 | 33 | var sns = new AWS.SNS({region:region}); 34 | var deleteTopic = sns.deleteTopic(params); 35 | 36 | deleteTopic.on('error',function(resp){ 37 | console.log('Error occured while deleting SNS topic: '); 38 | console.log(resp); 39 | }); 40 | deleteTopic.on('success',function(resp){ 41 | console.log('Successfully deleted SNS Topic',topicARN); 42 | // console.log(resp); 43 | }); 44 | deleteTopic.send(); 45 | } 46 | -------------------------------------------------------------------------------- /ec2/ebs.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var ec2 = new AWS.EC2({region:region}); 3 | var describeVolumes = ec2.describeVolumes(); 4 | 5 | describeVolumes.on('success',function(resp){ 6 | if(resp['data']['Volumes'].length>0){ 7 | for(var v in resp['data']['Volumes']){ 8 | if(resp['data']['Volumes'][v]['State']=='available'){ 9 | var volId = resp['data']['Volumes'][v]['VolumeId']; 10 | deleteVol(AWS,region,volId); 11 | } 12 | 13 | } 14 | } 15 | }); 16 | 17 | describeVolumes.on('error',function(resp){ 18 | if(resp['code']=='UnauthorizedOperation') 19 | console.log('ERROR: Access denied to describe EBS Volumes in',region); 20 | else{ 21 | console.log('Error occured while describing EBS Volume: '); 22 | console.log(resp); 23 | } 24 | }); 25 | 26 | describeVolumes.send(); 27 | }; 28 | module.exports.clean = clean; 29 | 30 | var deleteVol = function(AWS,region,volId){ 31 | var params = { 32 | VolumeId: volId 33 | }; 34 | 35 | var ec2 = new AWS.EC2({region:region}); 36 | var deleteVolume = ec2.deleteVolume(params); 37 | 38 | deleteVolume.on('error',function(resp){ 39 | console.log('Error occured while deleting EBS: '); 40 | console.log(resp); 41 | }); 42 | deleteVolume.on('success',function(resp){ 43 | console.log('Successfully deleted EBS volume',volId,'from region',region); 44 | // console.log(resp); 45 | }); 46 | deleteVolume.send(); 47 | } 48 | -------------------------------------------------------------------------------- /ec2/elb.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var elb = new AWS.ELB({region:region}); 3 | var describeLoadBalancers = elb.describeLoadBalancers(); 4 | 5 | 6 | describeLoadBalancers.on('success',function(resp){ 7 | if (resp.data.LoadBalancerDescriptions.length>0) { 8 | for(var lb in resp.data.LoadBalancerDescriptions){ 9 | var name = resp.data.LoadBalancerDescriptions[lb].LoadBalancerName; 10 | deleteELB(AWS,region,name); 11 | } 12 | } 13 | 14 | }); 15 | 16 | describeLoadBalancers.on('error',function(resp){ 17 | if(resp['code']=='AccessDenied') 18 | console.log('ERROR: Access denied to describe load balancers in',region); 19 | else{ 20 | console.log('Error occured while describing Balancers: '); 21 | console.log(resp); 22 | } 23 | }); 24 | 25 | describeLoadBalancers.send() 26 | } 27 | module.exports.clean = clean; 28 | 29 | 30 | var deleteELB = function(AWS,region,name){ 31 | var params = { 32 | LoadBalancerName: name // required 33 | }; 34 | 35 | var elb = new AWS.ELB({region:region}); 36 | var deleteLoadBalancer = elb.deleteLoadBalancer(params); 37 | 38 | 39 | deleteLoadBalancer.on('error',function(resp){ 40 | console.log('Error occured while deleting ELB: '); 41 | console.log(resp); 42 | }); 43 | deleteLoadBalancer.on('success',function(resp){ 44 | console.log('Successfully deleted ELB',name,'from region',region); 45 | // console.log(resp); 46 | }); 47 | deleteLoadBalancer.send(); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /ec2/eip.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var ec2 = new AWS.EC2({region:region}); 3 | var describeAddresses = ec2.describeAddresses(); 4 | 5 | describeAddresses.on('success',function(resp){ 6 | if (resp.data.Addresses.length>0) { 7 | for(var a in resp.data.Addresses){ 8 | if(resp.data.Addresses[a].Domain=='vpc'){ 9 | var AllocationId = resp.data.Addresses[a].AllocationId; 10 | release(AWS,region,AllocationId); 11 | }; 12 | } 13 | }; 14 | }); 15 | 16 | describeAddresses.on('error',function(resp){ 17 | if(resp['code']=='UnauthorizedOperation') 18 | console.log('ERROR: Access denied to describe network addresses in',region); 19 | else{ 20 | console.log('Error occured while describing Network Addresses: '); 21 | console.log(resp); 22 | } 23 | }); 24 | 25 | describeAddresses.send(); 26 | }; 27 | module.exports.clean = clean; 28 | 29 | var release = function(AWS,region,AllocationId){ 30 | var params = { 31 | AllocationId: AllocationId 32 | }; 33 | 34 | var ec2 = new AWS.EC2({region:region}); 35 | var releaseAddress = ec2.releaseAddress(params); 36 | 37 | releaseAddress.on('error',function(resp){ 38 | console.log('Error occured while releasing Network Addresses: '); 39 | console.log(releaseAddress); 40 | console.log(resp); 41 | }); 42 | releaseAddress.on('success',function(resp){ 43 | console.log('Successfully released EIP from region',region); 44 | // console.log(resp); 45 | }); 46 | releaseAddress.send(); 47 | } 48 | -------------------------------------------------------------------------------- /cloudwatch.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var cw = new AWS.CloudWatch({region:region}); 3 | var describeAlarms = cw.describeAlarms(); 4 | 5 | describeAlarms.on('success',function(resp){ 6 | 7 | if(resp.data.MetricAlarms.length>0){ 8 | for(var a in resp.data.MetricAlarms){ 9 | var Namespace = resp.data.MetricAlarms[a].Namespace; 10 | var Alarms = new Array(); //AlarmName 11 | if(Namespace != 'AWS/Billing'){ 12 | Alarms.push(resp.data.MetricAlarms[a].AlarmName); 13 | } 14 | } 15 | if(Alarms.length>0) 16 | deleteAlarms(AWS,region,Alarms); 17 | }; 18 | }); 19 | 20 | describeAlarms.on('error',function(resp){ 21 | 22 | // if(resp['code']=='AccessDenied') 23 | // console.log('ERROR: Access denied to describe AutoScaling Groups in',region); 24 | // else{ 25 | console.log('Error occured while describing CloudWatch Alarms: '); 26 | console.log(resp); 27 | // } 28 | 29 | }); 30 | 31 | describeAlarms.send(); 32 | }; 33 | module.exports.clean = clean; 34 | 35 | var deleteAlarms = function(AWS,region,AlarmNames){ 36 | var params = { 37 | AlarmNames: AlarmNames, 38 | }; 39 | 40 | var cw = new AWS.CloudWatch({region:region}); 41 | var deleteAlarms = cw.deleteAlarms(params); 42 | 43 | deleteAlarms.on('error',function(resp){ 44 | console.log('Error occured while deleting CloudWatch alarm in region',region); 45 | console.log(resp); 46 | }); 47 | 48 | deleteAlarms.on('success',function(resp){ 49 | console.log('Successfully deleted CloudWatch alarms from region',region); 50 | // console.log(resp); 51 | }); 52 | deleteAlarms.send(); 53 | } -------------------------------------------------------------------------------- /redshift/redshift.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var rs = new AWS.Redshift({region:region}); 3 | var describeClusters = rs.describeClusters(); 4 | 5 | describeClusters.on('success',function(resp){ 6 | //Check if service is available in region 7 | if(resp['data']['Clusters'].length>0){ 8 | for(var c in resp['data']['Clusters']){ 9 | var clusterIdentifier = resp['data']['Clusters'][c]['ClusterIdentifier']; 10 | deleteCluster(AWS,region,clusterIdentifier); 11 | } 12 | } 13 | }); 14 | 15 | describeClusters.on('error',function(resp){ 16 | if(resp['code']=='UnauthorizedOperation') 17 | console.log('ERROR: Access denied to describe Redshift Clusters in',region); 18 | else if(resp['errno']=='ENOTFOUND'){ 19 | console.log('Redshift service is not available in:',region); 20 | } 21 | else { 22 | console.log('Error occured while describing Redshift Cluster: '); 23 | console.log(resp); 24 | } 25 | }); 26 | 27 | describeClusters.send(); 28 | }; 29 | module.exports.clean = clean; 30 | 31 | var deleteCluster = function(AWS,region,clusterIdentifier){ 32 | var params = { 33 | ClusterIdentifier: clusterIdentifier, 34 | SkipFinalClusterSnapshot: true 35 | }; 36 | 37 | var rs = new AWS.Redshift({region:region}); 38 | var deleteCluster = rs.deleteCluster(params); 39 | 40 | deleteCluster.on('error',function(resp){ 41 | console.log('Error occured while deleting resdhift cluster: '); 42 | console.log(resp); 43 | }); 44 | deleteCluster.on('success',function(resp){ 45 | console.log('Successfully Redshift Cluster',clusterIdentifier,'from region',region); 46 | // console.log(resp); 47 | }); 48 | deleteCluster.send(); 49 | } 50 | -------------------------------------------------------------------------------- /rds/rds.js: -------------------------------------------------------------------------------- 1 | var DryRun = false; 2 | 3 | var clean = function clean(AWS,region){ 4 | var rds = new AWS.RDS({region:region}); 5 | var describeDBInstances = rds.describeDBInstances(); 6 | 7 | describeDBInstances.on('success',function(resp){ 8 | var response = resp.data; 9 | var Instances = new Array(); 10 | 11 | for(var i in response['DBInstances']){ 12 | if(response['DBInstances'][i]['DBInstanceStatus'] == 'available'){ 13 | var DBInstanceIdentifier = response['DBInstances'][i]['DBInstanceIdentifier']; 14 | deleteIstances(AWS,region,DBInstanceIdentifier); 15 | } 16 | } 17 | 18 | if(Instances.length > 0) 19 | deleteIstances(AWS,region,Instances); 20 | 21 | }); 22 | 23 | describeDBInstances.on('error',function(resp){ 24 | if(resp['code']=='AccessDenied') 25 | console.log('ERROR: Access denied to describe DB Instances in',region); 26 | else{ 27 | console.log('Error occured while describing DB Instances: '); 28 | console.log(resp); 29 | } 30 | 31 | }); 32 | describeDBInstances.send(); 33 | } 34 | module.exports.clean = clean; 35 | 36 | var deleteIstances = function(AWS,region, DBInstanceIdentifier){ 37 | var params = { 38 | DBInstanceIdentifier: DBInstanceIdentifier, 39 | SkipFinalSnapshot: true 40 | }; 41 | var rds = new AWS.RDS({region:region}); 42 | var deleteDBInstance = rds.deleteDBInstance(params); 43 | 44 | deleteDBInstance.on('success',function(resp){ 45 | console.log('Successfully deleted',DBInstanceIdentifier,'DB Instance from',region,'region'); 46 | }); 47 | 48 | deleteDBInstance.on('error',function(resp){ 49 | console.log('Error occured while terminating Instances: '); 50 | console.log(resp); 51 | }); 52 | 53 | deleteDBInstance.send(); 54 | } -------------------------------------------------------------------------------- /ec2/as.js: -------------------------------------------------------------------------------- 1 | var clean = function clean(AWS,region){ 2 | var as = new AWS.AutoScaling({region:region}); 3 | var describeAutoScalingGroups = as.describeAutoScalingGroups(); 4 | 5 | describeAutoScalingGroups.on('success',function(resp){ 6 | //resp['data']['AutoScalingGroups'][0]['AutoScalingGroupName'] 7 | if (resp.data.AutoScalingGroups.length>0) { 8 | for(var a in resp.data.AutoScalingGroups){ 9 | var ASGroupName = resp.data.AutoScalingGroups[a].AutoScalingGroupName; 10 | if(resp.data.AutoScalingGroups[a].DesiredCapacity != 0) 11 | // setCapacity(AWS,region,ASGroupName); 12 | updateASG(AWS,region,ASGroupName); 13 | 14 | } 15 | }; 16 | }); 17 | 18 | describeAutoScalingGroups.on('error',function(resp){ 19 | if(resp['code']=='AccessDenied') 20 | console.log('ERROR: Access denied to describe AutoScaling Groups in',region); 21 | else{ 22 | console.log('Error occured while describing AutoScaling Groups: '); 23 | console.log(resp); 24 | } 25 | 26 | }); 27 | 28 | describeAutoScalingGroups.send(); 29 | }; 30 | module.exports.clean = clean; 31 | 32 | var setCapacity = function(AWS,region,ASGroupName){ 33 | var params = { 34 | AutoScalingGroupName: ASGroupName, // required 35 | DesiredCapacity: 0, // required 36 | // HonorCooldown: true || false, 37 | }; 38 | 39 | var as = new AWS.AutoScaling({region:region}); 40 | var setDesiredCapacity = as.setDesiredCapacity(params); 41 | 42 | setDesiredCapacity.on('error',function(resp){ 43 | console.log('Error occured while setting capacity of AutoScaling Group'); 44 | console.log(resp); 45 | }); 46 | setDesiredCapacity.on('success',function(resp){ 47 | console.log('Successfully reset ASG', ASGroupName,'capacity in region',region); 48 | // console.log(resp); 49 | }); 50 | setDesiredCapacity.send(); 51 | } 52 | 53 | var updateASG = function(AWS,region,ASGroupName){ 54 | var params = { 55 | AutoScalingGroupName: ASGroupName, 56 | DesiredCapacity: 0, 57 | MaxSize: 0, 58 | MinSize: 0, 59 | }; 60 | 61 | var as = new AWS.AutoScaling({region:region}); 62 | var updateAutoScalingGroup = as.updateAutoScalingGroup(params); 63 | 64 | updateAutoScalingGroup.on('error',function(resp){ 65 | console.log('Error occured while setting capacity of AutoScaling Group'); 66 | console.log(resp); 67 | }); 68 | updateAutoScalingGroup.on('success',function(resp){ 69 | console.log('Successfully reset ASG', ASGroupName,'capacity in region',region); 70 | // console.log(resp); 71 | }); 72 | updateAutoScalingGroup.send(); 73 | 74 | } -------------------------------------------------------------------------------- /cleanup.js: -------------------------------------------------------------------------------- 1 | var AWS = require('aws-sdk'); 2 | var config = require('./config.json'); 3 | var ec2 = require('./ec2/ec2.js'); 4 | var eip = require('./ec2/eip.js'); 5 | var elb = require('./ec2/elb.js'); 6 | var ebs = require('./ec2/ebs.js'); 7 | var rds = require('./rds/rds.js'); 8 | var as = require('./ec2/as.js'); 9 | var redshift = require('./redshift/redshift.js'); 10 | var sns = require('./sns.js'); 11 | var emr = require('./emr.js'); 12 | var cloudwatch = require('./cloudwatch.js'); 13 | //var datapipeline = require('./datapipeline.js'); 14 | var prompt = require('prompt'); 15 | var fs = require('fs'); 16 | 17 | config = JSON.parse(JSON.stringify(config)); 18 | var cred = {}; 19 | 20 | if (fs.existsSync('./aws-credentials.json')) { 21 | AWS.config.loadFromPath('./aws-credentials.json'); 22 | confirm(); 23 | } 24 | else{ 25 | prompt.start(); 26 | prompt.get(['AWS_Access_Key', 'AWS_Secret_Access_Key'], function (err, result) { 27 | cred['accessKeyId'] = result.AWS_Access_Key; 28 | cred['secretAccessKey'] = result.AWS_Secret_Access_Key; 29 | cred['region'] = "us-east-1"; 30 | 31 | AWS.config.update(cred); 32 | confirm(); 33 | }); 34 | 35 | } 36 | 37 | function confirm(){ 38 | console.log('WARNING: You are about to delete your AWS resources permanently. Are you sure you want to proceed?') 39 | var property = { 40 | name: 'yesno', 41 | message: 'yes/no?', 42 | validator: /y[es]*|n[o]?/, 43 | warning: 'Must respond yes or no', 44 | default: 'no' 45 | }; 46 | prompt.get(property, function (err, result) { 47 | if(result.yesno == 'yes' || result.yesno == 'y') 48 | clean(); 49 | }); 50 | } 51 | 52 | function clean(){ 53 | var regions = config['regions']; 54 | console.log("Starting cleanup process ..."); 55 | for(var region in regions){ 56 | if(regions[region]=="true"){ 57 | if(config['services']['as']) 58 | as.clean(AWS,region); 59 | if(config['services']['ec2']) 60 | ec2.clean(AWS,region); 61 | if(config['services']['eip']) 62 | eip.clean(AWS,region); 63 | if(config['services']['elb']) 64 | elb.clean(AWS,region); 65 | if(config['services']['ebs']) 66 | ebs.clean(AWS,region); 67 | if(config['services']['rds']) 68 | rds.clean(AWS,region); 69 | if(config['services']['redshift']) 70 | redshift.clean(AWS,region); 71 | if(config['services']['sns']) 72 | sns.clean(AWS,region); 73 | if(config['services']['cloudwatch']) 74 | cloudwatch.clean(AWS,region); 75 | // if(config['services']['emr']) 76 | // emr.clean(AWS,region); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ec2/ec2.js: -------------------------------------------------------------------------------- 1 | var DryRun = false; 2 | 3 | var clean = function clean(AWS,region){ 4 | var ec2 = new AWS.EC2({region:region}); 5 | var describeInstances = ec2.describeInstances(); 6 | 7 | describeInstances.on('success',function(resp){ 8 | 9 | var response = resp.data; 10 | 11 | // Get list of instances 12 | for (var i in response['Reservations']) { 13 | var reservation = response['Reservations'][i]; 14 | for (var j in reservation['Instances']) { 15 | // console.log(reservation['Instances'][j]); 16 | if (reservation['Instances'][j]['State']['Name']=='running') { 17 | var InstanceId = reservation['Instances'][j]['InstanceId']; 18 | setForTermination(AWS,region,InstanceId); 19 | }; 20 | }; 21 | }; 22 | 23 | }); 24 | 25 | describeInstances.on('error',function(resp){ 26 | if(resp['code']=='UnauthorizedOperation') 27 | console.log('ERROR: Access denied to describe instances in',region); 28 | else{ 29 | console.log('Error occured while describing Instances: '); 30 | console.log(resp); 31 | } 32 | 33 | }); 34 | 35 | describeInstances.send(); 36 | } 37 | module.exports.clean = clean; 38 | 39 | 40 | var setForTermination = function(AWS,region,InstanceId){ 41 | var params = { 42 | Attribute: 'disableApiTermination', /* required */ 43 | InstanceId: InstanceId, /* required */ 44 | }; 45 | 46 | var Instances = new Array(); 47 | var ec2 = new AWS.EC2({region:region}); 48 | var describeInstanceAttribute = ec2.describeInstanceAttribute(params); 49 | 50 | describeInstanceAttribute.on('success',function(resp){ 51 | if(resp.data.DisableApiTermination.Value == false){ 52 | Instances.push(InstanceId); 53 | terminate(AWS,region,Instances); 54 | } 55 | else{ 56 | console.log('WARNING: EC2 instance',InstanceId,'in',region,'has Termination Protection Enabled'); 57 | } 58 | 59 | }); 60 | 61 | describeInstanceAttribute.on('error',function(resp){ 62 | console.log('Error Attribute: ',resp); 63 | }); 64 | 65 | describeInstanceAttribute.send(); 66 | } 67 | 68 | 69 | 70 | var terminate = function(AWS,region, Instances){ 71 | 72 | var params = { 73 | DryRun: DryRun, 74 | InstanceIds: Instances 75 | }; 76 | 77 | var ec2 = new AWS.EC2({region:region}); 78 | var terminateInstances = ec2.terminateInstances(params); 79 | 80 | terminateInstances.on('success',function(resp){ 81 | console.log('Successfully terminated',Instances.length,'Instances from ',region,'region'); 82 | }) 83 | 84 | terminateInstances.on('error',function(resp){ 85 | console.log('Error occured while terminating Instances: '); 86 | console.log(resp); 87 | }) 88 | 89 | terminateInstances.send(); 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aws-cleanup 2 | 3 | This project helps to terminate/delete all the resources in a given AWS account. 4 | 5 | This is particularly useful if you are learning to work with AWS & don't want to accidentally leave any service in running state only to find out that you have been charged on your credit card at month end. 6 | 7 | ## Installing 8 | 9 | You would require node.js installed on your system to use aws-cleanup. In case its not already installed, you can get it from here: http://nodejs.org/ 10 | 11 | You also need ```npm``` installed on your system so that required dependencies can be downloaded. Install it from the instructions provided at this site : https://www.npmjs.org/ 12 | 13 | If these are successfully installed, you should be able to get a valid results from the commands below 14 | 15 | ```sh 16 | node -v 17 | npm -v 18 | ``` 19 | 20 | You can get the code & required modules (including AWS-SDK for node.js) by executing the following commands 21 | 22 | ```sh 23 | git clone https://github.com/hsachdevah/aws-cleanup.git 24 | cd aws-cleanup 25 | npm install 26 | ``` 27 | You can execute the cleanup task by running cleanup.js. You would be asked to provide access-key & secret-access-key, please make sure you have all the required permissions for terminating/deleting resources. 28 | 29 | ```sh 30 | node cleanup.js 31 | ``` 32 | 33 | Note: You can also store credentials locally so you don't have to enter them every time you execute the cleanup task. Create a file with name "aws-credentials.json" in the same directory as cleanup.js with the following content 34 | 35 | ```json 36 | { 37 | "accessKeyId": "", 38 | "secretAccessKey": "", 39 | "region": "us-east-1" 40 | } 41 | ``` 42 | 43 | The given access key & secret key should have all the permissions to list/delete AWS resources. 44 | 45 | ## Supported Services 46 | 47 | The following services are supported in latest version: 48 | 49 | 50 | | Services | Notes | 51 | | --------------------- | --------------------------------------------------------- | 52 | | AutoScalingGroups | Sets Desired Capacity to 0 | 53 | | CloudWatch | Disabled by default, check config.json. Billing Alarms are not deleted | 54 | | EBS | Only volumes with status 'available' will get deleted | 55 | | EC2 | Only instances with status 'running' & 'Termination Protection' disabled will get terminated | 56 | | Elastic IP | Only EIPs with scope 'vpc' will get released | 57 | | ELB | | 58 | | Redshift | | 59 | | RDS | Only DB instances with status 'available' will get deleted | 60 | | SNS | Disabled by default, check config.json | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | aws-credentials.json 3 | config.json 4 | 5 | ======= 6 | ################# 7 | ## Eclipse 8 | ################# 9 | 10 | *.pydevproject 11 | .project 12 | .metadata 13 | bin/ 14 | tmp/ 15 | *.tmp 16 | *.bak 17 | *.swp 18 | *~.nib 19 | local.properties 20 | .classpath 21 | .settings/ 22 | .loadpath 23 | 24 | # External tool builders 25 | .externalToolBuilders/ 26 | 27 | # Locally stored "Eclipse launch configurations" 28 | *.launch 29 | 30 | # CDT-specific 31 | .cproject 32 | 33 | # PDT-specific 34 | .buildpath 35 | 36 | 37 | ################# 38 | ## Visual Studio 39 | ################# 40 | 41 | ## Ignore Visual Studio temporary files, build results, and 42 | ## files generated by popular Visual Studio add-ons. 43 | 44 | # User-specific files 45 | *.suo 46 | *.user 47 | *.sln.docstates 48 | 49 | # Build results 50 | 51 | [Dd]ebug/ 52 | [Rr]elease/ 53 | x64/ 54 | build/ 55 | [Bb]in/ 56 | [Oo]bj/ 57 | 58 | # MSTest test Results 59 | [Tt]est[Rr]esult*/ 60 | [Bb]uild[Ll]og.* 61 | 62 | *_i.c 63 | *_p.c 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.pch 68 | *.pdb 69 | *.pgc 70 | *.pgd 71 | *.rsp 72 | *.sbr 73 | *.tlb 74 | *.tli 75 | *.tlh 76 | *.tmp 77 | *.tmp_proj 78 | *.log 79 | *.vspscc 80 | *.vssscc 81 | .builds 82 | *.pidb 83 | *.log 84 | *.scc 85 | 86 | # Visual C++ cache files 87 | ipch/ 88 | *.aps 89 | *.ncb 90 | *.opensdf 91 | *.sdf 92 | *.cachefile 93 | 94 | # Visual Studio profiler 95 | *.psess 96 | *.vsp 97 | *.vspx 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | *.ncrunch* 114 | .*crunch*.local.xml 115 | 116 | # Installshield output folder 117 | [Ee]xpress/ 118 | 119 | # DocProject is a documentation generator add-in 120 | DocProject/buildhelp/ 121 | DocProject/Help/*.HxT 122 | DocProject/Help/*.HxC 123 | DocProject/Help/*.hhc 124 | DocProject/Help/*.hhk 125 | DocProject/Help/*.hhp 126 | DocProject/Help/Html2 127 | DocProject/Help/html 128 | 129 | # Click-Once directory 130 | publish/ 131 | 132 | # Publish Web Output 133 | *.Publish.xml 134 | *.pubxml 135 | 136 | # NuGet Packages Directory 137 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 138 | #packages/ 139 | 140 | # Windows Azure Build Output 141 | csx 142 | *.build.csdef 143 | 144 | # Windows Store app package directory 145 | AppPackages/ 146 | 147 | # Others 148 | sql/ 149 | *.Cache 150 | ClientBin/ 151 | [Ss]tyle[Cc]op.* 152 | ~$* 153 | *~ 154 | *.dbmdl 155 | *.[Pp]ublish.xml 156 | *.pfx 157 | *.publishsettings 158 | 159 | # RIA/Silverlight projects 160 | Generated_Code/ 161 | 162 | # Backup & report files from converting an old project file to a newer 163 | # Visual Studio version. Backup files are not needed, because we have git ;-) 164 | _UpgradeReport_Files/ 165 | Backup*/ 166 | UpgradeLog*.XML 167 | UpgradeLog*.htm 168 | 169 | # SQL Server files 170 | App_Data/*.mdf 171 | App_Data/*.ldf 172 | 173 | ############# 174 | ## Windows detritus 175 | ############# 176 | 177 | # Windows image file caches 178 | Thumbs.db 179 | ehthumbs.db 180 | 181 | # Folder config file 182 | Desktop.ini 183 | 184 | # Recycle Bin used on file shares 185 | $RECYCLE.BIN/ 186 | 187 | # Mac crap 188 | .DS_Store 189 | 190 | 191 | ############# 192 | ## Python 193 | ############# 194 | 195 | *.py[co] 196 | 197 | # Packages 198 | *.egg 199 | *.egg-info 200 | dist/ 201 | build/ 202 | eggs/ 203 | parts/ 204 | var/ 205 | sdist/ 206 | develop-eggs/ 207 | .installed.cfg 208 | 209 | # Installer logs 210 | pip-log.txt 211 | 212 | # Unit test / coverage reports 213 | .coverage 214 | .tox 215 | 216 | #Translations 217 | *.mo 218 | 219 | #Mr Developer 220 | .mr.developer.cfg 221 | 222 | --------------------------------------------------------------------------------