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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ require (
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.53.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.55.7 h1:yd6F0NesTmsJVOCINfKXB
github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.55.7/go.mod h1:t6XfFh0GZGngXjAlsmFedoylELOo9t/XetRCeTEfZEc=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.293.1 h1:hb/FbDMxNnHFiXa74to/sh/hfFa/euklzO765Cb3qZY=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.293.1/go.mod h1:rB577GvkmJADVOFGY8/j9sPv/ewcsEtQNsd9Lrn7Zx0=
github.com/aws/aws-sdk-go-v2/service/iam v1.53.4 h1:FUWGS7m97SYL0bk9Kb+Q4bVpcSrKOHNiIbEXIRFTRW4=
github.com/aws/aws-sdk-go-v2/service/iam v1.53.4/go.mod h1:seDE466zJ4haVuAVcRk+yIH4DWb3s6cqt3Od8GxnGAA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7suZk9UCJHE1Iw9GMZJJl0dAnKXXP1NaSDHwmw=
Expand Down
47 changes: 45 additions & 2 deletions pkg/backplane/backplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,29 @@ import (
"k8s.io/client-go/rest"
)

// ManagingClusterType represents the type of managing cluster for a remediation
type ManagingClusterType string

const (
// ManagingClusterTypeSpoke indicates the remediation is for the spoke cluster itself (nil in API)
ManagingClusterTypeSpoke ManagingClusterType = ""
// ManagingClusterTypeManagement indicates the remediation is for a Hypershift management cluster
ManagingClusterTypeManagement ManagingClusterType = "management"
// ManagingClusterTypeHive indicates the remediation is for a classic cluster's hive
ManagingClusterTypeHive ManagingClusterType = "hive"
)

// Client provides methods for interacting with the backplane API
type Client interface {
// CreateReport creates a new cluster report
CreateReport(ctx context.Context, clusterId string, summary string, reportData string) (*bpapi.Report, error)
// GetRestConfig creates a remediation and returns a rest.Config for connecting to the cluster's API server through the backplane proxy
//
// Deprecated: Use GetRestConfigWithManagingClusterType instead
GetRestConfig(ctx context.Context, clusterId string, remediationName string, isManagementCluster bool) (*RestConfig, error)
// GetRestConfigWithManagingClusterType creates a remediation and returns a rest.Config for connecting through the backplane proxy
// managingClusterType can be ManagingClusterTypeSpoke, ManagingClusterTypeManagement, or ManagingClusterTypeHive
GetRestConfigWithManagingClusterType(ctx context.Context, clusterId string, remediationName string, managingClusterType ManagingClusterType) (*RestConfig, error)
}

type Cleaner interface {
Expand Down Expand Up @@ -119,13 +136,31 @@ func (c *ClientImpl) CreateReport(ctx context.Context, clusterId string, summary
}

func (c *ClientImpl) GetRestConfig(ctx context.Context, clusterId string, remediationName string, isManagementCluster bool) (*RestConfig, error) {
managingClusterType := ManagingClusterTypeSpoke
if isManagementCluster {
managingClusterType = ManagingClusterTypeManagement
}
return c.GetRestConfigWithManagingClusterType(ctx, clusterId, remediationName, managingClusterType)
}

func (c *ClientImpl) GetRestConfigWithManagingClusterType(ctx context.Context, clusterId string, remediationName string, managingClusterType ManagingClusterType) (*RestConfig, error) {
createRemediationParams := bpapi.CreateRemediationParams{
RemediationName: remediationName,
ManagingCluster: nil, // If this parameter is nil in CreateRemediationParams, it specifies spoke cluster
}
if isManagementCluster {

// Set the managing cluster type based on the parameter
switch managingClusterType {
case ManagingClusterTypeManagement:
managingCluster := bpapi.CreateRemediationParamsManagingClusterManagement
createRemediationParams.ManagingCluster = &managingCluster
case ManagingClusterTypeHive:
managingCluster := bpapi.CreateRemediationParamsManagingClusterHive
createRemediationParams.ManagingCluster = &managingCluster
case ManagingClusterTypeSpoke:
// nil is already set, nothing to do
default:
return nil, fmt.Errorf("invalid managing cluster type: %s", managingClusterType)
}

ocmConnection := c.ocmClient.GetConnection()
Expand Down Expand Up @@ -171,9 +206,17 @@ func (c *ClientImpl) GetRestConfig(ctx context.Context, clusterId string, remedi
RemediationInstanceId: response.JSON200.RemediationInstanceId,
ManagingCluster: nil,
}
if isManagementCluster {

// Set the managing cluster type for deletion based on the parameter
switch managingClusterType {
case ManagingClusterTypeManagement:
managingCluster := bpapi.DeleteRemediationParamsManagingClusterManagement
deleteRemediationParams.ManagingCluster = &managingCluster
case ManagingClusterTypeHive:
managingCluster := bpapi.DeleteRemediationParamsManagingClusterHive
deleteRemediationParams.ManagingCluster = &managingCluster
case ManagingClusterTypeSpoke:
// nil is already set, nothing to do
}

restConfig := &RestConfig{
Expand Down
136 changes: 117 additions & 19 deletions pkg/backplane/mock/backplanemock.go

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

110 changes: 89 additions & 21 deletions pkg/investigations/investigation/investigation.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,30 @@ type Investigation interface {

// Resources holds all resources/tools required for alert investigations
type Resources struct {
Name string
Cluster *cmv1.Cluster
ClusterDeployment *hivev1.ClusterDeployment
AwsClient aws.Client
BpClient backplane.Client
RestConfig *backplane.RestConfig
K8sClient k8sclient.Client
OcmClient ocm.Client
PdClient pagerduty.Client
Notes *notewriter.NoteWriter
OCClient oc.Client
ManagementRestConfig *backplane.RestConfig
ManagementK8sClient k8sclient.Client
ManagementOCClient oc.Client
HCPNamespace string
HCNamespace string
Name string
Cluster *cmv1.Cluster
ClusterDeployment *hivev1.ClusterDeployment
AwsClient aws.Client
BpClient backplane.Client
RestConfig *backplane.RestConfig
K8sClient k8sclient.Client
OcmClient ocm.Client
PdClient pagerduty.Client
Notes *notewriter.NoteWriter
OCClient oc.Client
// ManagementRestConfig provides access to either:
// - The Hypershift management cluster (for HCP clusters)
// - The hive managing this cluster (for classic OSD/ROSA clusters)
ManagementRestConfig *backplane.RestConfig
// ManagementK8sClient is a K8s client for either the Hypershift management cluster or the hive
ManagementK8sClient k8sclient.Client
// ManagementOCClient is an OC client for either the Hypershift management cluster or the hive
ManagementOCClient oc.Client
// HCPNamespace is the namespace containing HCP resources (only for HCP clusters)
HCPNamespace string
// HCNamespace is the HostedCluster namespace (only for HCP clusters)
HCNamespace string
// IsHCP indicates if this is a Hypershift (HCP) cluster
IsHCP bool
IsInfrastructureCluster bool
ManagementClusterName string
Expand Down Expand Up @@ -292,16 +300,25 @@ func (r *ResourceBuilderT) Build() (*Resources, error) {
return r.builtResources, nil
}

// buildManagementClusterResources checks if the cluster is HCP and builds management cluster resources
// buildManagementClusterResources builds resources for either:
// - The Hypershift management cluster (for HCP clusters)
// - The hive managing this cluster (for classic OSD/ROSA clusters)
func (r *ResourceBuilderT) buildManagementClusterResources() error {
r.builtResources.IsHCP = false

hypershift := r.builtResources.Cluster.Hypershift()
if hypershift == nil || !hypershift.Enabled() {
logging.Infof("Cluster %s is not an HCP cluster, skipping management cluster resource creation", r.clusterId)
return nil
isHypershiftCluster := hypershift != nil && hypershift.Enabled()

if isHypershiftCluster {
return r.buildHypershiftManagementResources()
}

// For classic clusters (non-Hypershift), build hive resources
return r.buildHiveResources()
}

// buildHypershiftManagementResources builds management cluster resources for Hypershift clusters
func (r *ResourceBuilderT) buildHypershiftManagementResources() error {
r.builtResources.IsHCP = true
logging.Infof("Cluster %s is an HCP cluster, retrieving management cluster information", r.clusterId)

Expand Down Expand Up @@ -334,7 +351,12 @@ func (r *ResourceBuilderT) buildManagementClusterResources() error {

if r.buildManagementRestConfig && r.builtResources.ManagementRestConfig == nil {
logging.Infof("Creating RestConfig for management cluster")
r.builtResources.ManagementRestConfig, err = r.builtResources.BpClient.GetRestConfig(context.Background(), r.builtResources.Cluster.ID(), r.name, true)
r.builtResources.ManagementRestConfig, err = r.builtResources.BpClient.GetRestConfigWithManagingClusterType(
context.Background(),
r.builtResources.Cluster.ID(),
r.name,
backplane.ManagingClusterTypeManagement,
)
if err != nil {
return ManagementRestConfigError{
ClusterID: r.clusterId,
Expand Down Expand Up @@ -389,6 +411,52 @@ func (r *ResourceBuilderT) buildManagementClusterResources() error {
return nil
}

// buildHiveResources builds hive resources for classic (non-Hypershift) clusters
func (r *ResourceBuilderT) buildHiveResources() error {
logging.Infof("Cluster %s is a classic cluster, retrieving hive information", r.clusterId)

var err error
if r.buildManagementRestConfig && r.builtResources.ManagementRestConfig == nil {
logging.Infof("Creating RestConfig for hive")
r.builtResources.ManagementRestConfig, err = r.builtResources.BpClient.GetRestConfigWithManagingClusterType(
context.Background(),
r.builtResources.Cluster.ID(),
r.name,
backplane.ManagingClusterTypeHive,
)
if err != nil {
return ManagementRestConfigError{
ClusterID: r.clusterId,
Err: fmt.Errorf("failed to get hive RestConfig: %w", err),
}
}
}

if r.buildManagementK8sClient && r.builtResources.ManagementK8sClient == nil {
logging.Infof("Creating k8s client for hive of %s", r.clusterId)
r.builtResources.ManagementK8sClient, err = k8sclient.New(&r.builtResources.ManagementRestConfig.Config)
if err != nil {
return ManagementK8sClientError{
ClusterID: r.clusterId,
Err: fmt.Errorf("failed to create hive k8s client: %w", err),
}
}
}

if r.buildManagementOCClient && r.builtResources.ManagementOCClient == nil {
logging.Infof("Creating OC client for hive of %s", r.clusterId)
r.builtResources.ManagementOCClient, err = oc.New(context.Background(), &r.builtResources.ManagementRestConfig.Config)
if err != nil {
return ManagementOCClientError{
ClusterID: r.clusterId,
Err: fmt.Errorf("failed to create hive OC client: %w", err),
}
}
}

return nil
}

// This is an implementation to be used in tests, but putting it into a _test.go file will make it not resolvable.
type ResourceBuilderMock struct {
Resources *Resources
Expand Down
Loading