Skip to content

Commit

Permalink
Handle meta-data commands that return multiple values.
Browse files Browse the repository at this point in the history
  • Loading branch information
brocaar committed Apr 1, 2020
1 parent 69d841f commit dd47e36
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 4 deletions.
9 changes: 9 additions & 0 deletions cmd/chirpstack-gateway-bridge/cmd/configfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,15 @@ marshaler="{{ .Integration.Marshaler }}"
# Max. execution duration.
max_execution_duration="{{ .MetaData.Dynamic.MaxExecutionDuration }}"
# Split delimiter.
#
# When the output of a command returns multiple lines, ChirpStack Gateway Bridge
# assumes multiple values are returned. In this case it will split by the given delimiter
# to obtain the key / value of each row. The key will be prefixed with the name of the
# configured command.
split_delimiter="{{ .MetaData.Dynamic.SplitDelimiter }}"
# Commands to execute.
#
# The value of the stdout will be used as the key value (string).
Expand Down
1 change: 1 addition & 0 deletions cmd/chirpstack-gateway-bridge/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func init() {

viper.SetDefault("integration.mqtt.auth.azure_iot_hub.sas_token_expiration", 24*time.Hour)

viper.SetDefault("meta_data.dynamic.split_delimiter", "=")
viper.SetDefault("meta_data.dynamic.execution_interval", time.Minute)
viper.SetDefault("meta_data.dynamic.max_execution_duration", time.Second)

Expand Down
9 changes: 9 additions & 0 deletions docs/content/install/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,15 @@ marshaler="protobuf"
# Max. execution duration.
max_execution_duration="1s"

# Split delimiter.
#
# When the output of a command returns multiple lines, ChirpStack Gateway Bridge
# assumes multiple values are returned. In this case it will split by the given delimiter
# to obtain the key / value of each row. The key will be prefixed with the name of the
# configured command.
split_delimiter="="


# Commands to execute.
#
# The value of the stdout will be used as the key value (string).
Expand Down
3 changes: 2 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,14 @@ type Config struct {
EndpointEnabled bool `mapstructure:"endpoint_enabled"`
Bind string `mapstructure:"bind"`
} `mapstructure:"prometheus"`
} `mapstructure:"metrics"`
} `mapstructure:"metrics"`

MetaData struct {
Static map[string]string `mapstructure:"static"`
Dynamic struct {
ExecutionInterval time.Duration `mapstructure:"execution_interval"`
MaxExecutionDuration time.Duration `mapstructure:"max_execution_duration"`
SplitDelimiter string `mapstructure:"split_delimiter"`
Commands map[string]string `mapstructure:"commands"`
} `mapstructure:"dynamic"`
} `mapstructure:"meta_data"`
Expand Down
24 changes: 21 additions & 3 deletions internal/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ var (
cmnds map[string]string
cached map[string]string

interval time.Duration
maxExecution time.Duration
interval time.Duration
maxExecution time.Duration
splitDelimiter string
)

// Setup configures the metadata package.
Expand All @@ -36,6 +37,7 @@ func Setup(conf config.Config) error {

interval = conf.MetaData.Dynamic.ExecutionInterval
maxExecution = conf.MetaData.Dynamic.MaxExecutionDuration
splitDelimiter = conf.MetaData.Dynamic.SplitDelimiter

go func() {
for {
Expand Down Expand Up @@ -71,7 +73,23 @@ func runCommands() {
continue
}

newKV[k] = out
if strings.Contains(out, "\n") {
rows := strings.Split(out, "\n")
for _, row := range rows {
kv := strings.Split(row, splitDelimiter)

This comment has been minimized.

Copy link
@bconway

bconway Apr 2, 2020

If this was changed to strings.SplitN(row, splitDelimiter, 2), it would support rows that included the delimiter. For examples:

equation=a+b=c
VERSION My Version 2

The following length check still works for cases where the delimiter isn't present.

This comment has been minimized.

Copy link
@brocaar

brocaar Apr 3, 2020

Author Collaborator

Good point, see: 3c546d1

if len(kv) != 2 {
log.WithFields(log.Fields{
"row": row,
"split_delimiter": splitDelimiter,
}).Warning("metadata: can not split output in key / value")
} else {
newKV[k+"_"+kv[0]] = kv[1]
}
}

} else {
newKV[k] = out
}
}

mux.Lock()
Expand Down
11 changes: 11 additions & 0 deletions internal/metadata/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,20 @@ func TestMetaData(t *testing.T) {
"bar": "test2",
},
},
{
Name: "command returns multiple rows",
Commands: map[string]string{
"bar": `echo -e "foo=bar\nalice=bob"`,
},
Expected: map[string]string{
"bar_foo": "bar",
"bar_alice": "bob",
},
},
}

maxExecution = time.Second
splitDelimiter = "="

for _, tst := range tests {
t.Run(tst.Name, func(t *testing.T) {
Expand Down

0 comments on commit dd47e36

Please sign in to comment.