diff --git a/cmd/post.go b/cmd/post.go index ef1ca7bc..1dc378cd 100644 --- a/cmd/post.go +++ b/cmd/post.go @@ -19,26 +19,19 @@ import ( ) var ( - template, clusterUUID, caseID string - isURL bool - HTMLBody []byte - Message servicelog.Message - GoodReply servicelog.GoodReply - BadReply servicelog.BadReply + template string + isURL bool + HTMLBody []byte + Message servicelog.Message + GoodReply servicelog.GoodReply + BadReply servicelog.BadReply + templateParams, userParameterNames, userParameterValues []string ) const ( - defaultTemplate = "" - defaultClusterUUID = "" - defaultCaseID = "" - 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" - clusterParameter = "${CLUSTER_UUID}" - caseIDParameter = "${CASE_ID}" - clusterUUIDLongName = "cluster-external-id" - caseIDLongName = "support-case-id" - clusterUUIDShorthand = "c" - caseIDShorthand = "i" + 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" ) // postCmd represents the post command @@ -46,9 +39,18 @@ var postCmd = &cobra.Command{ Use: "post", Short: "Send a servicelog message to a given cluster", Run: func(cmd *cobra.Command, args []string) { - readTemplate() // verify and parse - replaceFlags(clusterUUID, defaultClusterUUID, clusterParameter, clusterUUIDLongName, clusterUUIDShorthand) - replaceFlags(caseID, defaultCaseID, caseIDParameter, caseIDLongName, caseIDShorthand) + + parseUserParameters() // parse all the '-p' user flags + + readTemplate() // parse the given JSON template provided via '-t' flag + + // For every '-p' flag, replace its related placeholder in the template + for k, v := range templateParams { + replaceFlags(userParameterValues[k], "", userParameterNames[k], userParameterNames[k], "p", v) + } + + // Check if there are any remaining placeholders in the template that are not replaced by a parameter + checkLeftovers() dir := tempDir() defer cleanup(dir) @@ -75,8 +77,23 @@ var postCmd = &cobra.Command{ func init() { // define required flags postCmd.Flags().StringVarP(&template, "template", "t", defaultTemplate, "Message template file or URL") - postCmd.Flags().StringVarP(&clusterUUID, clusterUUIDLongName, clusterUUIDShorthand, defaultClusterUUID, "Target cluster UUID") - postCmd.Flags().StringVarP(&caseID, caseIDLongName, caseIDShorthand, defaultCaseID, "Related ticket (RedHat Support Case ID)") + postCmd.Flags().StringArrayVarP(&templateParams, "param", "p", templateParams, "Specify a key-value pair (eg. -p FOO=BAR) to set/override a parameter value in the template.") +} + +// parseUserParameters parse all the '-p FOO=BAR' parameters and checks for syntax errors +func parseUserParameters() { + for k, v := range templateParams { + if !strings.Contains(v, "=") { + log.Fatalf("Wrong syntax of '-p' flag. Please use it like this: '-p FOO=BAR'") + } + + userParameterNames = append(userParameterNames, fmt.Sprintf("${%v}", strings.Split(v, "=")[0])) + userParameterValues = append(userParameterValues, strings.Split(v, "=")[1]) + + if userParameterValues[k] == "" { + log.Fatalf("Wrong syntax of '-p' flag. Please use it like this: '-p FOO=BAR'") + } + } } // accessTemplate checks if the provided template is currently accessible and returns an error @@ -146,16 +163,31 @@ func readTemplate() { } } -func replaceFlags(flagName, flagDefaultValue, flagParameter, flagLongName, flagShorthand string) { +func checkLeftovers() { + unusedParameters, found := Message.FindLeftovers() + if found { + for _, v := range unusedParameters { + regex := strings.NewReplacer("${", "", "}", "") + log.Errorf("The selected template is using '%s' parameter, but '--%s' flag is not set for this one. Use '-%s %v=\"FOOBAR\"' to fix this.", v, "param", "p", regex.Replace(v)) + } + if numberOfMissingParameters := len(unusedParameters); numberOfMissingParameters == 1 { + log.Fatal("Please define this missing parameter properly.") + } else { + log.Fatalf("Please define all %v missing parameters properly.", numberOfMissingParameters) + } + } +} + +func replaceFlags(flagName, flagDefaultValue, flagParameter, flagLongName, flagShorthand, parameter string) { if err := strings.Compare(flagName, flagDefaultValue); err == 0 { // The user didn't set the flag. Check if the template is using the flag. if found := Message.SearchFlag(flagParameter); found == true { - log.Fatalf("The selected template is using '%s' parameter, but '%s' flag is not set. Use '-%s' to fix this.", flagParameter, flagLongName, flagShorthand) + log.Fatalf("The selected template is using '%s' parameter, but '%s' flag was not set. Use '-%s' to fix this.", flagParameter, flagLongName, flagShorthand) } } else { // The user set the flag. Check if the template is using the flag. if found := Message.SearchFlag(flagParameter); found == false { - log.Fatalf("The selected template is not using '%s' parameter, but '%s' flag is set. Do not use '-%s' to fix this.", flagParameter, flagLongName, flagShorthand) + log.Fatalf("The selected template is not using '%s' parameter, but '--%s' flag was set. Do not use '-%s %s' to fix this.", flagParameter, "param", flagShorthand, parameter) } Message.ReplaceWithFlag(flagParameter, flagName) } @@ -261,8 +293,8 @@ func validateGoodResponse(body []byte) { log.Fatalf("Message sent, but wrong service_name information was passed (wanted %q, got %q)", Message.ServiceName, serviceName) } clusteruuid := GoodReply.ClusterUUID - if clusterUUID != clusteruuid { - log.Fatalf("Message sent, but to different cluster (wanted %q, got %q)", clusterUUID, clusteruuid) + if clusteruuid != Message.ClusterUUID { + log.Fatalf("Message sent, but to different cluster (wanted %q, got %q)", Message.ClusterUUID, clusteruuid) } summary := GoodReply.Summary if summary != Message.Summary { diff --git a/docs/command/osdctl_servicelog_post.md b/docs/command/osdctl_servicelog_post.md index 8c41bb9b..9339545c 100644 --- a/docs/command/osdctl_servicelog_post.md +++ b/docs/command/osdctl_servicelog_post.md @@ -13,10 +13,9 @@ osdctl servicelog post [flags] ### Options ``` - -c, --cluster-external-id string Target cluster UUID - -h, --help help for post - -i, --support-case-id string Related ticket (RedHat Support Case ID) - -t, --template string Message template file or URL + -h, --help help for post + -p, --param stringArray Specify a key-value pair (eg. -p FOO=BAR) to set/override a parameter value in the template. + -t, --template string Message template file or URL ``` ### Options inherited from parent commands diff --git a/internal/servicelog/template.go b/internal/servicelog/template.go index 2c751f5f..390c6ae5 100644 --- a/internal/servicelog/template.go +++ b/internal/servicelog/template.go @@ -1,6 +1,9 @@ package servicelog -import "strings" +import ( + "regexp" + "strings" +) // Message is the base template structure type Message struct { @@ -62,3 +65,13 @@ func (m *Message) SearchFlag(placeholder string) (found bool) { } return false } + +func (m *Message) FindLeftovers() (matches []string, found bool) { + r := regexp.MustCompile(`\${[^{}]*}`) + str := m.Severity + m.ServiceName + m.ClusterUUID + m.Summary + m.Description + matches = r.FindAllString(str, -1) + if len(matches) > 0 { + found = true + } + return matches, found +}