From 13a4900338d98851dca399742db80205cc03d971 Mon Sep 17 00:00:00 2001 From: Sander Blue Date: Wed, 28 Jun 2023 15:51:24 -0500 Subject: [PATCH] feat: [wip] prototype to support yaml file as input for synthetics monitor run command --- internal/synthetics/command_monitor.go | 16 ++++- internal/synthetics/command_monitor_run.go | 65 +++++++++++++++++++ .../synthetics/command_monitor_run_test.go | 19 ++++++ internal/utils/command_do.go | 38 ++--------- internal/utils/command_do_test.go | 19 ++++++ internal/utils/utils.go | 30 +++++++++ 6 files changed, 151 insertions(+), 36 deletions(-) create mode 100644 internal/synthetics/command_monitor_run.go create mode 100644 internal/synthetics/command_monitor_run_test.go create mode 100644 internal/utils/command_do_test.go diff --git a/internal/synthetics/command_monitor.go b/internal/synthetics/command_monitor.go index fda6b6e4d..bf7f18a38 100644 --- a/internal/synthetics/command_monitor.go +++ b/internal/synthetics/command_monitor.go @@ -18,9 +18,12 @@ import ( ) var ( - statusFilter string - monitorName string - monitorID string + statusFilter string + monitorName string + monitorID string + syntheticsMonitorGUID string + syntheticsMonitorLocationID string + syntheticsMonitorRunFlagsInputFile string ) // Command represents the synthetics command @@ -181,4 +184,11 @@ func init() { cmdMonSearch.Flags().StringVarP(&monitorName, "name", "n", "", "search for results matching the given Synthetics monitor name") cmdMon.AddCommand(cmdMonSearch) + + cmdMonitorRun.Flags().StringVarP(&syntheticsMonitorGUID, "guid", "g", "", "The monitor GUID for which to run the monitor check.") + cmdMonitorRun.Flags().StringVarP(&syntheticsMonitorLocationID, "locationId", "l", "", "The monitor location ID for which to run the monitor check.") + cmdMonitorRun.MarkFlagRequired("guid") + cmdMonitorRun.MarkFlagRequired("locationId") + cmdMon.AddCommand(cmdMonitorRun) + } diff --git a/internal/synthetics/command_monitor_run.go b/internal/synthetics/command_monitor_run.go new file mode 100644 index 000000000..a76eaa4c5 --- /dev/null +++ b/internal/synthetics/command_monitor_run.go @@ -0,0 +1,65 @@ +package synthetics + +import ( + "encoding/json" + "fmt" + "io/ioutil" + + "github.com/newrelic/newrelic-cli/internal/client" + "github.com/newrelic/newrelic-cli/internal/utils" + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" +) + +type commandInputs struct { + Flags map[string]interface{} `yaml:"flags"` +} + +var cmdMonitorRun = &cobra.Command{ + Use: "run", + Short: "Run a synthetics monitor check.", + Long: `Run a synthetics monitor check. + +The get command queues a manual request to execute a monitor check from the specified location. +`, + Example: `newrelic synthetics monitor run --guid "" --location=""`, + PreRun: client.RequireClient, + PreRunE: func(cmd *cobra.Command, args []string) error { + + // TODO + // If command flags are provided inline as well as an input file for flags, + // the inline flags will take precendence and the input file flags will be ignored. + // Provide a warning message, but return nil and continue command execution in Run(). + + if syntheticsMonitorGUID != "" || syntheticsMonitorLocationID != "" { + return nil + } + + inputFile, err := ioutil.ReadFile(syntheticsMonitorRunFlagsInputFile) + if err != nil { + return fmt.Errorf("YAML err %+v ", err) + } + + cmdInputs := commandInputs{} + err = yaml.Unmarshal(inputFile, &cmdInputs) + if err != nil { + err = json.Unmarshal(inputFile, &cmdInputs) + if err != nil { + return fmt.Errorf("error parsing input file %+v ", err) + } + } + + err = utils.SetFlagsFromFile(cmd, cmdInputs.Flags) + if err != nil { + return err + } + + return nil + }, + RunE: execCmdMonitorRunE, +} + +func execCmdMonitorRunE(cmd *cobra.Command, args []string) error { + // TODO: Wire up the client + return nil +} diff --git a/internal/synthetics/command_monitor_run_test.go b/internal/synthetics/command_monitor_run_test.go new file mode 100644 index 000000000..78ad95200 --- /dev/null +++ b/internal/synthetics/command_monitor_run_test.go @@ -0,0 +1,19 @@ +package synthetics + +import ( + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +func TestCmdSyntheticsMonitorRun(t *testing.T) { + cmd := &cobra.Command{ + Use: cmdMonitorRun.Use, + RunE: execCmdMonitorRunE, + } + + err := cmd.Execute() + + assert.NoError(t, err) +} diff --git a/internal/utils/command_do.go b/internal/utils/command_do.go index 7210e098e..89b1f9c4f 100644 --- a/internal/utils/command_do.go +++ b/internal/utils/command_do.go @@ -4,8 +4,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "reflect" - "strconv" "github.com/spf13/cobra" "gopkg.in/yaml.v3" @@ -47,45 +45,19 @@ var cmdDo = &cobra.Command{ } } - // Validate flags - err = setFlagsFromFile(cmd, cmdInputs.Flags) + err = SetFlagsFromFile(cmd, cmdInputs.Flags) if err != nil { return err } return nil }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("\n Command - flag from file (guid): %+v", guid) - fmt.Printf("\n Command - flag from file (other): %+v \n\n", otherFlag) - }, + RunE: runDoCommandE, } -// setFlagsFromFile sets the command flag values based on the provided input file contents. -// If also ensures the provided flags from an input file match the expected flags and their respective types. -// Nonexistent flags will result in an error. Incorrect types will result in an error. -func setFlagsFromFile(cmd *cobra.Command, flagsFromFile map[string]interface{}) error { - flagSet := cmd.Flags() - for k, v := range flagsFromFile { - // Ensure flag exists for the command - flag := flagSet.Lookup(k) - if flag == nil { - return fmt.Errorf("error: Invalid flag `%s` provided for command `%s` ", k, cmd.Name()) - } - - // Ensure correct type - flagType := flag.Value.Type() - if reflect.TypeOf(v).String() != flag.Value.Type() { - return fmt.Errorf("error: Invalid value `%v` for flag `%s` provided for command `%s`. Must be of type %s", v, k, cmd.Name(), flagType) - } - - switch t := flag.Value.Type(); t { - case "string": - flagSet.Set(k, v.(string)) - case "int": - flagSet.Set(k, strconv.Itoa(v.(int))) - } - } +func runDoCommandE(cmd *cobra.Command, args []string) error { + fmt.Printf("\n Command - flag from file (guid): %+v", guid) + fmt.Printf("\n Command - flag from file (other): %+v \n\n", otherFlag) return nil } diff --git a/internal/utils/command_do_test.go b/internal/utils/command_do_test.go new file mode 100644 index 000000000..273621536 --- /dev/null +++ b/internal/utils/command_do_test.go @@ -0,0 +1,19 @@ +package utils + +import ( + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +func TestCmdDo(t *testing.T) { + cmd := &cobra.Command{ + Use: cmdDo.Use, + RunE: runDoCommandE, + } + + err := cmd.Execute() + + assert.NoError(t, err) +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 2ec241767..cb193bce2 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -14,6 +14,7 @@ import ( "time" "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" log "github.com/sirupsen/logrus" ) @@ -185,3 +186,32 @@ func IsExitStatusCode(exitCode int, err error) bool { exitCodeString := fmt.Sprintf("exit status %d", exitCode) return strings.Contains(err.Error(), exitCodeString) } + +// SetFlagsFromFile sets the command flag values based on the provided input file contents. +// If also ensures the provided flags from an input file match the expected flags and their respective types. +// Nonexistent flags will result in an error. Incorrect types will result in an error. +func SetFlagsFromFile(cmd *cobra.Command, flagsFromFile map[string]interface{}) error { + flagSet := cmd.Flags() + for k, v := range flagsFromFile { + // Ensure flag exists for the command + flag := flagSet.Lookup(k) + if flag == nil { + return fmt.Errorf("error: Invalid flag `%s` provided for command `%s` ", k, cmd.Name()) + } + + // Ensure correct type + flagType := flag.Value.Type() + if reflect.TypeOf(v).String() != flag.Value.Type() { + return fmt.Errorf("error: Invalid value `%v` for flag `%s` provided for command `%s`. Must be of type %s", v, k, cmd.Name(), flagType) + } + + switch t := flag.Value.Type(); t { + case "string": + flagSet.Set(k, v.(string)) + case "int": + flagSet.Set(k, strconv.Itoa(v.(int))) + } + } + + return nil +}