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__ |