Skip to content
Merged
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
5 changes: 4 additions & 1 deletion agent/05_agent_configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ function add_dns_entry {
fi

# Add entries to etc/hosts for SNO IPV6 to sucessfully run the openshift conformance tests
if [[ $NUM_MASTERS == 1 && $IP_STACK == "v6" ]]; then
# Temp change added to also check v4 in case of SNO for OVE
if [[ $NUM_MASTERS == 1 ]] && [[ $IP_STACK == "v4" || $IP_STACK == "v6" ]]; then
AGENT_NODE0_IPSV6=${ip}
echo "${ip} console-openshift-console.apps.${CLUSTER_DOMAIN}" | sudo tee -a /etc/hosts
echo "${ip} oauth-openshift.apps.${CLUSTER_DOMAIN}" | sudo tee -a /etc/hosts
Expand Down Expand Up @@ -682,7 +683,9 @@ if [[ "${AGENT_E2E_TEST_BOOT_MODE}" != "ISO_NO_REGISTRY" ]] ; then
else
# For ISO_NO_REGISTRY mode with workers, add api-int to libvirt DNS
# Workers need to resolve api-int during bootstrap before joining the cluster
if [[ "${NUM_MASTERS}" > "1" ]]; then
add_dns_entry "${API_VIPS%${VIPS_SEPARATOR}*}" "api-int"
fi
fi

enable_isolated_baremetal_network
2 changes: 1 addition & 1 deletion agent/06_agent_create_cluster.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ function automate_rendezvousIP_selection(){

function check_assisted_install_UI(){
local rendezvousIP=$(getRendezvousIP)
local url="http://$rendezvousIP:3001"
local url="http://$(wrap_if_ipv6 ${rendezvousIP}):3001"
while true; do
if curl -s -o /dev/null -w "%{http_code}" "$url" | grep -q "^200$"; then
echo "Assisted install UI is up: $url"
Expand Down
2 changes: 1 addition & 1 deletion agent/cleanup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ sudo firewall-cmd --zone libvirt --remove-port=${MACHINE_CONFIG_SERVER_PORT}/tcp
sudo firewall-cmd --zone libvirt --remove-port=${KUBE_API_PORT}/tcp
sudo firewall-cmd --zone libvirt --remove-port=${INGRESS_ROUTER_PORT}/tcp

if [[ $NUM_MASTERS == 1 && $IP_STACK == "v6" ]]; then
if [[ $NUM_MASTERS == 1 ]] && [[ $IP_STACK == "v4" || $IP_STACK == "v6" ]]; then
sudo sed -i "/${AGENT_NODE0_IPSV6} console-openshift-console.apps.${CLUSTER_DOMAIN}/d" /etc/hosts
sudo sed -i "/${AGENT_NODE0_IPSV6} oauth-openshift.apps.${CLUSTER_DOMAIN}/d" /etc/hosts
sudo sed -i "/${AGENT_NODE0_IPSV6} thanos-querier-openshift-monitoring.apps.${CLUSTER_DOMAIN}/d" /etc/hosts
Expand Down
7 changes: 6 additions & 1 deletion agent/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function getReleaseImage() {
# If not installing from src, let's use the current version from the binary
elif [ -z "$KNI_INSTALL_FROM_GIT" ]; then
local openshift_install="$(realpath "${OCP_DIR}/openshift-install")"
releaseImage=$("${openshift_install}" --dir="${OCP_DIR}" version | grep "release image" | cut -d " " -f 3)
releaseImage=$("${openshift_install}" --dir="${OCP_DIR}" version | grep "release image" | cut -d " " -f 3)
fi
echo ${releaseImage}
}
Expand All @@ -92,11 +92,16 @@ if [ "${AGENT_E2E_TEST_BOOT_MODE}" == "ISO_NO_REGISTRY" ] ; then
if [[ -z "${NETWORKING_MODE}" ]]; then
export NETWORKING_MODE="DHCP"
fi
export MIRROR_IMAGES=false
fi

function getRendezvousIP() {
node_zero_mac_address=$(sudo virsh domiflist ${AGENT_RENDEZVOUS_NODE_HOSTNAME} | awk '$3 == "ostestbm" {print $5}')
rendezvousIP=$(ip neigh | grep $node_zero_mac_address | awk '{print $1}')
if [[ "${AGENT_E2E_TEST_BOOT_MODE}" == "ISO_NO_REGISTRY" ]] && [[ "${IP_STACK}" == "v6" ]]; then
# Filter out link-local addresses and get global/ULA IPv6
rendezvousIP=$(echo "$rendezvousIP" | tr ' ' '\n' | grep -vE '^fe[89ab][0-9a-f]:' | head -n1)
fi
echo $rendezvousIP | awk '{print $1}'
}

Expand Down
156 changes: 118 additions & 38 deletions agent/isobuilder/ui_driven_cluster_installation/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var (
ipStack = os.Getenv("IP_STACK")
workers = os.Getenv("NUM_WORKERS")
baseURL = fmt.Sprintf("http://%s:3001", rendezvousIP)
clustersURL = fmt.Sprintf("%s%s", baseURL, path.Join("/api/assisted-install/v2/clusters"))
clustersURL = fmt.Sprintf("%s%s", getBaseURL(ipStack, rendezvousIP), path.Join("/api/assisted-install/v2/clusters"))
)

// timestampedPath adds a timestamp to the filename
Expand Down Expand Up @@ -179,7 +179,7 @@ func main() {
browser := rod.New().ControlURL(url).MustConnect()
defer browser.MustClose()

page := browser.MustPage(baseURL)
page := browser.MustPage(getBaseURL(ipStack, rendezvousIP))
page.MustWaitLoad()

cwd, err := os.Getwd()
Expand All @@ -203,18 +203,15 @@ func main() {

// Wait for page to load and check if cluster creation completed in time
logrus.Info("Waiting for operators page to load...")
time.Sleep(3 * time.Second)
wait(10 * time.Second)
reload(page)

// Check if we got an error page because cluster wasn't created in time
errorMsg, _ := page.Timeout(2*time.Second).ElementR("div", "Cluster details not found")
if errorMsg != nil {
logrus.Info("Cluster not ready yet, waiting and reloading...")
// Wait longer for cluster creation to complete
time.Sleep(5 * time.Second)
// Reload the page
page.MustReload()
page.MustWaitLoad()
logrus.Info("Page reloaded, continuing...")
wait(5 * time.Second)
reload(page)
}

logrus.Info("Select virtualization bundle")
Expand Down Expand Up @@ -271,7 +268,7 @@ func main() {
stepNum++

// Wait for page to load
time.Sleep(3 * time.Second)
wait(5 * time.Second)

// Check if we're on Custom manifests page (4.22+) or Review page (< 4.22)
customManifestsHeading, _ := page.Timeout(2*time.Second).ElementR("h2", "Custom manifests")
Expand Down Expand Up @@ -362,7 +359,7 @@ func clusterDetails(page *rod.Page, path string) error {
// Clear template content and enter pull secret
pullSecretField.MustSelectAllText()
pullSecretField.MustInput("")
time.Sleep(500 * time.Millisecond)
wait(500 * time.Millisecond)

pullSecretField.MustInput(`{"auths":{"":{"auth":"dXNlcjpwYXNz"}}}`)
} else {
Expand All @@ -380,7 +377,7 @@ func clusterDetails(page *rod.Page, path string) error {
}

// Allow UI enough time to complete the background API call to create the cluster
time.Sleep(10 * time.Second)
wait(10 * time.Second)
page.MustElement("button[name='next']").MustWaitEnabled()

err = saveFullPageScreenshot(page, timestampedPath(path, "end"))
Expand Down Expand Up @@ -471,12 +468,35 @@ func virtualizationBundle(page *rod.Page, path string) error {
return err
}

checkbox := page.MustElement("#bundle-virtualization")
checkbox.MustScrollIntoView()
checkbox.MustClick()
// Allow UI enough time to complete the background API call
time.Sleep(2 * time.Second)
page.MustElement("button[name='next']").MustWaitEnabled()
if getControlPlaneCount() > 1 {
checkbox := page.MustElement("#bundle-virtualization")
checkbox.MustScrollIntoView()
checkbox.MustClick()
// Allow UI enough time to complete the background API call
wait(5 * time.Second)
} else {
logrus.Info("Looking for Single Operators button (SNO)...")
wait(5 * time.Second)

singleOpsButton, err := page.Timeout(10*time.Second).ElementR("button", "Single Operators")
if err != nil {
return fmt.Errorf("Single Operators button not found: %v", err)
}

err = singleOpsButton.WaitVisible()
if err != nil {
return fmt.Errorf("Single Operators button not visible: %v", err)
}

logrus.Info("Found Single Operators button")
err = selectAllEnabledOperators(page, singleOpsButton)
if err != nil {
return err
}
}

wait(5 * time.Second)
page.MustElement("button[name='next']").MustWaitEnabled().MustScrollIntoView().MustWaitEnabled()

err = saveFullPageScreenshot(page, timestampedPath(path, "end"))
if err != nil {
Expand Down Expand Up @@ -505,6 +525,7 @@ func verifyStorage(page *rod.Page, path string) error {
if err != nil {
return err
}
page.MustElement("button[name='next']").MustWaitEnabled()

err = saveFullPageScreenshot(page, timestampedPath(path, "end"))
if err != nil {
Expand All @@ -522,35 +543,42 @@ func networkingDetails(page *rod.Page, path string) error {
apiVip := apiVips
ingressVip := ingressVips

if ipStack == "v4v6" {
if ipStack == "v4" {
page.MustElement("#form-radio-stackType-singleStack-field")
logrus.Info("Selected IPV4 networking stack")
if getControlPlaneCount() == 1 {
logrus.Infof("Using default single-stack IPv4 networking (IP_STACK=%s) for SNO", ipStack)
}
} else if ipStack == "v4v6" {
dualStackRadio := page.MustElement("#form-radio-stackType-dualStack-field")
logrus.Info("Selected dualstack networking stack")
dualStackRadio.MustClick()
err = saveFullPageScreenshot(page, timestampedPath(path, "after-dualstack"))
if err != nil {
return err
}
apiVip = strings.Split(apiVips, ",")[0]
ingressVip = strings.Split(ingressVips, ",")[0]
} else {
logrus.Infof("Using default single-stack IPv4 networking (IP_STACK=%s)", ipStack)
}

apiVipField := page.MustElement("#form-input-apiVips-0-ip-field")
apiVipField.MustWaitVisible()
apiVipField.MustInput(apiVip)
if getControlPlaneCount() > 1 {
apiVipField := page.MustElement("#form-input-apiVips-0-ip-field")
apiVipField.MustWaitVisible()
apiVipField.MustInput(apiVip)

err = saveFullPageScreenshot(page, timestampedPath(path, "after-apivip"))
if err != nil {
return err
}
err = saveFullPageScreenshot(page, timestampedPath(path, "after-apivip"))
if err != nil {
return err
}

ingressVipField := page.MustElement("#form-input-ingressVips-0-ip-field")
ingressVipField.MustWaitVisible()
ingressVipField.MustInput(ingressVip)
ingressVipField := page.MustElement("#form-input-ingressVips-0-ip-field")
ingressVipField.MustWaitVisible()
ingressVipField.MustInput(ingressVip)

err = saveFullPageScreenshot(page, timestampedPath(path, "after-ingressvip"))
if err != nil {
return err
err = saveFullPageScreenshot(page, timestampedPath(path, "after-ingressvip"))
if err != nil {
return err
}
}

page.MustElement("#form-input-sshPublicKey-field").MustInput(sshPublicKey)
Expand Down Expand Up @@ -586,7 +614,7 @@ func downloadCredentials(page *rod.Page, client *resty.Client, path string) erro
}

page.MustElement("#credentials-download-agreement").MustClick()
time.Sleep(5 * time.Second)
wait(5 * time.Second)

page.MustElementR("button", "Download credentials").MustWaitEnabled().MustClick()

Expand Down Expand Up @@ -645,7 +673,7 @@ func waitForClusterConsoleLink(page *rod.Page, path string) error {
return err
}
i++
time.Sleep(5 * time.Minute)
wait(5 * time.Minute)
}

return nil
Expand Down Expand Up @@ -718,7 +746,7 @@ func saveCredentials(client *resty.Client, url, filename string) error {
logrus.Infof("%s download attempts %d/%d", filename, i+1, downloadAttempts)
resp, err := client.R().Get(fileURL)
if err != nil || resp.StatusCode() != http.StatusOK {
time.Sleep(10 * time.Second)
wait(10 * time.Second)
continue
}
if resp.StatusCode() == http.StatusOK {
Expand Down Expand Up @@ -796,7 +824,7 @@ func runDownloadLogs() {
defer browser.MustClose()

// Navigate to base URL - UI will redirect to current cluster
page := browser.MustPage(baseURL)
page := browser.MustPage(getBaseURL(ipStack, rendezvousIP))
page.MustWaitLoad()

logrus.Info("Connected to Assisted Installer UI")
Expand All @@ -814,3 +842,55 @@ func runDownloadLogs() {

logrus.Info("Download-logs mode complete")
}

func wait(timeToWait time.Duration) {
logrus.Infof("Waiting for %s ...", timeToWait)
time.Sleep(timeToWait)
}

func reload(page *rod.Page) {
page.MustReload()
page.MustWaitLoad()
logrus.Info("Page reloaded, continuing...")
}

func selectAllEnabledOperators(page *rod.Page, expandButton *rod.Element) error {
expandButton.MustWaitStable()
logrus.Info("Single Operators button is stable")

ariaExpanded, _ := expandButton.Attribute("aria-expanded")
if ariaExpanded == nil || *ariaExpanded == "false" {
logrus.Info("Expanding Single Operators section...")
expandButton.MustClick()

// Wait for expansion animation
wait(1 * time.Second)

logrus.Info("Single Operators section expanded")
} else {
logrus.Info("Single Operators section already expanded")
}

// Select all enabled, unchecked checkboxes
checkboxes := page.MustElements(`input[data-testid^="operator-checkbox-"]:not([disabled])`)
logrus.Infof("Found %d enabled checkboxes", len(checkboxes))

for i, checkbox := range checkboxes {
checked, _ := checkbox.Property("checked")
if !checked.Bool() {
checkbox.MustClick()
logrus.Infof("Checked checkbox %d", i+1)
wait(100 * time.Millisecond)
}
}

logrus.Info("All enabled operators selected")
return nil
}

func getBaseURL(ipStack, rendezvousIP string) string {
if ipStack == "v6" {
return fmt.Sprintf("http://[%s]:3001", rendezvousIP)
}
return fmt.Sprintf("http://%s:3001", rendezvousIP)
}
2 changes: 1 addition & 1 deletion network.sh
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ function configure_dnsmasq() {
rm -f "${PATH_CONF_DNSMASQ}"

add_dnsmasq_multi_entry "apivip" "${apiVips}"
if [[ "${AGENT_E2E_TEST_BOOT_MODE}" == "ISO_NO_REGISTRY" ]] ; then
if [[ ${AGENT_E2E_TEST_BOOT_MODE} == "ISO_NO_REGISTRY" ]] && [[ "${NUM_MASTERS}" > "1" ]]; then
add_dnsmasq_multi_entry "apiintvip" "${apiVips}"
fi
add_dnsmasq_multi_entry "ingressvip" "${ingressVips}"
Expand Down