Skip to content

Commit

Permalink
feat(servicelog): list current servicelogs
Browse files Browse the repository at this point in the history
- refactor `osdctl servicelog post`
  • Loading branch information
georgettica committed May 11, 2021
1 parent bdec0a4 commit 84931a0
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 79 deletions.
3 changes: 2 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/openshift/osdctl/cmd/cost"
"github.com/openshift/osdctl/cmd/federatedrole"
"github.com/openshift/osdctl/cmd/network"
"github.com/openshift/osdctl/cmd/servicelog"
)

// GitCommit is the short git commit hash from the environment
Expand Down Expand Up @@ -63,7 +64,7 @@ func NewCmdRoot(streams genericclioptions.IOStreams) *cobra.Command {
rootCmd.AddCommand(federatedrole.NewCmdFederatedRole(streams, kubeFlags))
rootCmd.AddCommand(network.NewCmdNetwork(streams, kubeFlags))
rootCmd.AddCommand(newCmdMetrics(streams, kubeFlags))
rootCmd.AddCommand(servicelogCmd)
rootCmd.AddCommand(servicelog.NewCmdServiceLog())

// add docs command
rootCmd.AddCommand(newCmdDocs(streams))
Expand Down
19 changes: 0 additions & 19 deletions cmd/servicelog.go

This file was deleted.

21 changes: 21 additions & 0 deletions cmd/servicelog/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package servicelog

import (
"github.com/spf13/cobra"
)

func NewCmdServiceLog() *cobra.Command {
var servicelogCmd = &cobra.Command{
Use: "servicelog",
Short: "OCM/Hive Service log",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

// Add subcommands
servicelogCmd.AddCommand(listCmd) // servicelog list
servicelogCmd.AddCommand(postCmd) // servicelog post

return servicelogCmd
}
57 changes: 57 additions & 0 deletions cmd/servicelog/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package servicelog

import (
"strings"

"github.com/openshift-online/ocm-cli/pkg/ocm"
sdk "github.com/openshift-online/ocm-sdk-go"
log "github.com/sirupsen/logrus"
)

var (
templateParams, userParameterNames, userParameterValues []string
isURL bool
HTMLBody []byte
)

const (
// in case you want to see the swagger code gen, you can look at
// https://api.openshift.com/?urls.primaryName=Service%20logs#/default/post_api_service_logs_v1_cluster_logs
targetAPIPath = "/api/service_logs/v1/cluster_logs"
)

func createConnection() *sdk.Connection {
connection, err := ocm.NewConnection().Build()
if err != nil {
if strings.Contains(err.Error(), "Not logged in, run the") {
log.Fatalf("Failed to create OCM connection: Authetication error, run the 'ocm login' command first.")
}
log.Fatalf("Failed to create OCM connection: %v", err)
}
return connection
}

func sendRequest(request *sdk.Request) *sdk.Response {
response, err := request.Send()
if err != nil {
log.Fatalf("Can't send request: %v", err)
}
return response
}

func check(response *sdk.Response, dir string) {
status := response.Status()

body := response.Bytes()

if status < 400 {
validateGoodResponse(body)
log.Info("Message has been successfully sent")

} else {
validateBadResponse(body)
cleanup(dir)
log.Fatalf("Failed to post message because of %q", BadReply.Reason)

}
}
121 changes: 121 additions & 0 deletions cmd/servicelog/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package servicelog

import (
"encoding/json"
"fmt"
"os"
"strings"

"github.com/openshift-online/ocm-cli/pkg/arguments"
"github.com/openshift-online/ocm-cli/pkg/dump"
sdk "github.com/openshift-online/ocm-sdk-go"
"github.com/openshift/osdctl/internal/servicelog"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

// listCmd represents the list command
var listCmd = &cobra.Command{
Use: "list",
Short: "gets all servicelog messages for a given cluster",
// validate only clusterid is provided
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clusterId := args[0]

// Create an OCM client to talk to the cluster API
// the user has to be logged in (e.g. 'ocm login')
ocmClient := createConnection()
defer func() {
if err := ocmClient.Close(); err != nil {
log.Errorf("Cannot close the ocmClient (possible memory leak): %q", err)
}
}()

// Use the OCM client to create the POST request
request := createClusterRequest(ocmClient, clusterId)
response := sendRequest(request)
clusterExternalId, err := extractExternalIdFromResponse(response)
if err != nil {
return err
}

// send it as logservice and validate the response
request = createListRequest(ocmClient, clusterExternalId, serviceLogListAllMessagesFlag)
response = sendRequest(request)

err = dump.Pretty(os.Stdout, response.Bytes())
if err != nil {
return err
}

return nil
},
}

var serviceLogListAllMessagesFlag = false

const listServiceLogAPIPath = "/api/service_logs/v1/clusters/%s/cluster_logs"

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")
}

func extractExternalIdFromResponse(response *sdk.Response) (string, error) {
status := response.Status()
body := response.Bytes()

if status >= 400 {
validateBadResponse(body)
log.Fatalf("Failed to list message because of %q", BadReply.Reason)
return "", nil
}

validateGoodResponse(body)
clusterListGoodReply := servicelog.ClusterListGoodReply{}
err := json.Unmarshal(body, &clusterListGoodReply)
if err != nil {
err = fmt.Errorf("cannot parse good clusterlist response: %w", err)
return "", err
}

if clusterListGoodReply.Total != 1 || len(clusterListGoodReply.Items) != 1 {
return "", fmt.Errorf("could not find an exact match for the clustername")
}

return clusterListGoodReply.Items[0].ExternalID, nil
}

func createClusterRequest(ocmClient *sdk.Connection, clusterId string) *sdk.Request {

searchString := fmt.Sprintf(`search=display_name like '%[1]s' or name like '%[1]s' or id like '%[1]s' or external_id like '%[1]s'`, clusterId)
searchString = strings.TrimSpace(searchString)
request := ocmClient.Get()
err := arguments.ApplyPathArg(request, "/api/clusters_mgmt/v1/clusters/")
if err != nil {
log.Fatalf("Can't parse API path '%s': %v\n", targetAPIPath, err)
}

arguments.ApplyParameterFlag(request, []string{searchString})

return request
}

func createListRequest(ocmClient *sdk.Connection, clusterId string, allMessages 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

formatMessage := fmt.Sprintf(`search=cluster_uuid = '%s'`, clusterId)
if !allMessages {
formatMessage += ` and service_name = 'SREManualAction'`
}
arguments.ApplyParameterFlag(request, []string{formatMessage})
arguments.ApplyHeaderFlag(request, empty)
return request
}
83 changes: 24 additions & 59 deletions cmd/post.go → cmd/servicelog/post.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,32 @@
package cmd
package servicelog

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strings"

"github.com/openshift-online/ocm-cli/pkg/arguments"
"github.com/openshift-online/ocm-cli/pkg/dump"
"github.com/openshift-online/ocm-cli/pkg/ocm"
sdk "github.com/openshift-online/ocm-sdk-go"
"github.com/openshift/osdctl/internal/servicelog"
"github.com/openshift/osdctl/internal/utils"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strings"
)

