]> git.proxmox.com Git - pve-network.git/blob - src/test/run_test_vnets_blackbox.pl
tests: test VNets functionality as a blackbox
[pve-network.git] / src / test / run_test_vnets_blackbox.pl
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use lib qw(..);
7 use File::Slurp;
8 use List::Util qw(first all);
9 use NetAddr::IP qw(:lower);
10
11 use Test::More;
12 use Test::MockModule;
13
14 use PVE::Tools qw(extract_param file_set_contents);
15
16 use PVE::Network::SDN;
17 use PVE::Network::SDN::Zones;
18 use PVE::Network::SDN::Zones::Plugin;
19 use PVE::Network::SDN::Controllers;
20 use PVE::Network::SDN::Dns;
21 use PVE::Network::SDN::Vnets;
22
23 use PVE::RESTEnvironment;
24
25 use PVE::API2::Network::SDN::Zones;
26 use PVE::API2::Network::SDN::Subnets;
27 use PVE::API2::Network::SDN::Vnets;
28 use PVE::API2::Network::SDN::Ipams;
29
30 my $TMP_ETHERS_FILE = "/tmp/ethers";
31
32 my $test_state = undef;
33 sub clear_test_state {
34 $test_state = {
35 locks => {},
36 datacenter_config => {},
37 subnets_config => {},
38 controller_config => {},
39 dns_config => {},
40 zones_config => {},
41 vnets_config => {},
42 macdb => {},
43 ipamdb => {},
44 ipam_config => {
45 'ids' => {
46 'pve' => {
47 'type' => 'pve'
48 },
49 }
50 },
51 };
52 PVE::Tools::file_set_contents($TMP_ETHERS_FILE, "\n");
53 }
54 clear_test_state();
55
56 my $mocked_cfs_lock_file = sub {
57 my ($filename, $timeout, $code, @param) = @_;
58
59 die "$filename already locked\n" if ($test_state->{locks}->{$filename});
60
61 $test_state->{locks}->{$filename} = 1;
62
63 my $res = eval { $code->(@param); };
64
65 delete $test_state->{locks}->{$filename};
66
67 return $res;
68 };
69
70 sub read_sdn_config {
71 my ($file) = @_;
72 # Read structure back in again
73 open my $in, '<', $file or die $!;
74 my $sdn_config;
75 {
76 local $/; # slurp mode
77 $sdn_config = eval <$in>;
78 }
79 close $in;
80 return $sdn_config;
81 }
82
83 my $mocked_pve_sdn;
84 $mocked_pve_sdn = Test::MockModule->new('PVE::Network::SDN');
85 $mocked_pve_sdn->mock(
86 cfs_lock_file => $mocked_cfs_lock_file,
87 );
88
89 my $mocked_pve_tools = Test::MockModule->new('PVE::Tools');
90 $mocked_pve_tools->mock(
91 lock_file => $mocked_cfs_lock_file,
92 );
93
94 my $mocked_sdn_zones;
95 $mocked_sdn_zones = Test::MockModule->new('PVE::Network::SDN::Zones');
96 $mocked_sdn_zones->mock(
97 config => sub {
98 return $test_state->{zones_config};
99 },
100 write_config => sub {
101 my ($cfg) = @_;
102 $test_state->{zones_config} = $cfg;
103 },
104 );
105
106 my $mocked_sdn_zones_super_plugin;
107 $mocked_sdn_zones_super_plugin = Test::MockModule->new('PVE::Network::SDN::Zones::Plugin');
108 $mocked_sdn_zones_super_plugin->mock(
109 datacenter_config => sub {
110 return $test_state->{datacenter_config};
111 },
112 );
113
114 my $mocked_sdn_vnets;
115 $mocked_sdn_vnets = Test::MockModule->new('PVE::Network::SDN::Vnets');
116 $mocked_sdn_vnets->mock(
117 config => sub {
118 return $test_state->{vnets_config};
119 },
120 write_config => sub {
121 my ($cfg) = @_;
122 $test_state->{vnets_config} = $cfg;
123 },
124 cfs_lock_file => $mocked_cfs_lock_file,
125 );
126
127 my $mocked_sdn_subnets;
128 $mocked_sdn_subnets = Test::MockModule->new('PVE::Network::SDN::Subnets');
129 $mocked_sdn_subnets->mock(
130 config => sub {
131 return $test_state->{subnets_config};
132 },
133 write_config => sub {
134 my ($cfg) = @_;
135 $test_state->{subnets_config} = $cfg;
136 },
137 cfs_lock_file => $mocked_cfs_lock_file,
138 );
139
140 my $mocked_sdn_controller;
141 $mocked_sdn_controller = Test::MockModule->new('PVE::Network::SDN::Controllers');
142 $mocked_sdn_controller->mock(
143 config => sub {
144 return $test_state->{controller_config};
145 },
146 write_config => sub {
147 my ($cfg) = @_;
148 $test_state->{controller_config} = $cfg;
149 },
150 cfs_lock_file => $mocked_cfs_lock_file,
151 );
152
153
154 my $mocked_sdn_dns;
155 $mocked_sdn_dns = Test::MockModule->new('PVE::Network::SDN::Dns');
156 $mocked_sdn_dns->mock(
157 config => sub {
158 return $test_state->{dns_config};
159 },
160 write_config => sub {
161 my ($cfg) = @_;
162 $test_state->{dns_config} = $cfg;
163 },
164 cfs_lock_file => $mocked_cfs_lock_file,
165 );
166
167
168 my $mocked_sdn_ipams;
169 $mocked_sdn_ipams = Test::MockModule->new('PVE::Network::SDN::Ipams');
170 $mocked_sdn_ipams->mock(
171 config => sub {
172 return $test_state->{ipam_config};
173 },
174 write_config => sub {
175 my ($cfg) = @_;
176 $test_state->{ipam_config} = $cfg;
177 },
178 read_macdb => sub {
179 return $test_state->{macdb};
180 },
181 write_macdb => sub {
182 my ($cfg) = @_;
183 $test_state->{macdb} = $cfg;
184 },
185 cfs_lock_file => $mocked_cfs_lock_file,
186 );
187
188 my $ipam_plugin = PVE::Network::SDN::Ipams::Plugin->lookup("pve"); # NOTE this is hard-coded to pve
189 my $mocked_ipam_plugin = Test::MockModule->new($ipam_plugin);
190 $mocked_ipam_plugin->mock(
191 read_db => sub {
192 return $test_state->{ipamdb};
193 },
194 write_db => sub {
195 my ($cfg) = @_;
196 $test_state->{ipamdb} = $cfg;
197 },
198 cfs_lock_file => $mocked_cfs_lock_file,
199 );
200
201 my $mocked_sdn_dhcp_dnsmasq = Test::MockModule->new('PVE::Network::SDN::Dhcp::Dnsmasq');
202 $mocked_sdn_dhcp_dnsmasq->mock(
203 assert_dnsmasq_installed => sub { return 1; },
204 before_configure => sub {},
205 ethers_file => sub { return "/tmp/ethers"; },
206 systemctl_service => sub {},
207 update_lease => sub {},
208 );
209
210 my $mocked_api_zones = Test::MockModule->new('PVE::API2::Network::SDN::Zones');
211 $mocked_api_zones->mock(
212 create_etc_interfaces_sdn_dir => sub {},
213 );
214
215 my $rpcenv = PVE::RESTEnvironment->init('priv');
216 $rpcenv->init_request();
217 $rpcenv->set_language("en_US.UTF-8");
218 $rpcenv->set_user('root@pam');
219
220 my $mocked_rpc_env_obj = Test::MockModule->new('PVE::RESTEnvironment');
221 $mocked_rpc_env_obj->mock(
222 check_any => sub { return 1; },
223 );
224
225 my $mocked_pve_cluster_obj = Test::MockModule->new('PVE::Cluster');
226 $mocked_pve_cluster_obj->mock(
227 check_cfs_quorum => sub { return 1; },
228 );
229
230 # ------- TEST FUNCTIONS --------------
231
232 sub nic_join {
233 my ($vnetid, $mac, $hostname, $vmid) = @_;
234 return PVE::Network::SDN::Vnets::add_next_free_cidr($vnetid, $hostname, $mac, "$vmid", undef, 1);
235 }
236
237 sub nic_leave {
238 my ($vnetid, $mac, $hostname) = @_;
239 return PVE::Network::SDN::Vnets::del_ips_from_mac($vnetid, $mac, $hostname);
240 }
241
242 sub nic_start {
243 my ($vnetid, $mac, $vmid, $hostname) = @_;
244 return PVE::Network::SDN::Vnets::add_dhcp_mapping($vnetid, $mac, $vmid, $hostname);
245 }
246
247
248 # ---- API HELPER FUNCTIONS FOR THE TESTS -----
249
250 my $t_invalid;
251 sub get_zone {
252 my ($id) = @_;
253 return eval { PVE::API2::Network::SDN::Zones->read({zone => $id}); };
254 }
255 # verify get_zone actually fails if invalid
256 $t_invalid = get_zone("invalid");
257 die("getting an invalid zone must fail") if (!$@);
258 fail("getting an invalid zone must fail") if (defined $t_invalid);
259
260 sub create_zone {
261 my ($params) = @_;
262 my $zoneid = $params->{zone};
263 # die if failed!
264 eval { PVE::API2::Network::SDN::Zones->create($params); };
265 die("creating zone failed: $@") if ($@);
266
267 my $zone = get_zone($zoneid);
268 die ("test setup: zone ($zoneid) not defined") if (!defined $zone);
269 return $zone;
270 }
271
272 sub get_vnet {
273 my ($id) = @_;
274 return eval { PVE::API2::Network::SDN::Vnets->read({vnet => $id}); };
275 }
276 # verify get_vnet
277 $t_invalid = get_vnet("invalid");
278 die("getting an invalid vnet must fail") if (!$@);
279 fail("getting an invalid vnet must fail") if (defined $t_invalid);
280
281 sub create_vnet {
282 my ($params) = @_;
283 my $vnetid = $params->{vnet};
284 PVE::API2::Network::SDN::Vnets->create($params);
285
286 my $vnet = get_vnet($vnetid);
287 die ("test setup: vnet ($vnetid) not defined") if (!defined $vnet);
288 return $vnet;
289 }
290
291 sub get_subnet {
292 my ($id) = @_;
293 return eval { PVE::API2::Network::SDN::Subnets->read({subnet => $id}); };
294 }
295 # verify get_subnet
296 $t_invalid = get_subnet("invalid");
297 die("getting an invalid subnet must fail") if (!$@);
298 fail("getting an invalid subnet must fail") if (defined $t_invalid);
299
300 sub create_subnet {
301 my ($params) = @_;
302 PVE::API2::Network::SDN::Subnets->create($params);
303 }
304
305 sub get_ipam_entries {
306 return PVE::API2::Network::SDN::Ipams->ipamindex({ipam => "pve"});
307 }
308
309 sub create_ip {
310 my ($param) = @_;
311 return PVE::API2::Network::SDN::Ips->ipcreate($param);
312 }
313
314 sub run_test {
315 my $test = shift;
316 clear_test_state();
317 $test->(@_);
318 }
319
320 sub get_ips_from_mac {
321 my ($mac) = @_;
322 my $ipam_entries = get_ipam_entries();
323 return grep { $_->{mac} eq $mac if defined $_->{mac} } $ipam_entries->@* if $ipam_entries;
324 }
325
326 sub get_ip4 {
327 my $ip4 = first { Net::IP::ip_is_ipv4($_->{ip}) } @_;
328 return $ip4->{ip} if defined $ip4;
329 }
330
331 sub get_ip6 {
332 my $ip6 = first { Net::IP::ip_is_ipv6($_->{ip}) } @_;
333 return $ip6->{ip} if defined $ip6;
334 }
335
336
337 # -------------- ACTUAL TESTS -----------------------
338
339 sub test_create_vnet_with_gateway {
340 my $test_name = (split(/::/,(caller(0))[3]))[-1];
341 my $zoneid = "TESTZONE";
342 my $vnetid = "testvnet";
343
344 my $zone = create_zone({
345 type => "simple",
346 dhcp => "dnsmasq",
347 ipam => "pve",
348 zone => $zoneid,
349 });
350
351 my $vnet = create_vnet({
352 type => "vnet",
353 zone => $zoneid,
354 vnet => $vnetid,
355 });
356
357 create_subnet({
358 type => "subnet",
359 vnet => $vnetid,
360 subnet => "10.0.0.0/24",
361 gateway => "10.0.0.1",
362 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
363 });
364
365 my ($p) = first { $_->{gateway} == 1 } get_ipam_entries()->@*;
366 ok ($p, "$test_name: Gateway IP was created in IPAM");
367 }
368 run_test(\&test_create_vnet_with_gateway);
369
370
371 sub test_without_subnet {
372 my $test_name = (split(/::/,(caller(0))[3]))[-1];
373
374 my $zoneid = "TESTZONE";
375 my $vnetid = "testvnet";
376
377 my $zone = create_zone({
378 type => "simple",
379 dhcp => "dnsmasq",
380 ipam => "pve",
381 zone => $zoneid,
382 });
383
384 my $vnet = create_vnet({
385 type => "vnet",
386 zone => $zoneid,
387 vnet => $vnetid,
388 });
389
390 my $hostname = "testhostname";
391 my $mac = "da:65:8f:18:9b:6f";
392 my $vmid = "999";
393
394 eval {
395 nic_join($vnetid, $mac, $hostname, $vmid);
396 };
397
398 if ($@) {
399 fail("$test_name: $@");
400 return;
401 }
402
403 my @ips = get_ips_from_mac($mac);
404 my $num_ips = scalar @ips;
405 is ($num_ips, 0, "$test_name: No IP allocated in IPAM");
406 }
407 run_test(\&test_without_subnet);
408
409
410 sub test_nic_join {
411 my ($test_name, $subnets) = @_;
412
413 die "$test_name: we're expecting an array of subnets" if !$subnets;
414 my $num_subnets = scalar $subnets->@*;
415 die "$test_name: we're expecting an array of subnets. $num_subnets elements found" if ($num_subnets < 1);
416 my $num_dhcp_ranges = scalar grep { $_->{'dhcp-range'} } $subnets->@*;
417
418 my $zoneid = "TESTZONE";
419 my $vnetid = "testvnet";
420
421 my $zone = create_zone({
422 type => "simple",
423 dhcp => "dnsmasq",
424 ipam => "pve",
425 zone => $zoneid,
426 });
427
428 my $vnet = create_vnet({
429 type => "vnet",
430 zone => $zoneid,
431 vnet => $vnetid,
432 });
433
434 foreach my $subnet ($subnets->@*) {
435 $subnet->{type} = "subnet";
436 $subnet->{vnet} = $vnetid;
437 create_subnet($subnet);
438 };
439
440 my $hostname = "testhostname";
441 my $mac = "da:65:8f:18:9b:6f";
442 my $vmid = "999";
443
444 eval {
445 nic_join($vnetid, $mac, $hostname, $vmid);
446 };
447
448 if ($@) {
449 fail("$test_name: $@");
450 return;
451 }
452
453 my @ips = get_ips_from_mac($mac);
454 my $num_ips = scalar @ips;
455 is ($num_ips, $num_dhcp_ranges, "$test_name: Expecting $num_dhcp_ranges IPs, found $num_ips");
456 ok ((all { ($_->{vnet} eq $vnetid && $_->{zone} eq $zoneid) } @ips),
457 "$test_name: all IPs in correct vnet and zone"
458 );
459 }
460
461 run_test(
462 \&test_nic_join,
463 "nic_join IPv4 no dhcp",
464 [{
465 subnet => "10.0.0.0/24",
466 gateway => "10.0.0.1",
467 },
468 ]);
469
470 run_test(
471 \&test_nic_join,
472 "nic_join IPv6 no dhcp",
473 [{
474 subnet => "8888::/64",
475 gateway => "8888::1",
476 },
477 ]);
478
479 run_test(
480 \&test_nic_join,
481 "nic_join IPv4+6 no dhcp",
482 [{
483 subnet => "10.0.0.0/24",
484 gateway => "10.0.0.1",
485 }, {
486 subnet => "8888::/64",
487 gateway => "8888::1",
488 },
489 ]);
490
491 run_test(
492 \&test_nic_join,
493 "nic_join IPv4 with dhcp",
494 [{
495 subnet => "10.0.0.0/24",
496 gateway => "10.0.0.1",
497 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
498 },
499 ]);
500
501 run_test(
502 \&test_nic_join,
503 "nic_join IPv6 with dhcp",
504 [{
505 subnet => "8888::/64",
506 gateway => "8888::1",
507 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
508 },
509 ]);
510
511 run_test(
512 \&test_nic_join,
513 "nic_join IPv4+6 with dhcp",
514 [{
515 subnet => "10.0.0.0/24",
516 gateway => "10.0.0.1",
517 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
518 }, {
519 subnet => "8888::/64",
520 gateway => "8888::1",
521 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
522 },
523 ]);
524
525 run_test(
526 \&test_nic_join,
527 "nic_join IPv4 no DHCP, IPv6 with DHCP",
528 [{
529 subnet => "10.0.0.0/24",
530 gateway => "10.0.0.1",
531 }, {
532 subnet => "8888::/64",
533 gateway => "8888::1",
534 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
535 },
536 ]);
537
538 run_test(
539 \&test_nic_join,
540 "nic_join IPv4 with DHCP, IPv6 no DHCP",
541 [{
542 subnet => "10.0.0.0/24",
543 gateway => "10.0.0.1",
544 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
545 }, {
546 subnet => "8888::/64",
547 gateway => "8888::1",
548 },
549 ]);
550
551
552 sub test_nic_join_full_dhcp_range {
553 my ($test_name, $subnets, $expected_ip4, $expected_ip6) = @_;
554
555 die "$test_name: we're expecting an array of subnets" if !$subnets;
556 my $num_subnets = scalar $subnets->@*;
557 die "$test_name: we're expecting an array of subnets. $num_subnets elements found" if ($num_subnets < 1);
558
559 my $zoneid = "TESTZONE";
560 my $vnetid = "testvnet";
561
562 my $zone = create_zone({
563 type => "simple",
564 dhcp => "dnsmasq",
565 ipam => "pve",
566 zone => $zoneid,
567 });
568
569 my $vnet = create_vnet({
570 type => "vnet",
571 zone => $zoneid,
572 vnet => $vnetid,
573 });
574
575 foreach my $subnet ($subnets->@*) {
576 $subnet->{type} = "subnet";
577 $subnet->{vnet} = $vnetid;
578 create_subnet($subnet);
579 };
580
581 my $hostname = "testhostname";
582 my $mac = "da:65:8f:18:9b:6f";
583 my $vmid = "999";
584
585 eval {
586 nic_join($vnetid, $mac, $hostname, $vmid);
587 };
588
589 if (! $@) {
590 fail ("$test_name: nic_join() is expected to fail because we cannot allocate all IPs");
591 }
592
593 my @ips = get_ips_from_mac($mac);
594 my $num_ips = scalar @ips;
595 is ($num_ips, 0, "$test_name: No IP allocated in IPAM");
596 }
597
598 run_test(
599 \&test_nic_join_full_dhcp_range,
600 "nic_join IPv4 with DHCP, dhcp-range full",
601 [{
602 subnet => "10.0.0.0/24",
603 gateway => "10.0.0.100", # the gateway uses the only available IP in the dhcp-range
604 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.100"],
605 }
606 ]);
607
608 run_test(
609 \&test_nic_join_full_dhcp_range,
610 "nic_join IPv6 with DHCP, dhcp-range full",
611 [{
612 subnet => "8888::/64",
613 gateway => "8888::100", # the gateway uses the only available IP in the dhcp-range
614 'dhcp-range' => ["start-address=8888::100,end-address=8888::100"],
615 },
616 ]);
617
618 run_test(
619 \&test_nic_join_full_dhcp_range,
620 "nic_join IPv4+6 with DHCP, dhcp-range full for both",
621 [{
622 subnet => "10.0.0.0/24",
623 gateway => "10.0.0.100",
624 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.100"],
625 }, {
626 subnet => "8888::/64",
627 gateway => "8888::100",
628 'dhcp-range' => ["start-address=8888::100,end-address=8888::100"],
629 }
630 ]);
631
632 run_test(
633 \&test_nic_join_full_dhcp_range,
634 "nic_join IPv4+6 with DHCP, dhcp-range full for IPv4",
635 [{
636 subnet => "10.0.0.0/24",
637 gateway => "10.0.0.100", # the gateway uses the only available IP in the dhcp-range
638 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.100"],
639 }, {
640 subnet => "8888::/64",
641 gateway => "8888::1",
642 'dhcp-range' => ["start-address=8888::100,end-address=8888::100"],
643 }],
644 );
645
646 run_test(
647 \&test_nic_join_full_dhcp_range,
648 "nic_join IPv4+6 with DHCP, dhcp-range full for IPv6",
649 [{
650 subnet => "10.0.0.0/24",
651 gateway => "10.0.0.1",
652 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.100"],
653 }, {
654 subnet => "8888::/64",
655 gateway => "8888::100",
656 'dhcp-range' => ["start-address=8888::100,end-address=8888::100"],
657 }],
658 );
659
660 run_test(
661 \&test_nic_join_full_dhcp_range,
662 "nic_join IPv4 no DHCP, dhcp-range full for IPv6",
663 [{
664 subnet => "10.0.0.0/24",
665 gateway => "10.0.0.1",
666 }, {
667 subnet => "8888::/64",
668 gateway => "8888::100",
669 'dhcp-range' => ["start-address=8888::100,end-address=8888::100"],
670 }],
671 );
672
673
674 # -------------- nic_start
675 sub test_nic_start {
676 my ($test_name, $subnets, $current_ip4, $current_ip6, $num_expected_ips) = @_;
677
678 die "$test_name: we're expecting an array of subnets" if !$subnets;
679 my $num_subnets = scalar $subnets->@*;
680 die "$test_name: we're expecting an array of subnets. $num_subnets elements found" if ($num_subnets < 1);
681
682 $num_expected_ips = scalar grep { $_->{'dhcp-range'} } $subnets->@* if !defined $num_expected_ips;
683
684 my $zoneid = "TESTZONE";
685 my $vnetid = "testvnet";
686
687 my $zone = create_zone({
688 type => "simple",
689 dhcp => "dnsmasq",
690 ipam => "pve",
691 zone => $zoneid,
692 });
693
694 my $vnet = create_vnet({
695 type => "vnet",
696 zone => $zoneid,
697 vnet => $vnetid,
698 });
699
700 foreach my $subnet ($subnets->@*) {
701 $subnet->{type} = "subnet";
702 $subnet->{vnet} = $vnetid;
703 create_subnet($subnet);
704 };
705
706 my $hostname = "testhostname";
707 my $mac = "da:65:8f:18:9b:6f";
708 my $vmid = "999";
709
710 if ($current_ip4) {
711 create_ip({
712 zone => $zoneid,
713 vnet => $vnetid,
714 mac => $mac,
715 ip => $current_ip4,
716 });
717 }
718
719 if ($current_ip6) {
720 create_ip({
721 zone => $zoneid,
722 vnet => $vnetid,
723 mac => $mac,
724 ip => $current_ip6,
725 });
726 }
727 my @current_ips = get_ips_from_mac($mac);
728 is ( get_ip4(@current_ips), $current_ip4, "$test_name: setup current IPv4: $current_ip4" ) if defined $current_ip4;
729 is ( get_ip6(@current_ips), $current_ip6, "$test_name: setup current IPv6: $current_ip6" ) if defined $current_ip6;
730
731 eval {
732 nic_start($vnetid, $mac, $hostname, $vmid);
733 };
734
735 if ($@) {
736 fail("$test_name: $@");
737 return;
738 }
739
740 my @ips = get_ips_from_mac($mac);
741 my $num_ips = scalar @ips;
742 is ($num_ips, $num_expected_ips, "$test_name: Expecting $num_expected_ips IPs, found $num_ips");
743 ok ((all { ($_->{vnet} eq $vnetid && $_->{zone} eq $zoneid) } @ips),
744 "$test_name: all IPs in correct vnet and zone"
745 );
746
747 is ( get_ip4(@ips), $current_ip4, "$test_name: still current IPv4: $current_ip4" ) if $current_ip4;
748 is ( get_ip6(@ips), $current_ip6, "$test_name: still current IPv6: $current_ip6" ) if $current_ip6;
749 }
750
751 run_test(
752 \&test_nic_start,
753 "nic_start no IP, IPv4 without dhcp",
754 [{
755 subnet => "10.0.0.0/24",
756 gateway => "10.0.0.1",
757 },
758 ]);
759
760 run_test(
761 \&test_nic_start,
762 "nic_start already IP, IPv4 without dhcp",
763 [{
764 subnet => "10.0.0.0/24",
765 gateway => "10.0.0.1",
766 }],
767 "10.0.0.99",
768 undef,
769 1
770 );
771
772 run_test(
773 \&test_nic_start,
774 "nic_start already IPv6, IPv6 without dhcp",
775 [{
776 subnet => "8888::/64",
777 gateway => "8888::1",
778 }],
779 undef,
780 "8888::99",
781 1
782 );
783
784 run_test(
785 \&test_nic_start,
786 "nic_start no IP, IPv4 subnet with dhcp",
787 [{
788 subnet => "10.0.0.0/24",
789 gateway => "10.0.0.1",
790 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
791 },
792 ]);
793
794 run_test(
795 \&test_nic_start,
796 "nic_start already IP, IPv4 subnet with dhcp",
797 [{
798 subnet => "10.0.0.0/24",
799 gateway => "10.0.0.1",
800 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
801 }],
802 "10.0.0.99"
803 );
804
805 run_test(
806 \&test_nic_start,
807 "nic_start already IP, IPv6 subnet with dhcp",
808 [{
809 subnet => "8888::/64",
810 gateway => "8888::1",
811 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
812 }],
813 undef,
814 "8888::99"
815 );
816
817 run_test(
818 \&test_nic_start,
819 "nic_start IP, IPv4+6 subnet with dhcp",
820 [{
821 subnet => "10.0.0.0/24",
822 gateway => "10.0.0.1",
823 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
824 }, {
825 subnet => "8888::/64",
826 gateway => "8888::1",
827 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
828 },
829 ]);
830
831 run_test(
832 \&test_nic_start,
833 "nic_start already IPv4, IPv4+6 subnet with dhcp",
834 [{
835 subnet => "10.0.0.0/24",
836 gateway => "10.0.0.1",
837 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
838 }, {
839 subnet => "8888::/64",
840 gateway => "8888::1",
841 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
842 }],
843 "10.0.0.99"
844 );
845
846 run_test(
847 \&test_nic_start,
848 "nic_start already IPv6, IPv4+6 subnet with dhcp",
849 [{
850 subnet => "10.0.0.0/24",
851 gateway => "10.0.0.1",
852 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
853 }, {
854 subnet => "8888::/64",
855 gateway => "8888::1",
856 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
857 }],
858 undef,
859 "8888::99"
860 );
861
862 run_test(
863 \&test_nic_start,
864 "nic_start already IPv4+6, IPv4+6 subnets with dhcp",
865 [{
866 subnet => "10.0.0.0/24",
867 gateway => "10.0.0.1",
868 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
869 }, {
870 subnet => "8888::/64",
871 gateway => "8888::1",
872 'dhcp-range' => ["start-address=8888::100,end-address=8888::200"],
873 }],
874 "10.0.0.99",
875 "8888::99"
876 );
877
878 run_test(
879 \&test_nic_start,
880 "nic_start already IPv4+6, only IPv4 subnet with dhcp",
881 [{
882 subnet => "10.0.0.0/24",
883 gateway => "10.0.0.1",
884 'dhcp-range' => ["start-address=10.0.0.100,end-address=10.0.0.200"],
885 }, {
886 subnet => "8888::/64",
887 gateway => "8888::1",
888 }],
889 "10.0.0.99",
890 "8888::99",
891 2
892 );
893
894 done_testing();