root/lib/Extra/EC2.pm

Revision 97e48246ee6cb7556cc86380d075e73e8d7d7f1b, 5.2 kB (checked in by Bryan Horstmann-Allen <bdha@mirrorshades.net>, 3 years ago)

Initial version of Extra::EC2, which serves up overview and cost data about running EC2 instances

  • Property mode set to 100644
Line 
1 package Extra::EC2;
2
3 use strict;
4 use warnings;
5
6 use base 'Resmon::Module';
7
8 use Resmon::ExtComm qw(run_command cache_command);
9
10 use Net::Amazon::EC2;
11
12 =pod
13
14 =head1 NAME
15
16 Extra::EC2 - Returns the number of EC2 instances by type and cost
17
18 =head1 SYNOPSIS
19
20  Extra::EC2 {
21     account1: aws_key => KEY1, aws_secret => SECRET1
22     account2: aws_key => KEY2, aws_secret => SECRET2
23  }
24
25 =head1 DESCRIPTION
26
27 This module returns the number of instances running on EC2, their live, daily,
28 and monthly billing costs. It also returns cost by security group, which should
29 give some idea of how much each "service" costs in aggregate.
30
31 =head1 REQUIREMENTS
32
33 Extra::EC2 requires Net::Amazon::EC2.
34
35 =head1 CONFIGURATION
36
37 =over
38
39 =item check_name
40
41 The check name defines an AWS account to inspect.
42
43 =back
44
45 =cut
46
47 sub handler {
48   my $self = shift;
49   my $config = $self->{'config'};
50   my $account = $self->{'check_name'};
51
52   my $result = {};
53
54   my %months;
55   my $total;
56
57   my $total_cost    = 0;
58   my $total_running = 0;
59
60   my %instances;
61
62   $instances{type}{'cc1.4xlarge'}{cost} = 1.60;
63   $instances{type}{'cg1.4xlarge'}{cost} = 2.10;
64
65   $instances{type}{'m2.4xlarge'}{cost}  = 2.00;
66   $instances{type}{'m2.2xlarge'}{cost}  = 1.00;
67   $instances{type}{'m2.xlarge'}{cost}   = 0.50;
68
69   $instances{type}{'m1.xlarge'}{cost}   = 0.50;
70   $instances{type}{'m1.large'}{cost}    = 0.34;
71   $instances{type}{'m1.small'}{cost}    = 0.085;
72
73   $instances{type}{'c1.medium'}{cost}   = 0.17;
74   $instances{type}{'c1.xlarge'}{cost}   = 0.68;
75
76   $instances{type}{'t1.micro'}{cost}    = 0.02;
77
78   my $m_mod = 31;
79   my $month = `/bin/date +%b`;
80   chomp $month;
81  
82   $months{'Feb'} = 28;
83   $months{'Apr'} = 30;
84   $months{'Jun'} = 30;
85   $months{'Sep'} = 30;
86   $months{'nov'} = 30;
87  
88   if ( $months{$month} ) { $m_mod = $months{$month} }
89
90   my $ec2 = Net::Amazon::EC2->new(
91     AWSAccessKeyId  => $config->{aws_key},
92     SecretAccessKey => $config->{aws_secret},
93   );
94
95   my $running_instances = $ec2->describe_instances;
96
97   # Net::Amazon::EC2 doesn't returns the error object... on eror. So we have to
98   # to determine if what we're getting back is an object, and if so, if it's an
99   # Error object.
100   use Scalar::Util qw(blessed); sub is_error { return blessed($_[0]) and $_[0]->isa('Net::Amazon::EC2::Error') }
101
102   if (is_error($running_instances)) {
103     my $errors = $running_instances->errors;
104     foreach my $error (@$errors) {
105       die $error->message;
106     }
107   }
108
109   foreach my $r ( @$running_instances ) {
110     my $type;
111  
112     foreach my $i ( $r->instances_set ) {
113       $type = $i->instance_type;
114       $instances{type}{$i->instance_type}{running}++;
115       $total_running++;
116     }
117  
118     foreach my $g ( $r->group_set ) {
119       $instances{group}{$g->group_id}{$type}++;
120     }
121   }
122  
123   foreach my $t ( sort keys %{$instances{type}} ) {
124     my $type = "type_$t";
125
126     unless ( $instances{type}{$t}{running} ) { $instances{type}{$t}{running} = 0 };
127
128     my $hour_cost   = $instances{type}{$t}{running} * $instances{type}{$t}{cost};
129     my $minute_cost = $hour_cost / 60;
130     my $day_cost    = $hour_cost * 24;
131     my $month_cost  = $day_cost * $m_mod;
132
133     $result->{"${type}_hour_cost"}   = [ $hour_cost, "n" ];
134     $result->{"${type}_minute_cost"} = [ $minute_cost, "n" ];
135     $result->{"${type}_day_cost"}    = [ $day_cost, "n" ];
136     $result->{"${type}_month_cost"}  = [ $month_cost, "n" ];
137     $result->{"${type}_running"}     = [ $instances{type}{$t}{running}, "i" ];
138
139     $total_cost = $total_cost + $result->{"${type}_month_cost"};
140   }
141
142   $result->{overview_total}    = [ $total_cost, "n" ];
143   $result->{overview_running}  = [ $total_running, "i" ];
144
145   foreach my $group ( sort keys %{$instances{group}} ) {
146     next if $group eq "default";
147
148     my $secgroup = "secgroup_$group";
149     my $running = 0;
150
151     my $group_hour_cost   = 0;
152     my $group_minute_cost = 0;
153     my $group_day_cost    = 0;
154     my $group_month_cost  = 0;
155
156     foreach my $i ( sort keys %{$instances{group}{$group}} ) {
157
158       my $hour_cost   = $instances{group}{$group}{$i} * $instances{type}{$i}{cost};
159       my $minute_cost = $hour_cost / 60;
160       my $day_cost    = $hour_cost * 24;
161       my $month_cost  = $day_cost * $m_mod;
162
163       $group_hour_cost    = $group_hour_cost + $hour_cost;
164       $group_minute_cost  = $group_minute_cost + $minute_cost;
165       $group_day_cost     = $group_day_cost + $day_cost;
166       $group_month_cost   = $group_month_cost + $month_cost;
167
168       $running++;
169     }
170
171     $result->{"${secgroup}_hour_cost"}    = [ 0, "n" ] unless $result->{"${secgroup}_hour_cost"};
172     $result->{"${secgroup}_minute_cost"}  = [ 0, "n" ] unless $result->{"${secgroup}_minute_cost"};
173     $result->{"${secgroup}_day_cost"}     = [ 0, "n" ] unless $result->{"${secgroup}_day_cost"};
174     $result->{"${secgroup}_month_cost"}   = [ 0, "n" ] unless $result->{"${secgroup}_month_cost"};
175     $result->{"${secgroup}_running"}      = [ 0, "n" ] unless $result->{"${secgroup}_running"};
176
177     $result->{"${secgroup}_hour_cost"}    = [ $group_hour_cost, "n" ];
178     $result->{"${secgroup}_minute_cost"}  = [ $group_minute_cost, "n" ];
179     $result->{"${secgroup}_day_cost"}     = [ $group_day_cost, "n" ];
180     $result->{"${secgroup}_month_cost"}   = [ $group_month_cost, "n" ];
181     $result->{"${secgroup}_running"}      = [ $running, "i" ];
182   }
183
184   return $result;
185 }
186
187 1;
Note: See TracBrowser for help on using the browser.