Skip to content

Commit

Permalink
Added error checking, extracted token and connetion builders to use t… (
Browse files Browse the repository at this point in the history
#227)

* Added error checking, extracted token and connetion builders to use the utils function, all support commands can use any cluster identifyer, etc

* change .each function on GetlimitedSupportReasons function for a loop
  • Loading branch information
luis-falcon authored Jul 14, 2022
1 parent 06dfff7 commit ed23eba
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 98 deletions.
31 changes: 8 additions & 23 deletions cmd/cluster/support/delete.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package support

import (
"context"
"encoding/json"
"fmt"
"log"
Expand Down Expand Up @@ -78,47 +77,33 @@ func (o *deleteOptions) complete(cmd *cobra.Command, args []string) error {

func (o *deleteOptions) run() error {

ctx := context.Background()

// Create an OCM client to talk to the cluster API
token := os.Getenv("OCM_TOKEN")
if token == "" {
ocmToken, err := ctlutil.GetOCMAccessToken()
if err != nil {
log.Fatalf("OCM token not set. Please configure by using the OCM_TOKEN environment variable or the ocm cli")
connection := ctlutil.CreateConnection()
defer func() {
if err := connection.Close(); err != nil {
fmt.Printf("Cannot close the connection: %q\n", err)
os.Exit(1)
}
token = *ocmToken
}
connection, err := sdk.NewConnectionBuilder().
Tokens(token).
Build()
if err != nil {
fmt.Fprintf(os.Stderr, "Can't build connection: %v\n", err)
os.Exit(1)
}
defer connection.Close()
}()

// Stop here if dry-run
if isDryRun {
return nil
}

// confirmSend prompt to confirm
err = confirmSend()
err := confirmSend()
if err != nil {
fmt.Println("failed to confirmSend(): ", err.Error())
return err
}

// Get cluster resource
clusterResource := connection.ClustersMgmt().V1().Clusters().Cluster(o.clusterID)
clusterResponse, err := clusterResource.Get().SendContext(ctx)
//getting the cluster
cluster, err := ctlutil.GetCluster(connection, o.clusterID)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't retrieve cluster: %v\n", err)
os.Exit(1)
}
cluster := clusterResponse.Body()

deleteRequest, err := createDeleteRequest(connection, cluster, o.limitedSupportReasonID)
if err != nil {
Expand Down
34 changes: 9 additions & 25 deletions cmd/cluster/support/post.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package support

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -86,30 +85,18 @@ func (o *postOptions) complete(cmd *cobra.Command, args []string) error {

func (o *postOptions) run() error {

ctx := context.Background()

// Parse the given JSON template provided via '-t' flag
// and load it into the LimitedSupport variable
readTemplate()

// Create an OCM client to talk to the cluster API
token := os.Getenv("OCM_TOKEN")
if token == "" {
ocmToken, err := ctlutil.GetOCMAccessToken()
if err != nil {
log.Fatalf("OCM token not set. Please configure by using the OCM_TOKEN environment variable or the ocm cli")
//create connection to sdk
connection := ctlutil.CreateConnection()
defer func() {
if err := connection.Close(); err != nil {
fmt.Printf("Cannot close the connection: %q\n", err)
os.Exit(1)
}
token = *ocmToken
}
connection, err := sdk.NewConnectionBuilder().
Tokens(token).
Build()
if err != nil {
fmt.Fprintf(os.Stderr, "Can't build connection: %v\n", err)
os.Exit(1)
}
defer connection.Close()
}()

// Print limited support template to be sent
fmt.Printf("The following limited support reason will be sent to %s:\n", o.clusterID)
Expand All @@ -124,20 +111,18 @@ func (o *postOptions) run() error {
}

// confirmSend prompt to confirm
err = confirmSend()
err := confirmSend()
if err != nil {
fmt.Println("failed to confirmSend(): ", err.Error())
return err
}

// Get cluster resource
clusterResource := connection.ClustersMgmt().V1().Clusters().Cluster(o.clusterID)
clusterResponse, err := clusterResource.Get().SendContext(ctx)
//getting the cluster
cluster, err := ctlutil.GetCluster(connection, o.clusterID)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't retrieve cluster: %v\n", err)
os.Exit(1)
}
cluster := clusterResponse.Body()

// postRequest calls createPostRequest and take in client and clustersmgmt/v1.cluster object
postRequest, err := createPostRequest(connection, cluster)
Expand Down Expand Up @@ -174,7 +159,6 @@ func createPostRequest(ocmClient *sdk.Connection, cluster *v1.Cluster) (request
if err != nil {
return nil, fmt.Errorf("cannot apply body flag '%s'", err)
}

return request, nil
}

Expand Down
65 changes: 15 additions & 50 deletions cmd/cluster/support/status.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
package support

import (
"context"
"fmt"
"log"
"os"

sdk "github.com/openshift-online/ocm-sdk-go"
"github.com/openshift/osdctl/internal/utils/globalflags"
"github.com/openshift/osdctl/pkg/printer"
"github.com/openshift/osdctl/pkg/utils"
ctlutil "github.com/openshift/osdctl/pkg/utils"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"

cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)

type limitedSupportReasonItem struct {
ID string
Summary string
Details string
}

// supportcheck defines the struct for running supportCheck command
// This command requires the ocm API Token https://cloud.redhat.com/openshift/token to be available in the OCM_TOKEN env variable.

type statusOptions struct {
output string
verbose bool
Expand Down Expand Up @@ -72,52 +59,30 @@ func (o *statusOptions) complete(cmd *cobra.Command, args []string) error {
}

func (o *statusOptions) run() error {
// Create a context:
ctx := context.Background()
// Ocm token
token := os.Getenv("OCM_TOKEN")
if token == "" {
ocmToken, err := utils.GetOCMAccessToken()
if err != nil {
log.Fatalf("OCM token not set. Please configure by using the OCM_TOKEN environment variable or the ocm cli")

//create connection to sdk
connection := ctlutil.CreateConnection()
defer func() {
if err := connection.Close(); err != nil {
fmt.Printf("Cannot close the connection: %q\n", err)
os.Exit(1)
}
token = *ocmToken
}
connection, err := sdk.NewConnectionBuilder().
Tokens(token).
Build()
}()

//getting the cluster
cluster, err := ctlutil.GetCluster(connection, o.clusterID)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't build connection: %v\n", err)
fmt.Fprintf(os.Stderr, "Can't retrieve cluster: %v\n", err)
os.Exit(1)
}
defer connection.Close()

// Get the client for the resource that manages the collection of clusters:
collection := connection.ClustersMgmt().V1().Clusters()
// Get cluster resource
resource := collection.Cluster(o.clusterID).LimitedSupportReasons()
// Send the request to retrieve the list of limited support reasons:
response, err := resource.List().SendContext(ctx)

//getting the limited support reasons for the cluster
clusterLimitedSupportReasons, err := ctlutil.GetClusterLimitedSupportReasons(connection, cluster.ID())
if err != nil {
fmt.Fprintf(os.Stderr, "Can't retrieve cluster limited support reasons: %v\n", err)
os.Exit(1)
}

reasons, _ := response.GetItems()

var clusterLimitedSupportReasons []*limitedSupportReasonItem

reasons.Each(func(limitedSupportReason *cmv1.LimitedSupportReason) bool {
clusterLimitedSupportReason := limitedSupportReasonItem{
ID: limitedSupportReason.ID(),
Summary: limitedSupportReason.Summary(),
Details: limitedSupportReason.Details(),
}
clusterLimitedSupportReasons = append(clusterLimitedSupportReasons, &clusterLimitedSupportReason)
return true
})

// No reasons found, cluster is fully supported
if len(clusterLimitedSupportReasons) == 0 {
fmt.Printf("Cluster is fully supported\n")
Expand Down
129 changes: 129 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,17 @@ import (
"os"
"os/exec"
"strings"

sdk "github.com/openshift-online/ocm-sdk-go"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
)

type lmtSprReasonItem struct {
ID string
Summary string
Details string
}

func GetOCMAccessToken() (*string, error) {
// Get ocm access token
ocmCmd := exec.Command("ocm", "token")
Expand All @@ -19,3 +28,123 @@ func GetOCMAccessToken() (*string, error) {

return &accessToken, nil
}

//GetCluster Function allows to get a single cluster with any identifier (displayname, ID, or external ID)
func GetCluster(connection *sdk.Connection, key string) (cluster *cmv1.Cluster, err error) {
// Prepare the resources that we will be using:
subsResource := connection.AccountsMgmt().V1().Subscriptions()
clustersResource := connection.ClustersMgmt().V1().Clusters()

// Try to find a matching subscription:
subsSearch := fmt.Sprintf(
"(display_name = '%s' or cluster_id = '%s' or external_cluster_id = '%s') and "+
"status in ('Reserved', 'Active')",
key, key, key,
)
subsListResponse, err := subsResource.List().
Search(subsSearch).
Size(1).
Send()
if err != nil {
err = fmt.Errorf("Can't retrieve subscription for key '%s': %v", key, err)
return
}

// If there is exactly one matching subscription then return the corresponding cluster:
subsTotal := subsListResponse.Total()
if subsTotal == 1 {
id, ok := subsListResponse.Items().Slice()[0].GetClusterID()
if ok {
var clusterGetResponse *cmv1.ClusterGetResponse
clusterGetResponse, err = clustersResource.Cluster(id).Get().
Send()
if err != nil {
err = fmt.Errorf(
"Can't retrieve cluster for key '%s': %v",
key, err,
)
return
}
cluster = clusterGetResponse.Body()
return
}
}

// If there are multiple subscriptions that match the cluster then we should report it as
// an error:
if subsTotal > 1 {
err = fmt.Errorf(
"There are %d subscriptions with cluster identifier or name '%s'",
subsTotal, key,
)
return
}

// If we are here then no subscription matches the passed key. It may still be possible that
// the cluster exists but it is not reporting metrics, so it will not have the external
// identifier in the accounts management service. To find those clusters we need to check
// directly in the clusters management service.
clustersSearch := fmt.Sprintf(
"id = '%s' or name = '%s' or external_id = '%s'",
key, key, key,
)
clustersListResponse, err := clustersResource.List().
Search(clustersSearch).
Size(1).
Send()
if err != nil {
err = fmt.Errorf("Can't retrieve clusters for key '%s': %v", key, err)
return
}

// If there is exactly one cluster matching then return it:
clustersTotal := clustersListResponse.Total()
if clustersTotal == 1 {
cluster = clustersListResponse.Items().Slice()[0]
return
}

// If there are multiple matching clusters then we should report it as an error:
if clustersTotal > 1 {
err = fmt.Errorf(
"There are %d clusters with identifier or name '%s'",
clustersTotal, key,
)
return
}

// If we are here then there are no subscriptions or clusters matching the passed key:
err = fmt.Errorf(
"There are no subscriptions or clusters with identifier or name '%s'",
key,
)
return
}

func GetClusterLimitedSupportReasons(connection *sdk.Connection, clusterID string) ([]*lmtSprReasonItem, error) {

limitedSupportReasons, err := connection.ClustersMgmt().V1().
Clusters().
Cluster(clusterID).
LimitedSupportReasons().
List().
Send()
if err != nil {
return nil, fmt.Errorf("Failed to get limited Support Reasons: %s", err)
}

lmtReason := limitedSupportReasons.Items().Slice()

var clusterLmtSprReasons []*lmtSprReasonItem

for _, reason := range lmtReason {
clusterLmtSprReason := lmtSprReasonItem{
ID: reason.ID(),
Summary: reason.Summary(),
Details: reason.Details(),
}
clusterLmtSprReasons = append(clusterLmtSprReasons, &clusterLmtSprReason)
}

return clusterLmtSprReasons, nil
}

0 comments on commit ed23eba

Please sign in to comment.