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
42 changes: 37 additions & 5 deletions cmd/ocm-backplane/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,12 @@ func GetRestConfig(bp config.BackplaneConfiguration, clusterID string) (*rest.Co
return BuildRestConfig(bpAPIClusterURL, accessToken, proxyURL)
}

// GetRestConfig returns a client-go *rest.Config which can be used to programmatically interact with the
// Kubernetes API of a provided clusterID
// GetRestConfigWithConn returns a client-go *rest.Config which can be used to programmatically interact with the
// Kubernetes API of a provided clusterID, using a provided OCM connection.
func GetRestConfigWithConn(bp config.BackplaneConfiguration, ocmConnection *ocmsdk.Connection, clusterID string) (*rest.Config, error) {
if ocmConnection == nil {
return nil, fmt.Errorf("nil OCM connection provided to GetRestConfigWithConn()")
}
cluster, err := ocm.DefaultOCMInterface.GetClusterInfoByIDWithConn(ocmConnection, clusterID)
if err != nil {
return nil, err
Expand All @@ -500,7 +503,7 @@ func GetRestConfigWithConn(bp config.BackplaneConfiguration, ocmConnection *ocms
return nil, err
}

bpAPIClusterURL, err := doLogin(bp.URL, clusterID, *accessToken)
bpAPIClusterURL, err := doLoginWithConn(bp.URL, clusterID, *accessToken, ocmConnection)
if err != nil {
return nil, fmt.Errorf("failed to backplane login to cluster %s: %v", cluster.Name(), err)
}
Expand Down Expand Up @@ -533,11 +536,40 @@ func GetRestConfigAsUser(bp config.BackplaneConfiguration, clusterID, username s
return cfg, nil
}

// GetRestConfigAsUserWithConn returns a client-go *rest.Config like GetRestConfig, but supports configuring an
// impersonation username. Commonly, this is "backplane-cluster-admin"
// best practice would be to add at least one elevationReason in order to justity the impersonation
// Uses provided OCM connection for attributes
func GetRestConfigAsUserWithConn(bp config.BackplaneConfiguration, ocmConn *ocmsdk.Connection, clusterID, username string, elevationReasons ...string) (*rest.Config, error) {
cfg, err := GetRestConfigWithConn(bp, ocmConn, clusterID)
if err != nil {
return nil, err
}

cfg.Impersonate = rest.ImpersonationConfig{
UserName: username,
}

if len(elevationReasons) > 0 {
cfg.Impersonate.Extra = map[string][]string{"reason": elevationReasons}
}

return cfg, nil
}

// doLogin returns the proxy url for the target cluster.
func doLogin(api, clusterID, accessToken string) (string, error) {
return doLoginWithConn(api, clusterID, accessToken, nil)
}

client, err := backplaneapi.DefaultClientUtils.MakeRawBackplaneAPIClientWithAccessToken(api, accessToken)

func doLoginWithConn(api, clusterID, accessToken string, ocmConn *ocmsdk.Connection) (string, error) {
var client BackplaneApi.ClientInterface
var err error = nil
if ocmConn != nil {
client, err = backplaneapi.DefaultClientUtils.MakeRawBackplaneAPIClientWithAccessTokenWithConn(api, accessToken, ocmConn)
} else {
client, err = backplaneapi.DefaultClientUtils.MakeRawBackplaneAPIClientWithAccessToken(api, accessToken)
}
if err != nil {
return "", fmt.Errorf("unable to create backplane api client")
}
Expand Down
18 changes: 15 additions & 3 deletions pkg/backplaneapi/clientUtils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ import (
"net/http"
"net/url"

ocmsdk "github.com/openshift-online/ocm-sdk-go"
BackplaneApi "github.com/openshift/backplane-api/pkg/client"
logger "github.com/sirupsen/logrus"

"github.com/openshift/backplane-cli/pkg/cli/config"
"github.com/openshift/backplane-cli/pkg/info"
"github.com/openshift/backplane-cli/pkg/ocm"
logger "github.com/sirupsen/logrus"
)

type ClientUtils interface {
MakeBackplaneAPIClient(base string) (BackplaneApi.ClientWithResponsesInterface, error)
MakeBackplaneAPIClientWithAccessToken(base, accessToken string) (BackplaneApi.ClientWithResponsesInterface, error)
MakeRawBackplaneAPIClientWithAccessToken(base, accessToken string) (BackplaneApi.ClientInterface, error)
MakeRawBackplaneAPIClientWithAccessTokenWithConn(base, accessToken string, ocmConn *ocmsdk.Connection) (BackplaneApi.ClientInterface, error)
MakeRawBackplaneAPIClient(base string) (BackplaneApi.ClientInterface, error)
GetBackplaneClient(backplaneURL string, ocmToken string, proxyURL *string) (client BackplaneApi.ClientInterface, err error)
SetClientProxyURL(proxyURL string) error
Expand All @@ -45,9 +46,20 @@ func makeClientOptions(accessToken string) BackplaneApi.ClientOption {
}

func (s *DefaultClientUtilsImpl) MakeRawBackplaneAPIClientWithAccessToken(base, accessToken string) (BackplaneApi.ClientInterface, error) {
return s.MakeRawBackplaneAPIClientWithAccessTokenWithConn(base, accessToken, nil)
}

func (s *DefaultClientUtilsImpl) MakeRawBackplaneAPIClientWithAccessTokenWithConn(base, accessToken string, ocmConn *ocmsdk.Connection) (BackplaneApi.ClientInterface, error) {

// Inject client Proxy Url from config
if s.clientProxyURL == "" {
bpConfig, err := config.GetBackplaneConfiguration()
var bpConfig config.BackplaneConfiguration
var err error
if ocmConn != nil {
bpConfig, err = config.GetBackplaneConfigurationWithConn(ocmConn)
} else {
bpConfig, err = config.GetBackplaneConfiguration()
}
if err != nil {
return nil, err
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/backplaneapi/mocks/clientUtilsMock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 43 additions & 9 deletions pkg/cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
logger "github.com/sirupsen/logrus"
"github.com/spf13/viper"

ocmsdk "github.com/openshift-online/ocm-sdk-go"
"github.com/openshift/backplane-cli/pkg/info"
"github.com/openshift/backplane-cli/pkg/ocm"
)
Expand Down Expand Up @@ -103,6 +104,12 @@ func GetConfigFilePath() (string, error) {

// GetBackplaneConfiguration parses and returns the given backplane configuration
func GetBackplaneConfiguration() (bpConfig BackplaneConfiguration, err error) {
return GetBackplaneConfigurationWithConn(nil)
}

// GetBackplaneConfiguration parses and returns the given backplane configuration using attributes
// from provided OCM connection
func GetBackplaneConfigurationWithConn(ocmConn *ocmsdk.Connection) (bpConfig BackplaneConfiguration, err error) {
viper.SetDefault(prodEnvNameKey, prodEnvNameDefaultValue)
viper.SetDefault(jiraBaseURLKey, JiraBaseURLDefaultValue)
viper.SetDefault(JiraConfigForAccessRequestsKey, JiraConfigForAccessRequestsDefaultValue)
Expand Down Expand Up @@ -146,22 +153,31 @@ func GetBackplaneConfiguration() (bpConfig BackplaneConfiguration, err error) {
} else {
logger.Debug("This is govcloud, no proxy to use")
}

// Warn user if url defined in the config file
if viper.GetString("url") != "" {
logger.Warn("Manual URL configuration is deprecated, please remove URL key from Backplane configuration")
}

// Warn if user has explicitly defined backplane URL via env
url, ok := getBackplaneEnv(info.BackplaneURLEnvName)
if ok {
logger.Warn(fmt.Sprintf("Manual URL configuration is deprecated, please unset the environment %s", info.BackplaneURLEnvName))
bpConfig.URL = url
} else {
// Fetch backplane URL from ocm env
if bpConfig.URL, err = bpConfig.GetBackplaneURL(); err != nil {
url, envURLok := getBackplaneEnv(info.BackplaneURLEnvName)
if envURLok {
logger.Warn(fmt.Printf("Manual URL configuration is deprecated, please unset the environment %s", info.BackplaneURLEnvName))
}

if ocmConn != nil {
// If an OCM connection is provided use this to fetch BP URL
// from its v1.environment info
if bpConfig.URL, err = bpConfig.GetBackplaneURLWithConn(ocmConn); err != nil {
return bpConfig, err
}
} else {
if envURLok {
bpConfig.URL = url
} else {
// Fetch backplane URL from ocm env
if bpConfig.URL, err = bpConfig.GetBackplaneURL(); err != nil {
return bpConfig, err
}
}
}

// proxyURL is required
Expand Down Expand Up @@ -255,6 +271,10 @@ var testProxy = func(ctx context.Context, testURL string, proxyURL url.URL) erro
return nil
}

func (config *BackplaneConfiguration) GetFirstWorkingProxyURL(s []string) string {
return config.getFirstWorkingProxyURL(s)
}

func (config *BackplaneConfiguration) getFirstWorkingProxyURL(s []string) string {
if len(s) == 0 {
logger.Debug("No proxy to use")
Expand Down Expand Up @@ -371,6 +391,20 @@ func GetConfigDirectory() (string, error) {
return configDirectory, nil
}

// GetBackplaneURL returns API URL
func (config *BackplaneConfiguration) GetBackplaneURLWithConn(ocmConn *ocmsdk.Connection) (string, error) {
ocmEnv, err := ocm.DefaultOCMInterface.GetOCMEnvironmentWithConn(ocmConn)
if err != nil {
return "", err
}
url, ok := ocmEnv.GetBackplaneURL()
if !ok {
return "", fmt.Errorf("the requested API endpoint is not available for the OCM environment: %v", ocmEnv.Name())
}
logger.Infof("Backplane URL retrieved via OCM environment: %s", url)
return url, nil
}

// GetBackplaneURL returns API URL
func (config *BackplaneConfiguration) GetBackplaneURL() (string, error) {

Expand Down
15 changes: 15 additions & 0 deletions pkg/ocm/mocks/ocmWrapperMock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion pkg/ocm/ocm.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type OCMInterface interface {
GetOCMEnvironment() (*cmv1.Environment, error)
GetOCMAccessTokenWithConn(ocmConnection *ocmsdk.Connection) (*string, error)
GetClusterInfoByIDWithConn(ocmConnection *ocmsdk.Connection, clusterID string) (*cmv1.Cluster, error)
GetOCMEnvironmentWithConn(connection *ocmsdk.Connection) (*cmv1.Environment, error)
IsClusterAccessProtectionEnabled(ocmConnection *ocmsdk.Connection, clusterID string) (bool, error)
GetClusterActiveAccessRequest(ocmConnection *ocmsdk.Connection, clusterID string) (*acctrspv1.AccessRequest, error)
CreateClusterAccessRequest(ocmConnection *ocmsdk.Connection, clusterID, reason, jiraIssueID, approvalDuration string) (*acctrspv1.AccessRequest, error)
Expand Down Expand Up @@ -387,14 +388,24 @@ func (o *DefaultOCMInterfaceImpl) GetStsSupportJumpRoleARN(ocmConnection *ocmsdk
return response.Body().RoleArn(), nil
}

// GetOCMEnvironment returns the Backplane API URL based on the OCM env
// GetOCMEnvironment returns the OCM v1.environment response (containing the Backplane API URL).
func (o *DefaultOCMInterfaceImpl) GetOCMEnvironment() (*cmv1.Environment, error) {
// Create the client for the OCM API
connection, err := o.SetupOCMConnection()
if err != nil {
return nil, fmt.Errorf("failed to create OCM connection: %v", err)
}

defer connection.Close()
return o.GetOCMEnvironmentWithConn(connection)
}

// GetOCMEnvironmentWithConn returns the v1.environment response for the provided
// OCM connection (containing the Backplane API URL)
func (o *DefaultOCMInterfaceImpl) GetOCMEnvironmentWithConn(connection *ocmsdk.Connection) (*cmv1.Environment, error) {
if connection == nil {
return nil, fmt.Errorf("err GetOCMEnvironmentWithConn() provided nil OCM connection")
}
responseEnv, err := connection.ClustersMgmt().V1().Environment().Get().Send()
if err != nil {
// Check if the error indicates a forbidden status
Expand Down