From 50c569aaeac9b48cc495f96891aab8552de971dc Mon Sep 17 00:00:00 2001 From: Marek Vacula Date: Wed, 17 Dec 2025 15:10:38 +0100 Subject: [PATCH 1/2] add helpers for cred ops Add helper function wrappers for HCP SDK credential operations. Implement both wait and no-wait variants of functions. Refactor admin credential lifecycle test case. https://issues.redhat.com/browse/ARO-23093 --- test/e2e/admin_credential_lifecycle.go | 19 ++-- test/util/framework/hcp_helper.go | 121 +++++++++++++++++++------ 2 files changed, 102 insertions(+), 38 deletions(-) diff --git a/test/e2e/admin_credential_lifecycle.go b/test/e2e/admin_credential_lifecycle.go index 7bd5a28b66..87fa6eb101 100644 --- a/test/e2e/admin_credential_lifecycle.go +++ b/test/e2e/admin_credential_lifecycle.go @@ -37,7 +37,6 @@ import ( "github.com/openshift-eng/openshift-tests-extension/pkg/util/sets" - hcpsdk20240610preview "github.com/Azure/ARO-HCP/test/sdk/resourcemanager/redhatopenshifthcp/armredhatopenshifthcp" "github.com/Azure/ARO-HCP/test/util/framework" "github.com/Azure/ARO-HCP/test/util/labels" "github.com/Azure/ARO-HCP/test/util/verifiers" @@ -45,7 +44,7 @@ import ( var _ = Describe("Customer", func() { - terminalProvisioningStates := sets.New(hcpsdk20240610preview.ProvisioningStateSucceeded, hcpsdk20240610preview.ProvisioningStateFailed, hcpsdk20240610preview.ProvisioningStateCanceled) + terminalProvisioningStates := sets.New(framework.ProvisioningStateSucceeded, framework.ProvisioningStateFailed, framework.ProvisioningStateCanceled) It("should be able to test admin credentials before cluster ready, then full admin credential lifecycle", labels.RequireNothing, @@ -102,7 +101,7 @@ var _ = Describe("Customer", func() { By("waiting for cluster to appear and testing admin credentials while in deploying state") // Poll the cluster state and test admin credentials when we find it deploying var testedWhileDeploying bool - var previousState hcpsdk20240610preview.ProvisioningState + var previousState framework.ProvisioningState GinkgoLogr.Info("creating cluster, waiting for it to reach a terminal state") Eventually(func() bool { cluster, err := framework.GetHCPCluster(ctx, clusterClient, *resourceGroup.Name, clusterName) @@ -125,11 +124,11 @@ var _ = Describe("Customer", func() { if !testedWhileDeploying && !terminalProvisioningStates.Has(*cluster.Properties.ProvisioningState) { By("testing admin credentials while cluster is in deploying state") testedWhileDeploying = true - _, err := clusterClient.BeginRequestAdminCredential( + _, err := framework.RequestAdminCredential( ctx, + clusterClient, *resourceGroup.Name, clusterName, - nil, ) var respErr *azcore.ResponseError if err != nil && errors.As(err, &respErr) && http.StatusConflict == respErr.StatusCode { @@ -141,7 +140,7 @@ var _ = Describe("Customer", func() { } // If cluster is ready, we're done - if *cluster.Properties.ProvisioningState == hcpsdk20240610preview.ProvisioningStateSucceeded { + if *cluster.Properties.ProvisioningState == framework.ProvisioningStateSucceeded { if !testedWhileDeploying { Fail("Cluster provisioned too quickly to test 409 behavior - unable to validate admin credentials fail during deployment") } @@ -149,7 +148,7 @@ var _ = Describe("Customer", func() { } // If cluster failed, that's an error - if *cluster.Properties.ProvisioningState == hcpsdk20240610preview.ProvisioningStateFailed { + if *cluster.Properties.ProvisioningState == framework.ProvisioningStateFailed { Fail("Cluster provisioning failed") } @@ -190,11 +189,7 @@ var _ = Describe("Customer", func() { } By("revoking all cluster admin credentials via ARO HCP RP API") - poller, err := clusterClient.BeginRevokeCredentials(ctx, *resourceGroup.Name, clusterName, nil) - Expect(err).NotTo(HaveOccurred()) - - By("waiting for revocation operation to complete") - _, err = poller.PollUntilDone(ctx, nil) + err = framework.RevokeCredentialsAndWait(ctx, clusterClient, *resourceGroup.Name, clusterName, 10*time.Minute) Expect(err).NotTo(HaveOccurred()) By("validating all admin credentials now fail after revocation") diff --git a/test/util/framework/hcp_helper.go b/test/util/framework/hcp_helper.go index 93d0d05a83..fd76c5d1cd 100644 --- a/test/util/framework/hcp_helper.go +++ b/test/util/framework/hcp_helper.go @@ -40,6 +40,14 @@ import ( hcpsdk20240610preview "github.com/Azure/ARO-HCP/test/sdk/resourcemanager/redhatopenshifthcp/armredhatopenshifthcp" ) +const ( + ProvisioningStateSucceeded = hcpsdk20240610preview.ProvisioningStateSucceeded + ProvisioningStateFailed = hcpsdk20240610preview.ProvisioningStateFailed + ProvisioningStateCanceled = hcpsdk20240610preview.ProvisioningStateCanceled +) + +type ProvisioningState = hcpsdk20240610preview.ProvisioningState + // checkOperationResult ensures the result model returned by a runtime.Poller // matches the resource model returned from a GET request. func checkOperationResult(expectModel, resultModel any) error { @@ -70,41 +78,18 @@ func (tc *perItOrDescribeTestContext) GetAdminRESTConfigForHCPCluster( hcpClusterName string, timeout time.Duration, // this is a POST request, so keep the timeout as it's async ) (*rest.Config, error) { - ctx, cancel := context.WithTimeoutCause(ctx, timeout, fmt.Errorf("timeout '%f' minutes exceeded during GetAdminRESTConfigForHCPCluster for cluster %s in resource group %s", timeout.Minutes(), hcpClusterName, resourceGroupName)) - defer cancel() - startTime := time.Now() defer func() { finishTime := time.Now() tc.RecordTestStep("Collect admin credentials for cluster", startTime, finishTime) }() - adminCredentialRequestPoller, err := hcpClient.BeginRequestAdminCredential( - ctx, - resourceGroupName, - hcpClusterName, - nil, - ) + credentialResponse, err := RequestAdminCredentialAndWait(ctx, hcpClient, resourceGroupName, hcpClusterName, timeout) if err != nil { - return nil, fmt.Errorf("failed to start credential request: %w", err) - } - - operationResult, err := adminCredentialRequestPoller.PollUntilDone(ctx, &runtime.PollUntilDoneOptions{ - Frequency: StandardPollInterval, - }) - if err != nil { - if errors.Is(err, context.DeadlineExceeded) { - return nil, fmt.Errorf("failed waiting for hcpCluster=%q in resourcegroup=%q to finish getting creds, caused by: %w, error: %w", hcpClusterName, resourceGroupName, context.Cause(ctx), err) - } - return nil, fmt.Errorf("failed waiting for hcpCluster=%q in resourcegroup=%q to finish getting creds: %w", hcpClusterName, resourceGroupName, err) + return nil, err } - switch m := any(operationResult).(type) { - case hcpsdk20240610preview.HcpOpenShiftClustersClientRequestAdminCredentialResponse: - return readStaticRESTConfig(m.Kubeconfig) - default: - return nil, fmt.Errorf("unknown type %T", m) - } + return readStaticRESTConfig(credentialResponse.Kubeconfig) } func readStaticRESTConfig(kubeconfigContent *string) (*rest.Config, error) { @@ -128,6 +113,90 @@ func readStaticRESTConfig(kubeconfigContent *string) (*rest.Config, error) { return ret, nil } +func RequestAdminCredential( + ctx context.Context, + hcpClient *hcpsdk20240610preview.HcpOpenShiftClustersClient, + resourceGroupName string, + hcpClusterName string, +) (*runtime.Poller[hcpsdk20240610preview.HcpOpenShiftClustersClientRequestAdminCredentialResponse], error) { + return hcpClient.BeginRequestAdminCredential(ctx, resourceGroupName, hcpClusterName, nil) +} + +func RevokeCredentials( + ctx context.Context, + hcpClient *hcpsdk20240610preview.HcpOpenShiftClustersClient, + resourceGroupName string, + hcpClusterName string, +) (*runtime.Poller[hcpsdk20240610preview.HcpOpenShiftClustersClientRevokeCredentialsResponse], error) { + return hcpClient.BeginRevokeCredentials(ctx, resourceGroupName, hcpClusterName, nil) +} + +func RequestAdminCredentialAndWait( + ctx context.Context, + hcpClient *hcpsdk20240610preview.HcpOpenShiftClustersClient, + resourceGroupName string, + hcpClusterName string, + timeout time.Duration, +) (*hcpsdk20240610preview.HcpOpenShiftClustersClientRequestAdminCredentialResponse, error) { + ctx, cancel := context.WithTimeoutCause(ctx, timeout, fmt.Errorf("timeout '%f' minutes exceeded during RequestAdminCredentialAndWait for cluster %s in resource group %s", timeout.Minutes(), hcpClusterName, resourceGroupName)) + defer cancel() + + poller, err := hcpClient.BeginRequestAdminCredential(ctx, resourceGroupName, hcpClusterName, nil) + if err != nil { + return nil, fmt.Errorf("failed to start credential request for hcpCluster=%q in resourcegroup=%q: %w", hcpClusterName, resourceGroupName, err) + } + + operationResult, err := poller.PollUntilDone(ctx, &runtime.PollUntilDoneOptions{ + Frequency: StandardPollInterval, + }) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) { + return nil, fmt.Errorf("failed waiting for hcpCluster=%q in resourcegroup=%q to finish getting creds, caused by: %w, error: %w", hcpClusterName, resourceGroupName, context.Cause(ctx), err) + } + return nil, fmt.Errorf("failed waiting for hcpCluster=%q in resourcegroup=%q to finish getting creds: %w", hcpClusterName, resourceGroupName, err) + } + + switch m := any(operationResult).(type) { + case hcpsdk20240610preview.HcpOpenShiftClustersClientRequestAdminCredentialResponse: + return &m, nil + default: + return nil, fmt.Errorf("unknown type %T", m) + } +} + +func RevokeCredentialsAndWait( + ctx context.Context, + hcpClient *hcpsdk20240610preview.HcpOpenShiftClustersClient, + resourceGroupName string, + hcpClusterName string, + timeout time.Duration, +) error { + ctx, cancel := context.WithTimeoutCause(ctx, timeout, fmt.Errorf("timeout '%f' minutes exceeded during RevokeCredentialsAndWait for cluster %s in resource group %s", timeout.Minutes(), hcpClusterName, resourceGroupName)) + defer cancel() + + poller, err := hcpClient.BeginRevokeCredentials(ctx, resourceGroupName, hcpClusterName, nil) + if err != nil { + return fmt.Errorf("failed to start credential revocation for hcpCluster=%q in resourcegroup=%q: %w", hcpClusterName, resourceGroupName, err) + } + + operationResult, err := poller.PollUntilDone(ctx, &runtime.PollUntilDoneOptions{ + Frequency: StandardPollInterval, + }) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) { + return fmt.Errorf("failed waiting for hcpCluster=%q in resourcegroup=%q to finish revoking creds, caused by: %w, error: %w", hcpClusterName, resourceGroupName, context.Cause(ctx), err) + } + return fmt.Errorf("failed waiting for hcpCluster=%q in resourcegroup=%q to finish revoking creds: %w", hcpClusterName, resourceGroupName, err) + } + + switch m := any(operationResult).(type) { + case hcpsdk20240610preview.HcpOpenShiftClustersClientRevokeCredentialsResponse: + return nil + default: + return fmt.Errorf("unknown type %T", m) + } +} + // DeleteHCPCluster deletes an hcp cluster and waits for the operation to complete func DeleteHCPCluster( ctx context.Context, From 02a237d8bed82541e17e4ecec9c2889aee734035 Mon Sep 17 00:00:00 2001 From: Marek Vacula Date: Fri, 19 Dec 2025 17:27:12 +0100 Subject: [PATCH 2/2] implement suggestions --- test/e2e/admin_credential_lifecycle.go | 13 +++++++------ test/util/framework/hcp_helper.go | 26 -------------------------- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/test/e2e/admin_credential_lifecycle.go b/test/e2e/admin_credential_lifecycle.go index 87fa6eb101..12ba9f8b86 100644 --- a/test/e2e/admin_credential_lifecycle.go +++ b/test/e2e/admin_credential_lifecycle.go @@ -37,6 +37,7 @@ import ( "github.com/openshift-eng/openshift-tests-extension/pkg/util/sets" + hcpsdk20240610preview "github.com/Azure/ARO-HCP/test/sdk/resourcemanager/redhatopenshifthcp/armredhatopenshifthcp" "github.com/Azure/ARO-HCP/test/util/framework" "github.com/Azure/ARO-HCP/test/util/labels" "github.com/Azure/ARO-HCP/test/util/verifiers" @@ -44,7 +45,7 @@ import ( var _ = Describe("Customer", func() { - terminalProvisioningStates := sets.New(framework.ProvisioningStateSucceeded, framework.ProvisioningStateFailed, framework.ProvisioningStateCanceled) + terminalProvisioningStates := sets.New(hcpsdk20240610preview.ProvisioningStateSucceeded, hcpsdk20240610preview.ProvisioningStateFailed, hcpsdk20240610preview.ProvisioningStateCanceled) It("should be able to test admin credentials before cluster ready, then full admin credential lifecycle", labels.RequireNothing, @@ -101,7 +102,7 @@ var _ = Describe("Customer", func() { By("waiting for cluster to appear and testing admin credentials while in deploying state") // Poll the cluster state and test admin credentials when we find it deploying var testedWhileDeploying bool - var previousState framework.ProvisioningState + var previousState hcpsdk20240610preview.ProvisioningState GinkgoLogr.Info("creating cluster, waiting for it to reach a terminal state") Eventually(func() bool { cluster, err := framework.GetHCPCluster(ctx, clusterClient, *resourceGroup.Name, clusterName) @@ -124,11 +125,11 @@ var _ = Describe("Customer", func() { if !testedWhileDeploying && !terminalProvisioningStates.Has(*cluster.Properties.ProvisioningState) { By("testing admin credentials while cluster is in deploying state") testedWhileDeploying = true - _, err := framework.RequestAdminCredential( + _, err := clusterClient.BeginRequestAdminCredential( ctx, - clusterClient, *resourceGroup.Name, clusterName, + nil, ) var respErr *azcore.ResponseError if err != nil && errors.As(err, &respErr) && http.StatusConflict == respErr.StatusCode { @@ -140,7 +141,7 @@ var _ = Describe("Customer", func() { } // If cluster is ready, we're done - if *cluster.Properties.ProvisioningState == framework.ProvisioningStateSucceeded { + if *cluster.Properties.ProvisioningState == hcpsdk20240610preview.ProvisioningStateSucceeded { if !testedWhileDeploying { Fail("Cluster provisioned too quickly to test 409 behavior - unable to validate admin credentials fail during deployment") } @@ -148,7 +149,7 @@ var _ = Describe("Customer", func() { } // If cluster failed, that's an error - if *cluster.Properties.ProvisioningState == framework.ProvisioningStateFailed { + if *cluster.Properties.ProvisioningState == hcpsdk20240610preview.ProvisioningStateFailed { Fail("Cluster provisioning failed") } diff --git a/test/util/framework/hcp_helper.go b/test/util/framework/hcp_helper.go index fd76c5d1cd..9bf06ae9e2 100644 --- a/test/util/framework/hcp_helper.go +++ b/test/util/framework/hcp_helper.go @@ -40,14 +40,6 @@ import ( hcpsdk20240610preview "github.com/Azure/ARO-HCP/test/sdk/resourcemanager/redhatopenshifthcp/armredhatopenshifthcp" ) -const ( - ProvisioningStateSucceeded = hcpsdk20240610preview.ProvisioningStateSucceeded - ProvisioningStateFailed = hcpsdk20240610preview.ProvisioningStateFailed - ProvisioningStateCanceled = hcpsdk20240610preview.ProvisioningStateCanceled -) - -type ProvisioningState = hcpsdk20240610preview.ProvisioningState - // checkOperationResult ensures the result model returned by a runtime.Poller // matches the resource model returned from a GET request. func checkOperationResult(expectModel, resultModel any) error { @@ -113,24 +105,6 @@ func readStaticRESTConfig(kubeconfigContent *string) (*rest.Config, error) { return ret, nil } -func RequestAdminCredential( - ctx context.Context, - hcpClient *hcpsdk20240610preview.HcpOpenShiftClustersClient, - resourceGroupName string, - hcpClusterName string, -) (*runtime.Poller[hcpsdk20240610preview.HcpOpenShiftClustersClientRequestAdminCredentialResponse], error) { - return hcpClient.BeginRequestAdminCredential(ctx, resourceGroupName, hcpClusterName, nil) -} - -func RevokeCredentials( - ctx context.Context, - hcpClient *hcpsdk20240610preview.HcpOpenShiftClustersClient, - resourceGroupName string, - hcpClusterName string, -) (*runtime.Poller[hcpsdk20240610preview.HcpOpenShiftClustersClientRevokeCredentialsResponse], error) { - return hcpClient.BeginRevokeCredentials(ctx, resourceGroupName, hcpClusterName, nil) -} - func RequestAdminCredentialAndWait( ctx context.Context, hcpClient *hcpsdk20240610preview.HcpOpenShiftClustersClient,