diff --git a/lib/sles4sap/azure_cli.pm b/lib/sles4sap/azure_cli.pm index 90c819a6d83d..555c72934840 100644 --- a/lib/sles4sap/azure_cli.pm +++ b/lib/sles4sap/azure_cli.pm @@ -33,8 +33,10 @@ our @EXPORT = qw( az_network_lb_rule_create az_vm_as_create az_vm_create + az_vm_name_get az_vm_openport az_vm_wait_cloudinit + az_vm_instance_view_get az_nic_id_get az_nic_name_get az_ipconfig_name_get @@ -81,11 +83,9 @@ sub az_group_create { assert_script_run($az_cmd); } - - =head2 az_group_name_get - az_group_name_get(); + my $ret = az_group_name_get(); Get the name of all existing Resource groups in the current subscription @@ -134,6 +134,11 @@ sub az_network_vnet_create { croak("Argument < $_ > missing") unless $args{$_}; } $args{address_prefixes} //= '192.168.0.0/16'; $args{subnet_prefixes} //= '192.168.0.0/24'; + foreach (qw(address_prefixes subnet_prefixes)) { + croak "Invalid IP range $args{$_} in $_" + unless ($args{$_} =~ /^[1-9]{1}[0-9]{0,2}\.(0|[1-9]{1,3})\.(0|[1-9]{1,3})\.(0|[1-9]{1,3})\/[0-9]+$/); + } + my $az_cmd = join(' ', 'az network vnet create', '--resource-group', $args{resource_group}, '--location', $args{region}, @@ -295,7 +300,7 @@ sub az_network_publicip_get { vnet => 'openqa-vnet', snet => 'openqa-subnet', backend => 'openqa-be', - frontend_ip => 'openqa-feip', + frontend_ip_name => 'openqa-feip', sku => 'Standard') Create a load balancer entity. @@ -316,7 +321,7 @@ SKU Standard (and not Basic) is needed to get some Metrics =item B - name to assign to created backend pool -=item B - name to assign to created frontend ip, will be reused in "az network lb rule create" +=item B - name to assign to created frontend ip, will be reused in "az network lb rule create" =item B - default Basic @@ -327,11 +332,16 @@ SKU Standard (and not Basic) is needed to get some Metrics sub az_network_lb_create { my (%args) = @_; - foreach (qw(resource_group name vnet snet backend frontend_ip)) { + foreach (qw(resource_group name vnet snet backend frontend_ip_name)) { croak("Argument < $_ > missing") unless $args{$_}; } $args{sku} //= 'Basic'; - my $fip_cmd = $args{fip} ? "--private-ip-address $args{fip}" : ''; + my $fip_cmd = ''; + if ($args{fip}) { + croak "Invalid IP address fip:$args{fip}" + unless ($args{fip} =~ /^[1-9]{1}[0-9]{0,2}\.(0|[1-9]{1,3})\.(0|[1-9]{1,3})\.[1-9]{1}[0-9]{0,2}$/); + $fip_cmd = "--private-ip-address $args{fip}"; + } my $az_cmd = join(' ', 'az network lb create', '--resource-group', $args{resource_group}, @@ -340,7 +350,7 @@ sub az_network_lb_create { '--vnet-name', $args{vnet}, '--subnet', $args{snet}, '--backend-pool-name', $args{backend}, - '--frontend-ip-name', $args{frontend_ip}, + '--frontend-ip-name', $args{frontend_ip_name}, $fip_cmd); assert_script_run($az_cmd); } @@ -555,6 +565,66 @@ sub az_vm_create { assert_script_run($az_cmd, timeout => 600); } +=head2 az_vm_name_get + + my $ret = az_vm_name_get(resource_group => 'openqa-rg'); + +Get the name of all existing VMs within a Resource groups + +=over 1 + +=item B - existing resource group where to create the network + +=back +=cut + +sub az_vm_name_get { + my (%args) = @_; + croak("Argument < resource_group > missing") unless $args{resource_group}; + my $az_cmd = join(' ', + 'az vm list', + "-g $args{resource_group}", + '--query "[].name"', + '-o json'); + return decode_json(script_output($az_cmd)); +} + +=head2 az_vm_instance_view_get + + my $res = az_vm_instance_view_get( + resource_group => 'openqa-rg', + name => 'openqa-vm') + +Get some details of a specific VM + +Json output looks like: + +[ + "PowerState/running", + "VM running" +] + +=over 2 + +=item B - existing resource group where to create the VM + +=item B - name of an existing virtual machine + +=back +=cut + +sub az_vm_instance_view_get { + my (%args) = @_; + foreach (qw(resource_group name)) { + croak("Argument < $_ > missing") unless $args{$_}; } + my $az_cmd = join(' ', + 'az vm get-instance-view', + '--name', $args{name}, + '--resource-group', $args{resource_group}, + '--query "instanceView.statuses[1].[code,displayStatus]"'); + return decode_json(script_output($az_cmd)); +} + =head2 az_vm_openport az_vm_openport( diff --git a/lib/sles4sap/ipaddr2.pm b/lib/sles4sap/ipaddr2.pm index b88f97d7b282..940bef4fd8ec 100644 --- a/lib/sles4sap/ipaddr2.pm +++ b/lib/sles4sap/ipaddr2.pm @@ -120,7 +120,7 @@ sub ipaddr2_azure_deployment { vnet => $vnet, snet => $subnet, backend => $lb_be, - frontend_ip => $lb_fe, + frontend_ip_name => $lb_fe, fip => $lb_feip, sku => 'Standard'); diff --git a/t/21_sles4sap_azure_cli.t b/t/21_sles4sap_azure_cli.t index d82b86049e88..65ff64809ff9 100644 --- a/t/21_sles4sap_azure_cli.t +++ b/t/21_sles4sap_azure_cli.t @@ -25,7 +25,6 @@ subtest '[az_group_create] missing args' => sub { dies_ok { az_group_create(name => 'Arlecchino') } 'Die for missing argument region'; }; - subtest '[az_group_name_get]' => sub { my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); my @calls; @@ -51,6 +50,34 @@ subtest '[az_network_vnet_create]' => sub { ok((any { /az network vnet create/ } @calls), 'Correct composition of the main command'); }; +subtest '[az_network_vnet_create] die on invalid IP' => sub { + my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); + my @calls; + $azcli->redefine(assert_script_run => sub { push @calls, $_[0]; return; }); + + foreach my $arg (qw(address_prefixes subnet_prefixes)) { + foreach my $test_pattern (qw(192.168.0/16 192.168..0/16 192.068.0.0/16 192.168.0.0 192.168.000.000/16 1192.168.0.0/16)) { + dies_ok { az_network_vnet_create( + resource_group => 'Arlecchino', + region => 'Pulcinella', + vnet => 'Pantalone', + snet => 'Colombina', + $arg => $test_pattern) } "Die for invalid IP $test_pattern as argument $arg"; + ok scalar @calls == 0, "No call to assert_script_run, croak before to run the command for invalid IP $test_pattern as argument $arg"; + @calls = (); + } + foreach my $test_pattern (qw(192.168.0.0/16 192.0.0.0/16 2.168.0.0/16)) { + az_network_vnet_create( + resource_group => 'Arlecchino', + region => 'Pulcinella', + vnet => 'Pantalone', + snet => 'Colombina', + $arg => $test_pattern); + ok scalar @calls > 0, "Some calls to assert_script_run for valid IP $test_pattern as argument $arg"; + @calls = (); + } + } +}; subtest '[az_network_nsg_create]' => sub { my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); @@ -126,11 +153,43 @@ subtest '[az_network_lb_create]' => sub { vnet => 'Pantalone', snet => 'Colombina', backend => 'Smeraldina', - frontend_ip => 'Momolo'); + frontend_ip_name => 'Momolo'); + note("\n --> " . join("\n --> ", @calls)); + ok((any { /az network lb create/ } @calls), 'Correct composition of the main command'); +}; + +subtest '[az_network_lb_create] with a fixed IP' => sub { + my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); + my @calls; + $azcli->redefine(assert_script_run => sub { push @calls, $_[0]; return; }); + az_network_lb_create( + resource_group => 'Arlecchino', + name => 'Truffaldino', + vnet => 'Pantalone', + snet => 'Colombina', + backend => 'Smeraldina', + frontend_ip_name => 'Momolo', + fip => '1.2.3.4'); note("\n --> " . join("\n --> ", @calls)); ok((any { /az network lb create/ } @calls), 'Correct composition of the main command'); }; +subtest '[az_network_lb_create] with an invalid fixed IP' => sub { + my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); + my @calls; + $azcli->redefine(assert_script_run => sub { push @calls, $_[0]; return; }); + + dies_ok { az_network_lb_create( + resource_group => 'Arlecchino', + name => 'Truffaldino', + vnet => 'Pantalone', + snet => 'Colombina', + backend => 'Smeraldina', + frontend_ip_name => 'Momolo', + fip => '1.2.3.') } "Die for invalid IP as fip argument"; + ok scalar @calls == 0, "No call to assert_script_run if IP is invalid"; +}; + subtest '[az_vm_as_create]' => sub { my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); my @calls; @@ -181,6 +240,31 @@ subtest '[az_vm_create] with no public IP' => sub { ok((any { /--public-ip-address ""/ } @calls), 'empty Public IP address'); }; +subtest '[az_vm_name_get]' => sub { + my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); + my @calls; + $azcli->redefine(script_output => sub { push @calls, $_[0]; return '["Mirandolina","Truffaldino"]'; }); + + my $res = az_vm_name_get(resource_group => 'Arlecchino'); + + note("\n --> " . join("\n --> ", @calls)); + ok((any { /az vm list/ } @calls), 'Correct composition of the main command'); + ok((any { /-g Arlecchino/ } @calls), 'Correct composition of the -g argument'); + ok((any { /Mirandolina/ } @$res), 'Correct result decoding'); +}; + +subtest '[az_vm_instance_view_get]' => sub { + my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); + my @calls; + $azcli->redefine(script_output => sub { push @calls, $_[0]; return '["PowerState/running","VM running"]'; }); + + my $res = az_vm_instance_view_get(resource_group => 'Arlecchino', name => 'Mirandolina'); + + note("\n --> " . join("\n --> ", @calls)); + ok((any { /az vm get-instance-view/ } @calls), 'Correct composition of the main command'); + ok((any { /VM running/ } @$res), 'Correct result decoding'); +}; + subtest '[az_vm_openport]' => sub { my $azcli = Test::MockModule->new('sles4sap::azure_cli', no_auto => 1); my @calls;