From 0ade05477c3d8f59e7c98d2914902ba8e51586cf Mon Sep 17 00:00:00 2001 From: Shawn Bai Date: Wed, 1 May 2024 10:45:46 +1200 Subject: [PATCH] Revert "[OSD-21438] Remove the fallback to old flow" --- cmd/ocm-backplane/cloud/common.go | 100 +++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 7 deletions(-) diff --git a/cmd/ocm-backplane/cloud/common.go b/cmd/ocm-backplane/cloud/common.go index cd6ef770..69bb784c 100644 --- a/cmd/ocm-backplane/cloud/common.go +++ b/cmd/ocm-backplane/cloud/common.go @@ -15,6 +15,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sts" ocmsdk "github.com/openshift-online/ocm-sdk-go" cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" + BackplaneApi "github.com/openshift/backplane-api/pkg/client" "github.com/openshift/backplane-cli/pkg/awsutil" "github.com/openshift/backplane-cli/pkg/backplaneapi" "github.com/openshift/backplane-cli/pkg/cli/config" @@ -69,14 +70,20 @@ func (cfg *QueryConfig) GetCloudConsole() (*ConsoleResponse, error) { isolatedBackplane, err := isIsolatedBackplaneAccess(cfg.Cluster, cfg.OcmConnection) if err != nil { - return nil, fmt.Errorf("failed to determine if the cluster is using isolated backplane access: %v", err) + logger.Infof("failed to determine if the cluster is using isolated backplane access: %v", err) + logger.Infof("for more information, try ocm get /api/clusters_mgmt/v1/clusters/%s/sts_support_jump_role", cfg.Cluster.ID()) + logger.Infof("attempting to fallback to %s", OldFlowSupportRole) } if isolatedBackplane { logger.Debugf("cluster is using isolated backplane") targetCredentials, err := cfg.getIsolatedCredentials(ocmToken) if err != nil { - return nil, fmt.Errorf("failed to assume role with isolated backplane flow: %v", err) + // TODO: This fallback should be removed in the future + // TODO: when we are more confident in our ability to access clusters using the isolated flow + logger.Infof("failed to assume role with isolated backplane flow: %v", err) + logger.Infof("attempting to fallback to %s", OldFlowSupportRole) + return cfg.getCloudConsoleFromPublicAPI(ocmToken) } resp, err := awsutil.GetSigninToken(targetCredentials, cfg.Cluster.Region().ID()) @@ -91,26 +98,64 @@ func (cfg *QueryConfig) GetCloudConsole() (*ConsoleResponse, error) { return &ConsoleResponse{ConsoleLink: signinFederationURL.String()}, nil } - return nil, fmt.Errorf("cluster is not using isolated backplane access") + return cfg.getCloudConsoleFromPublicAPI(ocmToken) +} + +// GetCloudConsole returns console response calling to public Backplane API +func (cfg *QueryConfig) getCloudConsoleFromPublicAPI(ocmToken string) (*ConsoleResponse, error) { + logger.Debugln("Getting Cloud Console") + + client, err := backplaneapi.DefaultClientUtils.GetBackplaneClient(cfg.BackplaneConfiguration.URL, ocmToken, cfg.BackplaneConfiguration.ProxyURL) + if err != nil { + return nil, err + } + resp, err := client.GetCloudConsole(context.TODO(), cfg.Cluster.ID()) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, utils.TryPrintAPIError(resp, false) + } + + credsResp, err := BackplaneApi.ParseGetCloudConsoleResponse(resp) + if err != nil { + return nil, fmt.Errorf("unable to parse response body from backplane:\n Status Code: %d", resp.StatusCode) + } + + if len(credsResp.Body) == 0 { + return nil, fmt.Errorf("empty response from backplane") + } + + cliResp := &ConsoleResponse{} + cliResp.ConsoleLink = *credsResp.JSON200.ConsoleLink + + return cliResp, nil } // GetCloudCredentials returns Cloud Credentials Response func (cfg *QueryConfig) GetCloudCredentials() (bpCredentials.Response, error) { ocmToken, _, err := cfg.OcmConnection.Tokens() if err != nil { - return nil, fmt.Errorf("unable to get token for ocm connection: %w", err) + return nil, fmt.Errorf("unable to get token for ocm connection") } isolatedBackplane, err := isIsolatedBackplaneAccess(cfg.Cluster, cfg.OcmConnection) if err != nil { - return nil, fmt.Errorf("failed to determine if the cluster is using isolated backplane access: %v", err) + logger.Infof("failed to determine if the cluster is using isolated backplane access: %v", err) + logger.Infof("for more information, try ocm get /api/clusters_mgmt/v1/clusters/%s/sts_support_jump_role", cfg.Cluster.ID()) + logger.Infof("attempting to fallback to %s", OldFlowSupportRole) } if isolatedBackplane { logger.Debugf("cluster is using isolated backplane") targetCredentials, err := cfg.getIsolatedCredentials(ocmToken) if err != nil { - return nil, fmt.Errorf("failed to assume role with isolated backplane flow: %v", err) + // TODO: This fallback should be removed in the future + // TODO: when we are more confident in our ability to access clusters using the isolated flow + logger.Infof("failed to assume role with isolated backplane flow: %v", err) + logger.Infof("attempting to fallback to %s", OldFlowSupportRole) + return cfg.getCloudCredentialsFromBackplaneAPI(ocmToken) } return &bpCredentials.AWSCredentialsResponse{ @@ -122,7 +167,48 @@ func (cfg *QueryConfig) GetCloudCredentials() (bpCredentials.Response, error) { }, nil } - return nil, fmt.Errorf("cluster is not using isolated backplane access") + return cfg.getCloudCredentialsFromBackplaneAPI(ocmToken) +} + +func (cfg *QueryConfig) getCloudCredentialsFromBackplaneAPI(ocmToken string) (bpCredentials.Response, error) { + client, err := backplaneapi.DefaultClientUtils.GetBackplaneClient(cfg.BackplaneConfiguration.URL, ocmToken, cfg.BackplaneConfiguration.ProxyURL) + if err != nil { + return nil, err + } + + resp, err := client.GetCloudCredentials(context.TODO(), cfg.Cluster.ID()) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, utils.TryPrintAPIError(resp, false) + } + + logger.Debugln("Parsing response") + + credsResp, err := BackplaneApi.ParseGetCloudCredentialsResponse(resp) + if err != nil { + return nil, fmt.Errorf("unable to parse response body from backplane:\n Status Code: %d : err: %v", resp.StatusCode, err) + } + + switch cfg.Cluster.CloudProvider().ID() { + case "aws": + cliResp := &bpCredentials.AWSCredentialsResponse{} + if err := json.Unmarshal([]byte(*credsResp.JSON200.Credentials), cliResp); err != nil { + return nil, fmt.Errorf("unable to unmarshal AWS credentials response from backplane %s: %w", *credsResp.JSON200.Credentials, err) + } + cliResp.Region = cfg.Cluster.Region().ID() + return cliResp, nil + case "gcp": + cliResp := &bpCredentials.GCPCredentialsResponse{} + if err := json.Unmarshal([]byte(*credsResp.JSON200.Credentials), cliResp); err != nil { + return nil, fmt.Errorf("unable to unmarshal GCP credentials response from backplane %s: %w", *credsResp.JSON200.Credentials, err) + } + return cliResp, nil + default: + return nil, fmt.Errorf("unsupported cloud provider: %s", cfg.Cluster.CloudProvider().ID()) + } } type assumeChainResponse struct {