var (
template string
isURL bool
HTMLBody []byte
Message servicelog.Message
GoodReply servicelog.GoodReply
BadReply servicelog.BadReply
templateParams, userParameterNames, userParameterValues []string
GoodReply servicelog.GoodReply
BadReply servicelog.BadReply
Message servicelog.Message
template string
)

const (
defaultTemplate = ""
targetAPIPath = "/api/service_logs/v1/cluster_logs" // https://api.openshift.com/?urls.primaryName=Service%20logs#/default/post_api_service_logs_v1_cluster_logs
modifiedJSON = "modified-template.json"
)

Expand Down Expand Up @@ -68,9 +64,15 @@ var postCmd = &cobra.Command{

// Use the OCM client to create the POST request
// send it as logservice and validate the response
request := createRequest(ocmClient, newData)
response := postRequest(request)
request := createPostRequest(ocmClient, newData)
response := sendRequest(request)

check(response, dir)

err := dump.Pretty(os.Stdout, response.Bytes())
if err != nil {
log.Errorf("cannot print post command: %q", err)
}
},
}

Expand Down Expand Up @@ -226,18 +228,7 @@ func modifyTemplate(dir string) (newData string) {
return newData
}

func createConnection() *sdk.Connection {
connection, err := ocm.NewConnection().Build()
if err != nil {
if strings.Contains(err.Error(), "Not logged in, run the") {
log.Fatalf("Failed to create OCM connection: Authetication error, run the 'ocm login' command first.")
}
log.Fatalf("Failed to create OCM connection: %v", err)
}
return connection
}

func createRequest(ocmClient *sdk.Connection, newData string) *sdk.Request {
func createPostRequest(ocmClient *sdk.Connection, newData string) *sdk.Request {
// Create and populate the request:
request := ocmClient.Post()
err := arguments.ApplyPathArg(request, targetAPIPath)
Expand All @@ -254,31 +245,6 @@ func createRequest(ocmClient *sdk.Connection, newData string) *sdk.Request {
return request
}

func postRequest(request *sdk.Request) *sdk.Response {
response, err := request.Send()
if err != nil {
log.Fatalf("Can't send request: %v", err)
}
return response
}

func check(response *sdk.Response, dir string) {
status := response.Status()

body := response.Bytes()

if status < 400 {
validateGoodResponse(body)
log.Info("Message has been successfully sent")

} else {
validateBadResponse(body)
cleanup(dir)
log.Fatalf("Failed to post message because of %q", BadReply.Reason)

}
}

func validateGoodResponse(body []byte) {
if err := parseGoodReply(body); err != nil {
log.Fatalf("Cannot not parse the JSON template.\nError: %q\n", err)
Expand All @@ -304,15 +270,14 @@ func validateGoodResponse(body []byte) {
if description != Message.Description {
log.Fatalf("Message sent, but wrong description information was passed (wanted %q, got %q)", Message.Description, description)
}

if err := dump.Pretty(os.Stdout, body); err != nil {
log.Fatalf("Server returned invalid JSON reply %q", err)
if ok := json.Valid(body); !ok {
log.Fatalf("Server returned invalid JSON")
}
}

func validateBadResponse(body []byte) {
if err := dump.Pretty(os.Stderr, body); err != nil {
log.Errorf("Server returned invalid JSON reply %q", err)
if ok := json.Valid(body); !ok {
log.Errorf("Server returned invalid JSON")
}

if err := parseBadReply(body); err != nil {
Expand Down
1 change: 1 addition & 0 deletions docs/command/osdctl_servicelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ osdctl servicelog [flags]
### SEE ALSO

* [osdctl](osdctl.md) - OSD CLI
* [osdctl servicelog list](osdctl_servicelog_list.md) - gets all servicelog messages for a given cluster
* [osdctl servicelog post](osdctl_servicelog_post.md) - Send a servicelog message to a given cluster

Loading

0 comments on commit 84931a0

Please sign in to comment.