diff --git a/agent/gather.sh b/agent/gather.sh index 201cc890e..2dfc0207f 100755 --- a/agent/gather.sh +++ b/agent/gather.sh @@ -5,14 +5,15 @@ set -euxo pipefail SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" source "$SCRIPTDIR"/common.sh +source "$SCRIPTDIR"/agent/common.sh -while read line +while read -r line do ip=$( echo "$line" | cut -d " " -f 1) host=$( echo "$line" | cut -d " " -f 2) echo "Trying to gather agent logs on host ${host}" if ssh -n -o 'ConnectTimeout=30' -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' core@"${ip}" agent-gather -O >agent-gather-"${host}".tar.xz; then - echo "Agent logs saved to agent-gather-"${host}".tar.xz" >&2 + echo "Agent logs saved to agent-gather-${host}.tar.xz" >&2 else if [ $? == 127 ]; then echo "Skipping gathering agent logs, agent-gather script not present on host ${host}." >&2 @@ -23,15 +24,40 @@ done < "${OCP_DIR}"/hosts num_tui_screenshots=$(find "${OCP_DIR}" -type f -name "*.ppm" | wc -l) num_ui_screenshots=$(find "${OCP_DIR}" -type f -name "*.png" | wc -l) -num_screenshots=$(($num_tui_screenshots + $num_ui_screenshots)) +num_screenshots=$((num_tui_screenshots + num_ui_screenshots)) if [[ "$num_screenshots" -gt 0 ]]; then archive_name="agent-gather-console-screenshots.tar.xz" echo "Gathering screenshots to $archive_name" + + # Attempt to download installation logs from the UI + if [[ "${AGENT_E2E_TEST_BOOT_MODE}" == "ISO_NO_REGISTRY" ]]; then + echo "Attempting to download installation logs from Assisted Installer UI" + rendezvousIP=$(getRendezvousIP) + ocp_dir_abs_path="$(realpath "${OCP_DIR}")" + + pushd agent/isobuilder/ui_driven_cluster_installation + RENDEZVOUS_IP=$rendezvousIP OCP_DIR=$ocp_dir_abs_path go run main.go --download-logs || true + popd + fi + + # Build list of files to archive + files_to_archive=() + + # Always include TUI screenshots + files_to_archive+=("${OCP_DIR}"/*.ppm) + + # Include UI screenshots if in ISO_NO_REGISTRY mode if [[ "${AGENT_E2E_TEST_BOOT_MODE}" == "ISO_NO_REGISTRY" ]] && compgen -G "${OCP_DIR}/*.png" > /dev/null; then - tar -cJf $archive_name ${OCP_DIR}/*.ppm ${OCP_DIR}/*.png - else - tar -cJf $archive_name ${OCP_DIR}/*.ppm + files_to_archive+=("${OCP_DIR}"/*.png) fi + + # Include installation logs if available + if [[ -f "${OCP_DIR}/installation-logs.tar" ]]; then + files_to_archive+=("${OCP_DIR}/installation-logs.tar") + fi + + # Create archive with all collected files + tar -cJf $archive_name "${files_to_archive[@]}" else echo "No screenshots found. Skipping screenshot gather." fi diff --git a/agent/isobuilder/ui_driven_cluster_installation/main.go b/agent/isobuilder/ui_driven_cluster_installation/main.go index 1ade00eca..9a1c8bb7b 100644 --- a/agent/isobuilder/ui_driven_cluster_installation/main.go +++ b/agent/isobuilder/ui_driven_cluster_installation/main.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "flag" "fmt" "log" "net/http" @@ -26,6 +27,7 @@ import ( ) var ( + downloadLogsFlag = flag.Bool("download-logs", false, "Download installation logs from UI and exit") clusterName = os.Getenv("CLUSTER_NAME") baseDomain = os.Getenv("BASE_DOMAIN") rendezvousIP = os.Getenv("RENDEZVOUS_IP") @@ -41,6 +43,16 @@ var ( ) func main() { + // Parse command-line flags + flag.Parse() + + // Check if download-logs mode requested + if *downloadLogsFlag { + runDownloadLogs() + return + } + + // Default mode: perform installation logrus.Info("Launching headless browser...") logConfiguration() @@ -462,3 +474,84 @@ func saveCredentials(client *resty.Client, url, filename string) error { } return errs.Errorf("%s was not downloaded after %d attempts", filename, downloadAttempts) } + +// downloadInstallationLogs downloads installation logs by clicking the download button +func downloadInstallationLogs(browser *rod.Browser, page *rod.Page) error { + logrus.Info("Attempting to download installation logs") + + // Check if ocpDir is set + if ocpDir == "" { + logrus.Warn("OCP_DIR not set, cannot download installation logs") + return errors.New("OCP_DIR environment variable not set") + } + + // OCP_DIR should already exist (created during installation) + // But ensure it exists just in case + if err := os.MkdirAll(ocpDir, 0755); err != nil { + return fmt.Errorf("failed to create OCP directory %s: %w", ocpDir, err) + } + + // Find the download button - case-insensitive search + downloadBtn, err := page.Timeout(10*time.Second).ElementR("button", "(?i)Download installation logs") + if err != nil { + logrus.Warnf("Could not find download logs button: %v", err) + return err + } + + if visible, _ := downloadBtn.Visible(); !visible { + logrus.Warn("Download logs button not visible") + return errors.New("download logs button not visible") + } + + // Set up download handler before clicking + wait := browser.MustWaitDownload() + + // Click the download button + logrus.Info("Clicking download logs button") + downloadBtn.MustClick() + + // Wait for download to complete and get the downloaded bytes + downloadData := wait() + + // Save to OCP_DIR alongside screenshots + logFile := filepath.Join(ocpDir, "installation-logs.tar") + logrus.Infof("Saving installation logs to %s", logFile) + + err = os.WriteFile(logFile, downloadData, 0644) + if err != nil { + return fmt.Errorf("failed to save logs to %s: %w", logFile, err) + } + + logrus.Infof("Installation logs saved successfully to %s", logFile) + return nil +} + +// runDownloadLogs connects to the UI and downloads installation logs if available +func runDownloadLogs() { + logrus.Info("Running in download-logs mode") + + // Launch browser + chromiumPath, _ := launcher.LookPath() + url := launcher.New().Bin(chromiumPath).NoSandbox(true).Headless(true).MustLaunch() + browser := rod.New().ControlURL(url).MustConnect() + defer browser.MustClose() + + // Navigate to base URL - UI will redirect to current cluster + page := browser.MustPage(baseURL) + page.MustWaitLoad() + + logrus.Info("Connected to Assisted Installer UI") + + // The download button is only available on certain pages (e.g., Installation Progress) + // The page may be on cluster details, progress, or completion page + // Best effort: try to download logs from wherever we are + if err := downloadInstallationLogs(browser, page); err != nil { + logrus.Warnf("Could not download installation logs: %v", err) + // Not a fatal error - button may not be visible on current page + // or logs may not be ready yet + } else { + logrus.Info("Installation logs downloaded successfully") + } + + logrus.Info("Download-logs mode complete") +}