Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions agent/gather.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
93 changes: 93 additions & 0 deletions agent/isobuilder/ui_driven_cluster_installation/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
Expand All @@ -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")
Expand All @@ -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()

Expand Down Expand Up @@ -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")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if these logs are already sanitized/redacted by AS?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔
The pull secret is redacted from metadata.json apparently.
Looking at agent-gather, we also redact:

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")
}