Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cmd): prototype support yaml and json as inputs for command flags #1481

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions internal/synthetics/command_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -181,4 +184,12 @@ func init() {

cmdMonSearch.Flags().StringVarP(&monitorName, "name", "n", "", "search for results matching the given Synthetics monitor name")
cmdMon.AddCommand(cmdMonSearch)

cmdMonitorRun.Flags().StringVarP(&syntheticsMonitorRunFlagsInputFile, "inputFile", "f", "", "Input file with command flags.")
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)

}
83 changes: 83 additions & 0 deletions internal/synthetics/command_monitor_run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package synthetics

import (
"encoding/json"
"fmt"
"io/ioutil"

"github.com/newrelic/newrelic-cli/internal/client"
"github.com/newrelic/newrelic-cli/internal/utils"
"github.com/newrelic/newrelic-client-go/v2/pkg/synthetics"
"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 "<monitorGUID>" --location="<locationId>"`,
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

fmt.Print("\n****************************\n")
fmt.Printf("\n execCmdMonitorRunE - guid: %+v \n", syntheticsMonitorGUID)

result, err := client.NRClient.Synthetics.SyntheticsRunMonitorWithContext(
utils.SignalCtx,
synthetics.EntityGUID(syntheticsMonitorGUID),
"AWS_US_WEST_2",
)
utils.LogIfFatal(err)

fmt.Printf("\n execCmdMonitorRunE - result: %+v \n", result.Errors)

// utils.LogIfFatal(output.Print(result))

fmt.Print("\n****************************\n")

return nil
}
21 changes: 21 additions & 0 deletions internal/synthetics/command_monitor_run_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build unit

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)
}
70 changes: 70 additions & 0 deletions internal/utils/command_do.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package utils

import (
"encoding/json"
"fmt"
"io/ioutil"

"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

var (
inputFile string // yaml/json file path
guid string
otherFlag int
)

type commandInputs struct {
Flags map[string]interface{} `yaml:"flags"`
}

var cmdDo = &cobra.Command{
Use: "do",
Short: "Provide json file as cmd args",
Long: `Testing json file as arguments to a command`,
Example: `newrelic do --file=./path/to/file`,
PreRunE: func(cmd *cobra.Command, args []string) error {
inputFile, err := ioutil.ReadFile(inputFile)
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)
}
}

// 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().

err = SetFlagsFromFile(cmd, cmdInputs.Flags)
if err != nil {
return err
}

return nil
},
RunE: runDoCommandE,
}

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
}

func init() {
Command.AddCommand(cmdDo)

cmdDo.Flags().StringVarP(&inputFile, "inputFile", "f", "", "a file that contains the flags for the command")
cmdDo.Flags().StringVar(&guid, "guid", "", "A flag with a string value")
cmdDo.Flags().IntVar(&otherFlag, "otherFlag", 0, "A flag with an integer value")
}
21 changes: 21 additions & 0 deletions internal/utils/command_do_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build unit

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)
}
30 changes: 30 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"time"

"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"

log "github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -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
}