File Coverage

blib/lib/MHA/AWS.pm
Criterion Covered Total %
statement 24 96 25.0
branch 0 26 0.0
condition 0 9 0.0
subroutine 8 18 44.4
pod 0 8 0.0
total 32 157 20.3


line stmt bran cond sub pod time code
1             package MHA::AWS;
2              
3 1     1   615 use 5.008001;
  1         3  
  1         30  
4 1     1   4 use strict;
  1         2  
  1         23  
5 1     1   5 use warnings;
  1         10  
  1         25  
6 1     1   708 use Log::Minimal;
  1         562319  
  1         6  
7 1     1   1051 use AWS::CLIWrapper;
  1         118441  
  1         155  
8 1     1   23 use Time::HiRes qw/ sleep /;
  1         5  
  1         40  
9 1     1   396 use Scalar::Util qw/ blessed /;
  1         5  
  1         114  
10 1     1   73521 use Moo;
  1         27212  
  1         10  
11              
12             our $VERSION = "0.05";
13             our $API_APPLIED_TIMEOUT = 120;
14             our $CHECK_INTERVAL = 5;
15              
16             has host => ( is => "rw" );
17             has orig_master_host => ( is => "rw" );
18             has new_master_host => ( is => "rw" );
19             has attachment_id => ( is => "rw" );
20             has vip => ( is => "rw" );
21             has ssh_user => ( is => "rw" );
22             has instance_ids => ( is => "rw", default => sub { +{} } );
23             has interface_id => ( is => "rw" );
24             has failover_method => ( is => "rw", required => 1 );
25             has route_table_id => ( is => "rw" );
26             has aws => (
27             is => "rw",
28             default => sub {
29             AWS::CLIWrapper->new();
30             },
31             );
32             has current_attached_instance_id => ( is => "rw" );
33              
34             sub _init_eni {
35 0     0     my $self = shift;
36 0           my $res;
37 0           $res = $self->ec2("describe-network-interfaces", {
38             network_interface_ids => $self->interface_id,
39             });
40 0           my $interface = $res->{NetworkInterfaces}->[0];
41 0 0         unless ($interface) {
42 0           critf "Can't find network interface: %s", $self->interface_id;
43 0           die;
44             }
45              
46 0           $self->attachment_id( $interface->{Attachment}->{AttachmentId} );
47 0           $self->current_attached_instance_id( $interface->{Attachment}->{InstanceId} );
48 0           $self->vip( $interface->{PrivateIpAddress} );
49             }
50              
51             sub _init_route_table {
52 0     0     my $self = shift;
53 0           my $res;
54 0           my $destination_cidr_block = sprintf("%s/32", $self->vip);
55 0           $res = $self->ec2("describe-route-tables", {
56             route_table_id => $self->route_table_id,
57             });
58 0 0         if ( !$res->{RouteTables}->[0] ) {
59 0           critf "Can't find route_table: %s", $self->route_table_id;
60 0           die;
61             }
62 0           for my $route (@{ $res->{RouteTables}->[0]->{Routes} }) {
  0            
63 0 0         if ($route->{DestinationCidrBlock} eq $destination_cidr_block) {
64 0           $self->current_attached_instance_id($route->{InstanceId});
65 0           return 1;
66             }
67             }
68             }
69              
70             sub init {
71 0     0 0   my $self = shift;
72              
73 0 0         if ($self->failover_method eq "eni") {
74 0           $self->_init_eni;
75             }
76             else {
77 0           $self->_init_route_table;
78             }
79              
80             # create mapping table (hostname => instance-id) from tags
81 0           my $res = $self->ec2("describe-tags");
82 0           for my $tag (@{ $res->{Tags} }) {
  0            
83 0 0 0       if ($tag->{ResourceType} eq "instance" && $tag->{Key} eq "Name") {
84 0           $self->instance_ids->{ $tag->{Value} } = $tag->{ResourceId};
85             }
86             }
87              
88 0 0 0       if ( $self->new_master_host && !$self->new_master_instance_id ) {
89 0           critf "Can't detect new_master_instance_id. abort";
90 0           die;
91             }
92 0 0 0       if ( $self->orig_master_host && !$self->orig_master_instance_id ) {
93 0           critf "Can't detect orig_master_instance_id. abort";
94 0           die;
95             }
96             }
97              
98             sub ec2 {
99 0     0 0   my $self = shift;
100 0           my ($command, $args) = @_;
101 0 0         infof "aws ec2 %s %s", $command, defined($args) ? ddf $args : "";
102 0           my $res = $self->aws->ec2($command, $args);
103 0 0         if ($res) {
104 0           debugf "result: %s", ddf $res;
105             }
106             else {
107 0           critf "failed";
108 0           die;
109             }
110 0           $res;
111             }
112              
113             sub ping {
114 0     0 0   my $self = shift;
115 0           my $ip_addr = shift;
116 0 0         system(qw/ timeout 3 ping -c 1 -t 3 /, $ip_addr) == 0 ? 1 : 0;
117             }
118              
119             sub host_instance_id {
120 0     0 0   my $self = shift;
121 0           $self->instance_ids->{ $self->host };
122             }
123              
124             sub new_master_instance_id {
125 0     0 0   my $self = shift;
126 0           $self->instance_ids->{ $self->new_master_host };
127             }
128              
129             sub orig_master_instance_id {
130 0     0 0   my $self = shift;
131 0           $self->instance_ids->{ $self->orig_master_host };
132             }
133              
134             sub dispatch {
135 0     0 0   my $self = shift;
136 0           my $command = shift;
137 0 0         if ( my $method = $self->can("_command_${command}") ) {
138 0           infof "Invoke command: %s::%s", ref $self, $command;
139 0           my $success = $method->($self);
140 0 0         if ($success) {
141 0           infof "Complete!";
142             }
143             else {
144 0           infof "Failed!";
145 0           die;
146             }
147             }
148             else {
149 0           critf("Unknown command: %s", $command);
150 0           die;
151             }
152             }
153              
154             sub info {
155 0     0 0   my $self = shift;
156 0           my $info = {};
157 0           for my $key (sort keys %$self) {
158 0 0         next if Scalar::Util::blessed($self->{$key});
159 0           $info->{$key} = $self->{$key};
160             }
161 0           $info;
162             }
163              
164             1;
165             __END__