diff --git a/cmd/debug.go b/cmd/debug.go index 0e8f23e..17b97bd 100644 --- a/cmd/debug.go +++ b/cmd/debug.go @@ -3,9 +3,8 @@ package cmd import ( "log" - "github.com/spf13/cobra" - "github.com/privateerproj/privateer-sdk/raidengine" + "github.com/spf13/cobra" ) var ( @@ -14,7 +13,7 @@ var ( Use: "debug", Short: "Run the Raid in debug mode", Run: func(cmd *cobra.Command, args []string) { - err := raidengine.Run(RaidName, getStrikes()) + err := raidengine.Run(RaidName, AvailableStrikes, Strikes) if err != nil { log.Fatal(err) } diff --git a/cmd/root.go b/cmd/root.go index b49ccb8..e1d9ef1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,17 +1,14 @@ package cmd import ( - "fmt" "os" "github.com/spf13/cobra" - "github.com/spf13/viper" + "github.com/privateerproj/privateer-pack-wireframe/strikes" "github.com/privateerproj/privateer-sdk/command" "github.com/privateerproj/privateer-sdk/plugin" "github.com/privateerproj/privateer-sdk/raidengine" - - "github.com/privateerproj/privateer-pack-wireframe/strikes" ) var ( @@ -21,6 +18,20 @@ var ( buildTime string RaidName = "Wireframe" // TODO: Change this to the name of your Raid + Strikes = &strikes.Antijokes{} + + AvailableStrikes = map[string][]raidengine.Strike{ + "CCC-Taxonomy": { + Strikes.KnockKnock, + Strikes.ChickenCrossedRoad, + }, + "CCC-Hardening": { + Strikes.ChickenCrossedRoad, + }, + "CIS": { + Strikes.ChickenCrossedRoad, + }, + } // runCmd represents the base command when called without any subcommands runCmd = &cobra.Command{ @@ -56,7 +67,6 @@ func Execute(version, commitHash, builtAt string) { func init() { command.SetBase(runCmd) // This initializes the base CLI functionality - viper.BindPFlag("raids.wireframe.tactic", runCmd.PersistentFlags().Lookup("tactic")) } // Raid meets the Privateer Service Pack interface @@ -73,29 +83,5 @@ func cleanupFunc() error { // Adding raidengine.SetupCloseHandler(cleanupFunc) will allow you to append custom cleanup behavior func (r *Raid) Start() error { raidengine.SetupCloseHandler(cleanupFunc) - return raidengine.Run(RaidName, getStrikes()) // Return errors from strike executions -} - -// GetStrikes returns a list of probe objects -func getStrikes() []raidengine.Strike { - logger := raidengine.GetLogger(RaidName, false) - a := &strikes.Antijokes{ - Log: logger, - } - availableStrikes := map[string][]raidengine.Strike{ - "CCC-Taxonomy": { - a.KnockKnock, - }, - "CIS": { - a.KnockKnock, - a.ChickenCrossedRoad, - }, - } - tactic := viper.GetString("raids.wireframe.tactic") - strikes := availableStrikes[tactic] - if len(strikes) == 0 { - message := fmt.Sprintf("No strikes were found for the provided strike set: %s", tactic) - logger.Error(message) - } - return strikes + return raidengine.Run(RaidName, AvailableStrikes, Strikes) } diff --git a/go.mod b/go.mod index 4ba0579..4e10393 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/hashicorp/go-hclog v1.2.0 - github.com/privateerproj/privateer-sdk v0.0.4 + github.com/privateerproj/privateer-sdk v0.0.5 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.15.0 ) diff --git a/go.sum b/go.sum index 09fed46..e0e330b 100644 --- a/go.sum +++ b/go.sum @@ -671,8 +671,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/privateerproj/privateer-sdk v0.0.3 h1:lQ+pC5H3K+Pq69zHMO1WvFV2yrcCiM94KdNugVYbS2A= -github.com/privateerproj/privateer-sdk v0.0.3/go.mod h1:wLc/yv9UDFXR9kZ0ioXpCOdWhm4hTSK3VqMEziJqMo4= +github.com/privateerproj/privateer-sdk v0.0.5 h1:GEgAIxUxRGNlXT0jNkV0tVZxKGvYYhaHA3HOM955WME= +github.com/privateerproj/privateer-sdk v0.0.5/go.mod h1:wLc/yv9UDFXR9kZ0ioXpCOdWhm4hTSK3VqMEziJqMo4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= diff --git a/sample_output/Wireframe-CCC-Taxonomy/results.json b/sample_output/Wireframe-CCC-Taxonomy/results.json new file mode 100644 index 0000000..2cf72f4 --- /dev/null +++ b/sample_output/Wireframe-CCC-Taxonomy/results.json @@ -0,0 +1 @@ +{"RaidName":"Wireframe-CCC-Taxonomy","StartTime":"2023-10-17 21:48:24.021963 -0500 CDT m=+0.008949251","EndTime":"2023-10-17 21:48:24.02247 -0500 CDT m=+0.009455792","StrikeResults":{"Chicken Crossed Road":{"Passed":true,"Description":"This is a demo strike for dev purposes","Message":"We tried, and that's all we really came here for.","DocsURL":"https://maintainer.com/docs/raids/wireframe","ControlID":"CCC-Taxonomy-2","Movements":{"JokerName":{"Passed":true,"Description":"JokerName must be found in the runtime configuration.","Message":"JokerName is set","Function":"github.com/privateerproj/privateer-pack-wireframe/strikes.getJokerName","Value":"Dean"}}},"Knock Knock":{"Passed":false,"Description":"This is a failure of a joke for dev purposes","Message":"Strike has not yet started.","DocsURL":"https://maintainer.com/docs/raids/wireframe","ControlID":"CCC-Taxonomy-1","Movements":{"JokeeName":{"Passed":true,"Description":"JokeeName must be found in the runtime configuration.","Message":"JokeeName is set","Function":"github.com/privateerproj/privateer-pack-wireframe/strikes.getJokeeName","Value":"Sam"},"JokerName":{"Passed":true,"Description":"JokerName must be found in the runtime configuration.","Message":"JokerName is set","Function":"github.com/privateerproj/privateer-pack-wireframe/strikes.getJokerName","Value":"Dean"},"knock knock":{"Passed":true,"Description":"Joke must be started by the joker.","Message":"Dean: Knock knock.","Function":"github.com/privateerproj/privateer-pack-wireframe/strikes.RunKnockKnock","Value":null},"punchline":{"Passed":true,"Description":"Jokee must respond with the punchline.","Message":"Dean: Sam","Function":"github.com/privateerproj/privateer-pack-wireframe/strikes.RunKnockKnock","Value":null},"who's there":{"Passed":true,"Description":"Jokee must respond with 'who's there?'","Message":"Sam: Who's there?","Function":"github.com/privateerproj/privateer-pack-wireframe/strikes.RunKnockKnock","Value":null}}}}} \ No newline at end of file diff --git a/sample_output/Wireframe-CCC-Taxonomy/results.yaml b/sample_output/Wireframe-CCC-Taxonomy/results.yaml new file mode 100644 index 0000000..fe54cda --- /dev/null +++ b/sample_output/Wireframe-CCC-Taxonomy/results.yaml @@ -0,0 +1,54 @@ +raidname: Wireframe-CCC-Taxonomy +starttime: 2023-10-17 21:48:24.021963 -0500 CDT m=+0.008949251 +endtime: 2023-10-17 21:48:24.02247 -0500 CDT m=+0.009455792 +strikeresults: + Chicken Crossed Road: + passed: true + description: This is a demo strike for dev purposes + message: We tried, and that's all we really came here for. + docsurl: https://maintainer.com/docs/raids/wireframe + controlid: CCC-Taxonomy-2 + movements: + JokerName: + passed: true + description: JokerName must be found in the runtime configuration. + message: JokerName is set + function: github.com/privateerproj/privateer-pack-wireframe/strikes.getJokerName + value: Dean + Knock Knock: + passed: false + description: This is a failure of a joke for dev purposes + message: Strike has not yet started. + docsurl: https://maintainer.com/docs/raids/wireframe + controlid: CCC-Taxonomy-1 + movements: + JokeeName: + passed: true + description: JokeeName must be found in the runtime configuration. + message: JokeeName is set + function: github.com/privateerproj/privateer-pack-wireframe/strikes.getJokeeName + value: Sam + JokerName: + passed: true + description: JokerName must be found in the runtime configuration. + message: JokerName is set + function: github.com/privateerproj/privateer-pack-wireframe/strikes.getJokerName + value: Dean + knock knock: + passed: true + description: Joke must be started by the joker. + message: 'Dean: Knock knock.' + function: github.com/privateerproj/privateer-pack-wireframe/strikes.RunKnockKnock + value: null + punchline: + passed: true + description: Jokee must respond with the punchline. + message: 'Dean: Sam' + function: github.com/privateerproj/privateer-pack-wireframe/strikes.RunKnockKnock + value: null + who's there: + passed: true + description: Jokee must respond with 'who's there?' + message: 'Sam: Who''s there?' + function: github.com/privateerproj/privateer-pack-wireframe/strikes.RunKnockKnock + value: null diff --git a/sample_output/Wireframe-CIS/results.json b/sample_output/Wireframe-CIS/results.json new file mode 100644 index 0000000..154f1f9 --- /dev/null +++ b/sample_output/Wireframe-CIS/results.json @@ -0,0 +1 @@ +{"RaidName":"Wireframe-CIS","StartTime":"2023-10-17 21:48:24.023261 -0500 CDT m=+0.010247459","EndTime":"2023-10-17 21:48:24.023339 -0500 CDT m=+0.010325209","StrikeResults":{"Chicken Crossed Road":{"Passed":true,"Description":"This is a demo strike for dev purposes","Message":"We tried, and that's all we really came here for.","DocsURL":"https://maintainer.com/docs/raids/wireframe","ControlID":"CIS-1","Movements":{"JokerName":{"Passed":true,"Description":"JokerName must be found in the runtime configuration.","Message":"JokerName is set","Function":"github.com/privateerproj/privateer-pack-wireframe/strikes.getJokerName","Value":"Dean"}}}}} \ No newline at end of file diff --git a/sample_output/Wireframe-CIS/results.yaml b/sample_output/Wireframe-CIS/results.yaml new file mode 100644 index 0000000..def5a84 --- /dev/null +++ b/sample_output/Wireframe-CIS/results.yaml @@ -0,0 +1,17 @@ +raidname: Wireframe-CIS +starttime: 2023-10-17 21:48:24.023261 -0500 CDT m=+0.010247459 +endtime: 2023-10-17 21:48:24.023339 -0500 CDT m=+0.010325209 +strikeresults: + Chicken Crossed Road: + passed: true + description: This is a demo strike for dev purposes + message: We tried, and that's all we really came here for. + docsurl: https://maintainer.com/docs/raids/wireframe + controlid: CIS-1 + movements: + JokerName: + passed: true + description: JokerName must be found in the runtime configuration. + message: JokerName is set + function: github.com/privateerproj/privateer-pack-wireframe/strikes.getJokerName + value: Dean diff --git a/strikes/antijokes.go b/strikes/antijokes.go index 0f72bc2..3a0b4ce 100644 --- a/strikes/antijokes.go +++ b/strikes/antijokes.go @@ -1,7 +1,6 @@ package strikes import ( - "errors" "fmt" "log" @@ -9,60 +8,145 @@ import ( "github.com/spf13/viper" "github.com/privateerproj/privateer-sdk/raidengine" + "github.com/privateerproj/privateer-sdk/utils" ) type Antijokes struct { - Log hclog.Logger + Log hclog.Logger // Recommended, allows you to set the log level for each log message + Results map[string]raidengine.StrikeResult // Optional, allows cross referencing between strikes +} + +func (a *Antijokes) SetLogger(loggerName string) { + a.Log = raidengine.GetLogger(loggerName, false) } // KnockKnock is a demo test for dev purposes func (a *Antijokes) KnockKnock() (strikeName string, result raidengine.StrikeResult) { strikeName = "Knock Knock" + log.Print(strikeName) // Default logs will be set as INFO + result = raidengine.StrikeResult{ - Passed: false, - Message: "", - DocsURL: "", + Passed: false, + Description: "This is a failure of a joke for dev purposes", + Message: "Strike has not yet started.", + DocsURL: "https://maintainer.com/docs/raids/wireframe", + ControlID: "CCC-Taxonomy-1", + Movements: make(map[string]raidengine.MovementResult), } - log.Printf("Knock Knock") - name, err := getJokeName() - if err != nil { + + // run getJokerName() as a movement + jokerNameMovement := getJokerName() + result.Movements["JokerName"] = jokerNameMovement + if !jokerNameMovement.Passed { + result.Message = jokerNameMovement.Message return } - log.Printf("Me: Knock Knock") - log.Printf(fmt.Sprintf("%s: Who's There?", name)) - // Demo the log timestamp - for i := 1; i < 5000000; i++ { - if i%500000 == 0 { - log.Printf("Me: (stares at %s)", name) - } + + // run getJokeeName() as a movement + jokeeNameMovement := getJokeeName() + result.Movements["JokeeName"] = jokeeNameMovement + if !jokeeNameMovement.Passed { + result.Message = jokeeNameMovement.Message + return } - log.Printf(fmt.Sprintf("%s: (lost interest and left)", name)) + + // Run multiple movements at once by passing the result object as a pointer + // Previous movement values must be cast to their type from interface{} before being used again + RunKnockKnock(jokerNameMovement.Value.(string), jokeeNameMovement.Value.(string), &result) return } // ChickenCrossedRoad is a demo test for dev purposes func (a *Antijokes) ChickenCrossedRoad() (strikeName string, result raidengine.StrikeResult) { + // If a strike is part of multiple tactics, you can use a map to reference the control ID to the selected tactic + controlIDs := map[string]string{ + "CCC-Taxonomy": "CCC-Taxonomy-2", + "CCC-Hardening": "CCC-Hardening-1", + "CIS": "CIS-1", + } strikeName = "Chicken Crossed Road" result = raidengine.StrikeResult{ - Passed: true, - Message: "", - DocsURL: "", + Passed: false, + Description: "This is a demo strike for dev purposes", + Message: "Strike has not yet started.", + DocsURL: "https://maintainer.com/docs/raids/wireframe", + ControlID: controlIDs[viper.GetString("raids.wireframe.tactic")], + Movements: make(map[string]raidengine.MovementResult), } - name, err := getJokeName() - if err != nil { + jokerNameMovement := getJokerName() + result.Movements["JokerName"] = jokerNameMovement + if !jokerNameMovement.Passed { + result.Message = jokerNameMovement.Message return } - a.Log.Warn("Me: This joke may offend someone.") - a.Log.Info("Me: Why did the chicken cross the road?") - a.Log.Trace(fmt.Sprintf("Me: (looks to see what %s's expression is)", name)) - a.Log.Info(fmt.Sprintf("%s: I'm busy, leave me alone.", name)) + + // Using an hclog logger will allow you to set the log level for each message + a.Log.Warn(fmt.Sprintf("%s: This joke may offend someone.", jokerNameMovement.Value)) + a.Log.Info(fmt.Sprintf("%s: Why did the chicken cross the road?", jokerNameMovement.Value)) + a.Log.Trace(fmt.Sprintf("%s: (looks to see what the stranger's expression is)", jokerNameMovement.Value)) + a.Log.Info("Stranger: I'm busy, leave me alone.") + + result.Passed = true + result.Message = "We tried, and that's all we really came here for." + return +} + +// getJokerName is a common movement for the strikes in this raid +func getJokerName() (result raidengine.MovementResult) { + result = raidengine.MovementResult{ + Description: "JokerName must be found in the runtime configuration.", + Function: utils.CallerPath(0), + } + if viper.IsSet("raids.wireframe.JokerName") { + result.Passed = true + result.Message = "JokerName is set" + result.Value = viper.GetString("raids.wireframe.JokerName") + } else { + result.Passed = false + result.Message = "JokerName must be set in the configuration." + } return } -func getJokeName() (string, error) { - if viper.IsSet("raids.wireframe.jokename") { - return viper.GetString("raids.wireframe.jokename"), nil +// getJokerName is a common movement for the strikes in this raid +func getJokeeName() (result raidengine.MovementResult) { + result = raidengine.MovementResult{ + Description: "JokeeName must be found in the runtime configuration.", + Function: utils.CallerPath(0), + } + if viper.IsSet("raids.wireframe.JokeeName") { + result.Passed = true + result.Message = "JokeeName is set" + result.Value = viper.GetString("raids.wireframe.JokeeName") + } else { + result.Passed = false + result.Message = "JokeeName must be set in the configuration." + } + return +} + +// RunKnockKnock is a set of movements for the Knock Knock strike, with each movement being added to the provided result +func RunKnockKnock(jokerName, jokeeName string, result *raidengine.StrikeResult) { + // say knock knock + result.Movements["knock knock"] = raidengine.MovementResult{ + Passed: true, + Description: "Joke must be started by the joker.", + Message: fmt.Sprintf("%s: Knock knock.", jokerName), + Function: utils.CallerPath(0), + } + // say who's there + result.Movements["who's there"] = raidengine.MovementResult{ + Passed: true, + Description: "Jokee must respond with 'who's there?'", + Message: fmt.Sprintf("%s: Who's there?", jokeeName), + Function: utils.CallerPath(0), + } + // say punchline + result.Movements["punchline"] = raidengine.MovementResult{ + Passed: true, + Description: "Jokee must respond with the punchline.", + Message: fmt.Sprintf("%s: %s", jokerName, jokeeName), + Function: utils.CallerPath(0), } - return "", errors.New("JokeName must be set in the config file or env vars (PVTR_WIREFRAME_JOKE_NAME)") }