Release 0.06
[MogileFS-Network.git] / t / multiple-networks-replpol.t
blobc17f9581b3e492c6503729d485994a40a8537e0d
1 #!/usr/bin/perl
3 use strict;
4 use warnings;
5 use Test::More;
6 use FindBin qw($Bin);
7 use Net::Netmask;
9 use MogileFS::Server;
10 use MogileFS::Util qw(error_code);
11 use MogileFS::ReplicationPolicy::MultipleNetworks;
12 use MogileFS::Test;
14 plan tests => 25;
16 # need just the one, so we only have to stuff the cache once
17 my $polclass = "MogileFS::ReplicationPolicy::MultipleNetworks";
18 my $pol = $polclass->new;
20 # test that the MultipleHosts stuff still works
21 # we cope when there are no ips
23 # already good.
24 is(rr("min=2 h1[d1=X d2=_] h2[d3=X d4=_]"),
25 "all_good", "all good");
27 # need to get it onto host2...
28 is(rr("min=2 h1[d1=X d2=_] h2[d3=_ d4=_]"),
29 "ideal(3,4)", "need host2");
31 # still needs to be on host2, even though 2 copies on host1
32 is(rr("min=2 h1[d1=X d2=X] h2[d3=_ d4=_]"),
33 "ideal(3,4)", "need host2, even though 2 on host1");
35 # anywhere will do. (can happen on, say, rebalance)
36 is(rr("min=2 h1[d1=_ d2=_] h2[d3=_ d4=_]"),
37 "ideal(1,2,3,4)", "anywhere");
39 # should desperately try d2, since host2 is down
40 is(rr("min=2 h1[d1=X d2=_] h2=down[d3=_ d4=_]"),
41 "desperate(2)");
43 # should try host3, since host2 is down
44 is(rr("min=2 h1[d1=X d2=_] h2=down[d3=_ d4=_] h3[d5=_ d6=_]"),
45 "ideal(5,6)");
47 # need a copy on a non-dead disk on host1
48 is(rr("min=2 h1[d1=_ d2=X,dead] h2=alive[d3=X d4=_]"),
49 "ideal(1)");
51 # this is an ideal move, since we only have 2 unique hosts:
52 is(rr("min=3 h1[d1=_ d2=X] h2[d3=X d4=_]"),
53 "ideal(1,4)");
55 # ... but if we have a 3rd host, it's gotta be there
56 is(rr("min=3 h1[d1=_ d2=X] h2[d3=X d4=_] h3[d5=_]"),
57 "ideal(5)");
59 # ... unless that host is down, in which case it's back to 1/4,
60 # but desperately
61 is(rr("min=3 h1[d1=_ d2=X] h2[d3=X d4=_] h3=down[d5=_]"),
62 "desperate(1,4)");
64 # too good, uniq hosts > min
65 is(rr("min=2 h1[d1=X d2=_] h2[d3=X d4=_] h3[d5=X]"),
66 "too_good");
68 # too good, but but with uniq hosts == min
69 is(rr("min=2 h1[d1=X d2=X] h2[d3=X d4=_]"),
70 "too_good");
72 # be happy with 3 copies, even though two are on same host (that's our max unique hosts)
73 is(rr("min=3 h1[d1=_ d2=X] h2[d3=X d4=X]"),
74 "all_good");
78 # actual network policy tests
79 my ($ad1, $ad2) = ("#192.168.0.2#" ,"#192.168.0.3#" );
80 my ($ad3, $ad4) = ("#10.0.0.2#" ,"#10.0.0.3#" );
81 my ($ad5, $ad6) = ("#146.101.246.2#","#146.101.142.130#");
83 # stuff the cache with the default, otherwise it'll go to the db
84 $pol->stuff_cache('192.168.0.2' , Net::Netmask->new('192.168.0.0/16'));
85 $pol->stuff_cache('192.168.0.3' , Net::Netmask->new('192.168.0.0/16'));
86 $pol->stuff_cache('10.0.0.2' , Net::Netmask->new('10.0.0.0/16'));
87 $pol->stuff_cache('10.0.0.3' , Net::Netmask->new('10.0.0.0/16'));
88 $pol->stuff_cache('146.101.246.2' , Net::Netmask->new('146.101.0.0/16'));
89 $pol->stuff_cache('146.101.142.130', Net::Netmask->new('146.101.0.0/16'));
91 # retest some multiple Host logic all on the same network
92 # already good. (there's only one network)
93 is(rr("min=2 h1[d1=X d2=_]$ad1 h2[d3=X d4=_]$ad2"),
94 "all_good", "all good");
96 # need to get it onto host2...
97 is(rr("min=2 h1[d1=X d2=_]$ad1 h2[d3=_ d4=_]$ad2"),
98 "desperate(2,3,4)", "need host2");
100 # still needs to be on host2, even though 2 copies on host1
101 is(rr("min=2 h1[d1=X d2=X]$ad1 h2[d3=_ d4=_]$ad2"),
102 "desperate(3,4)", "need host2, even though 2 on host1");
104 # target another network
105 is(rr("min=2 h1[d1=_ d2=X]$ad1 h2[d3=_ d4=_]$ad2 h3[d5=_ d6=_]$ad3 h4[d7=_ d8=_]$ad4"),
106 "ideal(5,6,7,8)","target other network"); # no device 3 or 4 (or 1) in the ideal
108 # other network down
109 is(rr("min=2 h1[d1=_ d2=X]$ad1 h2[d3=_ d4=_]$ad2 h3=down[d5=_ d6=_]$ad3 h4=down[d7=_ d8=_]$ad4"),
110 "desperate(1,3,4)", "desperate this network");
112 is(rr("min=2 h1[d1=_ d2=X]$ad1 h2[d3=_ d4=_]$ad2 h3[d5=_ d6=_]$ad3 h4[d7=_ d8=_]$ad5"),
113 "ideal(5,6,7,8)","include both other networks with three networks");
115 is(rr("min=2 h1[d1=_ d2=X]$ad1 h2[d3=_ d4=_]$ad2 h3=down[d5=_ d6=_]$ad3 h4[d7=_ d8=_]$ad5"),
116 "ideal(7,8)","one of three networks down");
118 is(rr("min=2 h1[d1=_ d2=X,dead]$ad1 h2=alive[d3=_ d4=_]$ad2 h3=alive[d5=X d6=_]$ad3"),
119 "ideal(1,3,4)","dead copies don't exclude a network");
121 is(rr("min=2 h1[d1=_ d2=X]$ad1 h2[d3=_ d4=_]$ad2 h3[d5=X d6=_]$ad3"),
122 "all_good","enough copies on different networks");
124 is(rr("min=2 h1[d1=_ d2=X]$ad1 h2[d3=X d4=X]$ad2"),
125 "too_good","3 copies on 2 networks with a min of 2 is too good");
127 # too many copies on one network, not enough on another, want to over-replicate
128 is(rr("min=2 h1[d1=X d2=X]$ad1 h2[d3=X d4=X]$ad2 h3[d5=_ d6=_]$ad3 h4[d7=_ d8=_]$ad4"),
129 "ideal(5,6,7,8)", "more than min hosts, but all on one network");
131 # mess with netmasks
132 $pol->stuff_cache('146.101.246.2' , Net::Netmask->new('146.101.246.0/24'));
133 $pol->stuff_cache('146.101.142.130', Net::Netmask->new('146.101.142.0/24'));
135 is(rr("min=2 h1[d1=_ d2=X]$ad6 h2[d3=_ d4=_]$ad5 h3[d5=_ d6=_]$ad4 h4[d7=_ d8=_]$ad3"),
136 "ideal(3,4,5,6,7,8)","target other network"); # ad5 and ad6 are no longer the same network
138 sub rr {
139 my ($state) = @_;
140 my $ostate = $state; # original
142 MogileFS::Factory::Host->t_wipe;
143 MogileFS::Factory::Device->t_wipe;
144 MogileFS::Config->set_config_no_broadcast("min_free_space", 100);
145 my $hfac = MogileFS::Factory::Host->get_factory;
146 my $dfac = MogileFS::Factory::Device->get_factory;
148 my $min = 2;
149 if ($state =~ s/^\bmin=(\d+)\b//) {
150 $min = $1;
153 my $hosts = {};
154 my $devs = {};
155 my $on_devs = [];
157 my $parse_error = sub {
158 die "Can't parse:\n $ostate\n"
160 while ($state =~ s/\bh(\d+)(?:=(.+?))?\[(.+?)\](#\d+\.\d+\.\d+\.\d+\.?#)?//) {
161 my ($n, $opts, $devstr, $ip) = ($1, $2, $3, $4);
162 $opts ||= "";
163 die "dup host $n" if $hosts->{$n};
165 # print "1 2 3 4 : <<$1>> <<$2>> <<$3>> <<$4>>\n";
166 # print "$state\n";
168 my %extras;
169 if ($ip) {
170 $ip =~ s/#//g;
171 $extras{hostip} = $ip;
174 my $h = $hosts->{$n} = $hfac->set({ hostid => $n,
175 status => ($opts || "alive"), observed_state => "reachable",
176 hostname => $n, %extras });
179 foreach my $ddecl (split(/\s+/, $devstr)) {
180 $ddecl =~ /^d(\d+)=([_X])(?:,(\w+))?$/
181 or $parse_error->();
182 my ($dn, $on_not, $status) = ($1, $2, $3);
183 die "dup device $dn" if $devs->{$dn};
184 my $d = $devs->{$dn} = $dfac->set({ devid => $dn,
185 hostid => $h->id, observed_state => "writeable",
186 status => ($status || "alive"), mb_total => 1000,
187 mb_used => 100, });
188 if ($on_not eq "X" && $d->dstate->should_have_files) {
189 push @$on_devs, $d;
193 $parse_error->() if $state =~ /\S/;
195 my $rr = $pol->replicate_to(
196 fid => 1,
197 on_devs => $on_devs,
198 all_devs => $devs,
199 failed => {},
200 min => $min,
202 return $rr->t_as_string;