diff --git a/data/elemental3/build-tpl.tar.gz b/data/elemental3/build-tpl.tar.gz index 0620b027a73e..337c19c01224 100644 Binary files a/data/elemental3/build-tpl.tar.gz and b/data/elemental3/build-tpl.tar.gz differ diff --git a/data/elemental3/build-tpl_recovery.tar.gz b/data/elemental3/build-tpl_recovery.tar.gz new file mode 100644 index 000000000000..52d611b54648 Binary files /dev/null and b/data/elemental3/build-tpl_recovery.tar.gz differ diff --git a/tests/elemental3/elemental_boot.pm b/tests/elemental3/elemental_boot.pm index 661ee8161f29..8845b091bf6c 100644 --- a/tests/elemental3/elemental_boot.pm +++ b/tests/elemental3/elemental_boot.pm @@ -9,6 +9,7 @@ use testapi; use lockapi; use mm_network qw(configure_hostname setup_static_mm_network); use serial_terminal qw(select_serial_terminal); +use power_action_utils qw(power_action); sub run { my ($self) = @_; @@ -23,6 +24,16 @@ sub run { wait_still_screen; } + # This ISO image does not install anything + # It is just the basic container that should be used with 'customize' command + if (check_var('TESTED_CMD', 'extract_iso')) { + # Just validate that the OS boot, no more + assert_screen('elemental3-tty1-selected', timeout => 120); + wait_still_screen; + record_info('ISO', 'ISO image booted!'); + return; + } + # OS installation is done automatically as well as the reboot after installation # We just have to wait for the VM to reboot $self->wait_grub(bootloader_time => bmwqemu::scale_timeout(300)); @@ -52,6 +63,30 @@ sub run { my $sys_state = script_output('systemctl is-system-running --wait', timeout => 240, proceed_on_failure => 1); die("Wrong OS state: $sys_state") unless ($sys_state =~ m/running/); } + + # Test reboot in recovery mode + if (check_var('TESTED_CMD', 'customize_recovery')) { + power_action('reboot', keepconsole => 1, textmode => 1); + + # Select SUT for bootloader + select_console('sut'); + + # Wait for GRUB + $self->wait_grub(); + + # Choose entry to test + send_key_until_needlematch('elemental3-bootmenu-recovery', 'down'); + send_key('ret', wait_screen_change => 1); + wait_still_screen(timeout => 120); + + # In recovery mode we have auto-login configured on tty1 + console('root-console')->set_tty(1); + select_console('root-console'); + + # Check for recovery boot option + assert_script_run('grep -q recovery /proc/cmdline'); + record_info('RECOVERY', 'Booted in recovery mode!'); + } } sub test_flags { diff --git a/tests/elemental3/generate_image.pm b/tests/elemental3/generate_image.pm index a0981ef359f4..6f049652e172 100644 --- a/tests/elemental3/generate_image.pm +++ b/tests/elemental3/generate_image.pm @@ -15,44 +15,66 @@ use serial_terminal qw(select_serial_terminal); use Mojo::File qw(path); use utils qw(file_content_replace); -=head2 get_sysext +=head2 build_installer_cmd - get_sysext( timeout => ); + build_installer cmd( img_filename => , k8s => , + rootpwd => , timeout => , + type => ); -Get systemd system extensions from SYSEXT_IMAGES_TO_TEST list and -prepare them to be used by elemental tool. +Create an OS image with `build-installer` command by using the specified +containerized OS image. =cut -sub get_sysext { +sub build_installer_cmd { my (%args) = @_; + my $image = get_required_var('CONTAINER_IMAGE_TO_TEST'); + my $krnlcmdline = get_var('KERNEL_CMD_LINE'); + my $isocmdline = get_var('ISO_CMD_LINE'); my $shared_dir = '/root/shared'; - my $overlay_dir = "$shared_dir/overlays"; - my $sysext_dir = "$overlay_dir/etc/extensions"; - my $ctl_oci; + my $config_file = "$shared_dir/config.sh"; + my $iso_config_file = "$shared_dir/config-iso.sh"; + my $device = get_var('INSTALL_DISK', '/dev/vda'); - record_info('SYSEXT', 'Download and configure systemd system extensions'); + # Configure the systemd sysexts + my ($overlay_dir, $ctl_oci) = get_sysext(timeout => $args{timeout}); - # Create directories - assert_script_run("mkdir -p $sysext_dir"); + # OS configuration script + assert_script_run( + "curl -sf -o $config_file " + . data_url('elemental3/' . path($config_file)->basename) + ); + file_content_replace( + $config_file, + '--sed-modifier' => 'g', + '%TEST_PASSWORD%' => $args{rootpwd}, + '%K8S%' => $args{k8s} + ); + assert_script_run("chmod 755 $config_file"); - # Get the system extensions - foreach my $img (split(/,/, get_required_var('SYSEXT_IMAGES_TO_TEST'))) { - assert_script_run( - "elemental3ctl --debug unpack-image --image ${img} --target ${sysext_dir}", - timeout => $args{timeout} - ); - $ctl_oci = $img if ($img =~ /\/elemental3ctl:/); - } + # ISO configuration script + assert_script_run( + "curl -sf -o $iso_config_file " + . data_url('elemental3/' . path($iso_config_file)->basename) + ); + assert_script_run("chmod 755 $iso_config_file"); - # Return systemd-sysexts file name - return ($overlay_dir, $ctl_oci); + record_info('ISO', 'Generate and upload ISO image'); + + # Generate OS image + assert_script_run( +"elemental3ctl --debug build-installer --type $args{type} --output . --name $args{img_filename} --os-image $image --cmdline '$isocmdline' --config $iso_config_file --overlay oci://$ctl_oci --install-overlay dir://$overlay_dir --install-config $config_file --install-cmdline '$krnlcmdline' --install-target $device", + timeout => $args{timeout} + ); + + # Return ISO image + return ("$args{img_filename}.iso"); } =head2 customize_cmd - customize_cmd( hddsize => , k8s => , timeout => , - rootpwd => ); + customize_cmd( hddsize => , k8s => , rootpwd => , + template => , timeout => ); Create an OS image with `customize` command by using the specified release-manifest. @@ -61,21 +83,22 @@ release-manifest. sub customize_cmd { my (%args) = @_; - my $build_dir = '/root/build'; my $crypto_policy = get_var('CRYPTO_POLICY'); my $device = get_var('INSTALL_DISK', '/dev/vda'); my $krnlcmdline = get_var('KERNEL_CMD_LINE'); my $manifest_uri = get_required_var('RELEASE_MANIFEST_URI'); - my $out = "$args{img_filename}.iso"; - my $tpl_tar = "$build_dir/build-tpl.tar.gz"; my $type = get_required_var('IMAGE_TYPE'); + my $build_dir = '/root/build'; + my $tpl_tar = "$build_dir/$args{template}"; + my $initial_hddsize = '4'; + my $out = "$args{img_filename}.iso"; # Create directories assert_script_run("mkdir -p $build_dir"); # Download build configuration files assert_script_run( - "curl -s -o $tpl_tar " + "curl -sf -o $tpl_tar " . data_url('elemental3/' . path($tpl_tar)->basename) ); assert_script_run("tar xzvf $tpl_tar -C $build_dir"); @@ -95,7 +118,7 @@ sub customize_cmd { "$build_dir/install.yaml", '--sed-modifier' => 'g', '%CRYPTO_POLICY%' => $crypto_policy, - '%HDDSIZE%' => $args{hddsize}, + '%HDDSIZE%' => $initial_hddsize, '%INSTALL_DISK%' => $device, '%KERNEL_CMD_LINE%' => $krnlcmdline ); @@ -105,6 +128,13 @@ sub customize_cmd { '%RELEASE_MANIFEST_URI%' => $manifest_uri, '%K8S%' => $args{k8s} ); + if (check_var('TESTED_CMD', 'customize_recovery')) { + file_content_replace( + "$build_dir/custom/scripts/50-firstboot.sh", + '--sed-modifier' => 'g', + '%INSTALL_DISK%' => $device, + ); + } # Generate OS image assert_script_run( @@ -113,73 +143,82 @@ sub customize_cmd { ); # Convert RAW to QCOW2 if needed + # NOTE: './' is needed in front of $out as the filename contains a ':' in it if ($type =~ m/raw/) { assert_script_run( "qemu-img convert -p -f raw -O qcow2 uc_image.$type ./$out", timeout => $args{timeout} ); + + # Extend HDD image to needed size + assert_script_run( + "qemu-img resize ./$out $args{hddsize}G", + timeout => $args{timeout} + ); } elsif ($type =~ m/iso/) { assert_script_run("mv uc_image.$type '$out'"); } - # Return HDD image + # Return OS image return ($out); } -=head2 build_installer_cmd +=head2 extract_iso - build_installer cmd( img_filename => , k8s => , - rootpwd => , timeout => , - type => ); + extract_iso( img_filename => , timeout => ); -Create an OS image with `build-installer` command by using the specified -containerized OS image. +Extract ISO image from container. =cut -sub build_installer_cmd { +sub extract_iso { my (%args) = @_; my $image = get_required_var('CONTAINER_IMAGE_TO_TEST'); - my $krnlcmdline = get_var('KERNEL_CMD_LINE'); - my $isocmdline = get_var('ISO_CMD_LINE'); - my $shared_dir = '/root/shared'; - my $config_file = "$shared_dir/config.sh"; - my $iso_config_file = "$shared_dir/config-iso.sh"; - my $device = get_var('INSTALL_DISK', '/dev/vda'); + my $iso = get_required_var('ISO_IMAGE_TO_TEST'); + my $runtime = get_required_var('CONTAINER_RUNTIMES'); + my $out = "$args{img_filename}.iso"; - # Configure the systemd sysexts - my ($overlay_dir, $ctl_oci) = get_sysext(timeout => $args{timeout}); + assert_script_run("$runtime pull $image"); + my $run_id = script_output("$runtime run -d $image"); + assert_script_run("$runtime cp ${run_id}:/iso/${iso} ."); + assert_script_run("mv $iso '$out'"); - # OS configuration script - assert_script_run( - "curl -s -o $config_file " - . data_url('elemental3/' . path($config_file)->basename) - ); - file_content_replace( - $config_file, - '--sed-modifier' => 'g', - '%TEST_PASSWORD%' => $args{rootpwd}, - '%K8S%' => $args{k8s} - ); - assert_script_run("chmod 755 $config_file"); + # Return OS image + return ($out); +} - # ISO configuration script - assert_script_run( - "curl -s -o $iso_config_file " - . data_url('elemental3/' . path($iso_config_file)->basename) - ); - assert_script_run("chmod 755 $iso_config_file"); +=head2 get_sysext - record_info('ISO', 'Generate and upload ISO image'); + get_sysext( timeout => ); - # Generate OS image - assert_script_run( -"elemental3ctl --debug build-installer --type $args{type} --output . --name $args{img_filename} --os-image $image --cmdline '$isocmdline' --config $iso_config_file --overlay oci://$ctl_oci --install-overlay dir://$overlay_dir --install-config $config_file --install-cmdline '$krnlcmdline' --install-target $device", - timeout => $args{timeout} - ); +Get systemd system extensions from SYSEXT_IMAGES_TO_TEST list and +prepare them to be used by elemental tool. - # Return ISO image - return ("$args{img_filename}.iso"); +=cut + +sub get_sysext { + my (%args) = @_; + my $shared_dir = '/root/shared'; + my $overlay_dir = "$shared_dir/overlays"; + my $sysext_dir = "$overlay_dir/etc/extensions"; + my $ctl_oci; + + record_info('SYSEXT', 'Download and configure systemd system extensions'); + + # Create directories + assert_script_run("mkdir -p $sysext_dir"); + + # Get the system extensions + foreach my $img (split(/,/, get_required_var('SYSEXT_IMAGES_TO_TEST'))) { + assert_script_run( + "elemental3ctl --debug unpack-image --image ${img} --target ${sysext_dir}", + timeout => $args{timeout} + ); + $ctl_oci = $img if ($img =~ /\/elemental3ctl:/); + } + + # Return systemd-sysexts file name + return ($overlay_dir, $ctl_oci); } =head2 install_cmd @@ -207,7 +246,7 @@ sub install_cmd { # OS configuration script assert_script_run( - "curl -s -o $config_file " + "curl -sf -o $config_file " . data_url('elemental3/' . path($config_file)->basename) ); file_content_replace( @@ -242,8 +281,8 @@ sub run { my $k8s = get_required_var('K8S'); my $hddsize = get_var('HDDSIZEGB', '30'); my $rootpwd = get_required_var('TEST_PASSWORD'); - my $build = get_required_var('BUILD'); my $img_filename = get_required_var('IMG_NAME'); + my $tpl_file = get_var('TEMPLATE', 'build-tpl.tar.gz'); my $timeout = 900; my $out_file; @@ -266,33 +305,36 @@ sub run { my $hashpwd = script_output("openssl passwd -6 $rootpwd"); # Create HDD image with different commands - $out_file = customize_cmd( - timeout => $timeout, + $out_file = build_installer_cmd( + img_filename => $img_filename, k8s => $k8s, - hddsize => $hddsize, rootpwd => $hashpwd, - build => $build, - img_filename => $img_filename - ) if check_var('TESTED_CMD', 'customize'); - - $out_file = build_installer_cmd( timeout => $timeout, + type => 'iso' + ) if (check_var('TESTED_CMD', 'build_installer_iso')); + + $out_file = customize_cmd( + hddsize => $hddsize, + img_filename => $img_filename, k8s => $k8s, - type => 'iso', rootpwd => $hashpwd, - build => $build, - img_filename => $img_filename - ) if check_var('TESTED_CMD', 'build_installer_iso'); + template => $tpl_file, + timeout => $timeout + ) if (check_var('TESTED_CMD', 'customize') || check_var('TESTED_CMD', 'customize_recovery')); + + $out_file = extract_iso( + img_filename => $img_filename, + timeout => $timeout + ) if (check_var('TESTED_CMD', 'extract_iso')); $out_file = install_cmd( - timeout => $timeout, arch => $arch, - k8s => $k8s, hddsize => $hddsize, + img_filename => $img_filename, + k8s => $k8s, rootpwd => $hashpwd, - build => $build, - img_filename => $img_filename - ) if check_var('TESTED_CMD', 'install'); + timeout => $timeout, + ) if (check_var('TESTED_CMD', 'install')); # Upload OS image upload_asset("$out_file", 1); diff --git a/tests/elemental3/set_global_variables.pm b/tests/elemental3/set_global_variables.pm index 1765291dda4d..65e712ef6a83 100644 --- a/tests/elemental3/set_global_variables.pm +++ b/tests/elemental3/set_global_variables.pm @@ -11,16 +11,16 @@ use serial_terminal qw(select_serial_terminal); =head2 get_values - get_values( filelist => , regex => ); + get_values( txt => , regex => ); -Get values from the list of files based on defined regex. +Get values from text based on defined regex. =cut sub get_values { my (%args) = @_; - return ($&, $1, $2) if ($args{filelist} =~ m/$args{regex}/); + return ($&, $1, $2) if ($args{txt} =~ m/$args{regex}/); } =head2 get_uri @@ -41,10 +41,17 @@ sub get_uri { sub run { my $arch = get_required_var('ARCH'); my $k8s = get_required_var('K8S'); - my $kernel = 'beta-uc-uc-base-os-kernel-' . get_required_var('KERNEL_TYPE') . '-' . get_required_var('VERSION'); + my $os_version = get_required_var('VERSION'); + my $kernel_type = get_var('KERNEL_TYPE'); + my $kernel = "base-os-kernel-${kernel_type}-${os_version}"; my $totest_path = get_required_var('TOTEST_PATH'); my $uc_version = get_required_var('UC_VERSION'); + # This is to test the ISO container:w + if (check_var('TESTED_CMD', 'extract_iso')) { + $kernel = "base-kernel-${kernel_type}-iso-${os_version}"; + } + # No GUI, easier and quicker to use the serial console select_serial_terminal(); @@ -55,30 +62,46 @@ sub run { my $files_list = script_output("curl -s ${totest_path}/containers/ | sed -n '/alt=\"\\[\\([[:blank:]]*\\|TXT\\)\\]/s/.*href=\"\\(.*\\)\">.*/\\1/gp' | sort -ur"); # Export RELEASE_MANIFEST_URI - my $manifest_regex = "beta-uc-release-manifest-${uc_version}_${k8s}_\(.*\)-\(.*\).${arch}-.*.registry.txt"; - my ($file, $version, $build) = get_values(filelist => ${files_list}, regex => ${manifest_regex}); + my $manifest_regex = ".*release-manifest-${uc_version}_${k8s}_\(.*\)-\(.*\).${arch}-.*.registry.txt"; + my ($file, $version, $build) = get_values(txt => ${files_list}, regex => ${manifest_regex}); my $k8s_version = $version; my $release_manifest_uri = get_uri(file => "${totest_path}/containers/${file}", regex => "pull\\s+\(.*:${uc_version}_${k8s}_${k8s_version}-${build}\)"); set_var('RELEASE_MANIFEST_URI', "$release_manifest_uri"); # Export SYSEXT_IMAGES_TO_TEST - my $elemental3ctl_regex = "beta-uc-elemental3ctl-${uc_version}_\(.*\)-\(.*\).${arch}-.*.registry.txt"; - ($file, $version, $build) = get_values(filelist => ${files_list}, regex => ${elemental3ctl_regex}); + my $elemental3ctl_regex = ".*elemental3ctl-${uc_version}_\(.*\)-\(.*\).${arch}-.*.registry.txt"; + ($file, $version, $build) = get_values(txt => ${files_list}, regex => ${elemental3ctl_regex}); my $elemental3ctl_uri = get_uri(file => "${totest_path}/containers/${file}", regex => "pull\\s+\(.*:${uc_version}_${version}-${build}\)"); - my $k8s_regex = "beta-uc-${k8s}-${k8s_version}_\(.*\)-\(.*\).${arch}-.*.registry.txt"; - ($file, $version, $build) = get_values(filelist => ${files_list}, regex => ${k8s_regex}); + my $k8s_regex = ".*${k8s}-${k8s_version}_\(.*\)-\(.*\).${arch}-.*.registry.txt"; + ($file, $version, $build) = get_values(txt => ${files_list}, regex => ${k8s_regex}); my $k8s_uri = get_uri(file => "${totest_path}/containers/${file}", regex => "pull\\s+\(.*:${k8s_version}_${version}-${build}\)"); set_var('SYSEXT_IMAGES_TO_TEST', "${elemental3ctl_uri},${k8s_uri}"); # Export CONTAINER_IMAGE_TO_TEST - my $kernel_regex = "${kernel}-\(.*\).${arch}-.*.registry.txt"; - ($file, $build) = get_values(filelist => ${files_list}, regex => ${kernel_regex}); - my $container_uri = get_uri(file => "${totest_path}/containers/${file}", regex => "pull\\s+\(.*:" . get_required_var('VERSION') . "-${build}\)"); + my $kernel_regex = ".*${kernel}-\(.*\).${arch}-.*.registry.txt"; + ($file, $build) = get_values(txt => ${files_list}, regex => ${kernel_regex}); + my $container_uri = get_uri(file => "${totest_path}/containers/${file}", regex => "pull\\s+\(.*:${os_version}-${build}\)"); set_var('CONTAINER_IMAGE_TO_TEST', "$container_uri"); # Export REPO_TO_TEST set_var('REPO_TO_TEST', "$totest_path/standard"); + + # Export ISO_IMAGE_TO_TEST + if (check_var('TESTED_CMD', 'extract_iso')) { + my $iso_regex = ".*/\(.*\):.*-\(.*\)"; + my (undef, $name, $build) = get_values(txt => ${container_uri}, regex => ${iso_regex}); + if ($name eq '' || $build eq '') { + record_info('ISO_IMAGE_TO_TEST', 'Required variable cannot be set!', result => 'fail'); + die('Required variable not set'); + } + set_var('ISO_IMAGE_TO_TEST', "${name}.${arch}-${os_version}-Build${build}.iso"); + } + + # Logs, could be useful for debugging purporses + foreach my $v ('SYSEXT_IMAGES_TO_TEST', 'RELEASE_MANIFEST_URI', 'CONTAINER_IMAGE_TO_TEST', 'REPO_TO_TEST', 'ISO_IMAGE_TO_TEST') { + record_info("$v", get_var("$v")); + } } sub test_flags { diff --git a/tests/elemental3/start_k8s.pm b/tests/elemental3/start_k8s.pm index ee87fda88acc..964f8e33db47 100644 --- a/tests/elemental3/start_k8s.pm +++ b/tests/elemental3/start_k8s.pm @@ -195,7 +195,7 @@ sub prepare_test_framework { # Framework configuration files foreach my $file ('/tmp/env', '/tmp/tfvars') { assert_script_run( - "curl -s -o $file " + "curl -sf -o $file " . data_url('elemental3/test-framework/' . path($file)->basename) ); file_content_replace( @@ -224,11 +224,19 @@ sub prepare_test_framework { } sub run { + my ($self) = @_; my $arch = get_required_var('ARCH'); my $k8s = get_required_var('K8S'); my $k8s_dir = "/etc/rancher/$k8s"; my $config_yaml = "$k8s_dir/config.yaml"; + # Skip the test with simple ISO container + if (check_var('TESTED_CMD', 'extract_iso')) { + record_info('SKIP', 'Skip test - No K8s installed in this basic container image'); + $self->result('skip'); + return; + } + # Set default root password $testapi::password = get_required_var('TEST_PASSWORD'); diff --git a/tests/elemental3/test_framework.pm b/tests/elemental3/test_framework.pm index 2f5036589f30..45ebdbff5ef4 100644 --- a/tests/elemental3/test_framework.pm +++ b/tests/elemental3/test_framework.pm @@ -33,8 +33,8 @@ sub run { my $ssh_dir = '/root/.ssh'; record_info('SSH config', 'Configure password-less SSH access'); assert_script_run("mkdir -p $ssh_dir"); - assert_script_run("curl -s -o $ssh_dir/config " . data_url('elemental3/config.ssh')); - assert_script_run("curl -s -o /tmp/id_ssh " . data_url('elemental3/id_ssh')); + assert_script_run("curl -sf -o $ssh_dir/config " . data_url('elemental3/config.ssh')); + assert_script_run("curl -sf -o /tmp/id_ssh " . data_url('elemental3/id_ssh')); assert_script_run("base64 -d /tmp/id_ssh > $ssh_dir/id_rsa"); assert_script_run("chmod -R go-rwx $ssh_dir"); diff --git a/tests/elemental3/validate_toolbox.pm b/tests/elemental3/validate_toolbox.pm index 541d8c504799..d5348a69a38a 100644 --- a/tests/elemental3/validate_toolbox.pm +++ b/tests/elemental3/validate_toolbox.pm @@ -9,13 +9,13 @@ use testapi; use serial_terminal qw(select_serial_terminal); sub run { - my $self = shift; + my ($self) = @_; select_serial_terminal(); # Skip the test in multi-machine mode if (get_var('PARALLEL_WITH')) { - record_info('SKIP', 'Skip test - Network is not up at this stage', result => 'ok'); + record_info('SKIP', 'Skip test - Network is not up at this stage'); $self->result('skip'); return; }