Skip to content

Commit

Permalink
Add trigger validation
Browse files Browse the repository at this point in the history
Add trigger validation on sync, removing invalid payload from process queue

Signed-off-by: Eddy Babetto <eddy.babetto@secomind.com>
  • Loading branch information
eddbbt committed Nov 16, 2023
1 parent d72bb53 commit 2f9c28b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 42 deletions.
2 changes: 1 addition & 1 deletion cmd/appengine/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ func getProtoInterface(deviceID string, deviceIdentifierType client.DeviceIdenti
// Just a trick to trick the parser into doing the right thing.
if isParametricInterface {
iface.Mappings = []interfaces.AstarteInterfaceMapping{
interfaces.AstarteInterfaceMapping{
{
Endpoint: "/it/%{is}/parametric",
},
}
Expand Down
77 changes: 36 additions & 41 deletions cmd/realm/triggers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ package realm
import (
"encoding/json"
"fmt"
"os"
"path/filepath"

"github.com/astarte-platform/astarte-go/triggers"

Check failure on line 20 in cmd/realm/triggers.go

View workflow job for this annotation

GitHub Actions / Build and Test (1.19.x, ubuntu-22.04)

no required module provides package github.com/astarte-platform/astarte-go/triggers; to add it:

Check failure on line 20 in cmd/realm/triggers.go

View workflow job for this annotation

GitHub Actions / Build and Test (1.20.x, ubuntu-22.04)

no required module provides package github.com/astarte-platform/astarte-go/triggers; to add it:
"github.com/astarte-platform/astartectl/utils"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
"path/filepath"
)

// triggersCmd represents the triggers command
Expand Down Expand Up @@ -72,10 +72,10 @@ var triggersDeleteCmd = &cobra.Command{
}

var triggersSaveCmd = &cobra.Command{
Use: "save [destination-path]",
Use: "save <destination-path>",
Short: "Save triggers to a local folder",
Long: `Save each trigger in a realm to a local folder. Each trigger will
be saved in a dedicated file whose name will be in the form '<trigger_name>_v<version>.json'.
be saved in a dedicated file whose name will be in the form '<trigger_name>.json'.
When no destination path is set, triggers will be saved in the current working directory.
This command does not support the --to-curl flag.`,
Example: ` astartectl realm-management triggers save`,
Expand All @@ -84,7 +84,7 @@ This command does not support the --to-curl flag.`,
}

var triggersSyncCmd = &cobra.Command{
Use: "sync <interface_files> [...]",
Use: "sync <trigger_files> [...]",
Short: "Synchronize triggers",
Long: `Synchronize triggers in the realm with the given files.
All given files will be parsed, and only new triggers will be installed in the
Expand All @@ -97,7 +97,7 @@ realm, depending on the realm's state. In order to force triggers update, use --
func init() {

RealmManagementCmd.AddCommand(triggersCmd)
triggersSyncCmd.Flags().Bool("force", false, "When set, force triggers update")
triggersSyncCmd.Flags().Lookup("force").NoOptDefVal = "false"
triggersCmd.AddCommand(
triggersListCmd,
triggersShowCmd,
Expand All @@ -115,12 +115,10 @@ func triggersListF(command *cobra.Command, args []string) error {
}

func triggersShowF(command *cobra.Command, args []string) error {

triggerName := args[0]
triggerDefinition, _ := getTriggerDefinition(realm, triggerName)
respJSON, _ := json.MarshalIndent(triggerDefinition, "", " ")
fmt.Println(string(respJSON))

return nil
}

Expand Down Expand Up @@ -226,28 +224,33 @@ func triggersSyncF(command *cobra.Command, args []string) error {
os.Exit(1)
}

triggerToInstall := []map[string]interface{}{}
triggerToUpdate := []map[string]interface{}{}
triggersToInstall := []map[string]interface{}{}
triggersToUpdate := []map[string]interface{}{}
invalidTriggers := []string{}

for _, f := range args {
triggerFile, err := os.ReadFile(f)
triggerFile, err := os.ReadFile(f)
if err != nil {
return err
}
if !validateTrigger(f) {
invalidTriggers = append(invalidTriggers, f)
continue
}

var astarteTrigger map[string]interface{}
var astarteTrigger map[string]triggers.Trigger{}

Check failure on line 241 in cmd/realm/triggers.go

View workflow job for this annotation

GitHub Actions / golangci-lint

expected ';', found '{' (typecheck)

Check failure on line 241 in cmd/realm/triggers.go

View workflow job for this annotation

GitHub Actions / Build and Test (1.19.x, ubuntu-22.04)

expected ';', found '{'

Check failure on line 241 in cmd/realm/triggers.go

View workflow job for this annotation

GitHub Actions / Build and Test (1.20.x, ubuntu-22.04)

expected ';', found '{'

Check failure on line 241 in cmd/realm/triggers.go

View workflow job for this annotation

GitHub Actions / Build and Test (1.20.x, macos-latest)

expected ';', found '{'
if err = json.Unmarshal(triggerFile, &astarteTrigger); err != nil {
return err
}

if _, err := getTriggerDefinition(realm, astarteTrigger["name"].(string)); err != nil {
// The trigger does not exist
triggerToInstall = append(triggerToInstall, astarteTrigger)
triggersToInstall = append(triggersToInstall, astarteTrigger)
} else {
triggerToUpdate = append(triggerToUpdate, astarteTrigger)
triggersToUpdate = append(triggersToUpdate, astarteTrigger)
}

if len(triggerToInstall) == 0 && len(triggerToUpdate) == 0 {
if len(triggersToInstall) == 0 && len(triggersToUpdate) == 0 {
// All good in the hood
fmt.Println("Your realm is in sync with the provided triggers files")
return nil
Expand All @@ -257,22 +260,21 @@ func triggersSyncF(command *cobra.Command, args []string) error {
// Notify the user about what we're about to do
list := []string{}

for _, v := range triggerToInstall {
for _, v := range triggersToInstall {
list = append(list, v["name"].(string))
}

list_existing := []string{}

for _, v := range triggerToUpdate {
for _, v := range triggersToUpdate {
list_existing = append(list_existing, v["name"].(string))
}

// Start syncing.
fmt.Printf("The following triggers are invalid and thus will not be processed: %+q \n", invalidTriggers)

//install new triggers
if len(triggerToInstall) > 0 {
if len(triggersToInstall) > 0 {

fmt.Printf("\n")
fmt.Printf("The following new triggers will be installed: %+q \n", list)
fmt.Printf("\n")

Expand All @@ -281,52 +283,38 @@ func triggersSyncF(command *cobra.Command, args []string) error {
return nil
}

for _, v := range triggerToInstall {
for _, v := range triggersToInstall {
if err := installTrigger(realm, v); err != nil {
fmt.Fprintf(os.Stderr, "Could not install trigger %s: %s\n", v["name"].(string), err)
} else {
fmt.Printf("trigger %s installed successfully\n", v["name"].(string))
}
}

fmt.Printf("\n")

}

if len(triggerToUpdate) > 0 {

if len(triggersToUpdate) > 0 {
y, err := command.Flags().GetBool("force")
if err != nil {
return err
}

if y {
fmt.Printf("The following triggers already exists and WILL be DELETED and RECREATED: %+q \n", list_existing)
fmt.Printf("\n")
if ok, err := utils.AskForConfirmation("Do you want to continue?"); !ok || err != nil {
fmt.Printf("aborting")
return nil
}

for _, v := range triggerToUpdate {
for _, v := range triggersToUpdate {
if err := updateTrigger(realm, v["name"].(string), v); err != nil {
fmt.Fprintf(os.Stderr, "Could not update trigger %s: %s\n", v["name"].(string), err)
} else {
fmt.Printf("trigger %s updated successfully\n", v["name"].(string))
}
}
fmt.Printf("\n")
fmt.Printf("\n")

} else {

// Start syncing.
fmt.Printf("The following triggers already exists and WILL NOT be updated: %+q \n", list_existing)
fmt.Printf("\n")

}
}

return nil
}

Expand All @@ -351,7 +339,6 @@ func installTrigger(realm string, trigger map[string]interface{}) error {
}

func updateTrigger(realm string, triggername string, newtrig map[string]interface{}) error {

deleteTriggercall, err := astarteAPIClient.DeleteTrigger(realm, triggername)
if err != nil {
return err
Expand Down Expand Up @@ -407,8 +394,8 @@ func getTriggerDefinition(realm, triggerName string) (map[string]interface{}, er
return nil, err
}

// When we're here in the context of `interfaces sync`, the to-curl flag
// is always false (`interfaces sync` has no `--to-curl` flag)
// When we're here in the context of `trigger sync`, the to-curl flag
// is always false (`trigger sync` has no `--to-curl` flag)
// and thus the call will never exit unexpectedly
utils.MaybeCurlAndExit(getTriggerCall, astarteAPIClient)

Expand All @@ -423,3 +410,11 @@ func getTriggerDefinition(realm, triggerName string) (map[string]interface{}, er
triggerDefinition, _ := rawTRigger.(map[string]interface{})
return triggerDefinition, nil
}

func validateTrigger(path string) bool {
if _, err := triggers.ParseTriggerFrom(path); err != nil {
return false
} else {
return true
}
}

0 comments on commit 2f9c28b

Please sign in to comment.