Skip to content

Commit

Permalink
Use new servicelog endpoint for listing service logs
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexVulaj committed Sep 27, 2023
1 parent 4679b7d commit ea9e445
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 132 deletions.
8 changes: 4 additions & 4 deletions cmd/cluster/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cluster
import (
"encoding/json"
"fmt"
v1 "github.com/openshift-online/ocm-sdk-go/servicelogs/v1"
"os"
"os/exec"
"sort"
Expand All @@ -17,7 +18,6 @@ import (
"github.com/aws/aws-sdk-go-v2/service/cloudtrail"
"github.com/aws/aws-sdk-go-v2/service/cloudtrail/types"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
sl "github.com/openshift/osdctl/internal/servicelog"
"github.com/openshift/osdctl/pkg/osdCloud"
"github.com/openshift/osdctl/pkg/osdctlConfig"
"github.com/openshift/osdctl/pkg/printer"
Expand Down Expand Up @@ -72,7 +72,7 @@ type contextData struct {
// limited Support Status
LimitedSupportReasons []*cmv1.LimitedSupportReason
// Service Logs
ServiceLogs []sl.ServiceLogShort
ServiceLogs []*v1.LogEntry

// Jira Cards
JiraIssues []jira.Issue
Expand Down Expand Up @@ -263,7 +263,7 @@ func (o *contextOptions) printShortOutput(data *contextData) {

var numInternalServiceLogs int
for _, serviceLog := range data.ServiceLogs {
if serviceLog.InternalOnly {
if serviceLog.InternalOnly() {
numInternalServiceLogs++
}
}
Expand Down Expand Up @@ -360,7 +360,7 @@ func (o *contextOptions) generateContextData() (*contextData, []error) {
if o.verbose {
fmt.Fprintln(os.Stderr, "Getting Service Logs...")
}
data.ServiceLogs, err = servicelog.GetServiceLogsSince(cluster.ID(), o.days)
data.ServiceLogs, err = servicelog.GetServiceLogsSince(cluster.ID(), o.days, false, false)
if err != nil {
errors = append(errors, fmt.Errorf("Error while getting the service logs: %v", err))
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/org/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
v1 "github.com/openshift-online/ocm-sdk-go/servicelogs/v1"
"os"
"strconv"
"sync"
Expand All @@ -14,7 +15,6 @@ import (
sdk "github.com/openshift-online/ocm-sdk-go"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
"github.com/openshift/osdctl/cmd/servicelog"
sl "github.com/openshift/osdctl/internal/servicelog"
"github.com/openshift/osdctl/pkg/printer"
pdProvider "github.com/openshift/osdctl/pkg/provider/pagerduty"
"github.com/openshift/osdctl/pkg/utils"
Expand All @@ -34,7 +34,7 @@ type ClusterInfo struct {
CloudProvider string
Plan string
NodeCount float64
ServiceLogs []sl.ServiceLogShort
ServiceLogs []*v1.LogEntry
PdAlerts map[string][]pd.Incident
JiraIssues []jira.Issue
LimitedSupportReasons []*cmv1.LimitedSupportReason
Expand Down Expand Up @@ -285,7 +285,7 @@ func addLimitedSupportReasons(clusterInfo *ClusterInfo, ocmClient *sdk.Connectio

func addServiceLogs(clusterInfo *ClusterInfo) error {
var err error
clusterInfo.ServiceLogs, err = servicelog.GetServiceLogsSince(clusterInfo.ID, ServiceLogDaysSince)
clusterInfo.ServiceLogs, err = servicelog.GetServiceLogsSince(clusterInfo.ID, ServiceLogDaysSince, false, false)
if err != nil {
return fmt.Errorf("failed to fetch service logs for cluster %v: %w", clusterInfo.ID, err)
}
Expand Down
71 changes: 58 additions & 13 deletions cmd/servicelog/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package servicelog
import (
"encoding/json"
"fmt"
sdk "github.com/openshift-online/ocm-sdk-go"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
v1 "github.com/openshift-online/ocm-sdk-go/servicelogs/v1"
"github.com/openshift/osdctl/internal/servicelog"
sl "github.com/openshift/osdctl/internal/servicelog"
"github.com/openshift/osdctl/pkg/utils"
"time"
)

Expand Down Expand Up @@ -61,30 +64,72 @@ func validateBadResponse(body []byte) (badReply *servicelog.BadReply, err error)
// time.Now() and time.Now()-duration. the first parameter will contain a slice
// of the service logs from the given time period, while the second return value
// indicates if an error has happened.
func GetServiceLogsSince(clusterID string, days int) ([]sl.ServiceLogShort, error) {
func GetServiceLogsSince(clusterID string, days int, allMessages bool, internalOnly bool) ([]*v1.LogEntry, error) {
// time.Now().Sub() returns the duration between two times, so we negate the duration in Add()
earliestTime := time.Now().AddDate(0, 0, -days)

slResponse, err := FetchServiceLogs(clusterID)
slResponse, err := FetchServiceLogs(clusterID, allMessages, internalOnly)
if err != nil {
return nil, err
}

var serviceLogs sl.ServiceLogShortList
err = json.Unmarshal(slResponse.Bytes(), &serviceLogs)
var errorServiceLogs []*v1.LogEntry
for _, serviceLog := range slResponse.Items().Slice() {
if serviceLog.CreatedAt().After(earliestTime) {
errorServiceLogs = append(errorServiceLogs, serviceLog)
}
}

return errorServiceLogs, nil
}

func FetchServiceLogs(clusterID string, allMessages bool, internalOnly bool) (*v1.ClustersClusterLogsListResponse, error) {
// Create OCM client to talk to cluster API
ocmClient, err := utils.CreateConnection()
if err != nil {
return nil, fmt.Errorf("failed to unmarshal the SL response %w", err)
return nil, err
}
defer func() {
if err := ocmClient.Close(); err != nil {
fmt.Printf("Cannot close the ocmClient (possible memory leak): %q", err)
}
}()

// Use the OCM client to retrieve clusters
clusters := utils.GetClusters(ocmClient, []string{clusterID})
if len(clusters) != 1 {
return nil, fmt.Errorf("GetClusters expected to return 1 cluster, got: %d", len(clusters))
}
cluster := clusters[0]

// Parsing the relevant service logs
// - We only care about SLs sent in the given duration
var errorServiceLogs []sl.ServiceLogShort
for _, serviceLog := range serviceLogs.Items {
if serviceLog.CreatedAt.After(earliestTime) {
errorServiceLogs = append(errorServiceLogs, serviceLog)
// Now get the SLs for the cluster
clusterLogsListResponse, err := sendClusterLogsListRequest(ocmClient, cluster, allMessages, internalOnly)
if err != nil {
return nil, fmt.Errorf("failed to fetch service logs for cluster %v: %w", clusterID, err)
}
return clusterLogsListResponse, nil
}

func sendClusterLogsListRequest(ocmClient *sdk.Connection, cluster *cmv1.Cluster, allMessages bool, internalMessages bool) (*v1.ClustersClusterLogsListResponse, error) {
request := ocmClient.ServiceLogs().V1().Clusters().ClusterLogs().List().
Parameter("cluster_id", cluster.ID()).
Parameter("cluster_uuid", cluster.ExternalID())

var searchQuery string
if !allMessages {
searchQuery = "service_name='SREManualAction'"
}
if internalMessages {
if searchQuery != "" {
searchQuery += " and "
}
searchQuery += "internal_only='true'"
}
request.Search(searchQuery)

return errorServiceLogs, nil
response, err := request.Send()
if err != nil {
return nil, fmt.Errorf("failed to fetch service logs: %w", err)
}
return response, nil
}
178 changes: 92 additions & 86 deletions cmd/servicelog/list.go
Original file line number Diff line number Diff line change
@@ -1,123 +1,129 @@
package servicelog

import (
"encoding/json"
"fmt"
slv1 "github.com/openshift-online/ocm-sdk-go/servicelogs/v1"
"os"
"time"

"github.com/openshift-online/ocm-cli/pkg/arguments"
"github.com/openshift-online/ocm-cli/pkg/dump"
sdk "github.com/openshift-online/ocm-sdk-go"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
"github.com/openshift/osdctl/pkg/utils"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
)

const (
AllMessagesFlag = "all-messages"
AllMessagesShortFlag = "A"
InternalFlag = "internal"
InternalShortFlag = "i"
)

// listCmd represents the list command
var listCmd = &cobra.Command{
Use: "list [flags] [options] cluster-identifier",
Short: "gets all servicelog messages for a given cluster",
Args: cobra.ArbitraryArgs,
SilenceErrors: true,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(complete(cmd, args))
cmdutil.CheckErr(run(cmd, args[0]))
},
}

func complete(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
err := cmd.Help()
Use: "list [flags] [options] cluster-identifier",
Short: "gets all servicelog messages for a given cluster",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
allMessages, err := cmd.Flags().GetBool(AllMessagesFlag)
if err != nil {
return fmt.Errorf("error calling cmd.Help(): %w", err)
return fmt.Errorf("failed to get flag `--%v`/`-%v`, %w", AllMessagesFlag, AllMessagesShortFlag, err)
}

internalOnly, err := cmd.Flags().GetBool(InternalFlag)
if err != nil {
return fmt.Errorf("failed to get flag `--%v`/`-%v`, %w", InternalFlag, InternalShortFlag, err)
}
return fmt.Errorf("cluster-identifier was not provided. please provide a cluster id, UUID, or name")
}

if len(args) != 1 {
log.Infof("Too many arguments. Expected 1 got %d", len(args))
}
return ListServiceLogs(args[0], allMessages, internalOnly)
},
}

return nil
func init() {
// define flags
listCmd.Flags().BoolP(AllMessagesFlag, AllMessagesShortFlag, false, "Toggle if we should see all of the messages or only SRE-P specific ones")
listCmd.Flags().BoolP(InternalFlag, InternalShortFlag, false, "Toggle if we should see internal messages")
}

func run(cmd *cobra.Command, clusterID string) error {
response, err := FetchServiceLogs(clusterID)
func ListServiceLogs(clusterID string, allMessages bool, internalOnly bool) error {
response, err := FetchServiceLogs(clusterID, allMessages, internalOnly)
if err != nil {
// If the response has errored, likely the input was bad, so show usage
helpErr := cmd.Help()
if helpErr != nil {
return helpErr
}
return err
return fmt.Errorf("failed to fetch service logs: %w", err)
}

err = dump.Pretty(os.Stdout, response.Bytes())
if err != nil {
// If outputing the data errored, there's likely an internal error, so just return the error
return err
if err = printServiceLogResponse(response); err != nil {
return fmt.Errorf("failed to print service logs: %w", err)
}

return nil
}

var serviceLogListAllMessagesFlag = false
var serviceLogListInternalOnlyFlag = false

func FetchServiceLogs(clusterID string) (*sdk.Response, error) {
// Create OCM client to talk to cluster API
ocmClient, err := utils.CreateConnection()
if err != nil {
return nil, err
func printServiceLogResponse(response *slv1.ClustersClusterLogsListResponse) error {
entryViews := logEntryToView(response.Items().Slice())
view := LogEntryResponseView{
Items: entryViews,
Kind: "ClusterLogList",
Page: response.Page(),
Size: response.Size(),
Total: response.Total(),
}
defer func() {
if err := ocmClient.Close(); err != nil {
fmt.Printf("Cannot close the ocmClient (possible memory leak): %q", err)
}
}()

// Use the OCM client to retrieve clusters
clusters := utils.GetClusters(ocmClient, []string{clusterID})
if len(clusters) != 1 {
return nil, fmt.Errorf("GetClusters expected to return 1 cluster, got: %d", len(clusters))
viewBytes, err := json.Marshal(view)
if err != nil {
return fmt.Errorf("failed to marshal response for output: %w", err)
}
cluster := clusters[0]

// Now get the SLs for the cluster
return utils.SendRequest(CreateListSLRequest(ocmClient, cluster, serviceLogListAllMessagesFlag, serviceLogListInternalOnlyFlag))
return dump.Pretty(os.Stdout, viewBytes)
}

func init() {
// define required flags
listCmd.Flags().BoolVarP(&serviceLogListAllMessagesFlag, "all-messages", "A", serviceLogListAllMessagesFlag, "Toggle if we should see all of the messages or only SRE-P specific ones")
listCmd.Flags().BoolVarP(&serviceLogListInternalOnlyFlag, "internal", "i", serviceLogListInternalOnlyFlag, "Toggle if we should see internal messages")
type LogEntryResponseView struct {
Items []*LogEntryView `json:"items"`
Kind string `json:"kind"`
Page int `json:"page"`
Size int `json:"size"`
Total int `json:"total"`
}

func CreateListSLRequest(ocmClient *sdk.Connection, cluster *cmv1.Cluster, allMessages bool, internalMessages bool) *sdk.Request {
// Create and populate the request:
request := ocmClient.Get()
err := arguments.ApplyPathArg(request, targetAPIPath)
if err != nil {
log.Fatalf("Can't parse API path '%s': %v\n", targetAPIPath, err)
}
var empty []string

// prefer cluster external over cluster internal ID
var formatMessage string
if cluster.ExternalID() != "" {
formatMessage = fmt.Sprintf(`search=cluster_uuid = '%s'`, cluster.ExternalID())
} else {
formatMessage = fmt.Sprintf(`search=cluster_id = '%s'`, cluster.ID())
}
type LogEntryView struct {
ClusterID string `json:"cluster_id"`
ClusterUUID string `json:"cluster_uuid"`
CreatedAt time.Time `json:"created_at"`
CreatedBy string `json:"created_by"`
Description string `json:"description"`
EventStreamID string `json:"event_stream_id"`
Href string `json:"href"`
ID string `json:"id"`
InternalOnly bool `json:"internal_only"`
Kind string `json:"kind"`
LogType string `json:"log_type"`
ServiceName string `json:"service_name"`
Severity string `json:"severity"`
Summary string `json:"summary"`
Timestamp time.Time `json:"timestamp"`
Username string `json:"username"`
}

if !allMessages {
formatMessage += ` and service_name = 'SREManualAction'`
}
if internalMessages {
formatMessage += ` and internal_only = 'true'`
func logEntryToView(entries []*slv1.LogEntry) []*LogEntryView {
entryViews := make([]*LogEntryView, 0, len(entries))
for _, entry := range entries {
entryView := &LogEntryView{
ClusterID: entry.ClusterID(),
ClusterUUID: entry.ClusterUUID(),
CreatedAt: entry.CreatedAt(),
CreatedBy: entry.CreatedBy(),
Description: entry.Description(),
EventStreamID: entry.EventStreamID(),
Href: entry.HREF(),
ID: entry.ID(),
InternalOnly: entry.InternalOnly(),
Kind: entry.Kind(),
LogType: string(entry.LogType()),
ServiceName: entry.ServiceName(),
Severity: string(entry.Severity()),
Summary: entry.Summary(),
Timestamp: entry.Timestamp(),
Username: entry.Username(),
}
entryViews = append(entryViews, entryView)
}
arguments.ApplyParameterFlag(request, []string{formatMessage})
arguments.ApplyHeaderFlag(request, empty)
return request
return entryViews
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ require (
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.27.7
github.com/openshift-online/ocm-cli v0.1.66
github.com/openshift-online/ocm-sdk-go v0.1.344
github.com/openshift-online/ocm-sdk-go v0.1.372
github.com/openshift/api v0.0.0-20230320211411-560b2fb170af
github.com/openshift/aws-account-operator/api v0.0.0-20230322125717-5b5a00a3e99f
github.com/openshift/backplane-cli v0.1.5
Expand Down
Loading

0 comments on commit ea9e445

Please sign in to comment.