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 26, 2023
1 parent 8003f64 commit a6b5854
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 127 deletions.
6 changes: 3 additions & 3 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
4 changes: 2 additions & 2 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
69 changes: 57 additions & 12 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,7 +64,7 @@ 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) ([]*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)

Expand All @@ -70,21 +73,63 @@ func GetServiceLogsSince(clusterID string, days int) ([]sl.ServiceLogShort, erro
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.Timestamp().After(earliestTime) { //TODO After https://github.com/openshift-online/ocm-sdk-go/pull/847, this should be "CreatedAt" instead of "Timestamp"
errorServiceLogs = append(errorServiceLogs, serviceLog)
}
}

return errorServiceLogs, nil
}

func FetchServiceLogs(clusterID string) (*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, serviceLogListAllMessagesFlag, serviceLogListInternalOnlyFlag)
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
}
168 changes: 84 additions & 84 deletions cmd/servicelog/list.go
Original file line number Diff line number Diff line change
@@ -1,123 +1,123 @@
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"
)

// 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]))
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 {
return ListServiceLogs(args[0])
},
}

func complete(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
err := cmd.Help()
if err != nil {
return fmt.Errorf("error calling cmd.Help(): %w", 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 nil
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")
}

func run(cmd *cobra.Command, clusterID string) error {
func ListServiceLogs(clusterID string) error {
response, err := FetchServiceLogs(clusterID)
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())
}
// TODO uncomment these fields after https://github.com/openshift-online/ocm-sdk-go/pull/847 is merged
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"`
//Email string `json:"email"`
EventStreamID string `json:"event_stream_id"`
//FirstName string `json:"first_name"`
Href string `json:"href"`
ID string `json:"id"`
InternalOnly bool `json:"internal_only"`
Kind string `json:"kind"`
//LastName string `json:"last_name"`
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'`
// TODO uncomment these fields after https://github.com/openshift-online/ocm-sdk-go/pull/847 is merged
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(),
//Email: entry.Email(),
EventStreamID: entry.EventStreamID(),
//FirstName: entry.FirstName(),
Href: entry.HREF(),
ID: entry.ID(),
InternalOnly: entry.InternalOnly(),
Kind: entry.Kind(),
//LastName: entry.LastName(),
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.368
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
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -586,8 +586,8 @@ github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
github.com/openshift-online/ocm-cli v0.1.66 h1:+zBcNLVF4zv5ru0tSelIlzWBb35/dxwXRTKwO9MYNgE=
github.com/openshift-online/ocm-cli v0.1.66/go.mod h1:lTq3/GbsStzceXeIijnMHbe80w1kDWqNnTvOQV43V+w=
github.com/openshift-online/ocm-sdk-go v0.1.344 h1:Dv2IhoQzR5ONwCoK2j8TYa3e3AXLvrdUgZa90Gpvovk=
github.com/openshift-online/ocm-sdk-go v0.1.344/go.mod h1:KYOw8kAKAHyPrJcQoVR82CneQ4ofC02Na4cXXaTq4Nw=
github.com/openshift-online/ocm-sdk-go v0.1.368 h1:qP+gkChV8WDwwpkUw1xUyjTXKdvrwyd70Gff2GMUSeU=
github.com/openshift-online/ocm-sdk-go v0.1.368/go.mod h1:KYOw8kAKAHyPrJcQoVR82CneQ4ofC02Na4cXXaTq4Nw=
github.com/openshift/api v0.0.0-20230320211411-560b2fb170af h1:js8+NVUCTK7cz+IO6i9MnKfKU14QYSMgOiJYvqhAMM0=
github.com/openshift/api v0.0.0-20230320211411-560b2fb170af/go.mod h1:ctXNyWanKEjGj8sss1KjjHQ3ENKFm33FFnS5BKaIPh4=
github.com/openshift/aws-account-operator/api v0.0.0-20230322125717-5b5a00a3e99f h1:sfv+SJc6S9r2m+c8/7N9RwzHIXQEVkXDl1odNcizwis=
Expand Down
Loading

0 comments on commit a6b5854

Please sign in to comment.