From e7f310569c2bd4d3a7ef64ae65c940ef19766af4 Mon Sep 17 00:00:00 2001 From: Joao Fula Date: Mon, 7 Sep 2026 17:47:55 +0200 Subject: [PATCH 1/2] migrating cluster pool to hypershift clusters migrating cluster pool to hypershift clusters fixing fixing disabling --- .../lightspeed-console-pre-commit.yaml | 140 +++++++----------- tests/support/global-setup.ts | 110 +++++++++++--- 2 files changed, 148 insertions(+), 102 deletions(-) diff --git a/.tekton/integration-tests/lightspeed-console-pre-commit.yaml b/.tekton/integration-tests/lightspeed-console-pre-commit.yaml index a556365ba..d2dfcec8b 100644 --- a/.tekton/integration-tests/lightspeed-console-pre-commit.yaml +++ b/.tekton/integration-tests/lightspeed-console-pre-commit.yaml @@ -37,68 +37,33 @@ spec: value: $(context.pipelineRun.name) - name: ownerUid value: $(context.pipelineRun.uid) - - name: provision-cluster + - name: provision-ephemeral-cluster + taskRef: + resolver: git + params: + - name: url + value: https://github.com/openshift/konflux-tasks + - name: revision + value: main + - name: pathInRepo + value: tasks/provision-ephemeral-cluster/0.1/provision-ephemeral-cluster.yaml + params: + - name: ownerName + value: $(context.pipelineRun.name) # Internal usage only, use always this value here + - name: ownerUid + value: $(context.pipelineRun.uid) # Internal usage only, use always this value here + - name: workflow + value: hypershift-hostedcluster-workflow + - name: clusterProfile + value: aws-konflux-prod + - name: env + value: '{"COMPUTE_NODE_TYPE": "m5.2xlarge", "HYPERSHIFT_NODE_COUNT": "1"}' + - name: releases + value: | + {"latest":{"release":{"channel":"stable","version":"4.19","architecture":"multi"}}} runAfter: - eaas-provision-space - lint - taskSpec: - results: - - name: clusterName - value: "$(steps.create-cluster.results.clusterName)" - steps: - - name: pick-version - ref: - resolver: git - params: - - name: url - value: https://github.com/konflux-ci/build-definitions.git - - name: revision - value: main - - name: pathInRepo - value: stepactions/eaas-get-latest-openshift-version-by-prefix/0.1/eaas-get-latest-openshift-version-by-prefix.yaml - params: - - name: prefix - value: "4.19." - - name: create-cluster - ref: - resolver: git - params: - - name: url - value: https://github.com/konflux-ci/build-definitions.git - - name: revision - value: main - - name: pathInRepo - value: stepactions/eaas-create-ephemeral-cluster-hypershift-aws/0.1/eaas-create-ephemeral-cluster-hypershift-aws.yaml - params: - - name: eaasSpaceSecretRef - value: $(tasks.eaas-provision-space.results.secretRef) - - name: version - value: "$(steps.pick-version.results.version)" - - name: instanceType - value: "m5.xlarge" - - name: imageContentSources - value: | - - source: registry.redhat.io/openshift-lightspeed/lightspeed-rhel9-operator - mirrors: - - quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/ols/lightspeed-operator - - source: registry.redhat.io/openshift-lightspeed/lightspeed-operator-bundle - mirrors: - - quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/ols/bundle - - source: registry.redhat.io/openshift-lightspeed/lightspeed-service-api-rhel9 - mirrors: - - quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/ols/lightspeed-service - - source: registry.redhat.io/openshift-lightspeed/lightspeed-console-plugin-rhel9 - mirrors: - - quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/ols/lightspeed-console - - source: registry.redhat.io/openshift-lightspeed/lightspeed-console-plugin-pf5-rhel9 - mirrors: - - quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/lightspeed-console-pf5 - - source: registry.redhat.io/openshift-lightspeed/lightspeed-to-dataverse-exporter-rhel9 - mirrors: - - quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/lightspeed-to-dataverse-exporter - - source: registry.redhat.io/openshift-lightspeed/openshift-mcp-server-rhel9 - mirrors: - - quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/openshift-mcp-server - name: extract-snapshot-metadata description: Extract console image and commit from SNAPSHOT input runAfter: @@ -174,12 +139,14 @@ spec: description: Task to run tests from service repository runAfter: - extract-snapshot-metadata - - provision-cluster + - provision-ephemeral-cluster params: - name: console-image value: $(tasks.extract-snapshot-metadata.results.console-image) - name: commit value: $(tasks.extract-snapshot-metadata.results.commit) + - name: clusterCredentialsSecretRef + value: $(tasks.provision-ephemeral-cluster.results.secretRef) taskSpec: volumes: - name: openai-token @@ -193,24 +160,10 @@ spec: params: - name: console-image - name: commit + - name: clusterCredentialsSecretRef + type: string + description: "The secret that holds the cluster credentials" steps: - - name: get-kubeconfig - ref: - resolver: git - params: - - name: url - value: https://github.com/konflux-ci/build-definitions.git - - name: revision - value: main - - name: pathInRepo - value: stepactions/eaas-get-ephemeral-cluster-credentials/0.1/eaas-get-ephemeral-cluster-credentials.yaml - params: - - name: eaasSpaceSecretRef - value: $(tasks.eaas-provision-space.results.secretRef) - - name: clusterName - value: "$(tasks.provision-cluster.results.clusterName)" - - name: credentials - value: credentials - name: run-e2e-tests onError: continue volumeMounts: @@ -220,7 +173,12 @@ spec: mountPath: /credentials env: - name: KUBECONFIG_PATH - value: "/credentials/$(steps.get-kubeconfig.results.kubeconfig)" + value: "/credentials/kubeconfig" + - name: KUBECONFIG_VALUE + valueFrom: + secretKeyRef: + name: $(params.clusterCredentialsSecretRef) + key: kubeconfig - name: LOGIN_IDP value: "kube:admin" - name: LLM_TOKEN_PATH @@ -229,17 +187,13 @@ spec: value: "$(params.console-image)" - name: COMMIT_SHA value: "$(params.commit)" - - name: PASSWORD_PATH - value: "/credentials/$(steps.get-kubeconfig.results.passwordPath)" - - name: BASE_URL - value: "$(steps.get-kubeconfig.results.consoleURL)" resources: limits: memory: 8Gi image: mcr.microsoft.com/playwright:v1.62.1-noble script: | + echo "$KUBECONFIG_VALUE" > /credentials/kubeconfig echo "COMMIT_SHA: ${COMMIT_SHA}" - echo "BASE_URL: ${BASE_URL}" echo "CONSOLE_IMAGE: ${CONSOLE_IMAGE}" echo "KUBECONFIG_PATH: ${KUBECONFIG_PATH}" echo "---------------------------------------------" @@ -248,6 +202,8 @@ spec: && chmod +x kubectl oc \ && mv oc kubectl /usr/local/bin/ echo "---------------------------------------------" + export BASE_URL=https://$(oc --kubeconfig "$KUBECONFIG_PATH" get route console -n openshift-console -o go-template --template="{{.spec.host}}") + echo "BASE_URL: ${BASE_URL}" export OPERATOR_SDK_VERSION=1.36.1 export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac) export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v${OPERATOR_SDK_VERSION} @@ -274,7 +230,6 @@ spec: echo "---------------------------------------------" NODE_OPTIONS=--max-old-space-size=4096 npm ci --omit=optional --no-fund echo "---------------------------------------------" - export LOGIN_PASSWORD=$(cat ${PASSWORD_PATH}) set +e npx playwright test err_status=$? @@ -300,7 +255,7 @@ spec: - name: credentials value: "credentials" - name: kubeconfig - value: "$(steps.get-kubeconfig.results.kubeconfig)" + value: "kubeconfig" - name: artifact-dir value: "/workspace/artifacts/konflux-artifacts" # validate that the cluster resources are available in another tekton step @@ -377,3 +332,18 @@ spec: value: "quay.io/openshift-lightspeed/ols-console-artifacts" - name: artifact-credentials-secret value: ols-konflux-artifacts-bot + - name: deprovision-ephemeral-cluster + taskRef: + resolver: git + params: + - name: url + value: https://github.com/openshift/konflux-tasks + - name: revision + value: main + - name: pathInRepo + value: tasks/deprovision-ephemeral-cluster/0.1/deprovision-ephemeral-cluster.yaml + params: + - name: testPlatformClusterClaimName + value: $(tasks.provision-ephemeral-cluster.results.testPlatformClusterClaimName) + - name: testPlatformClusterClaimNamespace + value: $(tasks.provision-ephemeral-cluster.results.testPlatformClusterClaimNamespace) \ No newline at end of file diff --git a/tests/support/global-setup.ts b/tests/support/global-setup.ts index 6a0e66ff0..dfb245eeb 100644 --- a/tests/support/global-setup.ts +++ b/tests/support/global-setup.ts @@ -20,6 +20,7 @@ const globalSetup = async (config: FullConfig) => { oc(['adm', 'policy', 'add-cluster-role-to-user', 'cluster-admin', username]); oc(['adm', 'policy', 'add-cluster-role-to-user', 'lightspeed-operator-query-access', username]); + let oauthOrigin: string | undefined; try { const oauthResult = oc([ 'get', @@ -29,7 +30,7 @@ const globalSetup = async (config: FullConfig) => { 'go-template', '--template={{index .redirectURIs 0}}', ]); - const oauthOrigin = new URL(oauthResult.trim().replace(/"/g, '')).origin; + oauthOrigin = new URL(oauthResult.trim().replace(/"/g, '')).origin; console.log(`OAuth origin: ${oauthOrigin}`); } catch { console.log('oauthclient not available on this cluster, skipping OAuth origin lookup'); @@ -56,6 +57,11 @@ spec: ols: defaultModel: gpt-4o-mini defaultProvider: openai + # The released operator bundle configures the MCP server with the removed + # metrics toolset, while its current MCP image only accepts + # observability/metrics. Disable introspection for console UI tests until + # the bundle and MCP image are published as a compatible pair. + introspectionEnabled: false logLevel: INFO`; // Check if operator is already installed @@ -245,29 +251,99 @@ spec: ]); } - // Log in via browser and save storageState + // Log in via browser and save storageState. The ephemeral-cluster task only + // guarantees an admin kubeconfig; unlike the legacy EaaS task, it does not + // guarantee a kubeadmin password. Its kubeconfig can be client-certificate + // based, in which case `oc whoami --show-token` has no token to return. + // Create a short-lived, cluster-admin service-account token for OAuth in + // that case instead of relying on an unsupported secret key. + let kubeToken: string; + try { + kubeToken = oc(['whoami', '--show-token']).trim(); + } catch { + const serviceAccount = 'playwright-e2e'; + try { + oc(['create', 'serviceaccount', serviceAccount, '-n', OLS_NAMESPACE]); + } catch { + // The account may have been created by an earlier setup attempt. + } + oc([ + 'adm', + 'policy', + 'add-cluster-role-to-user', + 'cluster-admin', + `system:serviceaccount:${OLS_NAMESPACE}:${serviceAccount}`, + ]); + kubeToken = oc([ + 'create', + 'token', + serviceAccount, + '-n', + OLS_NAMESPACE, + '--duration=1h', + ]).trim(); + } + const consoleOrigin = new URL(baseURL).origin; const browser = await chromium.launch(); const context = await browser.newContext({ ignoreHTTPSErrors: true }); - const page = await context.newPage(); - await page.goto(baseURL); + // Do not apply the admin token to every browser request: the console can + // load third-party resources. It is only needed by the console and OAuth + // origins while the authorization code and console session are established. + if (kubeToken) { + await context.route('**/*', async (route) => { + const request = route.request(); + const origin = new URL(request.url()).origin; + if (origin !== consoleOrigin && origin !== oauthOrigin) { + await route.continue(); + return; + } + await route.continue({ + headers: { ...request.headers(), authorization: `Bearer ${kubeToken}` }, + }); + }); + } - // Perform login - const idp = process.env.LOGIN_IDP || 'kube:admin'; - const password = process.env.LOGIN_PASSWORD!; + const page = await context.newPage(); + await page.goto(baseURL); - // Select IDP if the login page shows identity provider selection - const idpLink = page.locator(`a:has-text("${idp}")`); - if (await idpLink.isVisible({ timeout: 10_000 }).catch(() => false)) { - await idpLink.click(); - } + // A hosted-control-plane OAuth flow can return users directly to a console + // sub-page rather than the root path. Do not consider the OAuth callback to + // be loaded: it still needs to exchange the authorization code for the + // console session. + const waitForConsole = () => + page.waitForURL( + (url) => + url.origin === consoleOrigin && + !url.pathname.startsWith('/oauth') && + !url.pathname.startsWith('/auth') && + !url.pathname.startsWith('/login'), + { timeout: 2 * MINUTE, waitUntil: 'domcontentloaded' }, + ); + + // Retain password login for callers that explicitly provide it, but the + // ephemeral-cluster pipeline authenticates with the kubeconfig token above. + const usernameInput = page.locator('#inputUsername'); + if (await usernameInput.isVisible({ timeout: 10_000 }).catch(() => false)) { + const password = process.env.LOGIN_PASSWORD; + if (!password) { + throw new Error('OAuth bearer-token login did not succeed and LOGIN_PASSWORD is not set'); + } - await page.locator('#inputUsername').fill(username); - await page.locator('#inputPassword').fill(password); - await page.locator('button[type=submit]').click(); + const idp = process.env.LOGIN_IDP || 'kube:admin'; + const idpLink = page.locator(`a:has-text("${idp}")`); + if (await idpLink.isVisible({ timeout: 10_000 }).catch(() => false)) { + await idpLink.click(); + } - // Wait for console to load - await page.waitForURL('**/'); + await usernameInput.fill(username); + await page.locator('#inputPassword').fill(password); + const consoleNavigation = waitForConsole(); + await page.locator('button[type=submit]').click(); + await consoleNavigation; + } else { + await waitForConsole(); + } // Dismiss guided tour and set localStorage to prevent it reappearing const tourSettings = { From 13ab8c915549bee195d3e784e8dfdea2759ec670 Mon Sep 17 00:00:00 2001 From: Joao Fula Date: Wed, 9 Sep 2026 08:57:44 +0200 Subject: [PATCH 2/2] increasing node count and adding wait for OLS readiness addressing comments changing default model since openai no longer supports 4o-mini and this is causing failures changing default model since openai no longer supports 4o-mini and this is causing failures --- .../lightspeed-console-pre-commit.yaml | 2 +- tests/support/global-setup.ts | 18 +++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/.tekton/integration-tests/lightspeed-console-pre-commit.yaml b/.tekton/integration-tests/lightspeed-console-pre-commit.yaml index d2dfcec8b..78b57658c 100644 --- a/.tekton/integration-tests/lightspeed-console-pre-commit.yaml +++ b/.tekton/integration-tests/lightspeed-console-pre-commit.yaml @@ -57,7 +57,7 @@ spec: - name: clusterProfile value: aws-konflux-prod - name: env - value: '{"COMPUTE_NODE_TYPE": "m5.2xlarge", "HYPERSHIFT_NODE_COUNT": "1"}' + value: '{"COMPUTE_NODE_TYPE": "m5.2xlarge", "HYPERSHIFT_NODE_COUNT": "3"}' - name: releases value: | {"latest":{"release":{"channel":"stable","version":"4.19","architecture":"multi"}}} diff --git a/tests/support/global-setup.ts b/tests/support/global-setup.ts index dfb245eeb..b6aff5172 100644 --- a/tests/support/global-setup.ts +++ b/tests/support/global-setup.ts @@ -53,9 +53,9 @@ spec: name: openai-api-keys url: https://api.openai.com/v1 models: - - name: gpt-4o-mini + - name: gpt-5.4-mini ols: - defaultModel: gpt-4o-mini + defaultModel: gpt-5.4-mini defaultProvider: openai # The released operator bundle configures the MCP server with the removed # metrics toolset, while its current MCP image only accepts @@ -307,19 +307,7 @@ spec: const page = await context.newPage(); await page.goto(baseURL); - // A hosted-control-plane OAuth flow can return users directly to a console - // sub-page rather than the root path. Do not consider the OAuth callback to - // be loaded: it still needs to exchange the authorization code for the - // console session. - const waitForConsole = () => - page.waitForURL( - (url) => - url.origin === consoleOrigin && - !url.pathname.startsWith('/oauth') && - !url.pathname.startsWith('/auth') && - !url.pathname.startsWith('/login'), - { timeout: 2 * MINUTE, waitUntil: 'domcontentloaded' }, - ); + const waitForConsole = () => page.waitForURL('**/'); // Retain password login for callers that explicitly provide it, but the // ephemeral-cluster pipeline authenticates with the kubeconfig token above.